개요
형변환(Casting)은 액터에 대한 레퍼런스를 받아 다른 클래스로 변환하려고 할 때 흔히 사용하는 커뮤니케이션 방법입니다. 변환이 성공적으로 이루어졌다면 직접 액터 커뮤니케이션을 사용하여 정보 및 기능에 액세스할 수 있습니다.
이 방법은 형변환(Cast) 노드를 사용하여 액터의 레퍼런스를 특정 클래스로 변환해 볼 수 있도록 레벨의 액터에 대한 레퍼런스가 필요합니다. 이 커뮤니케이션 방법은 작업 중인 액터와 타깃 액터 사이의 일대일 관계를 사용합니다.
목표
이 퀵스타트 가이드에서는 형변환을 사용하여 타깃 액터의 정보에 액세스하는 방법을 배우게 됩니다.
세부 목표
-
변수 값에 기반하여 회전하는 액터를 생성합니다.
-
ThirdPersonCharacter 블루프린트를 수정하여 오버랩 시 회전하는 액터로 형변환합니다.
-
회전하는 액터로부터 여러 개의 자손 액터를 생성하여 동일한 부모를 공유하는 많은 액터에 형변환이 어떻게 작용하는지 확인합니다.
1 - 필수 구성
-
메뉴의 새 프로젝트 카테고리(New Project Categories) 섹션에서 게임(Games) 을 선택하고 다음(Next) 을 클릭합니다.
-
삼인칭(Third Person) 템플릿을 선택하고 다음(Next) 을 클릭합니다.
-
블루프린트(Blueprint) 및 시작용 콘텐츠 포함(With Starter Content) 옵션을 선택하고 프로젝트 생성(Create Project) 을 클릭합니다.
섹션 결과
이제 새로운 삼인칭 프로젝트가 생성되었으며, 형변환에 대해 배울 준비가 되었습니다.
2 - 회전하는 액터 생성하기
이 예시에서는 플레이어가 가까이 있으면 스태틱 메시를 회전하기 시작하는 액터를 생성할 것입니다.
-
콘텐츠 브라우저(Content Browser) 에서 우클릭한 다음 기본 에셋 생성(Create Basic Asset) 섹션에서 블루프린트 클래스(Blueprint Class) 를 클릭합니다.
-
액터(Actor) 를 부모 클래스로 선택하고 블루프린트 이름을 BP_RotateObject 로 설정합니다.
-
콘텐츠 브라우저(Content Browser) 에서 블루프린트를 더블 클릭하여 엽니다. 그런 다음 블루프린트 에디터 창에서 컴포넌트(Components) 패널로 이동하여 컴포넌트 추가(Add Component) 버튼을 클릭합니다. 스태틱 메시(Static Mesh) 를 검색해 선택합니다. 이렇게 하면 블루프린트에 스태틱 메시 컴포넌트가 추가됩니다.
-
스태틱 메시(Static Mesh) 컴포넌트가 선택된 상태에서 디테일(Details) 패널로 이동하여 스태틱 메시(Static Mesh) 드롭다운을 클릭합니다. Shape_Cube 를 검색해 선택합니다.
-
이벤트 그래프(Event Graph) 에서 우클릭하여 컨텍스트에 따라 검색 창을 열고, AddActorLocalRotation 을 검색 및 선택하여 이 노드를 그래프에 추가합니다.
-
AddActorLocalRotation 노드를 이벤트 틱(Event Tick) 에 연결합니다. Z 값(Z value) 은 2.0 으로 설정합니다.
-
블루프린트를 컴파일(Compile) 하고 저장(Save) 합니다.
-
BP_RotateObject 액터를 레벨로 드래그한 후 플레이(Play) 를 누릅니다. 큐브가 계속 회전하는 것을 볼 수 있습니다.
-
이제 플레이어가 가까이 왔을 때만 오브젝트가 스핀하도록 조건을 추가해 보겠습니다. 이벤트 그래프(Event Graph) 를 우클릭하여 분기(Branch) 노드를 추가합니다. 이벤트 틱(Event Tick) 의 출력 핀과 AddActorLocalRotation 노드의 입력 핀 사이의 노드를 연결합니다.
-
Can Rotate 라는 불린(Boolean) 타입 변수를 생성하고, 아래 이미지처럼 분기(Branch) 노드의 조건(Condition) 핀에 연결합니다.
-
블루프린트를 컴파일(Compile) 한 다음 CanRotate 의 디폴트 값(Default Value) 을 False 로 설정합니다.
-
내 블루프린트(My Blueprints) 탭으로 이동한 후 함수 추가(+ Function) 버튼을 클릭하여 새로운 함수를 생성합니다. 함수의 이름을 OverlappedPlayer 로 지정합니다.
-
함수가 선택된 상태에서 디테일(Details) 패널로 이동하여 새 파라미터 추가(+ New Parameter) 버튼을 클릭합니다. 새 불린 파라미터의 이름을 Begin Overlap 으로 지정합니다.
-
CanRotate 변수를 함수 안으로 드래그한 후 Set CanRotate 를 선택합니다. Overlapped Player 노드를 Set Can Rotate 노드에 연결합니다. 아래와 같이 Overlapped Player 노드의 Begin Overlap 핀을 Set Can Rotate 노드의 Can Rotate 핀에 연결합니다.
-
블루프린트를 컴파일(Compile) 하고 저장(Save) 합니다.
섹션 결과
이 섹션에서는 CanRotate 변수가 True 로 설정되면 스태틱 메시를 회전하는 액터를 생성해 보았습니다.
3 - 플레이어 블루프린트 수정하기
이 섹션에서는 ThirdPersonCharacter 블루프린트를 수정하여 BP_RotateObject 액터로 형변환하고, 플레이어가 가까이 있을 때 Rotate 변수가 True 가 되도록 설정해 보겠습니다.
-
ThirdPersonCharacter 블루프린트가 선택된 상태에서 월드 아웃라이너(World Outliner) 로 이동한 후 ThirdPersonCharacter 편집(Edit ThirdPersonCharacter) 을 클릭하여 블루프린트를 엽니다.
-
블루프린트 에디터 창에서 컴포넌트(Components) 패널로 이동하여 컴포넌트 추가(Add Component) 버튼을 클릭합니다. 구체 콜리전(Sphere Collision) 을 검색해 선택합니다. 이렇게 하면 블루프린트에 구체 콜리전 컴포넌트가 추가됩니다.
-
구체 콜리전(Sphere Collision) 컴포넌트를 선택한 상태로 디테일(Details) 패널로 이동해 반경(Radius) 을 200으로 설정합니다.
-
구체 콜리전(Sphere Collision) 컴포넌트를 우클릭하고 OnComponentBeginOverlap 및 OnComponentEndOverlap 이벤트를 선택하여 이벤트 그래프(Event Graph) 에 추가합니다.
-
컴포넌트 오버랩 시작 시(On Component Begin Overlap) 노드의 Other Actor 핀에서 드래그한 다음 BP_RotateObject에 형변환(cast to BP Rotate Object) 을 검색해 선택합니다.
-
As BP Rotate Object 핀에서 드래그한 다음 Overlapped Player 를 검색해 선택합니다. Overlapped Player 노드의 Begin Overlap 핀을 활성화합니다.
-
5단계 및 6단계를 반복하여 동일한 노드를 컴포넌트 오버랩 종료 시(On Component End Overlap) 노드에 어태치합니다. Overlapped Player 노드의 Begin Overlap 핀을 비활성화합니다.
-
블루프린트를 컴파일(Compile) 하고 저장(Save) 합니다.
-
플레이(Play) 를 누른 다음 BP_RotateObject 액터에 접근하여 플레이어가 가까이 있을 때만 회전하는 것을 확인합니다.
섹션 결과
이 섹션에서는 오버랩하는 모든 액터에 형변환 노드를 사용하는 ThirdPersonCharacter 블루프린트에 구체 오버랩 컴포넌트를 추가해 보았습니다.
ThirdPersonCharacter 블루프린트는 오버랩된 액터 레퍼런스를 사용하여 BP_RotateObject 로 형변환하고, 플레이어가 가까이 있을 때 CanRotate 변수를 True 로 설정합니다. 오버랩된 액터가 BP_RotateObject 클래스의 인스턴스가 아닐 경우, 노드는 실패하고 아무 변수도 설정되지 않습니다.
4 - 다양한 회전 셰이프 추가하기
이제 BP_RotateObject 액터 클래스에서 여러 개의 자손 액터를 생성하여 플레이어에게 반응하는 다양한 셰이프를 추가해 보겠습니다. 이 과정에서는 일반 부모 클래스로 형변환하는 기능을 유지하면서도 자손 액터를 사용하여 변경사항을 적용하거나 기능을 추가하는 방법을 볼 수 있습니다.
-
콘텐츠 브라우저(Content Browser) 에서 BP_RotateObject 를 우클릭하여 자손 블루프린트 클래스 생성(Create Child Blueprint Class) 을 선택합니다. 블루프린트 이름을 BP_RotateObject_Cone 으로 지정합니다.
-
위 과정을 두 번 더 반복하여 BP_RotateObject_Pyramid 및 BP_RotateObject_Torus 를 생성합니다.
-
BP_RotateObject_Cone 을 연 후 컴포넌트(Components) 창에서 스태틱 메시(Static Mesh) 컴포넌트를 선택합니다. 디테일(Details) 패널에서 스태틱 메시(Static Mesh) 드롭다운을 클릭한 다음 Shape_Cone 을 검색해 선택합니다.
-
Y 회전(Rotation) 을 90도로 설정합니다.
-
블루프린트를 컴파일(Compile) 하고 저장(Save) 합니다.
-
BP_RotateObject_Pyramid 에도 위 과정을 반복하고 Shape_Quad_Pyramid 를 스태틱 메시로 선택합니다.
-
BP_RotateObject_Torus 에도 위 과정을 반복하고 Shape_Torus 를 스태틱 메시로 선택합니다. 메시를 Y 방향으로 90도 회전합니다.
-
레벨로 각 셰이프를 드래그하고 플레이(Play) 를 눌러 플레이어가 가까이 있을 때 모든 셰이프가 회전하는 것을 확인합니다.
섹션 결과
이 섹션에서는 BP_RotateObject 액터에서 여러 개의 자손 액터를 생성하고 각 액터에 서로 다른 스태틱 메시(Static Mesh) 를 할당해 보았습니다.
또한 액터의 부모 클래스로 형변환하여 일반 기능에 액세스할 수 있다는 것도 배웠습니다. 이 경우에는 각각의 자손 액터를 오버랩하고 부모 클래스로 형변환하여 회전을 트리거한 것입니다.
다음 단계
지금까지 형변환 사용법을 알아보았으니, 액터 커뮤니케이션 문서 페이지에 나와 있는 다른 커뮤니케이션 타입도 확인해 보세요.
개요
블루프린트 클래스 형변환은 액터 클래스 블루프린트에 대한 레퍼런스를 사용하여 다른 클래스로 변환하는 커뮤니케이션 타입으로 흔히 사용됩니다. 변환이 성공적으로 이루어졌다면 직접 블루프린트 커뮤니케이션(Direct Blueprint communication)을 사용하여 정보 및 기능에 액세스할 수 있습니다.
이 방법에는 레벨의 액터 클래스 블루프린트에 대한 레퍼런스가 필요합니다. 그래야 형변환(Cast) 노드를 사용하여 레퍼런스를 특정 클래스로 변환하려고 시도할 수 있습니다. 이 커뮤니케이션 타입은 작업 중인 액터 클래스 블루프린트와 타깃 액터 클래스 블루프린트 사이의 일대일 관계를 사용합니다.
목표
이 퀵스타트 가이드에서는 C++에서 타깃 블루프린트의 정보에 액세스하는 블루프린트 형변환 기능을 갖춘 액터를 생성해 보겠습니다.
세부 목표
-
변수 값에 기반하여 회전하는 블루프린트를 생성합니다.
-
ThirdPersonCharacter 블루프린트를 수정하여 오버랩 시 회전하는 블루프린트로 형변환합니다.
-
회전하는 블루프린트로부터 여러 개의 자손 블루프린트 클래스를 생성하여 동일한 부모를 공유하는 많은 블루프린트 클래스에 대한 블루프린트 형변환이 어떻게 작용하는지 확인합니다.
1 - 필수 구성
-
메뉴의 새 프로젝트 카테고리(New Project Categories) 섹션에서 게임(Games) 을 선택하고 다음(Next) 을 클릭합니다.
-
삼인칭(Third Person) 템플릿을 선택하고 다음(Next) 을 클릭합니다.
-
C++ 및 시작용 콘텐츠 포함(With Starter Content) 옵션을 선택하고 프로젝트 생성(Create Project) 을 클릭합니다.
섹션 결과
이제 새로운 삼인칭 프로젝트가 생성되었으며, 액터 클래스 블루프린트 형변환을 알아볼 준비가 되었습니다.
2 - 회전하는 액터 생성
이 예시에서는 플레이어가 가까이 있으면 스태틱 메시 컴포넌트를 회전하는 기능이 있는 액터 클래스 블루프린트를 생성할 것입니다.
-
C++ 클래스 마법사(C++ Class Wizard) 에서 RotatingActor 라는 이름의 새 액터 클래스를 생성합니다.
-
RotatingActor.h 의 클래스 디폴트에 다음 코드를 구현합니다.
public: void SetbCanRotate(bool value); protected: // 게임 시작 또는 스폰 시 호출 virtual void BeginPlay() override; void RotateActor(); bool bCanRotate; UPROPERTY(EditAnywhere, BlueprintReadWrite) UStaticMeshComponent* MeshComp; -
RotatingActor.cpp 로 이동하여 생성자 ARotatingActor::ARotatingActor 에서 다음 코드를 선언합니다.
ARotatingActor::ARotatingActor() { RootComponent = CreateDefaultSubobject<USceneComponent>(TEXT("SceneComponent")); MeshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("StaticMesh")); MeshComp->SetupAttachment(RootComponent, FAttachmentTransformRules::KeepRelativeTransform); bCanRotate = false; } -
ARotatingActor::RotateActor 메서드에 대해 다음 코드를 구현합니다.
void ARotatingActor::RotateActor() { AddActorLocalRotation(ActorRotation); } -
ARotatingActor::Tick 메서드로 이동하여 다음 코드를 구현합니다.
void ARotatingActor::Tick(float DeltaTime) { Super::Tick(DeltaTime); if (bCanRotate) { RotateActor(); } }
완성된 코드
RotatingActor.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "RotatingActor.generated.h"
UCLASS()
class BPCOMMUNICATION_API ARotatingActor : public AActor
{
GENERATED_BODY()
public:
// 이 액터 프로퍼티의 디폴트값 설정
ARotatingActor();
void SetbCanRotate(bool value);
protected:
// 게임 시작 또는 스폰 시 호출
virtual void BeginPlay() override;
void RotateActor();
bool bCanRotate;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
UStaticMeshComponent* MeshComp;
//액터의 회전 속도
const FQuat ActorRotationRate =(FQuat(FRotator(0,2,0));
public:
// 프레임마다 호출
virtual void Tick(float DeltaTime) override;
};
RotatingActor.cpp
#include "RotatingActor.h"
// 디폴트값 설정
ARotatingActor::ARotatingActor()
{
// 이 액터가 프레임마다 Tick()을 호출하도록 설정합니다. 이 설정이 필요 없는 경우 비활성화하면 퍼포먼스가 향상됩니다.
PrimaryActorTick.bCanEverTick = true;
RootComponent = CreateDefaultSubobject<USceneComponent>(TEXT("SceneComponent"));
MeshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("MeshComp"));
MeshComp->SetupAttachment(RootComponent, FAttachmentTransformRules::KeepRelativeTransform);
bCanRotate = false;
}
void ARotatingActor::SetbCanRotate(bool value)
{
bCanRotate = value;
}
// 게임 시작 또는 스폰 시 호출
void ARotatingActor::BeginPlay()
{
Super::BeginPlay();
}
void ARotatingActor::RotateActor()
{
AddActorLocalRotation(ActorRotation);
}
// 프레임마다 호출
void ARotatingActor::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
if (bCanRotate)
{
RotateActor();
}
}
-
코드를 컴파일(Compile) 합니다.
-
에디터에서 C++ 클래스 폴더(C++ Classes folder) 로 이동하고 RotatingActor 를 우클릭한 다음 C++ 클래스 액션(C++ class actions) 드롭다운 메뉴에서 RotatingActor 기반 블루프린트 클래스 생성(Create Blueprint class based on RotatingActor) 을 선택한 다음 BP_RotatingActor 로 명명합니다.
-
BP_RotatingActor 블루프린트의 클래스 디폴트에서 컴포넌트(Components) 탭으로 이동한 다음 MeshComp 스태틱 메시 컴포넌트(Static Mesh Component) 를 선택하고 디테일 패널(Details panel) 로 이동합니다. 디테일 패널의 스태틱 메시 카테고리(Static Mesh category) 에서 스태틱 메시 변수(Static Mesh variable) 옆의 화살표를 선택합니다. 마지막으로 드롭다운 메뉴에서 Shape_Cube 스태틱 메시를 선택합니다.
-
블루프린트를 컴파일(Compile) 하고 저장(Save) 합니다.
-
콘텐츠 브라우저(Content Browser) 에서 BP_RotatingActor 의 인스턴스를 레벨로 드래그합니다.
섹션 결과
이 섹션에서는 bCanRotate 변수가 True 로 설정된 경우 틱 시에 스태틱 메시를 회전하는 기능을 포함하는 회전 액터 클래스 블루프린트를 생성했습니다.
3 - 삼인칭 캐릭터 클래스 수정
이 섹션에서는 BPCommunicationCharacter 클래스를 수정하여 회전 액터(Rotating Actor) 클래스로 형변환하고 플레이어가 가까이에 있을 때 bCanRotate 변수를 True 로 설정하겠습니다.
-
BPCommunicationCharacter.h 를 열고 다음을 구현합니다.
protected: virtual void NotifyActorBeginOverlap(AActor* OtherActor); virtual void NotifyActorEndOverlap(AActor* OtherActor); class USphereComponent* SphereComp; -
BPCommunicationCharacter.cpp 에 다음 클래스 라이브러리를 추가합니다.
#include "RotatingActor.h" #include "Components/SphereComponent.h" -
생성자 ABPCommunicationCharacter::BPCommunicationCharacter 에 다음 코드를 선언합니다.
SphereComp = CreateDefaultSubobject<USphereComponent>(TEXT("SphereComp")); SphereComp->AttachToComponent(GetMesh(), FAttachmentTransformRules::KeepRelativeTransform); SphereComp->SetSphereRadius(200); -
다음으로 ABPCommunicationCharacter::NotifyActorBeginOverlap 및 ABPCommunicationCharacter::NotifyActorEndOverlap 을 구현합니다.
void ABPCommunicationCharacter::NotifyActorBeginOverlap(AActor* OtherActor) { if (ARotatingActor* RotatingActorCheck =Cast<ARotatingActor>(OtherActor)) { ActorCheck->SetbCanRotate(true); } } void ABPCommunicationCharacter::NotifyActorEndOverlap(AActor* OtherActor) { if (ARotatingActor* RotatingActorCheck = Cast<ARotatingActor>(OtherActor)) { ActorCheck->SetbCanRotate(false); } } -
코드를 컴파일합니다.
완성된 코드
BPCommunicationCharacter.h
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "BPCommunicationCharacter.generated.h"
UCLASS(config=Game)
class ABPCommunicationCharacter : public ACharacter
{
GENERATED_BODY()
/** 캐릭터 뒤에 카메라를 배치하는 카메라 붐 */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))
class USpringArmComponent* CameraBoom;
/** 카메라 따라가기 */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))
class UCameraComponent* FollowCamera;
public:
ABPCommunicationCharacter();
/** 베이스 턴 속도, 단위는 각도/초. 다른 스케일 값 조절로 인해 최종 턴 속도가 영향을 받을 수 있습니다. */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera)
float BaseTurnRate;
/** 베이스 올려다보기/내려다보기 속도, 단위는 각도/초. 다른 스케일 값 조절로 인해 최종 속도가 영향을 받을 수 있습니다. */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera)
float BaseLookUpRate;
protected:
virtual void NotifyActorBeginOverlap(AActor* OtherActor);
virtual void NotifyActorEndOverlap(AActor* OtherActor);
UPROPERTY(EditAnywhere, BlueprintReadWrite)
class USphereComponent* SphereComp;
/** VR의 HMD 오리엔테이션을 리셋합니다. */
void OnResetVR();
/** 앞뒤 입력으로 호출 */
void MoveForward(float Value);
/** 좌우 입력으로 호출 */
void MoveRight(float Value);
/**
* 입력을 통해 호출되어 지정된 속도로 회전
* @param Rate 정규화된 비율이며, 1.0인 경우 100%만큼 돌아갔음을 의미합니다.
*/
void TurnAtRate(float Rate);
/**
* 입력을 통해 호출되어 지정된 속도로 올려다보기/내려다보기
* @param Rate 정규화된 비율이며, 1.0인 경우 100%만큼 돌아갔음을 의미합니다.
*/
void LookUpAtRate(float Rate);
/** 터치 입력 시작 시 핸들러 */
void TouchStarted(ETouchIndex::Type FingerIndex, FVector Location);
/** 터치 입력 중지 시 핸들러 */
void TouchStopped(ETouchIndex::Type FingerIndex, FVector Location);
protected:
// APawn 인터페이스
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
// APawn 인터페이스 종료
public:
/** CameraBoom 서브오브젝트 반환 **/
FORCEINLINE class USpringArmComponent* GetCameraBoom() const { return CameraBoom; }
/** FollowCamera 서브오브젝트 반환 **/
FORCEINLINE class UCameraComponent* GetFollowCamera() const { return FollowCamera; }
};
BPCommunication.cpp
// Copyright Epic Games, Inc. All Rights Reserved.
#include "BPCommunicationCharacter.h"
#include "HeadMountedDisplayFunctionLibrary.h"
#include "Camera/CameraComponent.h"
#include "Components/CapsuleComponent.h"
#include "Components/InputComponent.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "GameFramework/Controller.h"
#include "GameFramework/SpringArmComponent.h"
#include "CeilingLight.h"
#include "RotatingActor.h"
#include "Components/SphereComponent.h"
//////////////////////////////////////////////////////////////////////////
// ABPCommunicationCharacter
ABPCommunicationCharacter::ABPCommunicationCharacter()
{
// 콜리전 캡슐 크기 설정
GetCapsuleComponent()->InitCapsuleSize(42.f, 96.0f);
// 입력에 대한 턴 속도 설정
BaseTurnRate = 45.f;
BaseLookUpRate = 45.f;
// 컨트롤러 회전 시 회전하지 않습니다. 카메라에만 영향을 미치도록 합니다.
bUseControllerRotationPitch = false;
bUseControllerRotationYaw = false;
bUseControllerRotationRoll = false;
// 캐릭터 무브먼트 환경설정
GetCharacterMovement()->bOrientRotationToMovement = true; // 캐릭터가 입력 방향으로 이동
GetCharacterMovement()->RotationRate = FRotator(0.0f, 540.0f, 0.0f); // 위의 캐릭터가 이동하는 회전 속도
GetCharacterMovement()->JumpZVelocity = 600.f;
GetCharacterMovement()->AirControl = 0.2f;
// 카메라 붐 생성(콜리전 있을 시 플레이어 쪽으로 들어옴)
CameraBoom = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraBoom"));
CameraBoom->SetupAttachment(RootComponent);
CameraBoom->TargetArmLength = 300.0f; // 캐릭터 뒤의 카메라가 이 거리에서 따라옴
CameraBoom->bUsePawnControlRotation = true; // 컨트롤러 기반으로 암 회전
// 카메라 따라가기 생성
FollowCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("FollowCamera"));
FollowCamera->SetupAttachment(CameraBoom, USpringArmComponent::SocketName); // 카메라를 붐 끝에 어태치하여 붐이 컨트롤러 오리엔테이션에 맞추어 조절되도록 함
FollowCamera->bUsePawnControlRotation = false; // 카메라가 암 기준으로 회전하지 않음
SphereComp = CreateDefaultSubobject<USphereComponent>(TEXT("SphereComp"));
SphereComp->SetupAttachment(GetMesh(), FAttachmentTransformRules::KeepRelativeTransform);
SphereComp->SetSphereRadius(200);
// 참고: 캐릭터로부터 상속받는 메시 컴포넌트에 대한 스켈레탈 메시와 애님 블루프린트 레퍼런스는
// C++ 직접 콘텐츠 레퍼런스를 방지하기 위해 이름이 MyCharacter인 파생 블루프린트 에셋에서 설정됨
}
//////////////////////////////////////////////////////////////////////////
// 입력
void ABPCommunicationCharacter::SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent)
{
// 게임플레이 키 바인딩 설정
check(PlayerInputComponent);
PlayerInputComponent->BindAction("Jump", IE_Pressed, this, &ACharacter::Jump);
PlayerInputComponent->BindAction("Jump", IE_Released, this, &ACharacter::StopJumping);
PlayerInputComponent->BindAction("Use", IE_Pressed, this, &ABPCommunicationCharacter::ToggleCeilingLight);
PlayerInputComponent->BindAxis("MoveForward", this, &ABPCommunicationCharacter::MoveForward);
PlayerInputComponent->BindAxis("MoveRight", this, &ABPCommunicationCharacter::MoveRight);
// 2가지 버전의 회전 바인딩이 있어 서로 다른 종류의 디바이스를 다양한 방식으로 처리할 수 있습니다.
// 'turn'은 마우스와 같은 절대 델타를 제공하는 디바이스를 처리합니다.
// 'turnrate'는 아날로그 조이스틱과 같이 속도 변경으로 취급할 디바이스에 사용합니다.
PlayerInputComponent->BindAxis("Turn", this, &APawn::AddControllerYawInput);
PlayerInputComponent->BindAxis("TurnRate", this, &ABPCommunicationCharacter::TurnAtRate);
PlayerInputComponent->BindAxis("LookUp", this, &APawn::AddControllerPitchInput);
PlayerInputComponent->BindAxis("LookUpRate", this, &ABPCommunicationCharacter::LookUpAtRate);
// 터치 디바이스 처리
PlayerInputComponent->BindTouch(IE_Pressed, this, &ABPCommunicationCharacter::TouchStarted);
PlayerInputComponent->BindTouch(IE_Released, this, &ABPCommunicationCharacter::TouchStopped);
// VR 헤드셋 기능
PlayerInputComponent->BindAction("ResetVR", IE_Pressed, this, &ABPCommunicationCharacter::OnResetVR);
}
void ABPCommunicationCharacter::NotifyActorBeginOverlap(AActor* OtherActor)
{
if (ARotatingActor* RotatingActorCheck =Cast<ARotatingActor>(OtherActor))
{
ActorCheck->SetbCanRotate(true);
}
}
void ABPCommunicationCharacter::NotifyActorEndOverlap(AActor* OtherActor)
{
if (ARotatingActor* RotatingActorCheck = Cast<ARotatingActor>(OtherActor))
{
ActorCheck->SetbCanRotate(false);
}
}
void ABPCommunicationCharacter::OnResetVR()
{
// 언리얼 에디터의 '기능 추가'를 사용해 프로젝트에 BPCommunication을 추가한 경우, BPCommunication.Build.cs에서 HeadMountedDisplay의 종속성이 자동 전파되지 않습니다.
// 또한 링커 오류가 발생합니다.
// 다음 중 하나를 실행해야 합니다.
// [프로젝트 이름].Build.cs의 PublicDependencyModuleNames에 'HeadMountedDisplay'를 추가하면 빌드에 성공합니다. VR 지원 시 적합합니다.
// 또는
// 아래의 ResetOrientationAndPosition 호출을 코멘트 처리하거나 삭제합니다. VR 미지원 시 적합합니다.
UHeadMountedDisplayFunctionLibrary::ResetOrientationAndPosition();
}
void ABPCommunicationCharacter::TouchStarted(ETouchIndex::Type FingerIndex, FVector Location)
{
Jump();
}
void ABPCommunicationCharacter::TouchStopped(ETouchIndex::Type FingerIndex, FVector Location)
{
StopJumping();
}
void ABPCommunicationCharacter::TurnAtRate(float Rate)
{
// 속도 정보로부터 이 프레임에 대한 델타 계산
AddControllerYawInput(Rate * BaseTurnRate * GetWorld()->GetDeltaSeconds());
}
void ABPCommunicationCharacter::LookUpAtRate(float Rate)
{
// 속도 정보로부터 이 프레임에 대한 델타 계산
AddControllerPitchInput(Rate * BaseLookUpRate * GetWorld()->GetDeltaSeconds());
}
void ABPCommunicationCharacter::MoveForward(float Value)
{
if ((Controller != nullptr) && (Value != 0.0f))
{
// 앞쪽 찾기
const FRotator Rotation = Controller->GetControlRotation();
const FRotator YawRotation(0, Rotation.Yaw, 0);
// 앞쪽 벡터 구하기
const FVector Direction = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
AddMovementInput(Direction, Value);
}
}
void ABPCommunicationCharacter::MoveRight(float Value)
{
if ( (Controller != nullptr) && (Value != 0.0f) )
{
// 오른쪽 찾기
const FRotator Rotation = Controller->GetControlRotation();
const FRotator YawRotation(0, Rotation.Yaw, 0);
// 오른쪽 벡터 구하기
const FVector Direction = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);
// 해당 방향으로 이동 추가
AddMovementInput(Direction, Value);
}
}
-
플레이(Play)를 누른 다음 BP_RotateObject 액터에 접근하여 플레이어가 가까이 있을 때만 회전하는 것을 확인합니다.
섹션 결과
이 섹션에서는 구형 컴포넌트(Sphere Component) 를 BPCommunicationCharacter 클래스에 추가했습니다.
또한 RotatingActor 클래스로 형변환하고,플레이어 캐릭터의 구형 컴포넌트가 오버랩되면 bCanRotate 변수를 True 로 설정하는 SetbCanRotate 함수를 호출하기 위한 오랩 로직을 생성했습니다.
4 - 다양한 회전 셰이프 추가하기
이제 BP_RotatingActor 블루프린트로부터 여러 자손 블루프린트 클래스를 생성하여 플레이어 캐릭터에 반응하는 다양한 셰이프를 추가할 수 있습니다. 이 과정에서는 일반 부모 클래스로 형변환하는 기능을 유지하면서도 자손 블루프린트 클래스를 사용하여 변경사항을 적용하거나 기능을 추가 또는 수정하는 방법을 볼 수 있습니다.
-
콘텐츠 브라우저(Content Browser)에서 BP_Rotating Actor 를 우클릭하고 자손 블루프린트 클래스 생성(Create Child Blueprint Class) 을 선택합니다. 블루프린트 이름을 BP_RotateObject_Cone 으로 지정합니다.
-
1단계를 두 번 더 반복하여 BP_RotateObject_Pyramid 와 BP_RotateObject_Torus 블루프린트 클래스를 생성합니다.
-
블루프린트 에디터에서 BP_RotateObject_Cone 을 연 후 컴포넌트(Components) 탭에서 스태틱 메시(Static Mesh) 컴포넌트를 선택합니다. 디테일(Details) 패널에서 스태틱 메시(Static Mesh) 드롭다운을 클릭한 다음 Shape_Cone 을 검색하고 선택합니다.
-
Y 회전(Rotation) 을 90도로 설정합니다.
-
블루프린트를 컴파일(Compile) 하고 저장(Save) 합니다.
-
BP_RotatingActor_Pyramid 에서도 3~5단계를 반복하고 Shape_Quad_Pyramid 를 스태틱 메시로 선택합니다.
-
BP_RotatingActor_Torus 에서도 3~5단계를 반복하고 Shape_Torus 를 스태틱 메시로 선택합니다. 메시를 Y축 방향으로 90도 회전합니다.
-
레벨로 각 셰이프를 드래그하고 플레이(Play) 를 클릭하여 플레이어가 가까이 있을 때 모든 셰이프가 회전하는 것을 확인합니다.
섹션 결과
이 섹션에서는 BP_RotateObject 블루프린트로부터 여러 자손 블루프린트 클래스를 생성하고 각 액터에 서로 다른 스태틱 메시(Static Mesh) 를 할당했습니다.
또한 블루프린트 액터의 부모 클래스로 형변환하여 일반 기능에 액세스할 수 있다는 것도 배웠습니다. 이 경우에는 각각의 자손 블루프린트를 오버랩하고 부모 클래스를 호출하여 회전을 트리거했습니다.
다음 단계
지금까지 블루프린트 형변환 사용법을 알아보았습니다. 액터 커뮤니케이션 문서 페이지의 다른 커뮤니케이션 타입도 확인해 보세요.