[압량(Amnyang)] #4. 키 입력을 받아 2D 캐릭터 좌우 이동 구현하기

2022. 1. 22. 00:21Projects/Amnyang

 

 

 

Walk 애니메이션도 생겼겠다. 이제 캐릭터 좌우 이동을 구현할 차례다. 2D 게임이긴 하지만, 지금 개발하는 게임은 상하 이동은 요구되지 않는다. 그래서 간단하게 좌우 이동만 먼저 구현해보기로 했다.

 

  • Rigidbody 2D의 Velocity(속도)를 통해 좌우 이동 구현
  • Walk, Idle 애니메이션을 적절한 타이밍에 사용해주기
  • Transform의 Scale의 X 값의 부호를 바꿔서 캐릭터가 바라보는 방향 전환 구현
 
 

1. 키 입력 받기

 

Girl Controller라는 스크립트를 하나 만들어서 Character 오브젝트에 부착해줬다.

 

역시, 다 만들고 글을 쓰니 순서가 조금 엉망이다.

 

키 입력은 유니티에서 제공하는 Input.GetAxisRaw() 함수를 사용하여 받을 계획이다.

Input.GetAxisRaw("Horizontal")로 매개변수로 주면 다음과 같이 값을 리턴 해준다.

  • A키 또는 왼쪽 화살표 키를 누르면 -1 리턴
  • D키 또는 오른쪽 화살표 키를 누르면 1 리턴
  • 키 입력이 없으면 0 리턴

 

 

다음과 같이 멤버 변수로 선언한 변수에 키 입력 리턴 값을 저장해둘 것이다.

private float walkDirection;


void Update()
{
   walkDirection = Input.GetAxisRaw("Horizontal");
}

 

Rigidbody 컴포넌트를 통한 물리 기반으로 움직임을 구현할 것이기 때문에 키 입력을 Update() 함수에서 받았다.

 

 

 

2. 좌우 이동 구현하기

 

실제로 물리 기반 로직이 이루어지는 부분, 즉 이동이 직접적으로 구현되어지는 부분은 FixedUpdate() 함수에서 처리했다. 키 입력으로 받았던 "walkDirection" 값은 -1, 0, 1 값 중 하나이기 때문에 단위 벡터값으로 사용해도 된다.

여기에 속도 제어를 처리할 변수 "walkSpeed"를 곱해서 캐릭터의 이동속도를 조절했다.

public float walkSpeed;
private float walkDirection;
private Rigidbody2D _rigidBody;
...


void Start()
{
   _rigidBody = GetComponent<Rigidbody2D>();
   ...
}

void FixedUpdate()
{
   Walk();
}

private void Walk()
{
   bool hasControl = !Mathf.Approximately(walkDirection, 0f); // 애니메이션 처리에서 사용할 예정
   _rigidBody.velocity = new Vector2(walkDirection * walkSpeed, _rigidBody.velocity.y);
}

 

이렇게 작성했으니, 좌우 이동은 우선 구현이 됐다.

 

캐릭터 좌우 이동(방향전환, 애니메이션 적용 전)

 

하지만, 영상을 보면 알겠지만 아직 "Walk" 애니메이션을 적용해주지 않아, 가만히 서서 걷는 모습을 취하고 있고

이동 방향을 전환했을 때, 캐릭터도 반대로 돌아보지 않는 점이 아쉽다.

하나씩 차근차근 해결했다. 우선 애니메이션 부분부터 처리했다.

 

 

 

3. Walk 애니메이션 적용해주기

 

저번 글에서 말했지만, 현재 주인공 캐릭터는 "Character"라는 빈 게임 오브젝트가 최상단 부모 오브젝트이고,

그 밑에 "Girl"이라는 실제 캐릭터 오브젝트가 있다.

 

계층 구조가 현재 이런 식으로 되어 있다.

 

현재 Girl Controller 스크립트는 "Character" 오브젝트에, 애니메이터는 "Girl" 오브젝트에 부착되어 있는 상황이다.

그래서 GetComponentInChildren() 함수를 사용해서 자식에 붙어있는 애니메이터 컴포넌트를 담아올 계획이다.

public float walkSpeed;
private float walkDirection;
private Rigidbody2D _rigidBody;
private Animator animator;

void Start()
{
    _rigidBody = GetComponent<Rigidbody2D>();
    animator = GetComponentInChildren<Animator>();  // 추가
}

void FixedUpdate()
{
    Walk();
}

private void Walk()
{
    bool hasControl = !Mathf.Approximately(walkDirection, 0f);
    animator.SetBool("Walk", hasControl);           // 추가
    _rigidBody.velocity = new Vector2(walkDirection * walkSpeed, _rigidBody.velocity.y);
}

 

