Unity3D
Unity) [유니티 3D] 점프 애니메이션 제어
HSH12345
2023. 7. 4. 11:33
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
// 애니메이션 상태
const string PLAYER_MOVEMENT = "Movement";
const string PLAYER_JUMP = "Jump";
private CharacterController controller;
private Vector3 playerVelocity;
private bool isGrounded;
private float playerWalkSpeed = 2.0f;
private float playerRunSpeed = 5.0f;
private bool isMove;
private bool isRun;
private Vector3 dirMove;
private float verAxis;
private float horAxis;
private float currentSpeed;
private Vector3 jumpDirection;
private float jumpSpeed;
private float jumpHeight = 1.0f;
private float gravityValue = -20.0f;
private float groundDist = 0.18f;
private LayerMask groundMask;
private Camera camMain;
[SerializeField]
private float smoothness = 2f;
private Animator anim;
private string currentState;
public void Init()
{
this.camMain = Camera.main;
this.controller = this.gameObject.GetComponent<CharacterController>();
this.anim = this.gameObject.GetComponent<Animator>();
// 각각의 layer 이름으로 LayerMask를 받아온 뒤 OR 연산을 통해 합칩니다.
this.groundMask = (1 << 6) | (1 << 7);
this.ChangeAnimState(PLAYER_MOVEMENT);
}
private void Update()
{
// Raycasting을 이용한 grounded 판별
this.isGrounded = Physics.Raycast(this.transform.position, Vector3.down, this.groundDist, groundMask);
if (this.isGrounded && this.playerVelocity.y < 0)
{
this.playerVelocity.y = 0f;
if (this.currentState == PLAYER_JUMP)
{
if (this.anim.GetCurrentAnimatorStateInfo(0).normalizedTime > 1 && !this.anim.IsInTransition(0))
{
this.ChangeAnimState(PLAYER_MOVEMENT);
}
}
}
if (Input.GetButtonDown("Jump") && this.isGrounded && this.currentState == PLAYER_MOVEMENT)
{
// 제곱근을 사용하여 점프의 높이를 조절합니다.
this.playerVelocity.y = Mathf.Sqrt(this.jumpHeight * -2.0f * this.gravityValue);
this.ChangeAnimState(PLAYER_JUMP);
this.jumpDirection = this.dirMove.normalized;
this.jumpSpeed = this.currentSpeed;
}
// 시간을 사용하여 중력 가속도를 구현합니다.
this.playerVelocity.y += this.gravityValue * Time.deltaTime;
// 이동
if (this.currentState == PLAYER_MOVEMENT || this.currentState == PLAYER_JUMP)
{
this.MovePlayer();
}
// 점프
this.controller.Move(this.playerVelocity * Time.deltaTime);
// 달리기
if (Input.GetKey(KeyCode.LeftShift)) this.isRun = true;
else this.isRun = false;
}
private void MovePlayer()
{
this.currentSpeed = this.isRun ? this.playerRunSpeed : this.playerWalkSpeed;
// 카메라의 정면 방향 벡터의 y 값에 0을 곱합니다.
Vector3 currentVertical = Vector3.Scale(this.camMain.transform.forward, new Vector3(1, 0, 1));
// 카메라의 좌우 방향 벡터를 월드좌표로 변환합니다.
Vector3 currentHorizontal = this.camMain.transform.TransformDirection(Vector3.right);
// 카메라의 방향과 키 입력값을 방향벡터 값으로 사용합니다.
if (this.currentState == PLAYER_MOVEMENT)
{
this.verAxis = Input.GetAxisRaw("Vertical");
this.horAxis = Input.GetAxisRaw("Horizontal");
this.dirMove = currentVertical * this.verAxis + currentHorizontal * this.horAxis;
}
else if (this.currentState == PLAYER_JUMP)
{
// 점프 중을 때 방향과 속도입니다.
this.dirMove = this.jumpDirection;
this.currentSpeed = this.jumpSpeed;
}
// 캐릭터가 이동 중인지 감자힙나다.
if (this.dirMove.sqrMagnitude > 0.01f)
{
// 이동 방향을 바라보도록 합니다.
this.gameObject.transform.rotation = Quaternion.Slerp(this.gameObject.transform.rotation,
Quaternion.LookRotation(this.dirMove), Time.deltaTime * this.smoothness);
this.isMove = true;
}
else
{
this.isMove = false;
}
this.controller.Move(this.dirMove.normalized * this.currentSpeed * Time.deltaTime);
// 애니메이션 Blend를 제어합니다.
float movementPer = (this.isRun ? 0.8f : 0.4f) * this.dirMove.normalized.magnitude;
this.anim.SetFloat("Movemnet_Blend", movementPer, 0.2f, Time.deltaTime);
float jumpPer = (this.isMove ? 1f : 0f);
this.anim.SetFloat("Jump_Blend", jumpPer, 0f, Time.deltaTime);
}
private void OnDrawGizmos()
{
Gizmos.color = Color.red;
Gizmos.DrawRay(this.transform.position, Vector3.down * this.groundDist);
}
private void ChangeAnimState(string newState)
{
if (this.currentState == newState) return;
anim.Play(newState);
this.currentState = newState;
}
}