카테고리 없음

260204 언리얼엔진 본캠프 122일차 기상모션과 MotionWarping

parkjinnam 2026. 2. 4. 17:44

기상 모션 작업을 해보자

 

지난 글을 통해서 우리는 넉백으로 인해 캐릭터가 넘어지는 모션을 구현했었다. 하지만 영상을 보면 알겠지만 캐릭터가 넘어지는 모션이 종료되고 나서 바로 기상하는 것을 볼 수 있다. 자연스러운 기상 애니메이션을 추가해서 캐릭터가 넉백에서 회복되는 한 사이클을 구현해보려고 한다. 그렇기 위해선 이전에 작업했던 넉백 몽타주에 적절한 기상 애니메이션 시퀀스를 찾아서 추가해 준 다음 섹션작업을 해주어야 한다.

애니메이션 시퀀스를 추가하고 섹션 작업을 해주었다.

 

일단 Rise 섹션을 추가해서 캐릭터가 일어나는 구간을 지정해주고 새롭게 Lying섹션을 추가해서 캐릭터가 누워있는 걸 지속하는 섹션을 추가해 주었다. 왜 이렇게 했는가?

 

플레이어의 의도에 따른 기상을 구현하자.

일단 캐릭터가 넉백으로 인해 넘어지면 게임마다 여러가지 방식으로 캐릭터를 기상하게 된다. 정해진 시간이 지나면 저절로 기상하게 되거나 플레이어가 특정 키를 입력해야만 일어나게끔 하는 게임도 많고 두 기능을 적절히 섞어 쓰는 게임도 존재한다. 이가 대표적으로 몬스터헌터 시리즈이며 해당 시리즈에서는 캐릭터가 넉백 등으로 인해 다운 시 최대 5초까지 키입력을 하지 않으면 그 시간 동안 누워있게 되어 그만큼 무적 시간을 가져갈 수 있게 된다. 만약 그 사이에 이동과 같은 키입력이 발생하면 그 시점부터 캐릭터가 기상을 시작하여 플레이어가 유동적으로 넉백으로 인해 발생한 무적 시간을 선택해서 가져갈 수 있게 구현해 두었다. 우리는 이 시스템을 차용해서 구현을 하려고 한다.

 

그렇기에 위의 사진에서의 Lying 섹션이 필요한 것이다. 플레이어의 입력이 있기 전까지 캐릭터는 누워있는 것을 지속해야 하기에 누워있는 자세를 유지할 필요가 있는 것이다. 이제 몽타주 작업은 끝났으니 캐릭터 블루프린트로 넘어가서 우리가 작성한 로직을 수정해보도록 하자. 일전에 우리는 캐릭터가 캐릭터가 바라보는 방향의 반대로 넉백 되게끔 했었다. 그렇기에 캐릭터가 오른쪽에서 피격을 당해도 캐릭터는 왼쪽이 아닌 뒤로 날아가게끔 되어 있다. 그렇기에 다음처럼 로직을 작성해서 피격 순간 캐릭터가 공격한 대상을 바라보게끔 회전시키는 로직을 일단 추가해 주었다.

CurrentDamageCauserLocation은 공격한 대상의 위치를 담는 변수이다.

 

이제 우리는 일단 캐릭터가 넉백 되고 나면 Lying에서 Loop에 걸려서 계속 누워있는 것까지는 구현된 상태이다. 이 상태에서 타이머를 이용해 5초 뒤에 다음 몽타주 섹션으로 점프를 시켜주면 될 것이다. 이때 커스텀 이벤트를 만들어서 경우를 나누어 먼저 일어날지 시간을 다 채워 자동으로 일어날지를 선택하는 로직을 작성하면 된다. 그렇기에 다음처럼 블루프린트 노드를 구성해 준다.

 

몽타주 섹션이 End로 넘어가서 Lying 루프에 걸려있는 동안 bIsLying이라는 bool 변수를 true로, bCanRise라는 변수를 False로 해서 누워있는 상태에 기상입력을 하지 못하는 상태로 만든다. 그다음 1.5초의 딜레이 이후에 bCanRise를 True로 해서 기상 입력이 유효하게 함과 동시에 5초의 타이머를 세팅해 준다. 해당 타이머가 종료되면 WakeUp이라는 커스텀 이벤트가 동작하여 bIsLying이 true인지 체크한 후 false로 전환, CanRise를 false로 전환해 준 뒤 몽타주 섹션을 Rise로 점프시켜 준다.

 