키 입력이 있다면 "Idle" → "Walk"로 상태 전이가 일어나고, 키 입력이 없다면 다시 "Walk" → "Idle"이 될 것이다.

 

캐릭터 좌우 이동(방향전환 구현 전)

 

캐릭터가 바닥에서 조금 미끄러지듯 걸어서, 애니메이션 재생 속도캐릭터의 이동 속도를 조절해줬다.

이제 마지막으로 캐릭터가 보는 방향 전환 구현만 남았다.

 

 

 

4. 캐릭터가 바라보는 방향 전환 구현하기

 

본 블로그의 Unity 카테고리에서 2D 캐릭터가 바라보는 방향 전환에 대한 글을 다룬 적이 있었다. 본인은 Transform의 Scale의 X 값의 부호를 바꿔주는 방법을 통해 구현해줬다.

 

초기 Transform.Scale.x의 값을 저장해두고, 이 값과 단위 벡터로 활용할 수 있는 "walkDirection" 값을 곱한 값이 다르다면 방향 전환을 해주는 방식을 생각했고, 이대로 적용했다.

public float walkSpeed;
public Transform girlTransform;  // Transform은 왜 GetComponentInChildren이 적용되지 않을까?
private Rigidbody2D _rigidBody;
private Animator animator;
private float walkDirection;
private float initScaleX;        // 추가


void Start()
{
    _rigidBody = GetComponent<Rigidbody2D>();
    animator = GetComponentInChildren<Animator>();
    initScaleX = girlTransform.localScale.x;    // 추가
}

void FixedUpdate()
{
    Walk();
}

private void Walk()
{
    bool hasControl = !Mathf.Approximately(walkDirection, 0f);
    TurnOtherSide(hasControl);                // 추가
    
    animator.SetBool("Walk", hasControl);
    _rigidBody.velocity = new Vector2(walkDirection * walkSpeed, _rigidBody.velocity.y);
}


private void TurnOtherSide(bool hasControl)  // 추가
{
    if (!hasControl)
       return;

    var scaleX = girlTransform.localScale.x;
    if (Mathf.Approximately(walkDirection * scaleX, initScaleX))
       return;
       
    var scaleY = girlTransform.localScale.y;
    var scaleZ = girlTransform.localScale.z;
    
    // 코드가 너무 길어져서, 가독성을 위해 변수에 담았다.
    girlTransform.localScale = new Vector3(-scaleX, scaleY, scaleZ);
}

 

이렇게 함으로써, 최종적으로 캐릭터 좌우 이동이 구현 완료되었다.

 

캐릭터 좌우 이동 구현 완료

 

이 외에도 달리기, 상호작용, 점프, 숨기 정도의 애니메이션이 더 있는데 언제 또 만들지,,, 천천히 빠르게 해보자,,,ㅎㅎㅎ

혹시 몰라 도움이 필요하실 분들을 위해 전체 소스코드 아래에 첨부하겠습니다.

더보기

"Girl Controller" 전체 소스코드

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GirlController : MonoBehaviour
{

    public float walkSpeed;

    private Animator animator;
    private SpriteRenderer[] _sprite;
    public Transform girlTransform;
    private Rigidbody2D _rigidBody;
    private float walkDirection;
    private float initScaleX;

    void Start()
    {
        _rigidBody = GetComponent<Rigidbody2D>();
        //girlTransform = GetComponentInChildren<Transform>();  // Transform은 적용이 안 되네?
        _sprite = GetComponentsInChildren<SpriteRenderer>();
        animator = GetComponentInChildren<Animator>();          
        initScaleX = girlTransform.localScale.x;
    }

    void Update()
    {
        walkDirection = Input.GetAxisRaw("Horizontal");
    }


    void FixedUpdate()
    {
        Walk();
    }

    private void Walk()
    {
        bool hasControl = !Mathf.Approximately(walkDirection, 0f);
        TurnOtherSide(hasControl);
        animator.SetBool("Walk", hasControl);
        _rigidBody.velocity = new Vector2(walkDirection * walkSpeed, _rigidBody.velocity.y);
    }


    private void TurnOtherSide(bool hasControl)
    {
        if (!hasControl)
            return;

        var scaleX = girlTransform.localScale.x;
        if (Mathf.Approximately(walkDirection * scaleX, initScaleX))
            return;

        var scaleY = girlTransform.localScale.y;
        var scaleZ = girlTransform.localScale.z;

        girlTransform.localScale = new Vector3(-scaleX, scaleY, scaleZ);
    }
}

 

 

728x90
반응형