[2025_11_20]3d에서 캐릭터의 물리 문제

2025. 11. 20. 21:18TIL

문제 상황

증상

플레이어가 장애물과 상호작용할 때 비정상적인 동작 발생:

  • 장애물을 통과하거나 내부에 박힘
  • 이동이 불안정
  • Y, Z축 속도가 의도치 않은 큰 음수 값으로 변경
 
 
csharp
// 문제가 발생한 코드 구조
private void FixedUpdate()
{
    Slide();           // AddForce() 사용
    Move();            // MovePosition() 사용
    ApplyGravity();    // velocity 직접 수정
}

private void Slide()
{
    // 슬라이드 시 힘 추가
    rb.AddForce(slideDownSpeed * Vector3.down, ForceMode.Impulse);
}

private void Move()
{
    // 계산된 속도로 이동
    rb.MovePosition(rb.position + runSpeed * Time.fixedDeltaTime * Vector3.forward);
}

private void ApplyGravity()
{
    if (IsFalling())
    {
        // velocity 직접 수정
        rb.velocity += fallAccel * Time.fixedDeltaTime * Vector3.down;
    }
}

원인 파악

핵심 문제: 물리 메서드 혼용

FixedUpdate()에서 여러 물리 메서드를 동시에 사용했기 때문:

  1. MovePosition() - 위치 기반 이동
  2. AddForce() - 힘 기반 이동
  3. velocity 직접 수정 - 속도 벡터 직접 변경
 
 
csharp
// 문제 코드
FixedUpdate()
{
    rb.AddForce(...)        // 1. 내부적으로 velocity 변경
    rb.MovePosition(...)    // 2. position 변경 (velocity는 무시)
    rb.velocity += ...      // 3. velocity 직접 덮어쓰기
}
// 세 메서드가 서로 충돌하며 Rigidbody의 속도 벡터가 예측 불가능하게 변경됨!

각 메서드가 하는 일:

메서드동작 방식내부 처리
AddForce() 힘을 가함 velocity에 힘을 누적
MovePosition() 위치를 이동 position 변경, velocity 계산 무시
velocity = 속도 직접 설정 velocity를 덮어씀

충돌 과정:

 
 
1. AddForce() -> velocity = (5, -2, 0)
2. MovePosition() -> position 변경, velocity는 뭔지 모르게 됨
3. velocity += ... -> 이미 이상해진 velocity에 더함
4. 물리 엔진 혼란 -> 벽 통과, 버그 발생

해결 방안

핵심: Velocity 벡터 하나로 통일

모든 힘과 이동량을 velocity 벡터 하나에 누적한 뒤, 마지막에 한 번에 적용

 
 
csharp
private void FixedUpdate()
{
    //  1. 현재 velocity 가져오기
    Vector3 newVelocity = rb.velocity;
    
    //  2. 모든 이동/힘을 velocity에 누적
    if (IsSliding())
    {
        // AddForce 대신 velocity에 직접 추가
        newVelocity += slideDownSpeed * Vector3.down;
    }
    
    if (IsMoving())
    {
        // MovePosition 대신 velocity로 계산
        newVelocity = runSpeed * Vector3.forward;
    }
    
    if (IsFalling())
    {
        // 중력 가속도 추가
        newVelocity += fallAccel * Time.fixedDeltaTime * Vector3.down;
    }
    
    //  3. 마지막에 한 번만 적용
    rb.velocity = newVelocity;
}

 

배운 점

1. Rigidbody 물리 메서드는 혼용하면 안 됨

 
 
csharp
// 이렇게 섞어 쓰지 말기
rb.AddForce(...)
rb.MovePosition(...)
rb.velocity = ...

// 하나만 선택해서 사용
rb.velocity = ...  // 추천: 직접적이고 예측 가능

2. 각 메서드의 용도

메서드언제 쓸까?

velocity 직접 속도를 제어하고 싶을 때 (추천)
AddForce() 현실적인 힘 기반 물리가 필요할 때
MovePosition() 충돌 감지는 하되 물리 영향은 무시할 때