[Unity] 플레이어 이동 - 2D

이정석·2023년 8월 25일
0

Unity

목록 보기
17/22

Player

1. 격자이동

게임의 이동방식중에 격자이동을 하는 게임이 있는데 예를들면 포켓몬스터-골드쯔끄루 게임과 같은 2D게임이 있다. 격자이동의 예시는 아래그림과 같다.

위 그림이 격자이동을 나타낸 그림이고 아래그림이 격자이동이 아닌 그림을 나타낸 그림이다. 격자이동은 각 Cell의 좌표번호로 나타낼 수 있다. 즉, 특정 방향으로 이동할 때 일정거리씩 움직여야 한다.

격자이동을 구현하기 위해 이동과정을 크게 세부분으로 나눌 수 있다.

  1. 입력
  2. 목표좌표설정
  3. 이동처리

입력단계는 이동을 위한 입력(키보드, 마우스)을 입력받는 단계로 입력을 받으면 바로 움직이는 것이 아닌 이동하는 방향을 설정한다.

    Vector3Int _cellPos = Vector3Int.zero;
    bool _isMoving = false;
    MoveDir _dir = MoveDir.Down
    
    if (Input.GetKey(KeyCode.W))
    {
        Dir = MoveDir.Up;
    }
    else if (Input.GetKey(KeyCode.S))
    {
        Dir = MoveDir.Down;
    }
    else if (Input.GetKey(KeyCode.A))
    {
        Dir = MoveDir.Left;
    }
    else if (Input.GetKey(KeyCode.D))
    {
        Dir = MoveDir.Right;
    }
    else
    {
        Dir = MoveDir.None;
    }

목표좌표설정단계는 설정된 이동방향에 따라 캐릭터가 이동하고자 하는 좌표를 설정하는 단계로 좌표를 설정하면 이동상태를 변화시켜 이동이 완료되기전까지 좌표를 변경할 수 없도록한다.

    if (_ismoving == false)
    {
        switch (_dir)
        {
            case movedir.up:
                _cellpos += vector3int.up;
                _ismoving = true;
                break;
            case movedir.down:
                _cellpos += vector3int.down;
                _ismoving = true;
                break;
            case movedir.left:
                _cellpos += vector3int.left;
                _ismoving = true;
                break;
            case movedir.right:
                _cellpos += vector3int.right;
                _ismoving = true;
                break;
        }
    }

이동처리단계는 실제 이동을 하는 단계로 남은거리와 속도를 감안해 최종적인 이동을 처리한다. 주의해야 할 점은 프레임사이의 이동하는 거리가 남은거리보다 클 경우에는 좌표를 고정시키고 이동을 멈추는 작업이 포함되야한다.

    if (_isMoving == false)
        return;

    Vector3 destPos = Managers.Map.CurrentGrid.CellToWorld(_cellPos) + new Vector3(0.5f, 0.5f);
    Vector3 moveDir = destPos - transform.position;

    float dist = moveDir.magnitude;

    if (dist < _speed * Time.deltaTime)
    {
        transform.position = destPos;
        _isMoving = false;
    }
    else
    {
        transform.position += moveDir.normalized * _speed * Time.deltaTime;
        _isMoving = true;
    }

2. Sprite

Sprite는 2D 이미지를 표현하는데 사용되며, 여러 Sprite들을 연속으로 표현하여 애니메이션 효과를 나타낼 수 있다. 플레이어의 움직임, 공격 모션 등 게임 내에서 다양한 애니메이션을 표현하는 데 사용할 수 있고 Animator 클래스를 통해 Sprite 애니메이션을 제어한다.

	Animator _animator;
	_animator.Play("WALK_BACK");

3. 충돌

캐릭터가 벽이나 건물과 같이 이동할 수 없는 위치에 있으면 안되기 때문에 충돌개념이 필요하다. 2D에도 3D와 같이 Collider 컴포넌트가 존재한다. 하지만 건물입구와 같이 특정 위치는 충돌판정이 필요하지 않은 경우에는 Collider를 사용하기 어렵다.

아이디어는 보이지않는 Collision Layer를 설정하는 것이다. 맵을 좌표로 나타낼 수 있다는 것은 N차원 배열로 충돌영역을 저장할 수 있고 만약 이동하고자하는 위치가 충돌영역에 해당한다면 이동을 하지 않는 방식으로 구현할 수 있다.

실제 게임에서는 Conllision Layer를 비활성화 시켜 보이지는 않지만 코드상에서는 데이터를 가져오는 방식으로 구현할 수 있으며 맵을 불러올때마다 모든 영역을 탐색하는 방법도 있지만 충돌영역만 txt파일로 저장해놓는것도 하나의 방법이 될 수 있다.

    bool[,] _collision;

    public bool CanGo(Vector3Int cellPos)
    {
        if (cellPos.x < MinX || cellPos.y > MaxX)
            return false;
        if (cellPos.y < MinY || cellPos.x > MaxY)
            return false;

        int x = cellPos.x - MinX;
        int y = MaxY - cellPos.y;
        return !_collision[y, x];
    }

4. 카메라

3D와 달리 2D는 축이 하나 없기 때문에 바로 카메라의 position을 설정해도 된다.

    Camera.main.transform.position = new Vector3(transform.position.x, transform.position.y, -10);

3D 카메라에서 World좌표 시점고정에 대해서 언급한적이 있다.

profile
게임 개발자가 되고 싶은 한 소?년

0개의 댓글