2022. 2. 6. 17:24ㆍProjects/Amnyang
점프를 구현하기 전에 우선 점프 조작에 대한 컨셉을 확실히 잡고 가야할 것 같았다. 점프 중 좌우 이동이 가능한지, 아니면 점프를 진행한 방향으로만 이동이 가능한지 등에 대한 확실한 기획이 필요했다. 의논해본 결과, 배틀그라운드 게임처럼의 조작감을 생각하면 될 것 같다고 했다. 즉, 요구사항은 다음과 같았다.
- 제자리 점프일 경우, 좌우 이동 불가
- 이동 중 점프할 경우, 포물선 궤도를 그리며 점프
- 점프 중엔 반대 방향으로 돌아보는 모션 불가
- 점프 후 착지 시 약간의 경직이 있음
일단 만들기 전, 기획자와 얘기를 하며 의논한 부분은 위와 같다. 제자리 점프, 이동 중 점프, 착지 모션 이렇게 3개가 필요할 것 같다. 글이 길어질 것 같기에, 이 글에서는 제자리 점프와 착지 애니메이션을 통한 제자리 점프 내용만 작성했다.
1. 제자리 점프(Sargent Jump) 애니메이션 만들기
구글에 "Jump Motion"이라고 검색해서 나온 자료 및 Mixamo 사이트에서 비슷한 애니메이션을 찾아보며 참고했다.
제자리 점프 특성상 무릎을 접었다가 피는 차징(Charging) 동작이 있기 때문에 조금 까다로웠다.
뛰어 오르는 동작까지만 구현했다. 떨어지는 모션이 없기 때문에 마지막 40 프레임일 때의 모습으로 바닥까지 떨어진다.
바닥에 떨어졌다면, 착지 모션을 재생해주면 될 것이다.
주의사항
애니메이션 클립을 제작할 때, 최상단 루트에 있는 게임 오브젝트의 트랜스폼 값을 변경시키면 안 된다.
작업하다가 실수한 부분이기에, 이 글을 보시는 분들께서는 잘 해결하셨으면 하는 바람에 적는다.
스크립트에서 제어하지 않는 오브젝트는 애니메이션에서 트랜스폼을 건드려도 상관없다. 하지만, 스크립트(Script)에서 움직임을 제어하는 게임 오브젝트에 대해서 애니메이션에서도 트랜스폼을 건드려버리면, 두 컴포넌트가 싸우게 된다. 즉, 비정상적인 이상한 움직임이 포착될 수 있다.
지구를 공전하고 있는 달을 가진 채로 이리저리 움직이는 지구를 생각해보면 좋은 예시일 것 같다. 지구 움직임은 스크립트를 통해 제어하지만, 달의 공전은 스크립트로 제어하지 않고 애니메이션으로 제어하기 때문에 서로 문제가 되지 않는다.
이런 상황에 애니메이션이 지구의 움직임까지 제어를 해버린다면, 당연히 스크립트와 애니메이션이 서로 싸우게 되며 이상한 움직임이 포착될 것이다.
2. 착지(Landing) 애니메이션 만들기
제자리 점프 애니메이션을 만들었다면, 착지는 정말 쉽다. 제자리 점프 애니메이션에서 무릎을 접은 상태와 처음 일어서있던 자세의 키 프레임을 복사해와서 붙이면 끝이다.
3. 애니메이터 설정하기
고민을 정말 많이 해본 파트가 여기였다. 처음에는 블렌드 트리(Blend Tree)를 사용해서 값에 따라 제자리 점프, 이동 중 점프, 착지 이렇게 필요에 따라 해당 애니메이션으로 전환되도록 할까 했다.
그런데, 착지 애니메이션이 왜인지는 모르겠으나 제대로 작동하지 않아서 이 방법은 일단 보류했다. 본 게임에서 그리 많은 동작을 요구하지 않기에 그냥 일반적인 방법으로 우선 구현했다. 나중에 서브 스테이트 머신(Sub StateMachine)을 하나 만들어서 안에 다 넣어서 정리해도 좋을 것 같긴하다.
Move → Suji_SargentJump 전환은,
이동 중 바로 전환이 될 수 있도록 Has Exit Time을 꺼주고, 전환에 걸리는 시간없이 바로 두 애니메이션을 겹쳐줬다.
트랜지션 조건은 "Jump"가 True일 때로 설정해줬다.
Suji_SargentJump → Suji_Landing 전환에도 Has Exit Time을 꺼주고, 바로 전환되면 안 되니 조금의 전환 텀을 줬다.
트랜지션 조건은 "Landing" Trigger로 줬다.
Suji_Landing → Move 전환은 Has Exit Time을 꺼주고, 착지 애니메이션이 거의 다 재생된 후에 전환되도록 겹쳐줬다.
트랜지션 조건으로 "Jump"가 False일 때로 설정해줬다.
4. 스크립트 작성하기
점프 로직은 다음과 같이 구성했다. 키 입력은 Update() 함수에서, 실제 로직은 FixedUpdate() 함수에서 구현하고 싶었으나, 프레임 차이인진 몰라도 키가 잘 안 먹는 현상이 발생해서 Update()에서 다 구현했다.
private const float JUMP_CHARGING_DELAY = 0.55f;
private bool isJumping;
void Update()
{
walkDirection = Input.GetAxisRaw("Horizontal");
hasControl = !Mathf.Approximately(walkDirection, 0f);
isRunning = Input.GetButton("Run");
if(Input.GetButtonDown("Jump") && !isJumping)
{
Jump();
}
}
private void Jump()
{
isJumping = true;
if (!hasControl)
{
animator.SetBool("Jump", true);
Invoke("_Jump", JUMP_CHARGING_DELAY);
}
}
private void _Jump()
{
_rigidBody.AddForce(Vector2.up * jumpPower, ForceMode2D.Impulse);
}
점프 중에는 이동 키 입력이 먹히지 않도록 설정해줬다.
private void Move()
{
if (isJumping) // 추가
return;
....
}
점프 중에도 방향 전환이 되지 않도록 설정해줬다.
private void TurnOtherSide()
{
if (!hasControl || isJumping) // 추가
return;
...
}
착지 및 점프 가능 상태로 만드는 로직은 OnCollisionEnter2D() 메서드를 사용했다. 콜라이더를 부착한 임시 바닥을 씬에 생성해놓고, "Jumpable_Floor"라는 레이어를 하나 만들어서 해당 바닥에 설정해줬다.
private void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.layer == LayerMask.NameToLayer("Jumpable_Floor") && isJumping)
{
// 우선 임시적으로 이렇게 구현
animator.SetTrigger("Landing");
animator.SetBool("Jump", false);
isJumping = false;
}
}
이로써, 제자리 점프를 구현하는 것을 완료했다.
'Projects > Amnyang' 카테고리의 다른 글
[압량(Amnyang)] #9. 2D 게임 배경 간단히 배치 및 카메라 추적 이동 구현하기 (0) | 2022.02.13 |
---|---|
[압량(Amnyang)] #8. 2D 주인공 이동 중 점프(Move Jump), 착지 후 경직 딜레이 구현하기 (0) | 2022.02.07 |
[압량(Amnyang)] #6. 2D 주인공 캐릭터 달리기(Run) 애니메이션 추가하기 (0) | 2022.02.05 |
[압량(Amnyang)] #5. 2D에서 Y축 회전을 통한 문 열리고 닫는 효과 구현하기 (0) | 2022.01.22 |
[압량(Amnyang)] #4. 키 입력을 받아 2D 캐릭터 좌우 이동 구현하기 (0) | 2022.01.22 |