이제는 스페이스바에 기상 로직을 구현해 주면 된다. 기존의 스페이스바에는 Roll이라는 함수가 바인딩되어 있다. C++코드에 OnWakeUp이라는 함수를 추가해 주고 Roll에서 해당 함수를 호출하게끔 한 다음 정의는 블루프린트에서 정의해 준다.

void AT3CharacterBase::Roll(const FInputActionValue& Value)
{
	TObjectPtr<UT3CombatComponent> Combat = GetCombatComponent();
	if (!Combat || GetCurrentStamina() < 20.f) 
		return GEngine->AddOnScreenDebugMessage(-1,1.f,FColor::Emerald,FString::Printf(TEXT("You Need Stamina"))); // 스태미나 부족 시 실행 불가
	
	OnWakeUp();
	
    // 기타 로직
}

 

이렇게 하면 캐릭터의 넉백, 기상의 한 사이클이 완성된다만, 넉백과 기상 중에 공격이 되면 안 되기 때문에 앞서 공격과 구르기 등이 불가능하도록 변수들을 조정해 주었는데 해당 사이클의 끝에 조정했던 변수들을 원복 시켜줘야 그다음 행동이 가능할 것이기에 다음처럼 PlayMontage의 끝에 작업을 해준다.

 

이렇게 하면 기상 애니메이션이 모두 종료된 후 공격과 구르기, 움직임이 가능하게 된다.

아직 넉백 중에 무적 판정을 넣지 않아 지속적인 넉백이 되는 모습이지만 기상 타이밍의 취사선택이 가능하다.

 

MotionWarping을 공격모션에 구현하자

이번에는 일반 평타에 해당하는 공격모션에 Motion Warping을 적용해보려고 한다. Motion Warping이란 말 그대로 모션 중에 워프 시키는 기술로서 캐릭터가 특정 행동을 할 때 타깃의 위치로 자연스럽게 이동하게 해주는 기술이다. 요컨대 우리의 공격 모션 중에서 특정 모션구간 동안 대상을 향해 자연스럽게 이동시키면서 공격이 유도되는 느낌을 주거나 공격을 더 잘 맞출 수 있도록 하는 것이다. 해당 기능을 위해서는 MotionWarping 플러그인을 활성화해주어야 하며 이미 팀원이 해당 기능을 사용하기 위해 활성화 시킨 바 있기에 우리는 이를 우리의 애니메이션에 적용시키는것 만 해보도록 하자.

 

플러그인을 정상적으로 활성화 해 주었다면 애님 몽타주에서 노티파이 트랙을 추가해 주고 새 노티파이 스테이트를 추가해주려 할때 해당 항목에 MotionWarping 항목이 추가될 것이다. 우리는 해당 노티파이 스테이트를 추가해주고 구간을 모션 중에서 이동할 때 나올만한 구간으로 지정해 준 다음 디테일 패널에서 WarpTargetName을 AttackTarget으로 지정해 준다.

 

이제 캐릭터 블루프린트로 이동해서 Add or Update Warp Target from Location and Rotation 노드를 꺼내준다. 이 노드는 위치와 회전으로부터 타깃의 좌표를 얻고 이를 업데이트 해주는 함수이다. 즉 모션워핑이 시작될 때 이동할 좌표를 갱신해주는 노드이다. 우리는 공격이 Lock On 상태일 때에만 모션워핑 기능이 사용되어 적을 추적하는 느낌을 얻는것을 원한다. 그렇기에 일단 bLockOn이라는 변수가 true인지를 체크해주는것이 처음이며, 그 다음 멀리 있는 적한테 순간이동해서 떼리는 것은 원하지 않기 때문에 모션 워핑이 작동하는 거리의 제한을 줄 것이다. 다행히도 Lock On 로직 중에서 타겟 액터를 담는 변수가 존재하기 때문에 해당 변수를 이용해서 로직을 구현해줄 것이다.

기존의 공격 로직에서 모션워핑에만 해당하는 부분

 

LockOn이 true라면 대상과 플레이어 캐릭터의 좌표를 구해서 거리를 계산한 뒤 그 값이 100보다 작을 경우에는 모션 워핑이 작동하고 아닐 경우에는 워프 타겟의 정보를 지워서 모션 워핑이 작동하지 않도록 구성했다. LockOn이 아닐 경우 바로 Chooser로 연결되어 일반적인 애니메이션이 재생되도록 구성해 주었다.

거리를 늘리면 그만큼 멀리서도 접근할 수 있다.