TriggerBox 를 상속 받은 C++ 클래스 CamLockTrigger 생성
#include "../Header/global.h"
#include "LockCameraActor.h"
#include "CoreMinimal.h"
#include "Engine/TriggerBox.h"
#include "CamLockTrigger.generated.h"
USTRUCT(Atomic, BlueprintType)
struct FTriggerArea
{
GENERATED_BODY();
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (AllowPrivateAccess = "true"))
int32 Left;
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (AllowPrivateAccess = "true"))
int32 Top;
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (AllowPrivateAccess = "true"))
int32 Right;
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (AllowPrivateAccess = "true"))
int32 Bottom;
public:
int32 GetWidth() { return abs(Right - Left); }
int32 GetHeight() { return abs(Bottom - Top); }
};
UCLASS()
class UNREAL_3TH_API ACamLockTrigger : public ATriggerBox
{
GENERATED_BODY()
private:
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (AllowPrivateAccess = "true"))
ALockCameraActor* m_SwitchCam;
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (AllowPrivateAccess = "true"))
FTriggerArea m_Area;
public:
virtual void BeginPlay() override;
virtual void Tick(float _DT) override;
public:
// OverlapDelegate
UFUNCTION()
void BeginTrigger(AActor* _TriggerActor, AActor* _OtherActor);
UFUNCTION()
void EndTrigger(AActor* _TriggerActor, AActor* _OtherActor);
public:
ACamLockTrigger();
~ACamLockTrigger();
};
#include "CamLockTrigger.h"
ACamLockTrigger::ACamLockTrigger()
{
PrimaryActorTick.Target = this;
PrimaryActorTick.bCanEverTick = true;
}
ACamLockTrigger::~ACamLockTrigger()
{
}
void ACamLockTrigger::BeginPlay()
{
Super::BeginPlay();
LOG(LogTemp, Warning, TEXT("ACamLockTrigger BeginPlay"));
OnActorBeginOverlap.AddDynamic(this, &ACamLockTrigger::BeginTrigger);
OnActorEndOverlap.AddDynamic(this, &ACamLockTrigger::EndTrigger);
}
void ACamLockTrigger::Tick(float _DT)
{
Super::Tick(_DT);
if (m_bOverlap)
{
if (IsValid(m_SwitchCam))
{
m_SwitchCam->PositionUpdate();
}
}
}
void ACamLockTrigger::BeginTrigger(AActor* _TriggerActor, AActor* _OtherActor)
{
LOG(LogTemp, Warning, TEXT("BeginOverlap Trigger"));
// 카메라의 시점 변경하기
if (IsValid(m_SwitchCam))
{
APlayerController* pController = UGameplayStatics::GetPlayerController(GetWorld(), 0);
pController->SetViewTargetWithBlend(m_SwitchCam, 0.f);
// trigger 로 들어온 actor 를 쫓아 다니게 설정
m_SwitchCam->SetTarget(_OtherActor);
m_SwitchCam->SetTrigger(this);
m_bOverlap = true;
m_SwitchCam->PositionUpdate();
}
}
void ACamLockTrigger::EndTrigger(AActor* _TriggerActor, AActor* _OtherActor)
{
LOG(LogTemp, Warning, TEXT("EndOverlap Trigger"));
if (IsValid(m_SwitchCam))
{
APlayerController* pController = UGameplayStatics::GetPlayerController(GetWorld(), 0);
pController->SetViewTargetWithBlend(pController->GetPawn(), 0.f);
// 시점 카메라에 추적 대상을 해제
m_SwitchCam->SetTarget(nullptr);
m_SwitchCam->SetTrigger(nullptr);
m_bOverlap = false;
}
}
프로젝트 세팅 -> 콜리전 -> 새 오브젝트 채널 -> TriggerGroup (ignore)
CameraActor 상속 받은 C++ 클래스 LockCameraActor 생성
PostEditChangeProperty 제작
UCLASS()
class UNREAL_3TH_API ACamLockTrigger : public ATriggerBox
{
GENERATED_BODY()
private:
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (AllowPrivateAccess = "true"))
FTriggerArea m_Area;
FTriggerArea m_Area_Prev;
public:
#if WITH_EDITOR
virtual void PostEditChangeProperty(FPropertyChangedEvent& _event) override;
#endif
}
------------------------------------------------------------------------------------------------
#if WITH_EDITOR
void ACamLockTrigger::PostEditChangeProperty(FPropertyChangedEvent& _event)
{
Super::PostEditChangeProperty(_event);
LOG(LogTemp, Warning, TEXT("CamLockTrigger"));
UBoxComponent* pBox = Cast<UBoxComponent>(GetCollisionComponent());
if (!IsValid(pBox))
return;
// 변화량
float XChange = ((m_Area.Left - m_Area_Prev.Left) + (m_Area.Right - m_Area_Prev.Right));
float ZChange = ((m_Area.Top - m_Area_Prev.Top) + (m_Area.Bottom - m_Area_Prev.Bottom));
FVector vTriggerLocation = GetActorLocation();
FVector vNewLocation = FVector(vTriggerLocation.X + XChange / 2.f
, vTriggerLocation.Y
, vTriggerLocation.Z + ZChange / 2.f);
SetActorLocation(vNewLocation);
pBox->SetBoxExtent(FVector(m_Area.GetWidth() / 2.f
, pBox->GetUnscaledBoxExtent().Y
, m_Area.GetHeight() / 2.f));
m_Area_Prev = m_Area;
}
#endif
카메라 액터가 트리거의 우측을 벗어나지 못하게 카메라 락을 건다.
#include "../Header/global.h"
#include "CoreMinimal.h"
#include "Camera/CameraActor.h"
#include "LockCameraActor.generated.h"
class ACamLockTrigger;
UCLASS()
class UNREAL_3TH_API ALockCameraActor : public ACameraActor
{
GENERATED_BODY()
private:
UPROPERTY()
AActor* m_Target;
UPROPERTY()
ACamLockTrigger* m_Trigger;
public:
void SetTarget(AActor* _Target) { m_Target = _Target; }
void SetTrigger(ACamLockTrigger* _Trigger) { m_Trigger = _Trigger; }
public:
void PositionUpdate();
};
void ALockCameraActor::PositionUpdate()
{
// 트리거로 진입한 타겟의 위치값을 알아낸다.
FVector vLocation = m_Target->GetActorLocation();
vLocation.Y += 200.f;
// 카메라 본인의 직교 투영 범위를 체크한다
float OrthoWidth = GetCameraComponent()->OrthoWidth;
float OrthHeight = OrthoWidth / GetCameraComponent()->AspectRatio;
// 트리거의 중심에서부터의 박스 크기 정보를 알아낸다.
UBoxComponent* pBox = Cast<UBoxComponent>(m_Trigger->GetCollisionComponent());
FVector BoxExtent = pBox->GetUnscaledBoxExtent();
// 트리거의 중심 위치를 알아낸다.
FVector vTriggerPos = m_Trigger->GetActorLocation();
// 트리거의 중심에서 박스 크기를 더한 우측 지점보다,
// 타겟 위치에서 카메라가 투영시 투영의 범위 우측이 더 오른쪽으로 초과한 부분이 있다면
if (vTriggerPos.X + BoxExtent.X < vLocation.X + (OrthoWidth / 2.f))
{
// 초과량을 계산 후, 원래 예정된 이동 위치(타겟의 위치)에서 빼주고 그 곳을 최종 이동 목적지로 한다.
float fOver = vLocation.X + (OrthoWidth / 2.f) - (vLocation.X + BoxExtent.X);
vLocation.X -= fOver;
}
SetActorLocation(vLocation);
}
'언리얼 5' 카테고리의 다른 글
231108 언리얼 엔진 5 의 새로운 기술 (2) | 2023.11.08 |
---|---|
231026 시네마틱 시퀀서 연출 (0) | 2023.10.26 |
231024 언리얼을 활용한 2D Game 제작 (움직임, 정적 카메라, 타일맵) (0) | 2023.10.25 |
231023 언리얼을 활용한 2D Game 제작 (0) | 2023.10.23 |
231018 물리 엔진 (사운드 재생) / 레벨 스트리밍 (0) | 2023.10.18 |