나만의 작은 도서관
[TIL][C++] 251017 MMO 서버 개발 117일차: [언리얼-Trouble Shooting] 원하지 않는 콜리전 충돌 제거한 사례 몇 가지, 캐릭터 무브먼트 컴포넌트(CMC)에 입력에 의한 이동 명령이 정상적으로 적용될 수 있는지 확인하는 방법들 본문
Today I Learn
[TIL][C++] 251017 MMO 서버 개발 117일차: [언리얼-Trouble Shooting] 원하지 않는 콜리전 충돌 제거한 사례 몇 가지, 캐릭터 무브먼트 컴포넌트(CMC)에 입력에 의한 이동 명령이 정상적으로 적용될 수 있는지 확인하는 방법들
pledge24 2025. 10. 17. 21:42주의사항: 해당 글은 일기와 같은 기록용으로, 다듬지 않은 날것 그대로인 글입니다.
[언리얼-Trouble Shooting] 원하지 않는 콜리전 충돌 제거한 사례 몇 가지
Problem1. 캐릭터끼리 겹치면 이상하게 다리가 들린다.
- 캐릭터들끼리 콜리전이 발생해서 생긴 문제. 캐릭터를 만들었을때 콜리전은 캡슐 컴포넌트에도 있고 SkeletalMesh에도 있을 수 있기 때문에 충돌이 완전히 발생하지 않도록 하기 위해선 모든 컴포넌트의 콜리전을 변경해야한다.
Solve1.
- 캐릭터 액터의 캡슐 컴포넌트 + 메인 SkeletalMesh의 콜리전의 드롭다운에서 SkeletalMesh로 변경
Problem2. 캐릭터끼리 겹치는 경우 카메라가 초근접상태로 된다.
- SpringArm 컴포넌트가 캐릭터의 콜리전과 충돌해서 발생한 문제. SpringArm 컴포넌트가 콜리전과 충돌하면 해당 콜리전을 넘어가지 못하게되고, 이로 인해 초근접으로 카메라가 시점이 변경된 것
Solve2.
- 카메라가 충돌하지 않도록 변경하면 된다. C++에서 DoCollisionTest를 false로 설정하거나, 에디터의 디테일 패널에서 DoCollistion 옵션을 해제해주면 된다.
Problem3. 칼을 휘두르면 캐릭터가 튕겨나간다.
- 단순히 칼의 콜리전에 의해 물리 시뮬레이션이 작동한 것. 캐릭터가 칼에 맞으면서 날라간 것이다.
Solve3.
- 칼은 Static Mesh Component로 표현되므로, Static Mesh Component의 콜리전을 제거하면 된다.(No Collision) -> 칼에 콜리전이 있었던 것이 문제 -> 콜리전이 발동하면서 캐릭터가 튕겨나감
[언리얼] 캐릭터 무브먼트 컴포넌트(CMC)에 입력에 의한 이동 명령이 정상적으로 적용될 수 있는지 확인하는 방법들
- 몽타주에 루트 모션이 포함되어 있고, ABP에서 몽타주의 루트 모션을 적용하도록 설정되어 있다면, CMC의 입력으로 이동하는 대신 애니메이션의 루트 본 움직임에 의해 제어된다.
- 이로 인해 아무리 AddMovementInput() 함수를 호출한다한들, 적용이 안 될 수 있는데, 이번엔 적용이 안되는 상황을 거르는 여러가지 방법들을 알아보았다.
CMC의 이동 모드 확인하기
- CMC(UCharacterMovementComponent)에는 현재 캐릭터의 이동 상태를 확인할 수 있는 이동 모드가 존재한다.
- 이 이동 모드(MovementMode)를 통해 현재 캐릭터가 입력에 의해 이동 명령이 적용되어있는지 확인할 수 있다. CMC에는 각 이동 상태인지 확인할 수 있도록 함수로 제공하고 있다.
UCharacterMovemeneComponent::IsMovingOnGround(); // 현재 이동 모드가 MovingOnGround?
UCharacterMovemeneComponent::IsFalling(); // 현재 이동 모드가 Falling?
UCharacterMovemeneComponent::IsFlying(); // 현재 이동 모드가 Flying?
UCharacterMovemeneComponent::IsWalking(); // 현재 이동 모드가 Walking?
- 만약, 루트 모션이 들어간 몽타주가 재생중이라서 이동 명령이 안들어가는 상황인지 확인하고 싶다면, MovementMode가 MOVE_None인지 확인하면 된다. (루트 모션이 활성화되어 있는 경우 보통 이 Move_None 등으로 전환되어 있음)
UCharacterMovementComponent* MovementComponent = GetCharacterMovement();
if(MovementComponent)
{
if(MovementComponent->MovementMode == EMovementMode::MOVE_None)
{
return true;
}
}
- 여기서 더 쉬운 방법이 있는데, 언리얼에서 ‘현재 캐릭터가 움직일 수 있는 상태인지’를 종합적으로 확인해서 bool값으로 반환해주는 함수인 UCharacterMovementComponent::IsMovementEnabled()를 사용하는 것이다.
- (UE5에는 없다고 한다)
if (Character->GetCharacterMovement()->IsMovementEnabled())
{
// 이동 가능
}
else
{
// 이동 불가 (루트모션, 피직스, Disable 등)
}
루트 모션 자체를 확인하기
- 아주 편리하게도 루트 모션이 활성화되어 있음을 알 수 있는 함수를 미리 만들어놨다. 그래서 아래와 같이 캐릭터 액터에선 쉽게 루트 모션이 활성화되어 있는 상태인지 확인할 수 있다.
if(!Character->HasRootMotion() && !Character->GetCharacterMovement()->HasAnimRootMotion())
{
// 루트 모션이 켜져있지 않음 보장
}
몽타주 재생중임을 직접 확인하기
- 이것도 함수로 미리 만들어두었다.(찾아보면 진짜 별걸 미리 다 만들어두었다)
if (!AnimInstance->Montage_IsPlaying(RootMotionMontage))
{
// 이동 명령 안전
}
최종 코드
if (CMC->IsMovementEnabled() &&
!Character->HasRootMotion() &&
!CMC->HasAnimRootMotion())
{
// 이동 명령 적용 가능 시점
}
PlayMontage에 대해 알아보기

