feat: 적과 충돌 시 미끄러짐 방지 및 8방향 양자화

- OnControllerColliderHit으로 적 충돌 감지
- 충돌 방향으로의 이동만 차단하여 튕겨나가지 않음
- 충돌 normal을 45도 간격으로 양자화하여 8각형 충돌 느낌 구현
- Enemy 레이어 추가

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
2026-03-16 10:07:09 +09:00
parent f3a995d297
commit 03e1b1303c
4 changed files with 315 additions and 28 deletions

View File

@@ -31,6 +31,10 @@ namespace Colosseum.Player
private bool isJumping;
private bool wasGrounded;
// 적 충돌 방향 (이동 차단용)
private Vector3 blockedDirection;
private int enemyLayerMask;
/// <summary>
/// 현재 이동 속도 (애니메이션용)
/// </summary>
@@ -79,6 +83,9 @@ namespace Colosseum.Player
// 카메라 설정
SetupCamera();
// 적 레이어 마스크 초기화
enemyLayerMask = LayerMask.GetMask("Enemy");
}
/// <summary>
@@ -233,10 +240,24 @@ namespace Colosseum.Player
moveDirection = TransformDirectionByCamera(moveDirection);
moveDirection.Normalize();
// 충돌 방향으로의 이동 차단 (미끄러짐 방지)
if (blockedDirection != Vector3.zero)
{
float blockedAmount = Vector3.Dot(moveDirection, blockedDirection);
if (blockedAmount > 0f)
{
moveDirection -= blockedDirection * blockedAmount;
moveDirection.Normalize();
}
}
// 이동 적용
Vector3 moveVector = moveDirection * moveSpeed * Time.deltaTime;
characterController.Move(moveVector + velocity * Time.deltaTime);
// 충돌 방향 리셋
blockedDirection = Vector3.zero;
// 회전 (이동 중일 때만)
if (moveDirection != Vector3.zero)
{
@@ -330,5 +351,43 @@ namespace Colosseum.Player
wasGrounded = characterController.isGrounded;
}
/// <summary>
/// CharacterController 충돌 처리. 적과 충돌 시 해당 방향 이동을 차단합니다.
/// 충돌 normal을 8방향으로 양자화하여 각진 충돌 느낌을 줍니다.
/// </summary>
private void OnControllerColliderHit(ControllerColliderHit hit)
{
// 적과의 충돌인지 확인
if ((enemyLayerMask & (1 << hit.gameObject.layer)) != 0)
{
// 충돌 방향 저장 (이동 차단용)
blockedDirection = hit.normal;
blockedDirection.y = 0f;
blockedDirection.Normalize();
// 8방향으로 양자화 (45도 간격)
blockedDirection = QuantizeToOctagon(blockedDirection);
}
}
/// <summary>
/// 방향을 8각형(45도 간격) 방향으로 양자화합니다.
/// </summary>
private Vector3 QuantizeToOctagon(Vector3 direction)
{
if (direction == Vector3.zero)
return direction;
// 각도 계산
float angle = Mathf.Atan2(direction.x, direction.z) * Mathf.Rad2Deg;
// 45도 단위로 반올림
float snappedAngle = Mathf.Round(angle / 45f) * 45f;
// 다시 벡터로 변환
float radians = snappedAngle * Mathf.Deg2Rad;
return new Vector3(Mathf.Sin(radians), 0f, Mathf.Cos(radians));
}
}
}