경사면을 감지하여 플레이어를 미끄러지게 하는 것은 게임의 현실성을 높이기 위해 사용됩니다. 또한, 개발자가 의도하지 않은 공간으로 이동하지 못하도록 제한할 수 있습니다.
💬 서론
- RigidBody는 자동으로 경사면 미끄러짐을 지원합니다. 하지만 캐릭터 컨트롤러는 지원하지 않기에 캐릭터 컨트롤러에서 경사면 미끄러짐을 구현합니다.
- 이 기능은 캐릭터 컨트롤러 (CharacterController) 컴포넌트를 사용하는 대상에서 적용이 가능합니다.
📺 미끄러짐 유무 차이
- 미끄러짐 기능이 없을때는 플레이어가 무한정으로 점프를하여 이동할 수 있습니다.
- 하지만 미끄러짐 기능을 추가하면 플레이어는 미끄러질때 더 이상 점프를 할 수 없어 의도하지 않은 곳으로 이동할 수 없습니다.
✅ 구현(함수)
- 기존 게임 프로젝트에서 사용하는 PlayerController에 미끄러짐 기능을 추가한 스크립트이기에 본 글의 주제인 미끄러짐에 관련된 내용만 요약하여 스크립트를 재구성하였습니다.
//PlayerController.cs
...
public class PlayerController : BaseFSM
{
...
public static bool IsSliding { private set; get; } = false;
[Header("미끄러질경우 미끄러짐 속도")]
[SerializeField] private float mSlideSpeed = 3f; // 미끄러질 때의 속도
...
[HideInInspector] public CharacterController CharController; //캐릭터 컨트롤러
[HideInInspector] public Animator Animator; //애니메이터
...
private void Awake()
{
CharController = GetComponent<CharacterController>();
...
IsSliding = false;
}
...
/// <summary>
/// 미끄러짐 검사 및 미끄러질경우 이동
/// </summary>
public void SlidingCharacter()
{
if(!CharController.isGrounded)
return;
RaycastHit hit;
if (Physics.Raycast(transform.position, Vector3.down, out hit, CharController.height / 2))
{
// 경사면의 기울기가 slopeLimit 보다 클경우 미끄러짐 처리
if (Vector3.Angle(hit.normal, Vector3.up) > CharController.slopeLimit)
{
//애니메이션 블렌드 트리의 값 설정
Animator.SetFloat("_MovementSpeed", CharController.velocity.magnitude);
//이동
CharController.Move(-Vector3.ProjectOnPlane(-Physics.gravity, hit.normal).normalized * Time.deltaTime * mSlideSpeed);
IsSliding = true;
return;
}
}
IsSliding = false;
}
...
}
[Header("미끄러질경우 미끄러짐 속도")]
[SerializeField] private float mSlideSpeed = 3f; // 미끄러질 때의 속도
- 미끄러짐 속도를 설정합니다.
public static bool IsSliding { private set; get; } = false;
- 현재 플레이어가 미끄러지고있는 상태인지 확인합니다.
- 플레이어가 미끄러지고있다면, 이 값은 TRUE가 됩니다.
- 이 값이 TRUE일경우 점프를 제한하는 등 여러가지 기능을 제한할 수 있습니다.
/// <summary>
/// 미끄러짐 검사 및 미끄러질경우 이동
/// </summary>
public void SlidingCharacter()
{
if(!CharController.isGrounded)
return;
RaycastHit hit;
if (Physics.Raycast(transform.position, Vector3.down, out hit, CharController.height / 2))
{
// 경사면의 기울기가 slopeLimit 보다 클경우 미끄러짐 처리
if (Vector3.Angle(hit.normal, Vector3.up) > CharController.slopeLimit)
{
//애니메이션 블렌드 트리의 값 설정
Animator.SetFloat("_MovementSpeed", CharController.velocity.magnitude);
//이동
CharController.Move(-Vector3.ProjectOnPlane(-Physics.gravity, hit.normal).normalized * Time.deltaTime * mSlideSpeed);
IsSliding = true;
return;
}
}
IsSliding = false;
}
- 미끄러짐을 검사하고, 조건에 맞을경우 플레이어를 미끄러지게 합니다.
- Raycast를 바닥으로 쏘아 플레이어가 서있는 경사면을 감지합니다.
- Vector3.Angle(hit.normal, Vector3.up)을 통해 경사면의 각도를 얻습니다. 이 각도가 캐릭터 컨트롤러의 경사각보다 크다면 미끄러짐을 적용합니다.
- ProjectOnPlane 함수를 이용하여 경사면의 수직인 벡터를 얻습니다.
- 그 후에 캐릭터 컨트롤러를 이동시킵니다.
✅ 사용 예시
public override void Execute(PlayerController entity)
{
//떨어짐 체크
entity.CheckFalling();
entity.SlidingCharacter();
}
- 매 프레임마다 미끄러짐을 계산합니다.
- 미끄러짐이 활성화되면 IsSliding이 참이됩니다.
/// <summary>
/// 점프 키를 눌러 점프를 하도록 한다.
/// </summary>
/// <returns>점프를 한 경우에 true가 반환된다.</returns>
public bool Jump()
{
//현재 커서가 언락 상태라면? false 리턴
if(UtilityManager.IsCursorUnlock || IsSliding) { return false; }
if (CharController.isGrounded && Input.GetButton("Jump"))
{
mMoveDir.y = mJumpForce;
CharController.Move(mMoveDir * Time.deltaTime);
return true;
}
return false;
}
- 플레이어가 점프를 시도하기 위한 함수입니다.
- IsSliding이 참인경우 리턴하여 미끄러지고있는 상태에서 더 이상 점프를 하지 못하게 합니다.
'unity game modules' 카테고리의 다른 글
[유니티] 상점 시스템(2) - 상점 (0) | 2023.04.02 |
---|---|
[유니티] 상점 시스템(1) - 상점 슬롯 (0) | 2023.04.02 |
[유니티] 대화 시스템(3) - 말풍선 (1) | 2023.03.27 |
[유니티] 대화 시스템(2) - 선택지 (0) | 2023.03.27 |
[유니티] 대화 시스템(1) - Overlay Canvas (0) | 2023.03.27 |