서론
- 고1때 만들었던 게임 리팩토링입니다.
- 코드가 너무 난해해서 사실상 다시 만드는 수준으로 하고 있습니다.
- 스프라이트, 음악 파일등은 전 게임에서 그대로 따오고 코드만 갈아엎는 방식으로 진행하고 있습니다.
-> 스크립트도 복잡하고 스프라이트도 정리가 되어 있지 않은 모습
1. 플레이어 이동
1.1. 기존 이동 방식
- 대각선 이동이 제한된 수직,수평 이동 방식
- InputManager를 활용(ex : Input.GetAxis())
- 조작감 향상을 위해 키 2개를 동시에 누르는 경우, 나중에 누른 키를 기준으로 이동할 수 있도록 설계했으나, 실제로는 수직이동에서만 적용되고, 수평이동에서는 적용되지 않았음.
기존 코드
void Move() {
Ar_x = Input.GetAxisRaw("Horizontal");
bool isMovingHorizontal = Mathf.Abs(Ar_x) > 0.5f;
Ar_y = Input.GetAxisRaw("Vertical");
bool isMovingVertical = Mathf.Abs(Ar_y) > 0.5f;
bool wasMovingVertical = true;
if (isMovingHorizontal && isMovingVertical) { //두개의 버튼이 눌린 경우
if (wasMovingVertical) {
rigid.velocity = new Vector2(Ar_x * speed, 0); //수평이동
lastMove = new Vector2(Ar_x, 0f);
Ar_y = 0; //
} else {
rigid.velocity = new Vector2(0f, Ar_y * speed); // 수직이동
Ar_x = 0; //
}
} else if (isMovingHorizontal) {
rigid.velocity = new Vector2(Ar_x * speed, 0f);
wasMovingVertical = false;
lastMove = new Vector2(0f, Ar_x);
Ar_y = 0; //
} else if (isMovingVertical) {
rigid.velocity = new Vector2(0, Ar_y * speed);
wasMovingVertical = true;
lastMove = new Vector2(0f, Ar_y);
Ar_x = 0; //
} else {
rigid.velocity = Vector2.zero;
}
}
1.2. 수정 방향
- InputSystem을 활용 (ex : OnMove())
- 조작감 향상을 위해 키 2개를 누르는 경우엔 나중에 누른 키를 기준으로 이동하는 시스템 구성
1.3. 해결 과정
1.3.2. 조작감 향상을 위한 코드 설계
변경 코드
public void OnMove(InputValue value)
{
inputVec = value.Get<Vector2>();
/*입력받은 벡터의 x,y값 크기를 1로 보정*/
if (inputVec.x != 0)
inputVec.x = inputVec.x > 0 ? 1 : -1;
if (inputVec.y != 0)
inputVec.y = inputVec.y > 0 ? 1 : -1;
if (Mathf.Abs(inputVec.x + inputVec.y) == 1) // 키 하나만 입력
{
dir = inputVec;
preVec = dir;
}
else if (inputVec.x == 0 && inputVec.y == 0) // 입력이 없으면
dir = Vector2.zero;
else if (preVec != inputVec) // 2개의 키를 입력할 때
{
preVec = inputVec - preVec;
dir = preVec;
}
}
private void Update()
{
rigid.MovePosition(rigid.position + dir * speed * Time.deltaTime);
rigid.velocity = Vector2.zero;
}
2. 플레이어 애니메이션
2.1. 기존 애니메이션
- 애니메이터의 구성이 복잡해서 한번에 보기 힘들었음.
- 애니메이터의 구조적 문제로 인해 왼쪽에서 오른쪽으로 이동할 때 필연적으로 디폴트값, 정면을 바라보는 애니메이션을 거쳐가야 했기에 부자연스러운 부분 존재.
- 애니메이션 전환에 사용되는 Parameter가 직관적이지 않음.
- Parameter가 직관적이지 않으므로 애니메이션 구현 코드도 복잡함.
if (Ar_x == 0 && Ar_y == 1) {
anim.SetInteger("Direction", 1);
anim.SetBool("Move", true);
direction = 3;
} else if (Ar_x == 1 && Ar_y == 0) {
anim.SetInteger("Direction", 2);
anim.SetBool("Move", true);
direction = 2;
} else if (Ar_x == 0 && Ar_y == -1) {
anim.SetInteger("Direction", 3);
anim.SetBool("Move", true);
direction = 1;
} else if (Ar_x == -1 && Ar_y == 0) {
anim.SetInteger("Direction", 4);
anim.SetBool("Move", true);
direction = 0;
}
if ((Input.GetKeyDown(KeyCode.R) || b_fire) && !fired && firework_Count > 0) // 폭죽 발사 코드
{
Instantiate(firework, transform.position, Quaternion.Euler(0, 0, 90 * direction));
fired = true;
firework_Count -= 1;
b_fire = false;
}
if (Ar_x == 0 && Ar_y == 0)
{
anim.SetBool("Move", false);
anim.SetInteger("Direction", 0);
isMove = false;
}
else
isMove = true;
2.2. 수정 방향
2.3. 해결 과정
- Parameter를 DirX, DirY, IsMove로 직관화
- 블렌더 트리를 활용해서 애니메이션 정리
애니메이터 구조
블렌더 트리 내부
- InputSystem의 값을 기반으로 코드 설계
private void Animate() // animDir : 플레이어가 바라보는 방향 벡터
{
if (dir.x != 0 || dir.y != 0) // 플레이어가 움직이는 경우
{
animDir = dir;
anim.SetBool("IsMove", true);
}
else
anim.SetBool("IsMove", false);
anim.SetFloat("DirX", animDir.x);
anim.SetFloat("DirY", animDir.y);
}