초보 코린이의 성장 일지

UE4 SubAction Fist, Camera Move 본문

언리얼

UE4 SubAction Fist, Camera Move

코오린이 2023. 6. 21. 16:09

Fist 스킬을 시전할때 카메라 이동 효과를 주게끔 만들어 볼 것이다. 노티파이로 카메라 시전 효과를 주게되는데 중요한 점이 하나있다.

 

CameraLocal = 카메라 공간을 나타낸다.

World = 월드 위치

UserDefinded = 나의 공간

 

이걸 알고 넘어가야 하는 이유는, 각자의 공간에서 UserDefinded이 아니면 회전값을 사용할 수가 없다. 내가 정해놓은 플레이 기준으로 회전값을 줘야하기 때문이다.


더보기
#pragma once

#include "CoreMinimal.h"
#include "Animation/AnimNotifies/AnimNotifyState.h"
#include "CAnimNotifyState_CameraAnim.generated.h"

UCLASS()
class U2212_06_API UCAnimNotifyState_CameraAnim : public UAnimNotifyState
{
    GENERATED_BODY()

private:
    UPROPERTY(EditAnywhere, Category = "Camera")
        class UCameraAnim* CameraAnim;

    UPROPERTY(EditAnywhere, Category = "Camera")
        float PlayRatio = 1.0f;

    UPROPERTY(EditAnywhere, Category = "Camera")
        float BlendInTime = 0.0f; // 원래 카메라에서 Animation 카메라로 전환되는 시간

    UPROPERTY(EditAnywhere, Category = "Camera")
        float BlendOutTime = 0.0f; // Animation 카메라에서 원래 카메라로 전환되는 시간

    UPROPERTY(EditAnywhere, Category = "Camera")
        TSoftObjectPtr<class ACharacter> Target;

    UPROPERTY(EditAnywhere, Category = "Modifier")
        FVector LocationOffset = FVector(-400, 0, 90);

    UPROPERTY(EditAnywhere, Category = "Modifier")
        float PitchOffset = -15.0f; // pitch 각도

public:
    UCAnimNotifyState_CameraAnim();

public:
    FString GetNotifyName_Implementation() const override;

    virtual void NotifyBegin(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation, float TotalDuration) override;
    virtual void NotifyEnd(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation) override;

private:
    class UCCameraModifier* Modifier;

};
#include "Notifies/CAnimNotifyState_CameraAnim.h"
#include "Global.h"
#include "GameFramework/Character.h"
#include "GameFramework/PlayerController.h" //Camaera Manager에 사용.
#include "Camera/PlayerCameraManager.h"
#include "Camera/CameraAnim.h"
#include "Weapons/AddOns/CCameraModifier.h"

UCAnimNotifyState_CameraAnim::UCAnimNotifyState_CameraAnim()
{
	ModifierClass = UCCameraModifier::StaticClass();
}

FString UCAnimNotifyState_CameraAnim::GetNotifyName_Implementation() const
{
	return "CameraAnim";
}

void UCAnimNotifyState_CameraAnim::NotifyBegin(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation, float TotalDuration)
{
	Super::NotifyBegin(MeshComp, Animation, TotalDuration);

	CheckNull(MeshComp);
	CheckNull(MeshComp->GetOwner());
	CheckNull(CameraAnim);

	ACharacter* character = Cast<ACharacter>(MeshComp->GetOwner());
	CheckNull(character);

	APlayerController* controller = character->GetController<APlayerController>();
	CheckNull(controller);
	
	// 카메라는 우리가 만든 공간을 사용, 상대좌표를 사용하게끔 설정.
	controller->PlayerCameraManager->PlayCameraAnim(CameraAnim, PlayRatio, 1, BlendInTime, BlendOutTime, false, false, 0, ECameraShakePlaySpace::UserDefined, controller->GetControlRotation());

}

void UCAnimNotifyState_CameraAnim::NotifyEnd(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation)
{
	Super::NotifyEnd(MeshComp, Animation);

	CheckNull(MeshComp);
	CheckNull(MeshComp->GetOwner());
	CheckNull(CameraAnim);

}

