2 분 소요

점프구현 && 점프 애니메이션 추가


이번 포스팅에서는 캐릭터의 점프와 점프하는 애니메이션을 추가할 것입니다.

점프


점프를 추가하는것은 간단합니다. 먼저, PlayerControl 스크립트를 열어서 jumpPower 라는 변수를 하나 선언해줍니다. 그리고 Update 함수에서 다음 코드를 넣어줍니다.

 public float jumpPower;
//점프
        if (Input.GetButtonDown("Jump"))
        {
            rigid.AddForce(Vector2.up * jumpPower, ForceMode2D.Impulse);
        }


코드 두줄로 점프를 간단하게 구현할 수 있습니다. Jump버튼은 스페이스바입니다. 이제 Player를 클릭하여 Inspector에서 jumpPower를 원하는대로 설정해줍니다. 게임을 시작하고 스페이스바를 눌러보면 점프가 되는것을 확인할 수 있습니다. 하지만 조금 이상한것을 느끼셨을겁니다.

Player의 Rigid Body를 보면 Gravity Scale이 있습니다. 이것은 중력인데, 2정도로 수정해줍니다. 이제 다시 점프를해보면 좀더 자연스러운 점프가 되었을겁니다.

점프애니메이션


저번 포스팅에서 했던것처럼 점프 애니메이션도 추가해줍니다. 점프 애니메이션은 반복하면 이상하므로 Loop는 체크해제해줍니다. 그리고 Animator를 열어 Bool타입의 isJumping 파라미터를 만들어줍니다.

Idle -> Jump -> Idle Walk -> Jump -> Walk

모두 가능하므로, MakeTransition해서 트랜지션을 만들어줍니다.

image


이제 각각의 트랜지션에 Has Exit Time은 해제하고, Condition(isWalking, isJumping)을 추가합니다.

  • Idle -> Jump : isWalking(false) isJumping(true)
  • Jump -> Idle : isWalking(false) isJumping(false)
  • Walk -> Jump : isWalking(true) isJumping(true)
  • Jump -> Walk : isWalking(true) isJumping(false)


다시 PlayerControl 스크립트를 열어 아까 작성한 코드에 한줄을 추가해줍니다.

//점프
        if (Input.GetButtonDown("Jump"))
        {
            rigid.AddForce(Vector2.up * jumpPower, ForceMode2D.Impulse);
            anim.SetBool("isJumping", true);        
        }


자, 이렇게 하고 게임을 실행해보면 점프할 때 애니메이션이 바뀌는것을 볼 수 있습니다. 문제는 착지후에도 원래모션으로 되돌아가지않고 점프 애니메이션상태에서 멈춰있습니다.

이것을 해결하기위해 Ray 라는것을 사용합니다. 먼저 플레이어의 Collider Size를 0.8, 0.9정도로 설정해줍니다.

그리고, Floor를 하나 선택하여 Inspector의 Layer를 눌러 “Floor”라는 이름의 Layer를 추가해줍니다. 이것을 만들어둔 Floor에 전부 적용해줍니다.

그런다음 다음 코드를 추가합니다.

void FixedUpdate()
    {
        //키보드 방향키 입력으로 움직임
        float h = Input.GetAxisRaw("Horizontal");

        rigid.AddForce(Vector2.right * h, ForceMode2D.Impulse);

        if (rigid.velocity.x > maxSpeed) //오른쪽 속도
            rigid.velocity = new Vector2(maxSpeed, rigid.velocity.y);
        else if (rigid.velocity.x < maxSpeed * (-1))  //왼쪽 속도
            rigid.velocity = new Vector2(maxSpeed * (-1), rigid.velocity.y);

        //착지(캐릭터가 떨어지고있을 때)
        if (rigid.velocity.y < 0)
        {
            Debug.DrawRay(rigid.position, Vector3.down, new Color(1, 0, 0));
            RaycastHit2D rayHit = Physics2D.Raycast(rigid.position, Vector3.down, 1, LayerMask.GetMask("Floor"));
            if (rayHit.collider != null)
            {
                if (rayHit.distance <= 0.45f)
                    anim.SetBool("isJumping", false);
            }
        }
    }


