결과물

빠른 속도로 눌러야만 인식되는 버튼을 구현했습니다.
구현 내용
1. ISequenceable.h / .cpp
ActorSequence라는 기능을 활용해서 버튼을 눌렀을 때 눌리는 연출을 출력하려고 합니다. 하지만, 현재 ActorSequence는 Experimental 기능이기 때문에 C++에서 컴포넌트로 추가했을 때 블루프린트 에디터에서 Sequence 탭이 보이지 않는 버그가 존재합니다. 따라서, ActorSequence는 블루프린트 에디터 상에서 추가하고, 재생 기능은 C++로 관리합니다.
Sequence의 시작과 끝 이벤트에 함수를 바인딩하도록 해서 추후 이벤트 설계에 용이하게 진행하려고 합니다.
ISequenceable.h
더보기
#pragma once
#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "Sequenceable.generated.h"
UINTERFACE(NotBlueprintable)
class USequenceable : public UInterface
{
GENERATED_BODY()
};
class VIRTUALREALITY_API ISequenceable
{
GENERATED_BODY()
public:
UFUNCTION()
virtual void OnSequenceStarted() = 0;
UFUNCTION()
virtual void OnSequenceEnded() = 0;
protected:
void PlaySequence();
private:
uint8 bIsBound : 1 = false;
};
ISequenceable.cpp
더보기
#include "Sequenceable.h"
#include "ActorSequenceComponent.h"
#include "ActorSequencePlayer.h"
#include "VirtualReality.h"
void ISequenceable::PlaySequence()
{
AActor* Owner = Cast<AActor>(this);
if (!Owner)
{
LOG(TEXT("Sequenceable는 AActor에만 적용 가능합니다. 함수를 종료합니다."));
return;
}
UActorSequenceComponent* SeqComp = Owner->FindComponentByClass<UActorSequenceComponent>();
if (!SeqComp)
{
LOG(TEXT("ActorSequence가 존재하지 않습니다."));
return;
}
UActorSequencePlayer* Player = SeqComp->GetSequencePlayer();
if (!Player) return;
if (!bIsBound)
{
Player->OnPlay.AddDynamic(this, &ThisClass::OnSequenceStarted);
Player->OnFinished.AddDynamic(this, &ThisClass::OnSequenceEnded);
bIsBound = true;
}
Player->Play();
}
2. ATriggerableActor.h / .cpp
이번엔 Collision에 닿았을 때 이벤트가 발생하는 오브젝트를 구현하고자 합니다. 해당 오브젝트들의 베이스 클래스를 구현해주었습니다. 자식들은 OnTriggered 함수를 오버라이딩 함으로써 간단하게 Trigger 이벤트를 구현할 수 있습니다. 현재는 테스트 용으로 VRHand가 Z축으로 닿는 속도가 300이상일 때에만 이벤트가 트리거 되도록 구현했습니다.
ATriggerableActor.h
더보기
#pragma once
#include "CoreMinimal.h"
#include "Actor/VRActorBase.h"
#include "TriggerableActor.generated.h"
class UBoxComponent;
UCLASS()
class VIRTUALREALITY_API ATriggerableActor : public AVRActorBase
{
GENERATED_BODY()
public:
ATriggerableActor();
virtual void BeginPlay() override;
protected:
virtual void OnTriggered();
private:
UFUNCTION()
void OnOverlapBegin(UPrimitiveComponent* OverlappedComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);
protected:
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "변수|컴포넌트")
TObjectPtr<UBoxComponent> TriggerRegion;
};
ATriggerableActor.cpp
더보기
#include "TriggerableActor.h"
#include "VirtualReality.h"
#include "Components/BoxComponent.h"
#include "Player/VRHand.h"
ATriggerableActor::ATriggerableActor()
{
TriggerRegion = CreateDefaultSubobject<UBoxComponent>(TEXT("TriggerRegion"));
TriggerRegion->SetupAttachment(Mesh);
}
void ATriggerableActor::BeginPlay()
{
Super::BeginPlay();
TriggerRegion->OnComponentBeginOverlap.AddDynamic(this, &ATriggerableActor::OnOverlapBegin);
}
void ATriggerableActor::OnTriggered()
{
}
void ATriggerableActor::OnOverlapBegin(UPrimitiveComponent* OverlappedComp, AActor* OtherActor,
UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
if (!OtherActor || OtherActor == this) return;
if (AVRHand* Hand = Cast<AVRHand>(OtherActor))
{
if (FMath::Abs(Hand->GetHandVelocity().Z) >= 300.0f)
{
GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Yellow, FString::Printf(TEXT("Overlap with: %s"), *OtherActor->GetName()));
OnTriggered();
}
}
}
3. ARedButton.h / .cpp
빨간 버튼 오브젝트를 위한 클래스를 구현해주었습니다. 추가적인 구현사항은 아직 없습니다.
ARedButton.h
더보기
#pragma once
#include "CoreMinimal.h"
#include "Actor/Triggerable/TriggerableActor.h"
#include "Interface/Sequenceable.h"
#include "RedButton.generated.h"
UCLASS()
class VIRTUALREALITY_API ARedButton : public ATriggerableActor, public ISequenceable
{
GENERATED_BODY()
public:
ARedButton();
public:
virtual void OnSequenceStarted() override;
virtual void OnSequenceEnded() override;
protected:
virtual void OnTriggered() override;
protected:
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "변수|컴포넌트")
TObjectPtr<UStaticMeshComponent> ButtonMesh;
};
ARedButton.cpp
더보기
#include "RedButton.h"
ARedButton::ARedButton()
{
// 버튼 메시 컴포넌트를 생성하고 루트에 부착합니다.
ButtonMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Button"));
ButtonMesh->SetupAttachment(Mesh);
}
void ARedButton::OnSequenceStarted()
{
GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, TEXT("Red Button Sequence Started"));
}
void ARedButton::OnSequenceEnded()
{
GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, TEXT("Red Button Sequence Ended"));
}
void ARedButton::OnTriggered()
{
Super::OnTriggered();
PlaySequence();
}
마무리
하루종일 Procedural Grip 모션에 대해서 이것저것 찾아보다가 뭐라도 구현해야겠다 싶어서 버튼을 하나 구현했습니다. ActorSequence가 Experimental 기능이라 여러 프로젝트에서 참 아픈 손가락처럼 다가왔었는데, 이번 VR 프로젝트 덕분에 ActorSequence에 범용적으로 활용할 수 있는 인터페이스를 설계해놔서 한시름 놓을 수 있을 것 같네요 ㅎㅎ
'Unreal Engine 프로젝트 > VR 공포게임' 카테고리의 다른 글
| [언리얼엔진] 6. VR Hand 애니메이션 제작 (0) | 2026.04.09 |
|---|---|
| [언리얼엔진] 5. VR 최적화 (0) | 2026.04.09 |
| [언리얼엔진] 4. VR 레버 구현 (2) | 2026.04.08 |
| [언리얼엔진] 3. VR Hand 물리 효과 구현 (0) | 2026.04.04 |
| [언리얼엔진] 1. VR Grab/Release 기능 구현 (C++) (0) | 2026.04.04 |