입력 핀
- In Skeletal Mesh Component: 몽타주를 재생할 스켈레탈 메시
- Montage to Play: 재생할 몽타주
출력 핀
- On Completed: 애니메이션이 끝까지 재생되었을때 발생하는 이벤트
- On Blend Out: 애니메이션간 점진적 전환이 시작되었을때 발생하는 이벤트. 대부분의 몽타주는 짧은 블렌딩 시간을 가지므로, 몽타주 재생시 대부분 발생하는 이벤트
- On Interrupted: 다른 몽타주로 덮어쓰여지거나 수동으로 Stop을 호출하는 등, 재생 중인 애니메이션이 중간에 멈춘 경우 발생하는 이벤트
- On Notigy Begin: 노티파이 이벤트 발생 시작 시
- On Notify End: 노티파이 이벤트 종료시
이동 보간 중 몽타주를 정확하게 실행하려면?
Solve 1. 클라이언트에서 워프 정렬을 한다.
FTransform MontageStartTransform = DesiredMontageTransform;
Character->SetActorTransform(MontageStartTransform);
Solve 2. 짧은 보간을 사용
// CMC를 거쳐서 이동하는 방식이 아니기 때문에 미끄러지며 움직이는 현상이 있을 수 있다
Character->SetActorLocation(FMath::VInterpTo(Chracter->GetActorLocation(),
DesiredMontageTransform.GetLocation(), DeltaTime, 10.0f);
[언리얼] CMC로 인한 움직임 비활성화하기
CMC 잠그기
UCharacterMovementComponent* MoveComp = Character->GetCharacterMovement();
MoveComp->DisableMovement(); // 이동 봉인
- 이 경우 반드시 SimulatePhysics가 true인 상태여야한다. 다른게 아니라 이게 false라면 물리 엔진에 의한 외부 물리 영향도 받지 않는 상태가 되기 때문. CMC를 거쳐서 움직이는 부분만 막고 싶다면 이 점을 확인하자.
Root Motion이 설정된 애니메이션 재생중 추락과 같은 물리효과를 받을까?
- 받음(해 봄)
- Root Motion은 AnimInstance → USkeletalMeshComponent → CMC 순으로 이동에 대한 Delta값을 전달함.
- Root Motion이 적용 중인 프레임에는 애니메이션 루트 본의 이동이 직접 액터 좌표에 반영됨.
- 이때 CMC의 자연스러운 물리 계산(중력, 지면 충돌 등…)은 부분적으로 무시됨.
- 캐릭터의 이동 모드(Movement Mode)에 따라 달라지는 부분이 있음
- 수평 이동(XY): 루트 모션이 그대로 적용된다.
- 수직 이동(Z):
- 지상에 있을 때: 루트 모션의 Z값은 무시되고, 캐릭터는 지면에 붙어있는다.
- 공중에 있을 때: 중력의 영향을 받는다. (루트 모션 Z값 + 중력 가속도)
- 루트 모션의 Z축이 완전히 적용되며, 중력의 영향을 받지 않는다.
- 점프 공격이나 공중 콤보에 유용하다.
- Walking/Falling 모드일 때
Room Motion Mode 종류
| RootMotionMode | 설명 | 물리효과 |
| NoRootMotionExtraction | Root Motion 무시, 일반 물리 적용 | ✔️ 적용 |
| IgnoreRootMotion | Root Motion 계산하지만 적용 안 함 | ✔️ 적용 |
| RootMotionFromEverything | 모든 Root Motion 애니메이션 적용 | ❌ 중력, 슬라이딩 등 대부분 무시 |
| RootMotionFromMontagesOnly | 몽타주에서만 Root Motion 적용 | ❌ 적용 중엔 중력 무시, 끝나면 복귀 |
