[UE] 카메라 애니메이션 구현하기
카메라 효과는 게임 스킬에 드라마틱한 요소를 준다. 스킬 구현 시 카메라가 플레이어 주위를 돌게 만들어 스킬에 극적인 효과를 추가하자.
목차
Plugins |
||||
Weapon |
||||
Resource |
||||
Icon128.png weapon_thumbnail_icon.png |
||||
Source |
||||
Weapon | ||||
SWeaponCheckBoxes.h .cpp SWeaponDetailsView.h .cpp SWeaponDoActionData.h .cpp SWeaponEquipmentData.h .cpp SWeaponHitData.h .cpp SWeaponLeftArea.h .cpp Weapon.Build.cs WeaponAssetEditor.h .cpp WeaponAssetFactory.h .cpp WeaponCommand.h .cpp WeaponContextMenu.h .cpp WeaponModule.h .cpp WeaponStyle.h .cpp |
||||
Source | ||
U2212_06 | ||
Characters | ||
CAnimInstance.h .cpp CEnemy.h .cpp CPlayer.h .cpp ICharacter.h .cpp |
||
Components | ||
CMontagesComponent.h .cpp CMovementComponent.h .cpp CStateComponent.h .cpp CStatusComponent.h .cpp CWeaponComponent.h .cpp |
||
Notifies | ||
CAnimNotifyState_BeginAction.h .cpp CAnimNotify_CameraShake.h .cpp CAnimNotifyState_EndAction.h .cpp CAnimNotify_EndState.h .cpp CAnimNotifyState.h .cpp CAnimNotifyState_CameraAnim.h .cpp 생성 CAnimNotifyState_Collision.h .cpp CAnimNotifyState_Combo.h .cpp CAnimNotifyState_Equip.h .cpp CAnimNotifyState_SubAction.h .cpp |
||
Utilities | ||
CHelper.h CLog.h .cpp |
||
Weapons | ||
CCamerModifier.h .cpp 생성 CDoAction_Combo.h .cpp CSubAction_Fist.h .cpp CAttachment.h .cpp CDoAction.h .cpp CEquipment.h .cpp CSubAction.h .cpp CWeaponAsset.h .cpp CWeaponStructures.h .cpp |
||
Global.h CGameMode.h .cpp U2212_06.Build.cs |
||
U2212_06.uproject | ||
강 참조와 약 참조
강 참조 vs. 약 참조
강 참조
Object A 로드 시 Object B가 로드되게 만든다. 다른말로 하면 Object A를 만들 때 Object B가 불러져야 된다.
게임이 실행되는 상황
- 직접 참조
- 아무것도 할당하지 않은 상황.
- ex. UPROPERTY 매크로
- Editor에서 Property를 값을 넣으면 강 참조가 일어난다.
- 생성시간 참조
- 프로그래머가 직접 설정하는 경우.
- Property를 Object 생성시 일부분으로 설정하는 경우
- Object가 로드 및 초기화되면 강 참조된 에셋도 로드된다. 따라서 다수의 에셋이 한 번에 로드되면 메모리 부하가 높아지는 문제가 발생할 수 있다. 그 로딩을 유예(=지연=deferred)시키고 실행시간에 로드할 부분을 결정하고자 하면 간접 프로퍼티 참조를 사용하는게 좋다.
약 참조
Object A가 Object B를 참조한다.
- 간접 프로퍼티 참조
- TSoftObjectPtr 을 사용하여 애셋 로드 시점을 쉽게 제어할 수 있다.
- 직접 포인터 레퍼런스 대신, 애셋의 로드 여부에 대한 안전 검사가 가능한 템플릿 코드와 함께 프로퍼티가 스트링으로 저장됩니다
TSoftObjectPtr
- 약 연결
- TSoftObjectPtr 안에 포인터가 있으면 리턴하고 없으면 쓰지 않는다.
- TSoftObjectPtr 을 사용하려면 애셋을 수동으로 로드해야 한다.
- 주소를 가지고 있거나 주소를 가지고 있지 않는 경우 모두 가능.
- 실행시간에 메시를 지연시켜
LoadObject<>() 메서드나 StaticLoadObject()는 유사하다. LoadObject<>() 메서드가 StaticLoadObject()를 콜하는 방식이다. LoadObject<>()와 StaticLoadObject()는 동기화 방식이다? 비동기화 방식으로 사용할 때는 Thread를 활용한다.
LoadObject<>()나 StaticLoadObject(). 사용예시: 게임에서 맵을 이동 후 한번에 불러야 할 때 사용.
위 생성자에서 ConstructorHelpers 클래스는 메모리에서 애셋을 찾아본 다음, 없으면 로드합니다. 로드할 것을 지정하는 데 애셋에 대한 전체 경로가 쓰인 것이 보입니다. 애셋이 존재하지 않거나 오류로 인해 로드할 수 없는 경우, 프로퍼티는 nullptr 로 설정됩니다. 그런 일이 발생하면, 텍스처를 접근하려는 코드는 크래시가 납니다. 어서트를 통해 애셋을 제대로 로드시켜 나중의 코드에서 레퍼런스가 유효하다 간주할 수 있도록 합니다.
UPROPERTY 선언은 이전의 강 레퍼런스 예제에서도 똑같이 나타납니다. 초기 설정 부분만 빼면 동일한 방식으로 작동합니다. 강 참조에 대해 한 가지 고려할 점은, 오브젝트가 로드 및 초기화되면 강 참조된 애셋도 로드된다는 점입니다. 세심히 주의를 기울이지 않으면 다수의 애셋이 한꺼번에 로드되어 메모리가 눈덩이처럼 불어날 것입니다. 그 로딩을 유예시키고 실행시간에 로드할 부분을 결정하고자 한다면, 다음 부분이 도움이 될 것입니다.
참고 자료: 언리얼 공식문서 링크
Camera Animation 구현하기
CA_Fist 생성
Movement 추가
- 0초, 3초, 6초에 위치 할당.
CAnimNotifyState_CameraAnim 생성
새 C++ 클래스 - AnimNotifyState - CAnimNotifyState_CameraAnim 생성
CAnimNotifyState_CameraAnim.h
#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()
public:
UCAnimNotifyState_CameraAnim();//생성자
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")
TSubclassOf<class UCameraModifier> ModifierClass;
UPROPERTY(EditAnywhere, Category = "Modifier")
FVector LocationOffset = FVector(-400, 0, 90);
UPROPERTY(EditAnywhere, Category = "Modifier")
float PitchOffset = -15.0f;
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;
};
CAnimNotifyState_CameraAnim.cpp
#include "Notifies/CAnimNotifyState_CameraAnim.h"
#include "Global.h"
#include "GameFramework/Character.h"
#include "GameFramework/PlayerController.h"//Player CameraManager를 가지고 있다.
#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;//Unreal Editor에서 설정하지 않으면 기본값은 Player다.
if (Target.IsNull() == false)//Target이 있다면(=Unreal Editor에서 Target을 지정했다면)
target = Target.Get();
FVector location = target->GetActorLocation();//Target의 위치
float yaw = controller->GetControlRotation().Yaw;
location += FRotator(0., yaw, 0).RotateVector(LocationOffset);//LocationOffset에서 yaw만큼 돌린 값을 더한다.
CheckNull(ModifierClass);//CameraModifier가 없다면 리턴.
UCameraModifier* modifier = controller->PlayerCameraManager->AddNewCameraModifier(ModifierClass);
Modifier = Cast<UCCameraModifier>(modifier);//CameraModifier 할당.
Modifier->SetLocation(location);//위치 값을 넣어준다.
Modifier->SetRotation(FRotator(PitchOffset, yaw, 0));//회전값을 넣어준다.
controller->SetControlRotation(FRotator(0, controller->GetControlRotation().Yaw, 0));//controller의 Yaw값을 고정시켜준다.
controller->PlayerCameraManager->PlayCameraAnim(CameraAnim, PlayRatio, 1, BlendInTime, BlendOutTime, false, false, 0, ECameraShakePlaySpace::UserDefined, controller->GetControlRotation());//UserDefined는 우리공간 기준(우리가 Play하는 곳 기점), World는 월드위치, CameraLocal은 relative위치
}
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);
controller->PlayerCameraManager->RemoveCameraModifier(Modifier);//끝난 후에 해제.
}
CCameraModifier 생성
새 C++ 클래스 - CameraModifier - CCameraModifier 생성
Camera Modifier는 APlayerCameraManager에서 계산된 후에 최종 카메라 프로퍼티를 조정할 수 있는 오브젝트의 베이스 클래스입니다.
CameraModifier는 State에 기반하여, 특정 APlayerCameraManager에 고유하게 연관되어 있습니다.
CCameraModifier 사용하는 이유는?
카메라를 사용하는 애들은 전부 Camera Modifier를 가지고 있다. Camera Modifier가 등록되어 있는 상태에서 게임을 플레이 하면 Camera Modifier에 의해 Camera 값(location, rotator 등등)이 수정이 된다.
CCameraModifier.h
#pragma once
#include "CoreMinimal.h"
#include "Camera/CameraModifier.h"
#include "CCameraModifier.generated.h"
UCLASS()
class U2212_06_API UCCameraModifier : public UCameraModifier
{
GENERATED_BODY()
public:
//외부에서 값을 넣어줄 수 있게 FORCEINLINE 함수 사용.
FORCEINLINE void SetLocation(const FVector& InLocation) { Location = InLocation; }
FORCEINLINE void SetRotation(const FRotator& InRotation) { Rotation = InRotation; }
protected:
void ModifyCamera(float DeltaTime, FVector ViewLocation, FRotator ViewRotation, float FOV, FVector& NewViewLocation, FRotator& NewViewRotation, float& NewFOV) override;
private:
FVector Location;
FRotator Rotation;
};
CCameraModifier.cpp
#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;
}
Fist_Skill_Montage에 Camera Animation 넣어주기
Fist_Skill_Montage에 노티파이 트랙을 추가하고 CAnimNotifyState_CameraAnim을 넣어준다.
- CameraAnim: CA_Fist 할당
- Play Ratio: 5.0 설정. 원하는 시간(초)를 설정해준다.
- Blend in Time: 0.0 설정. 원래 카메라에서 Animation 카메라로 전환되는 시간
- Blend out Time: 0.0 설정. Animation 카메라에서 원래 카메라로 전환되는 시간
- Target: 타켓을 CEnemy로 설정.
실행화면
'⭐ Unreal Engine > UE RPG Skill' 카테고리의 다른 글
[UE] 해머 스킬 만들기 (0) | 2023.06.27 |
---|---|
[UE] 일섬 스킬 충돌, 해머 스킬 만들기 (0) | 2023.06.26 |
[UE] 주먹 스킬 충돌처리, 전진 찌르기 스킬 구현하기 (0) | 2023.06.23 |
[UE] 잔상효과 구현하기 (0) | 2023.06.22 |
[UE] 주먹 난타 스킬 구현하기 (0) | 2023.06.20 |
댓글
이 글 공유하기
다른 글
-
[UE] 일섬 스킬 충돌, 해머 스킬 만들기
[UE] 일섬 스킬 충돌, 해머 스킬 만들기
2023.06.26 -
[UE] 주먹 스킬 충돌처리, 전진 찌르기 스킬 구현하기
[UE] 주먹 스킬 충돌처리, 전진 찌르기 스킬 구현하기
2023.06.23 -
[UE] 잔상효과 구현하기
[UE] 잔상효과 구현하기
2023.06.22 -
[UE] 주먹 난타 스킬 구현하기
[UE] 주먹 난타 스킬 구현하기
2023.06.20