이번 글에서는 전 글에서 파쿠르를 다른 방식으로 구현한것을 설명 해보겠습니다.
처음 구현한것은 여기에서 확인 하실수 있습니다.
https://dove-dove.tistory.com/32
전글에서는 파쿠르를 구현 하였지만 불안정 하였습니다. 이번에는 개선 한 파쿠르를 정리 해보겠습니다.
전 글에서 처럼 레이 케스트를 이용하여 파쿠르 벽을 인식하는건 같습니다. 하지만 전 글에서 벽은 양쪽에
안보이는 오브젝트를 추가 해서 지정한 값으로 전달 하는 방식 입니다.
if (Input.GetKey(KeyCode.Space))
{
float Distance = 0.85f;
RaycastHit hit;
Vector3 playerPos = transform.position;
playerPos.y -= 0.3f;
Debug.DrawRay(playerPos, transform.forward * Distance, Color.yellow);
if (Physics.Raycast(playerPos, transform.forward, out hit, Distance))
{
// 닿은 물체의 이름을 출력
if(hit.collider.gameObject.tag == "Well")
{
float moveAction = 0;
//충돌한 오브젝트와 플레이어의 높이 차이를 확인
float objectHeight = hit.collider.gameObject.transform.position.y - transform.position.y + 0.5f;
//애니메이션 시작
if(objectHeight < 0.15f)
{
anim.CrossFade("Jumping Over Into Combat", 0.2f);
moveAction = hit.transform.localScale.z + 0.6f;
}
else
{
anim.CrossFade("slideAction", 0.2f);
moveAction = hit.transform.localScale.z + 0.6f;
}
StartCoroutine(pAction(1.1f, moveAction, hit.collider.transform));
}
}
}
업데이트에서 스페이스 바 키를 눌렀을 때 레이케스트가 발사가 되고 그 tag가 벽이이라면 충돌한 오브젝트의 높이를 확인 후
if 문에서 어떤 애니메이션을 실행하는지 배정 및 움직이는 액션할때 움직이는 거리를 확인하고 코루틴을 실행을 합니다.
IEnumerator pAction(float actionTime, float move, Transform hitObject)
{
rb.isKinematic = true;
Vector3 startPosition = transform.position;
Vector3 targetPosition = startPosition;
float elapsedTime = 0f;
// 플레이어와 충돌한 물체 간의 방향 벡터 계산
Vector3 directionToPlayer = transform.position - hitObject.position;
Vector3 objectForward = hitObject.forward;
float dotProduct = Vector3.Dot(objectForward, directionToPlayer);
bool isBehind = dotProduct > 0;
// 이동 방향 설정
if (isBehind)
targetPosition += transform.forward * move;
else
targetPosition += transform.forward * move;
while (elapsedTime < actionTime)
{
transform.position = Vector3.Lerp(startPosition, targetPosition, elapsedTime / actionTime);
elapsedTime += Time.deltaTime;
if (isBehind)
transform.rotation = Quaternion.Euler(transform.rotation.x, hitObject.eulerAngles.y - 180f, transform.rotation.z);
else
transform.rotation = Quaternion.Euler(transform.rotation.x, hitObject.eulerAngles.y, transform.rotation.z);
yield return null;
}
transform.position = targetPosition;
rb.isKinematic = false;
}
이 코드는 코루틴 즉 애니메이션을 시작하면서 시간 ,충돌 postion , 충돌한 물체 포지션을 받아옵니다.
여기에서 하나식 설명을 해보겠습니다.
여기에서 방향을 먼저 구해야 합니다.
Vector3 directionToPlayer = transform.position - hitObject.position;
Vector3 objectForward = hitObject.forward;
float dotProduct = Vector3.Dot(objectForward, directionToPlayer);
bool isBehind = dotProduct > 0;
플레이어의 포지션과 충돌한 오브젝트의 포지션을 구하고 빼고 난 후 충돌한 오브젝트의 forward를 구합니다.
그리고 Dot를 이용하여 두 백터의 내적을 확인을 하고
양수라면 비슷한 방향이고 음수라면 반대 방향을 나타납니다.
이제 bool 값이 완료가 되면 이제 이동할 값을 구합니다.
targetPosition += transform.forward * move;
이렇게 넣으면 됩니다.
이제 while문을 이용하여 targetPosition까지 이동하면 끝이 납니다.
while (elapsedTime < actionTime)
{
transform.position = Vector3.Lerp(startPosition, targetPosition, elapsedTime / actionTime);
elapsedTime += Time.deltaTime;
if (isBehind)
transform.rotation = Quaternion.Euler(transform.rotation.x, hitObject.eulerAngles.y - 180f, transform.rotation.z);
else
transform.rotation = Quaternion.Euler(transform.rotation.x, hitObject.eulerAngles.y, transform.rotation.z);
yield return null;
}
Quaternion.Euler는 현재 상태에서 오일러 각으로 회전 시키는 것을 말합니다.
Quaternion는 짐벌락 현상 즉 축이 겹처지기 않게 3개의 축을 다 돌립니다.
짐벌락 현상이 일어나면 2D처럼 회전이 제한 될수 있습니다.

이제 마지막으로 isKinematic는 = false 로 position 은 목표위치로 하면 끝이 납니다.
transform.position = targetPosition;
rb.isKinematic = false;
이렇게 하였는대 다시 원위치로 돌아오는 경우 목표위치가 벽 안쪽에 있어서 다시 돌아올수 있으니 확인을 해야합니다.


이렇게 파쿠르를 구현 하였습니다.
이것을 이용하여 여러가지 파쿠르를 구현을 할수 있습니다.
이상 파쿠르 구현 정리를 끝내겠습니다.
'유니티 개발 > 계륵' 카테고리의 다른 글
| Unity - 유닛 클릭 이동 (1) | 2025.08.05 |
|---|---|
| Unity - 발소리 구현 (0) | 2025.08.04 |
| Unity - 파쿠르 첫 구현 (0) | 2025.07.23 |
| Unity - 후레쉬 혹은 빛나는 오브젝트 구현 (3) | 2025.07.23 |
| Unity - 밤 , 안개 (0) | 2025.07.23 |