최근에 디자인패턴 책을 보며 공부를 시작했다
결과물만 나오면 장땡일 수준은 한참 지났으니까 구조에 대해서도 공부를 제대로 해야겠다라는 마음으로.
그래서 한번 배운거 써먹어보기위해 캐릭터 입력 구조를 개선해보기로 했다
먼저, 기존의 구조를 보면
키 입력 여부를 관리하는 PlayerInputKey 클래스를 만들어놓고, 캐릭터 행동을 구현해놓은 클래스에서 접근해가지고 그에따라 처리하도록 되어있다
대충 그려보자면 대충 이런식으로 접근하고 있는데,
그럼 이걸 어떻게 바꿀 것이냐
그림을 좀 난잡하게 그리긴 했는데 암튼...
컨트롤러를 아예 캐릭터랑 분리시킨 후, 키를 누르면 컨트롤러에 들어있는 액터에게 명령을 내리는 식으로 바꿀 예정.
이렇게 되면 액터를 상속받은 다른 캐릭터 조작을 만들때도 편하다고 책에서 그러더라
근데 책에서는 pressed 만 한다는 가정을 깔아놓고 예제가 만들어져 있었다
하지만 모든 액터의 행동들이 반드시 pressed만 필요로 할 리는 절대 없을 것이다
즉, pressed, hold, released 모두를 지원해야된다는 건데...
캐릭터 쪽에서는 그런거 일일이 신경안쓰고 인터페이스 구현만 하면 되게끔 만들고싶단 말이지
근데 또 그렇게 되면 'pressed, hold, released 했을 경우' 를 키마다 전부 컨트롤러랑 액터에서 일일이 만들어줘야된다는 점이 굉장히 마음에 안든다
뭔가 다른 방법이 있을것이다
그냥 액터에서 행동 인자값을 강제해버리면 되지않을까?
컨트롤러에서 액터한테 명령을 내릴때 인트값 하나를 보내서
0 = pressed, 1 = hold, 2 = released
이런 식으로 처리를 하게끔 만들면 어떨까
아싸리 열거형으로 만들어도 되고
그럼 이방식으로 만들어봐야겠다
아싸리 이럴거면 글에서 꺼내지 않은 이동키 관련 문제도 따로 벡터를 받기로 하자
아근데 다시생각해보니까 컨트롤러에선 pressed, hold, released 다 따로만들어야되는건 똑같네
그냥 액터 내부 지저분해지는거 막은걸로 만족해야겠다
먼저 컨트롤러부터 만들기로 했다
만드는 중에 키 입력 관련해서 굉장히 반복적이라는 걸 발견했다
void CheckDodgeKey()
{
if (Input.GetKeyDown(_keyDodge)) _useActor.OnDodge(InputState.PRESSED);
if (Input.GetKey(_keyDodge)) _useActor.OnDodge(InputState.HOLD);
if (Input.GetKeyUp(_keyDodge)) _useActor.OnDodge(InputState.RELEASED);
}
컨트롤러에서 만든 회피 키 입력에 대한 부분이다
보면 조건에 들어가는 키코드와 참일 경우 실행하는 메소드가 셋 다 동일하다
이걸 인자로 뺀다면 각 키마다 함수를 만들어야하는 노가다를 안해도 된다는 생각에 바로 아래 코드로 고쳤다
void CheckActionKey(KeyCode key, Action<InputState> inputAction)
{
if (Input.GetKeyDown(key)) inputAction(InputState.PRESSED);
if (Input.GetKey(key)) inputAction(InputState.HOLD);
if (Input.GetKeyUp(key)) inputAction(InputState.RELEASED);
}
이렇게 써놓으면 이제 키와 해당 행동에 대한 메소드만 액션으로 넣어주면 키 입력 체크가 가능하다
void Update()
{
CheckMoveDirection();
CheckActionKey(_keyNormalAtk, _useActor.OnNormalAtk);
CheckActionKey(_keyDodge, _useActor.OnDodge);
}
엄청 간결해져서 조작키를 추가하게 되도 부담이 없게 되었다
public class ActorController : MonoBehaviour
{
public enum InputState
{
PRESSED,
HOLD,
RELEASED
};
[SerializeField] Actor _useActor;
[Header("Move Key")]
[SerializeField] KeyCode _left;
[SerializeField] KeyCode _right;
[SerializeField] KeyCode _front;
[SerializeField] KeyCode _back;
[Header("Action Key")]
[SerializeField] KeyCode _keyNormalAtk;
[SerializeField] KeyCode _keyDodge;
void Update()
{
CheckMoveDirection();
CheckActionKey(_keyNormalAtk, _useActor.OnNormalAtk);
CheckActionKey(_keyDodge, _useActor.OnDodge);
}
void CheckMoveDirection()
{
int a = 0, b = 0, c = 0, d = 0;
a = Input.GetKey(_left) ? 1 : 0;
b = Input.GetKey(_right) ? 1 : 0;
c = Input.GetKey(_front) ? 1 : 0;
d = Input.GetKey(_back) ? 1 : 0;
Vector3 result = new Vector3(b - a, 0.0f, c - d);
_useActor.MovingCheck(result);
}
void CheckActionKey(KeyCode key, Action<InputState> inputAction)
{
if (Input.GetKeyDown(key)) inputAction(InputState.PRESSED);
if (Input.GetKey(key)) inputAction(InputState.HOLD);
if (Input.GetKeyUp(key)) inputAction(InputState.RELEASED);
}
}
최종 코드는 이렇다
이제 조작키에 해당하는 가상함수를 액터에 만들어준다
public class Actor : MonoBehaviour
{
public virtual void MovingCheck(Vector3 moveDir) { }
public virtual void OnNormalAtk(ActorController.InputState state) { }
public virtual void OnDodge(ActorController.InputState state) { }
}
abstract가 아닌 virtual로 만든 이유는 모든 액터가 반드시 모든 행동을 다 할 수 있을거란 보장이 없기 때문이다
예를 들어, 포탑 액터를 조종한다고 치자
포탑은 한 곳에 박혀있기 때문에(그렇게 만드려고 의도했기 때문에) 굳이 MovingCheck가 필요하지 않다
하지만 컨트롤러는 내가 지금 조종하는 액터의 이동가능여부를 체크하지 않고 함수를 호출한다.
이게 virtual 함수라면 그냥 냅두면 되지만 abstract라면 상속받은 포탑 클래스에서 굳이 필요하지 않은 이동 함수를 구현을 해줘야한다(아무런 처리내용이 없다 하더라도)
이게 지금처럼 조작키가 적으면 모를까, 10개가 넘어가는데 새로 만들 캐릭터는 그중 2개의 키만 사용한다고 하면 사용하지도 않는 8개의 함수를 정의해줘야 하는 귀찮음에 시달려야 한다
그래서 virtaul로 만들었다
솔직히 액터에 뭐 더 붙여야 할 것도 같지만 일단은 그냥 키입력 구조만 교체하는거니까 나머지는 진행하면서 추가할 생각이다.
이제 기존의 캐릭터 클래스를 수정해야한다
FSM 구조를 포함해서.
위에 사진은 캐릭터매니저 클래스고, 아래는 각 상태 만들때 상속받아서 쓰는 BaseActioin 클래스다
캐릭터매니저에서는 액터를 상속받아서 키 입력받았다는 내용으로 인터페이스를 구현해주려하고,
키 입력 정보를 현재 상태에 맞는 상태액션에 전달할 수 있도록 BaseAction에다가 CheckInputKeys 를 추가해주었다
일단은 이렇게 틀만 잡아놓고 포스팅을 끝내야겠다
나머지는 자고일어나서 해야지
벌써 5시반이네
'플밍' 카테고리의 다른 글
유니티 액션겜 개발일지 - 공격 구현 진행중 (5) | 2021.05.05 |
---|---|
유니티 액션겜 개발일지 - 캐릭터 컨트롤러 구조개선(2) (0) | 2021.04.28 |
유니티 커스텀에디터 알아보는 글 - 1 (0) | 2021.01.07 |
PUN2 - OnRoomListUpdate (0) | 2020.09.30 |
리듬겜 프로토 제작일기 - 7 (0) | 2020.08.23 |