사용할 드래곤 캐릭터를 idle 모션이 적용되어있는 애님클래스와 스켈레탈 메시를 적용시켜줍니다
컨트롤러를 만들어준뒤 마우스클릭한곳을 쫒아가게 해주었습니다
void ADragonController::MoveToMouseCursor()
{
GetHitResultUnderCursor(ECC_Visibility, false, mouseHit);
if (mouseHit.bBlockingHit)
{
SetNewDestination(mouseHit.ImpactPoint);
}
}
void ADragonController::SetNewDestination(const FVector destination)
{
if (dragonCharacter)
{
float const distance = FVector::Dist(destination, dragonCharacter->GetActorLocation());
if (distance > 120.0f)
{
UAIBlueprintHelperLibrary::SimpleMoveToLocation(this, destination);
}
}
}
마우스가 클릭한곳으로 이동합니다
드래곤 전용 블렌드스페이스 작업을 해줍니다
애님인스턴스 로 움직임이 있으면 블렌드스페이스에 적용되어있는 애니메이션이 실행되도록 합니다
virtual void NativeInitializeAnimation() override;
virtual void NativeThreadSafeUpdateAnimation(float DeltaSeconds);
UPROPERTY()
ADragonCharacter* dragonCharacter;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="MySettings")
float groundSpeed;
UPROPERTY(VisibleDefaultsOnly, BlueprintReadOnly, Category = "Animation|LocomotionData")
bool bHasAcceleration;
void UDrangonAnimInstance::NativeInitializeAnimation()
{
Super::NativeInitializeAnimation();
dragonCharacter = Cast<ADragonCharacter>(TryGetPawnOwner());
}
void UDrangonAnimInstance::NativeThreadSafeUpdateAnimation(float DeltaSeconds)
{
if (dragonCharacter != nullptr)
{
groundSpeed = dragonCharacter->GetVelocity().Size2D();
if (groundSpeed > 0.f)
{
bHasAcceleration = true;
}
}
}
해당 변경되는 조건에는 변수로 만들어둔 HasAcceleration을 true 혹은 false를 넣어줍니다
또한 groundspeed변수값을 넣어줍니다
MouseToMouseCursor함수를 수정해줍니다
SetActorRotation함수는 bUseControllerRotationYaw = true인 경우, 캐릭터의 회전은 컨트롤러의 Yaw 회전을 따르기에
컨트롤러 회전값을 덮어씌워지기떄문에 SetControlRotation으로 방향을 변경시킵니다
또한 보간이동으로 부드럽게 고개가 돌아가도록 합니다
void ADragonController::MoveToMouseCursor()
{
GetHitResultUnderCursor(ECC_Visibility, false, mouseHit);
if (mouseHit.bBlockingHit)
{
SetNewDestination(mouseHit.ImpactPoint);
if (dragonCharacter)
{
FVector mouseToTarget = mouseHit.ImpactPoint - dragonCharacter->GetActorLocation();
FRotator mouseLookDirection = mouseToTarget.Rotation();
mouseLookDirection.Pitch = 0.f;
mouseLookDirection.Roll = 0.f;
FRotator currentRot = GetControlRotation();
FRotator newRot = FMath::RInterpTo(currentRot, mouseLookDirection, GetWorld()->GetDeltaSeconds(), 20.f);
SetControlRotation(newRot);
}
}
}
스페이스바를 누르면 날아올라 공중체공 하도록 만들었습니다
FVector startLoc;
FVector flyingTargetLoc;
bool bInterpZ = true;
float zInterpTime = 0.5f;
float zInterpElapsed = 0.f;
노티파이에서 호출할 날아오르거나 착지하는 함수입니다
void ADragonCharacter::OnTakeOff()
{
GetCharacterMovement()->StopMovementImmediately();
GetCharacterMovement()->SetMovementMode(MOVE_Flying);
GetCharacterMovement()->GravityScale = 0.f;
bFlying = true;
dragonAnimInstance->bGliding = true;
targetFOV = 110.f;
}
void ADragonCharacter::OnTakeOn()
{
GetCharacterMovement()->SetMovementMode(MOVE_Walking);
GetCharacterMovement()->GravityScale = 1.f;
bFlying = false;
dragonAnimInstance->bGliding = false;
targetFOV = 90.f;
}
void ADragonCharacter::DragonFlying()
{
startLoc = GetActorLocation();
flyingTargetLoc = startLoc + FVector(0.f, 0.f, 300.f);
zInterpElapsed = 0.f;
bInterpZ = true;
targetFOV = 110.f;
fovInterpSpeed = 1.5f;
OnTakeOff();
}
z축 방향으로 보간이동 하여 위로 이동합니다
void ADragonCharacter::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
if (bInterpZ)
{
zInterpElapsed += DeltaTime;
float progressAlpha = FMath::Clamp(zInterpElapsed / zInterpTime, 0.f, 1.f);
FVector NewLocation = FMath::Lerp(startLoc, flyingTargetLoc, progressAlpha);
SetActorLocation(NewLocation);
if (progressAlpha >= 1.f)
{
bInterpZ = false;
}
}
}
공중에서 x y 축으로 보간 이동합니다
void ADragonCharacter::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
if (bFlyingMoveToTarget)
{
FVector currentLoc = GetActorLocation();
FVector direction = (flyingTargetLocation - currentLoc).GetSafeNormal();
float flyingSpeed = 600.f;
AddMovementInput(direction, 1.f);
if (FVector::DistSquared(currentLoc, flyingTargetLocation) < FMath::Square(100.f))
{
bFlyingMoveToTarget = false;
}
}
}
토글방식의 글라이드 함수입니다
토글 쿨타임을 1.0초로 주었습니다
UPROPERTY(EditAnywhere, Category = "Flight")
float flyToggleCoolDown = 5.f;
void ADragonCharacter::ToggleFlying()
{
if (!bToggleFly)
{
return;
}
bToggleFly = false;
if (bFlying)
{
PlayAnimMontage(takeOnMontage);
}
else
{
PlayAnimMontage(takeOffMontage);
}
GetWorld()->GetTimerManager().SetTimer(th_ToggleFly, FTimerDelegate::CreateLambda([this]()
{
bToggleFly = true;
}),
flyToggleCoolDown, false);
}
애님인스턴스에서 드래곤캐릭터에서 만든 함수를 연동해줍니다
void UDrangonAnimInstance::AnimNotify_TakeOff()
{
dragonCharacter->OnTakeOff();
}
void UDrangonAnimInstance::AnimNotify_TakeOn()
{
dragonCharacter->OnTakeOn();
}
void UDrangonAnimInstance::AnimNotify_FlyingStart()
{
dragonCharacter->DragonFlying();
}
void UDrangonAnimInstance::AnimNotify_FlyingStop()
{
dragonCharacter->DragonStopFlying();
}
캐릭터의 StateMachine에 날아오른뒤에 날기를 유지하는 애니메이션을
스테이트 에일리어스를 통해 모든 상황에서 적용되도록 해주었습니다
Alias -> FlyForwardAnim [ bGlide = true ]
FlyForwardAnim -> WalkIdle [ bGlide = false ]
TakeOff
FlyForward
TakeOn
결과물
'Unreal5 프로젝트 다이어리' 카테고리의 다른 글
Unreal - Material Parameter Collection 사용하기 (0) | 2025.06.21 |
---|---|
Unreal - 드래곤 캐릭터 만들기(2) (3) | 2025.06.14 |
Unreal - 데미지 오버레이 만들기 (0) | 2025.06.08 |
Unreal - 딜레이 프로그래스바 (0) | 2025.06.07 |
Unreal - 일시정지 위젯 만들기 (0) | 2025.06.07 |