StartPlay();
플레이가 시작되었을 때, 게임 모드에서 액터들의 BeginPlay() 함수를 호출하는 역할.
GEngine;
전역에 선언되어 있는 엔진 포인터. 사용하기 위해서는 "Engine.h"를 포함해줘야 한다. 엔진에서 실행되는 경우가 아닐 경우, 값이 유효하지 않을 수 있으니 사용하기 전에 반드시 GEngine이 유효한 상태인지 체크하고 사용해야 한다.
GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Yellow, TEXT("Hello World"));
뷰포트에 디버그 메시지를 띄우는데 사용되는 함수
FColor Color;
언리얼 엔진에서 색상으로 표현하는데 사용되는 구조체
FColor::Red; FColor::Blue; FColor::Emerald;
언리얼 엔진에서는 기본적인 색상을 스태틱으로 미리 만들어놓았다.
프로젝트를 생성하고 Pawn 클래스를 상속받는 "CollidingPawn"을 생성한다. 이 폰은 컴포넌트를 가지고 레벨 안에서 이동하고 입체 오브젝트와 충돌하게 된다.
CollidingPawn.h의 클래스 정의 하단 부에 UParticleSystemComponent를 추가한다.
UParticleSystemComponent* OutParticleSystem;
만약 에러 발생 시, Engine/Classes/Particles/ParticleSystemComponent.h 를 포함시켜 주면 된다.
멤버 변수로 만들지 않아도 컴포넌트를 만들 수 있지만, 코드에서 컴포넌트를 사용하려면 클래스 멤버 변수로 만들어야 한다.
이 다음에는
CollidingPawn.cpp의 ACollidingPawn::ACollidingPawn() 생성자 함수를 편집해서 필요한 컴포넌트들을 스폰할 코드를 추가하고 계층구조로 배치해야 한다.
물리 월드와 상호작용을 위한 Sphere Component, 콜리전 모양을 시작적으로 보여줄 Static Mesh Component, 시각적인 효과를 더하며 켜고 끌 수 있는 Particle System Component, 게임 내의 시점 제어를 위해 Camera Component에 덧붙을 Spring Arm Component를 만든다.
먼저 계층구조에서 루트가 될 컴포넌트를 결정해야 한다.
이 튜토리얼에서 Sphere Component가 루트 컴포넌트가 된다. 물리적으로 실존이 있고, 게임 월드와의 상호작용이 가능하기 때문이다.
#include "Engine/Classes/Components/SphereComponent.h"
USphereComponent* SphereComponent = CreateDefaultSubobject<USphereComponent>(TEXT("RootComponent"));
RootComponent = SphereComponent;
SphereComponent->InitSphereRadius(40.0f);
SphereComponent->SetCollisionProfileName(TEXT("Pawn"));
다음은, 구형의 스태틱메시 컴포넌트를 만들어서 적절한 크기와 위치로 만들어서 루트 컴포넌트에 붙여준다.
#include "Engine/Classes/Components/StaticMeshComponent.h"
#include "ConstructorHelpers.h"
UStaticMeshComponent* SphereVisual = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("VisualRepresentation"));
SphereVisual->SetupAttachment(RootComponent);
static ConstructorHelpers::FObjectFinder<UStaticMesh> SphereVisualAsset(TEXT("/Game/StarterContent/Shapes/Shape_Sphere.Shape_Sphere"));
if (SphereVisualAsset.Succeeded())
{
SphereVisual->SetStaticMesh(SphereVisualAsset.Object);
SphereVisual->SetRelativeLocation(FVector(0.0f, 0.0f, -40.0f));
SphereVisual->SetWorldScale3D(FVector(0.8f));
}
이번엔 Particle System Component를 붙인다. 이 컴포넌트는 코드를 통해서 켜고 끄는 등의 제어를 할 수 있으며, 루트가 아닌 스태틱 메시에 붙어있으며 게임 플레이 도중에 더 잘 보이게 하기 위해 메시의 정중앙이 아닌 약간 아래쪽에 오프셋되어 있다.
OurParticleSystem = CreateDefaultSubobject<UParticleSystemComponent>(TEXT("MovementParticles"));
OurParticleSystem->SetupAttachment(SphereVisual);
OurParticleSystem->bAutoActivate = false;
OurParticleSystem->SetRelativeLocation(FVector(-20.0f, 0.0f, 20.0f));
static ConstructorHelpers::FObjectFinder<UParticleSystem> ParticleAsset(TEXT("/Game/StarterContent/Particles/P_Fire.P_Fire"));
if (ParticleAsset.Succeeded())
{
OurParticleSystem->SetTemplate(ParticleAsset.Object);
}
Spring Arm Component는 폰보다 느린 가속/감속을 따라다니는 카메라에 적용시킬 수 있기 때문에, 카메라의 부드러운 부착점이 된다. 또한 카메라가 입체 오브젝트를 뚫고 지나가지 못하게 하는 기능을 내장하고 있어서, 삼인칭 게임에서 구석에서 벽을 등지는 상황에 유용하게 사용된다.
#include "Engine/Classes/GameFramework/SpringArmComponent.h"
USpringArmComponent* SpringArm = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraAttachmentArm"));
SpringArm->SetupAttachment(RootComponent);
SpringArm->SetRelativeRotation(FRotator(-45.0f, 0.0f, 0.0f));
SpringArm->TargetArmLength = 400.0f;
SpringArm->bEnableCameraLag = true;
SpringArm->CameraLagSpeed = 3.0f;
Camera Component를 생성해서 Spring Arm Component에 붙여준다. Spring Arm Component에는 소켓이 내장되어 있어서 베이스가 아닌 소켓에 카메라를 붙일 수 있다.
#include "Engine/Classes/Camera/CameraComponent.h"
UCameraComponent* Camera = CreateDefaultSubobject<UCameraComponent>(TEXT("ActualCamera"));
Camera->SetupAttachment(SpringArm, USpringArmComponent::SocketName);
모든 컴포넌트를 붙인 뒤에는, 기본 플레이어가 이 폰을 조종하도록 설정해야 한다.
AutoPossessPlayer = EAutoReceiveInput::Player0;
게임에서 사용할 수 있는 입력 매핑이 생겼으니, 입력 매핑으로부터 받은 데이터를 저장할 멤버 변수를 구성하자.
업데이트 중에 이동과 마우스 방향 축을 알아야 하는데, 이 값으로는 FVector2D 타입이 적합하다.
void ADedicatedFPSCharacter::SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent)
{
// Set up action bindings
if (UEnhancedInputComponent* EnhancedInputComponent = CastChecked<UEnhancedInputComponent>(PlayerInputComponent)) {
//Jumping
EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Triggered, this, &ACharacter::Jump);
EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Completed, this, &ACharacter::StopJumping);
//Moving
EnhancedInputComponent->BindAction(MoveAction, ETriggerEvent::Triggered, this, &ADedicatedFPSCharacter::Move);
//Looking
EnhancedInputComponent->BindAction(LookAction, ETriggerEvent::Triggered, this, &ADedicatedFPSCharacter::Look);
//Equip
EnhancedInputComponent->BindAction(EquipAction, ETriggerEvent::Triggered, this, &ADedicatedFPSCharacter::Equip);
//Fire
EnhancedInputComponent->BindAction(FireAction, ETriggerEvent::Completed, this, &ADedicatedFPSCharacter::FirePressed);
EnhancedInputComponent->BindAction(FireAction, ETriggerEvent::Completed, this, &ADedicatedFPSCharacter::FireReleased);
}
}
void Move(const FInputActionValue& Value);
void Look(const FInputActionValue& Value);
void Equip(const FInputActionValue& Value);
이런 식으로.. Enhanced Input을 바인딩할 수 있는데 이것은 에디터 상에서 하는 것이 더 편한 것 같다.
Quit 종료 기능을 만든다.
유익한 글 잘 봤습니다, 감사합니다.