총알이 적에 맞았을 때 뒤로 밀려나는 넉백 효과를 구현한 과정을 기록한다.
삽질이 많았던 파트!
1. 넉백이란?
적이 공격을 받았을 때 뒤로 밀려나는 효과. 게임에서 타격감을 주는 핵심 요소다.
총알 → → → 💥 적
적 → → (뒤로 밀려남)
구현에 필요한 것
- Enemy에 Rigidbody - 물리 힘을 받을 수 있어야 함
- AddForce() - Rigidbody에 힘을 가하는 함수
- NavMeshAgent 비활성화 - Agent가 위치를 잡으면 밀리지 않음
2. Enemy에 Rigidbody 추가

설정은 다음과 같다.
- Is Kinematic: 체크 ✅ - 평소에는 물리 영향 안 받음 (NavMeshAgent가 이동 담당)
- Use Gravity: 해제 - NavMeshAgent가 바닥에 붙여주니까 불필요
Is Kinematic이란? 체크하면 물리 엔진이 이 오브젝트를 직접 움직이지 않는다. 코드에서 isKinematic = false로 풀어줄 때만 물리가 적용된다.
3. 넉백 코드
private void OnCollisionEnter(Collision collision)
{
Enemy enemy = collision.gameObject.GetComponentInParent<Enemy>();
if (enemy != null)
{
// 1. NavMeshAgent 끄기 (안 끄면 Agent가 위치를 잡아서 안 밀림)
NavMeshAgent agent = enemy.GetComponent<NavMeshAgent>();
if (agent != null)
agent.enabled = false;
// 2. Rigidbody 물리 활성화
Rigidbody enemyRb = enemy.GetComponent<Rigidbody>();
if (enemyRb != null)
{
enemyRb.isKinematic = false;
enemyRb.constraints = FreezePositionY | FreezeRotation;
enemyRb.linearDamping = 5f;
// 3. 밀려나는 방향 계산 (총알→적 방향, 수평만)
Vector3 knockbackDirection = (enemy.transform.position - transform.position);
knockbackDirection.y = 0f;
knockbackDirection.Normalize();
// 4. 힘 가하기
enemyRb.AddForce(knockbackDirection * knockbackForce, ForceMode.Impulse);
}
enemy.Die();
}
}
흐름 순서
- NavMeshAgent 끄기 → Agent가 위치를 고정하지 않게
- isKinematic = false → 물리 엔진이 움직일 수 있게
- 방향 계산 → 총알 위치에서 적 위치 방향 (수평만)
- AddForce(Impulse) → 한 번에 강하게 밀기
- Die() → 죽기 상태로 전환
4. 이슈 기록 (꽤 많이 헤맸다!)
이슈 1: 넉백이 적용 안 됨
원인: NavMeshAgent가 켜져 있으면 매 프레임 위치를 제어해서 AddForce가 무시됨.
해결: 넉백 전에 agent.enabled = false로 먼저 끄기.
이슈 2: "ResetPath" can only be called on an active agent

원인: Bullet.cs에서 NavMeshAgent를 먼저 껐는데, Enemy.cs의 Die 상태 초기화에서 _agent.ResetPath()를 호출 → 이미 꺼진 Agent에 명령을 보내서 에러.
해결: if (_agent.enabled) _agent.ResetPath(); 로 활성 상태일 때만 호출.
이슈 3: NullReferenceException (Play 멈출 때)

원인: Play를 멈추면 OnDisable()이 호출되는데, _inputActions가 이미 null인 상태에서 .Disable() 호출.
해결: if (_inputActions != null) _inputActions.Disable(); null 체크 추가.
이슈 4: 적이 앞으로 밀림 (뒤가 아니라!???)
원인: transform.forward (총알의 앞 방향)를 밀어내는 방향으로 썼는데, 총알이 적을 향해 날아가니까 forward가 적 쪽을 가리킴 → 적이 앞으로 밀림.
해결: 방향 계산을 적 위치 - 총알 위치로 변경. 총알에서 적 쪽으로 향하는 벡터 = 적이 밀려나는 방향.
이슈 5: 적이 위로 떠오름
원인: knockbackDirection에 Y값이 있어서 위쪽으로도 힘이 가해짐.
해결:
- knockbackDirection.y = 0f — 수평으로만 밀기
- FreezePositionY — Y축 이동 잠금
이슈 6: 적이 맵 끝까지 미끄러짐
원인: 처음에 미는 힘을 100으로 설정하여 너무 강했다. FreezeRotation 때문에 마찰이 안 먹어서 멈추질 않음.
해결: linearDamping = 5f 마찰(Drag)을 넣어서 자연스럽게 감속.
5. 새로 배운 개념들
AddForce와 ForceMode
enemyRb.AddForce(방향 * 힘, ForceMode.Impulse);
AddForce는 오브젝트에 힘을 가하는 함수이고, ForceMode는 그 힘을 한 번에 줄지(Impulse), 계속 줄지(Force), 아니면 속도를 바로 바꿀지(VelocityChange)를 결정하는 옵션이다.
RigidbodyConstraints - 축 잠금
enemyRb.constraints = RigidbodyConstraints.FreezePositionY
| RigidbodyConstraints.FreezeRotation;
- FreezePositionY: Y축(위아래) 이동 잠금 → 위로 안 뜸
- FreezeRotation: 회전 잠금 → 굴러가지 않음
- | (OR 연산자): 여러 제약을 동시에 적용
linearDamping - 마찰/공기저항
linearDamping = 0 → 힘 받으면 영원히 미끄러짐 (우주 공간)
linearDamping = 5 → 힘 받고 자연스럽게 감속 후 멈춤
linearDamping = 50 → 힘 받아도 거의 안 움직임 (진흙탕)
GetComponentInParent - 부모까지 검색
Enemy enemy = collision.gameObject.GetComponentInParent<Enemy>();
- GetComponent: 해당 오브젝트에서만 찾음
- GetComponentInParent: 해당 오브젝트 + 모든 부모에서 찾음
총알이 오리의 자식 오브젝트(Body, Leg 등)에 맞을 수 있으니 부모까지 검색해야 Enemy를 찾을 수 있다.
6. Apply Root Motion

Animator의 Apply Root Motion이 켜져있으면 애니메이션이 오브젝트 위치를 제어한다. 넉백 중에 stun 애니메이션이 위치를 덮어쓸 수 있어서 해제했다.
7. 이번 작업에서 배운 것 요약
- 넉백 = NavMeshAgent 끄기 → isKinematic 끄기 → AddForce
- 이 순서가 중요! Agent가 켜져있으면 물리가 무시됨
- AddForce(Impulse) = 한 번에 강하게 밀기
- FreezePositionY = 위로 안 뜨게(상황에 따라)
- linearDamping = 자연스럽게 감속
- 넉백 방향 = 적 위치 - 총알 위치 (transform.forward 아님!)
- GetComponentInParent = 자식에서 충돌해도 부모의 컴포넌트를 찾음
- 비활성화된 컴포넌트에 메서드 호출하면 에러 → null/enabled 체크!
'Unity 궁둥이 쪼물쪼물' 카테고리의 다른 글
| 009. 적 체력(HP) 시스템 (0) | 2026.04.13 |
|---|---|
| 008. 넉백 코드 리팩토링 (0) | 2026.04.13 |
| 006. 총알에 오브젝트 풀링 적용하기 (0) | 2026.04.06 |
| 005. 발사체(Projectile) 구현 (0) | 2026.04.06 |
| 004. Enemy(적) 애니메이션 구현 (0) | 2026.04.06 |