Ray라는것은 레이저라고 생각하면되는데, DrawRay를 사용하여 Ray를 볼 수 있습니다.

RaycasyHit2D로 초기화를 하게되는데, 이것은 레이저와 맞은 객체를 반환합니다. 초기화할 때 4번째 인자값으로 “Floor” 레이어만 감지하도록 했습니다. 따라서 레이저와 Floor 레이어가 부딪히면 Floor 객체를 반환하게됩니다.

Ray는 도큐먼트를 한번 읽어보는것을 추천드립니다.


이제 게임을 실행해보면 점프후 착지할 때 애니메이션이 원래대로 돌아오게됩니다.

마지막으로 한가지 문제가 더있는데, 지금상태에서는 무한으로 점프가 가능한 문제가있습니다. 한번만 점프가 가능하도록 코드를 추가해줍니다.

맨처음 작성했던 Jump 부분의 조건문에 다음을 추가합니다.

//점프(1단점프만 가능)
        if (Input.GetButtonDown("Jump") && !anim.GetBool("isJumping"))
        {
            rigid.AddForce(Vector2.up * jumpPower, ForceMode2D.Impulse);
            anim.SetBool("isJumping", true);        
        }

전체코드

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

public class PlayerControl : MonoBehaviour
{
    Rigidbody2D rigid;
    SpriteRenderer spriteRenderer;
    Animator anim;

    public float maxSpeed;
    public float jumpPower;

    private void Awake()
    {
        rigid = GetComponent<Rigidbody2D>();
        spriteRenderer = GetComponent<SpriteRenderer>();
        anim = GetComponent<Animator>();
    }
    // Start is called before the first frame update
    void Start()
    {

    }

    void Update()
    {
        //키보드 뗏을때 속도감소(멈춤)
        if (Input.GetButtonUp("Horizontal"))
        {
            //normalized : 단위벡터화
            rigid.velocity = new Vector2(0.5f * rigid.velocity.normalized.x, rigid.velocity.y);

        }

        //플레이어 방향 전환
        if (Input.GetButtonDown("Horizontal"))
            spriteRenderer.flipX = Input.GetAxisRaw("Horizontal") == -1;

        //Walking Animation 설정
        if (Mathf.Abs(rigid.velocity.x) < 0.3f)
            anim.SetBool("isWalking", false);
        else
            anim.SetBool("isWalking", true);

        //점프(1단점프만 가능)
        if (Input.GetButtonDown("Jump") && !anim.GetBool("isJumping"))
        {
            rigid.AddForce(Vector2.up * jumpPower, ForceMode2D.Impulse);
            anim.SetBool("isJumping", true);        
        }
    }

    void FixedUpdate()
    {
        //키보드 방향키 입력으로 움직임
        float h = Input.GetAxisRaw("Horizontal");

        rigid.AddForce(Vector2.right * h, ForceMode2D.Impulse);

        if (rigid.velocity.x > maxSpeed) //오른쪽 속도
            rigid.velocity = new Vector2(maxSpeed, rigid.velocity.y);
        else if (rigid.velocity.x < maxSpeed * (-1))  //왼쪽 속도
            rigid.velocity = new Vector2(maxSpeed * (-1), rigid.velocity.y);

        //착지(캐릭터가 떨어지고있을 때)
        if (rigid.velocity.y < 0)
        {
            Debug.DrawRay(rigid.position, Vector3.down, new Color(1, 0, 0));
            RaycastHit2D rayHit = Physics2D.Raycast(rigid.position, Vector3.down, 1, LayerMask.GetMask("Floor"));
            if (rayHit.collider != null)
            {
                if (rayHit.distance <= 0.45f)
                    anim.SetBool("isJumping", false);
            }
        }
    }
}

댓글남기기