1. 카메라 공간을 우리가 정해놓은 공간 플레이어 기준으로 결정하고 회전값을 주게끔 만들어 준다.

1. 노티파이를 넣어준다.

1. 카메라가 정해진 라인을 따라서 회전하는걸 확인할 수 있다.

2. 실행할때 플레이어 등 뒤에서 실행하게 되는데 그 이유는 원래는 플레이어 위치에서 시작되는게 맞으나 충돌되서 뒤로 밀려나와서 실행되서 그렇게 보이는것 뿐이다.

3. 일정간격을 줘서 떨어진 상태로 자연스럽게 이동하도록 만들어 볼 것이다.


1. Modifier에 등록해서 사용할 것이다. 그래서 클래스를 생성해준다.

 

1. 상속받은 부모 UCameraModifier로 들어가서 Override할 함수를 가져와서 사용할 것이다.

더보기
#pragma once

#include "CoreMinimal.h"
#include "Camera/CameraModifier.h"
#include "CCameraModifier.generated.h"

UCLASS()
class U2212_06_API UCCameraModifier : public UCameraModifier
{
	GENERATED_BODY()

protected:
	void ModifyCamera(float DeltaTime, FVector ViewLocation, FRotator ViewRotation, float FOV, FVector& NewViewLocation, FRotator& NewViewRotation, float& NewFOV) override;

private:
	FVector Location;
	FRotator Rotation;

public:
	// 외부에서 값 넣어주기
	FORCEINLINE void SetLocation(const FVector& InLocation) { Location = InLocation; }
	FORCEINLINE void SetRotation(const FRotator& InRotation) { Rotation = InRotation; }
};
#include "Weapons/AddOns/CCameraModifier.h"
#include "Global.h"

void UCCameraModifier::ModifyCamera(float DeltaTime, FVector ViewLocation, FRotator ViewRotation, float FOV, FVector& NewViewLocation, FRotator& NewViewRotation, float& NewFOV)
{
	Super::ModifyCamera(DeltaTime, ViewLocation, ViewRotation, FOV, NewViewLocation, NewViewRotation, NewFOV);

	// 원래 있던 값에서, 계산해서 넣어줄 새로운 값
	NewViewLocation = Location;
	NewViewRotation = Rotation;

}

1. 매개변수에 값을 전부 사용하는게 아닌 필요한 값만 설정해서 사용할 것이다.

2. 새로운 값을 넣어서 사용한다.


더보기
#pragma once

#include "CoreMinimal.h"
#include "Animation/AnimNotifies/AnimNotifyState.h"
#include "CAnimNotifyState_CameraAnim.generated.h"

UCLASS()
class U2212_06_API UCAnimNotifyState_CameraAnim : public UAnimNotifyState
{
    GENERATED_BODY()

private:
    // 타입을 받아와서 사용하기 위해,
    UPROPERTY(EditAnywhere, Category = "Modifier")
        TSubclassOf<class UCameraModifier> ModifierClass;
public:
    UCAnimNotifyState_CameraAnim();

public:
    FString GetNotifyName_Implementation() const override;

    virtual void NotifyBegin(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation, float TotalDuration) override;
    virtual void NotifyEnd(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation) override;

private:
    class UCCameraModifier* Modifier;

};
#include "Notifies/CAnimNotifyState_CameraAnim.h"
#include "Global.h"
#include "GameFramework/Character.h"
#include "GameFramework/PlayerController.h" //Camaera Manager에 사용.
#include "Camera/PlayerCameraManager.h"
#include "Camera/CameraAnim.h"
#include "Weapons/AddOns/CCameraModifier.h"

UCAnimNotifyState_CameraAnim::UCAnimNotifyState_CameraAnim()
{
	// 기본값
	ModifierClass = UCCameraModifier::StaticClass();
}

FString UCAnimNotifyState_CameraAnim::GetNotifyName_Implementation() const
{
	return "CameraAnim";
}

