카메라 효과는 게임 스킬에 드라마틱한 요소를 준다. 스킬 구현 시 카메라가 플레이어 주위를 돌게 만들어 스킬에 극적인 효과를 추가하자.  

 

목차

     

     


     

     

     

     

     
    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가 불러져야 된다.

    게임이 실행되는 상황

    1. 직접 참조
      • 아무것도 할당하지 않은 상황. 
      • ex. UPROPERTY 매크로
      • Editor에서 Property를 값을 넣으면 강 참조가 일어난다.
    2. 생성시간 참조
      • 프로그래머가 직접 설정하는 경우.
      • Property를 Object 생성시 일부분으로 설정하는 경우
      • Object가 로드 및 초기화되면 강 참조된 에셋도 로드된다. 따라서 다수의 에셋이 한 번에 로드되면 메모리 부하가 높아지는 문제가 발생할 수 있다. 그 로딩을 유예(=지연=deferred)시키고 실행시간에 로드할 부분을 결정하고자 하면 간접 프로퍼티 참조를 사용하는게 좋다.

     

     

     

     

    약 참조

    Object A가 Object B를 참조한다.

     

    1. 간접 프로퍼티 참조
      •  TSoftObjectPtr 을 사용하여 애셋 로드 시점을 쉽게 제어할 수 있다.
      • 직접 포인터 레퍼런스 대신, 애셋의 로드 여부에 대한 안전 검사가 가능한 템플릿 코드와 함께 프로퍼티가 스트링으로 저장됩니다

     

     

    TSoftObjectPtr

    • 약 연결
    • TSoftObjectPtr 안에 포인터가 있으면 리턴하고 없으면 쓰지 않는다.
    • TSoftObjectPtr 을 사용하려면 애셋을 수동으로 로드해야 한다.
    • 주소를 가지고 있거나 주소를 가지고 있지 않는 경우 모두 가능. 
    • 실행시간에 메시를 지연시켜

     

    LoadObject<>() 메서드나 StaticLoadObject()는 유사하다. LoadObject<>() 메서드가 StaticLoadObject()를 콜하는 방식이다. LoadObject<>()와 StaticLoadObject()는 동기화 방식이다? 비동기화 방식으로 사용할 때는 Thread를 활용한다. 

     

    LoadObject<>()나 StaticLoadObject(). 사용예시: 게임에서 맵을 이동 후 한번에 불러야 할 때 사용. 

     

    더보기

    위 생성자에서 ConstructorHelpers 클래스는 메모리에서 애셋을 찾아본 다음, 없으면 로드합니다. 로드할 것을 지정하는 데 애셋에 대한 전체 경로가 쓰인 것이 보입니다. 애셋이 존재하지 않거나 오류로 인해 로드할 수 없는 경우, 프로퍼티는 nullptr 로 설정됩니다. 그런 일이 발생하면, 텍스처를 접근하려는 코드는 크래시가 납니다. 어서트를 통해 애셋을 제대로 로드시켜 나중의 코드에서 레퍼런스가 유효하다 간주할 수 있도록 합니다.

    UPROPERTY 선언은 이전의 강 레퍼런스 예제에서도 똑같이 나타납니다. 초기 설정 부분만 빼면 동일한 방식으로 작동합니다. 강 참조에 대해 한 가지 고려할 점은, 오브젝트가 로드 및 초기화되면 강 참조된 애셋도 로드된다는 점입니다. 세심히 주의를 기울이지 않으면 다수의 애셋이 한꺼번에 로드되어 메모리가 눈덩이처럼 불어날 것입니다. 그 로딩을 유예시키고 실행시간에 로드할 부분을 결정하고자 한다면, 다음 부분이 도움이 될 것입니다.

     

     


     

     

    참고 자료: 언리얼 공식문서 링크

     

    https://docs.unrealengine.com/4.27/ko/ProgrammingAndScripting/ProgrammingWithCPP/Assets/ReferencingAssets/

     

    애셋 참조

     

    docs.unrealengine.com

    https://docs.unrealengine.com/4.27/ko/ProgrammingAndScripting/ProgrammingWithCPP/Assets/AsyncLoading/

     

    비동기 애셋 로딩

    실행시간에 애셋을 로드/언로드하는 메서드입니다.

    docs.unrealengine.com

     

     


     

     

     

     

    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로 설정.

     


     

     

    실행화면