void UCAnimNotifyState_CameraAnim::NotifyBegin(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation, float TotalDuration)
{
	Super::NotifyBegin(MeshComp, Animation, TotalDuration);

	CheckNull(MeshComp);
	CheckNull(MeshComp->GetOwner());
	CheckNull(CameraAnim);

	ACharacter* character = Cast<ACharacter>(MeshComp->GetOwner());
	CheckNull(character);

	APlayerController* controller = character->GetController<APlayerController>();
	CheckNull(controller);
	
	ACharacter* target = character;
	if (Target.IsNull() == false) // 타겟이 있다면 지정한 target를 기준으로 움직이게 설정해준다.
		target = Target.Get();

	FVector location = target->GetActorLocation();

	// 카메라 위치 값을 주는 부분
	float yaw = controller->GetControlRotation().Yaw;
	location += FRotator(0, yaw, 0).RotateVector(LocationOffset);

	CheckNull(ModifierClass); // 없으면 실행하면 안된다.
	UCameraModifier* modifier = controller->PlayerCameraManager->AddNewCameraModifier(ModifierClass);
	Modifier = Cast<UCCameraModifier>(modifier);

	// 위치 계산된 새로운 값
	Modifier->SetLocation(location);
	Modifier->SetRotation(FRotator(PitchOffset, yaw, 0)); // Pitch는 우리가 정해준 값, Yaw값은 누적되서 바뀌게 되므로 고정시켜준다.

	controller->SetControlRotation(FRotator(0, controller->GetControlRotation().Yaw, 0)); // Yaw값은 GetControlRotation꺼 사용
	// 카메라는 우리가 만든 공간을 사용, 상대좌표를 사용하게끔 설정.
	controller->PlayerCameraManager->PlayCameraAnim(CameraAnim, PlayRatio, 1, BlendInTime, BlendOutTime, false, false, 0, ECameraShakePlaySpace::UserDefined, controller->GetControlRotation());

}

void UCAnimNotifyState_CameraAnim::NotifyEnd(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation)
{
	Super::NotifyEnd(MeshComp, Animation);

	CheckNull(MeshComp);
	CheckNull(MeshComp->GetOwner());
	CheckNull(CameraAnim);

	ACharacter* character = Cast<ACharacter>(MeshComp->GetOwner());
	CheckNull(character);

	APlayerController* controller = character->GetController<APlayerController>();
	CheckNull(controller);

	// Modifier가 등록해 놓은면 모든 카메라에 영향을 주므로, 사용했으면 바로 해제해준다.
	controller->PlayerCameraManager->RemoveCameraModifier(Modifier);
}

1. Target이 지정되어 있다면 Target 기준으로 회전하고, 지정을 해주지 않는다면 플레이어 기준으로 회전을 하게 만들어 준다.

2. 새로운 위치값을 지정해주고 설정.

3. Yaw값과 Pitch값을 지정해 주는 부분을 보면 이유가 존재한다. 회전값이 누적되서 Yaw가 변하기 때문에 만일 고정을 시켜주지 않는다면 이상한 각도에서 스킬을 시전하면 플레이어 기준이 아닌 꺽여진 이상한 각도에서 회전해 버리면서 이상한 상황이 연출된다.

1. 실행해보면 자연스럽게 이동하지만 중간에 끊기는 부분이 존재하는데 이건 노티파이가 끝나는 지점에 보이는 현상이다.

1. 이를 자연스럽게 보이도록 만들어 주려면, Play Ratio로 속도를 빠르게 만들어주면 된다.


https://www.youtube.com/watch?v=lEqboU_MwUc 

 

'언리얼' 카테고리의 다른 글

UE4 SubAction Fist, Sword Skill  (0) 2023.06.23
UE4 SubAction Fist, Ghost Trail  (0) 2023.06.22
UE4 SubAction Fist  (0) 2023.06.20
UE4 SubAction Fist  (0) 2023.06.20
UE4 Weapon Plugin (10)  (0) 2023.06.15
Comments