일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 데이터베이스
- 프린세스메이커
- node
- Unseen
- 으
- 정글사관학교
- EnhancedInput
- 스터디
- 게임개발
- 파이썬서버
- flask
- Ajax
- Bootstrap4
- JWT
- 디자드
- 스마일게이트
- 언리얼프로그래머
- 마인크래프트뮤지컬
- 언리얼
- R
- VUE
- Enhanced Input System
- Express
- Jinja2
- 레베카
- 카렌
- 언리얼뮤지컬
- 알고풀자
- 프메
- 미니프로젝트
- Today
- Total
Showing
[Unreal] 액터 C++ 클래스와 블루프린트 호환 및 컴포넌트의 이해 본문
컴포넌트와 액터
언리얼에서 월드는 아래 4가지를 제공한다.
- 레벨
- 액터 : 각종 컴포넌트를 붙여 다양한 기능의 구현체가 될 수 있다(시각, 물리...etc)
- 시간(가상 공간에서 흐르는 시간이므로 조절 가능)
- 물리(액터들 사이의 작용, 콜리전 정보 이용)
언리얼은 컴포넌트 구조를 채택하여 액터는 여러 개의 컴포넌트를 가질 수 있고, 대표되는 하나의 컴포넌트를 루트 컴포넌트라고 한다.(스태틱메쉬, 스켈레탈 메쉬, 박스(콜리전), 무브먼트, 카메라, 파티클, 라이트 컴포넌트 등..)
내가 소유한 언리얼 오브젝트 : 서브 오브젝트
나의 주인이 되는 언리얼 오브젝트 : 아우
블루프린트로 만든 컴포넌트 구조와 똑같이 C++로 작성할 수 있다.
우선 액터로 c++ 클래스를 생성해준다.
헤더파일
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "STorch.generated.h"
UCLASS()
class TRACESOFTHEFOX_API ASTorch : public AActor
{
GENERATED_BODY()
public:
ASTorch();
private:
UPROPERTY(VisibleAnywhere, Category="Troch")
TObjectPtr<class UBoxComponent> BoxComponent;
UPROPERTY(VisibleAnywhere, Category = "Troch")
TObjectPtr<class UStaticMeshComponent> BodyStaticMeshComponent;
UPROPERTY(VisibleAnywhere, Category = "Troch")
TObjectPtr<class UPointLightComponent> PointLightComponent;
UPROPERTY(VisibleAnywhere, Category = "Troch")
TObjectPtr<class UParticleSystemComponent> ParticleSystemComponent;
};
필요한 컴포넌트들을 전부 달아준 코드 상황
UPROPERTY()는 언리얼 오브젝트 클래스의 속성이라는 뜻
VisibleAnywhere은 에디터에서 수정할 수 있다는 뜻으로, 사실 TObjectPtr 포인터는 주소값을 알면 값을 바꿀 수 있다는 사실을 이용한 예약어이다. (단, 포인터 타입은 VisibleAnywhere로 충분하지만 값 타입은 EditAnywhere로 해주어야 한다)
BP_class에서만 바꾸고 싶다면 EditDefaultOnly 인스턴스에서만 바꾸고 싶다면 EditInstanceOnly
참고로 UE4 스타일
UE5 스타일 : 언리얼 측에서 TObjectPtr를 쓸 것을 권장했기 때문이다.(기능 추가와 안전성이 올라갔다고 한다)
cpp
#include "WorldStatics/STorch.h"
#include "Components/BoxComponent.h"
#include "Components/PointLightComponent.h"
#include "Particles/ParticleSystemComponent.h"
ASTorch::ASTorch()
{
PrimaryActorTick.bCanEverTick = false;
BoxComponent = CreateDefaultSubobject<UBoxComponent>(TEXT("RootBoxComponent"));
SetRootComponent(BoxComponent);
BodyStaticMeshComponent = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("My Static Mesh"));
BodyStaticMeshComponent->SetupAttachment(GetRootComponent());
BodyStaticMeshComponent->SetRelativeLocation(FVector(0.f, 0.f, -30.f));
PointLightComponent = CreateDefaultSubobject<UPointLightComponent>(TEXT("PointLight"));
PointLightComponent->SetupAttachment(GetRootComponent());
PointLightComponent->SetRelativeLocation(FVector(0.f, 0.f, 500.f));
ParticleSystemComponent = CreateDefaultSubobject<UParticleSystemComponent>(TEXT("ParticleSystem"));
ParticleSystemComponent->SetupAttachment(GetRootComponent());
ParticleSystemComponent->SetRelativeLocation(FVector(0.f, 0.f, 500.f));
}
PrimaryActorTick.bCanEverTick = false; tick 함수는 부하가 많기 때문에 최대한 로직을 안 넣기 위해 노력해야 하며, 아예 tick 함수를 쓰지 않을 경우에는 false로 바꾸어준다.
CreateDefaultSubobject<자료형> 내가 가질 특정 <자료형>인 Subobject를 만든다. 바로 뒤에 붙는 해시값 (TEXT("RootBoxComponent")); 등으로 유니크한 id가 만들어지는데 웬만하면 변수명으로 쓰면 된다.
참고로 루트 컴포넌트가 된 컴포넌트는 액터의 방향, 위치와 동일하므로 블루프린트 상에서 볼 수 없다. 따라서 컴포넌트의 방향과 위치를 보고 싶다면 Get Actor Rotation() Get Actor Location() 하면 된다! 액터를 수정하는 것은 곧 루트 컴포넌트를 수정하는 것과 같다.
BodyStaticMeshComponent->SetupAttachment(GetRootComponent()); GetRootComponent의 자식으로 들어간다
또한 C++에서 Location을 작성해놓으면 에디터 상에서의 디폴트 값이 된다.(뒤로가기 버튼이 생기지 않는다)
기존에 만들어둔 블루프린트의 부모를 방금 만든 c++ 클래스로 바꾸어줄 수 있다!
넣자마자 컴포넌트창에 변화가 생긴다. Edit in C++이라는 표시와 함께 c++에서 작성했던 컴포넌트들이 추가되었다.
따라서 블루프린트에서 만든 것을 작성하면 아래와 같이 초기화된다.
에셋 디폴트 지정
에셋 경로를 하드코딩으로 지정해줄 수 있다.
아트 팀에서 경로를 많이 변경할 수 있기 때문에 소속 컨벤션에 따라 선택 사항이다.
#include "WorldStatics/STorch.h"
#include "Components/BoxComponent.h"
#include "Components/PointLightComponent.h"
#include "Particles/ParticleSystemComponent.h"
ASTorch::ASTorch()
{
PrimaryActorTick.bCanEverTick = false;
BoxComponent = CreateDefaultSubobject<UBoxComponent>(TEXT("RootBoxComponent"));
SetRootComponent(BoxComponent);
BodyStaticMeshComponent = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("My Static Mesh"));
BodyStaticMeshComponent->SetupAttachment(GetRootComponent());
BodyStaticMeshComponent->SetRelativeLocation(FVector(0.f, 0.f, -30.f));
static ConstructorHelpers::FObjectFinder<UStaticMesh> BodyStaticMesh(TEXT("/Script/Engine.StaticMesh'/Game/StarterContent/Architecture/Pillar_50x500.Pillar_50x500'"));
if (BodyStaticMesh.Succeeded())
{
BodyStaticMeshComponent->SetStaticMesh(BodyStaticMesh.Object);
}
PointLightComponent = CreateDefaultSubobject<UPointLightComponent>(TEXT("PointLight"));
PointLightComponent->SetupAttachment(GetRootComponent());
PointLightComponent->SetRelativeLocation(FVector(0.f, 0.f, 500.f));
ParticleSystemComponent = CreateDefaultSubobject<UParticleSystemComponent>(TEXT("ParticleSystem"));
ParticleSystemComponent->SetupAttachment(GetRootComponent());
ParticleSystemComponent->SetRelativeLocation(FVector(0.f, 0.f, 500.f));
}
아래와 같이 다양한 변주를 넣어줄 수도 있을 것이다.(디폴트로)
결국 코드로 작성한다는 것은 어떠한 설정을 디폴트화 한다는 것이다.
meshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("static meshComp"));
meshComp->SetupAttachment(RootComponent);
static ConstructorHelpers::FObjectFinder<UStaticMesh> SphereMeshAsset(TEXT("/Game/StarterContent/Shapes/Shape_Sphere.Shape_Sphere"));//추가
if (SphereMeshAsset.Succeeded())
{
meshComp->SetStaticMesh(SphereMeshAsset.Object);
meshComp->SetRelativeScale3D(FVector(0.1f, 0.1f, 0.1f));
meshComp->SetRelativeLocation(FVector(0.0f, 0.0f, -5.0f));
}
파티클도 마찬가지로 처리해줄 수 있는데 함수명이 다른 점만 염두에 두면 될 것이다.
#include "WorldStatics/STorch.h"
#include "Components/BoxComponent.h"
#include "Components/PointLightComponent.h"
#include "Particles/ParticleSystemComponent.h"
ASTorch::ASTorch()
{
PrimaryActorTick.bCanEverTick = false;
BoxComponent = CreateDefaultSubobject<UBoxComponent>(TEXT("RootBoxComponent"));
SetRootComponent(BoxComponent);
BodyStaticMeshComponent = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("My Static Mesh"));
BodyStaticMeshComponent->SetupAttachment(GetRootComponent());
BodyStaticMeshComponent->SetRelativeLocation(FVector(0.f, 0.f, -30.f));
static ConstructorHelpers::FObjectFinder<UStaticMesh> BodyStaticMesh(TEXT("/Script/Engine.StaticMesh'/Game/StarterContent/Architecture/Pillar_50x500.Pillar_50x500'"));
if (BodyStaticMesh.Succeeded())
{
BodyStaticMeshComponent->SetStaticMesh(BodyStaticMesh.Object);
}
PointLightComponent = CreateDefaultSubobject<UPointLightComponent>(TEXT("PointLight"));
PointLightComponent->SetupAttachment(GetRootComponent());
PointLightComponent->SetRelativeLocation(FVector(0.f, 0.f, 500.f));
ParticleSystemComponent = CreateDefaultSubobject<UParticleSystemComponent>(TEXT("ParticleSystem"));
ParticleSystemComponent->SetupAttachment(GetRootComponent());
ParticleSystemComponent->SetRelativeLocation(FVector(0.f, 0.f, 500.f));
static ConstructorHelpers::FObjectFinder<UParticleSystem> FireParticle(TEXT("/Script/Engine.ParticleSystem'/Game/StarterContent/Particles/P_Fire.P_Fire'"));
if (FireParticle.Succeeded())
{
ParticleSystemComponent->SetTemplate(FireParticle.Object);
}
}
초속 회전 시키기
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "STorch.generated.h"
UCLASS()
class TRACESOFTHEFOX_API ASTorch : public AActor
{
GENERATED_BODY()
protected:
virtual void BeginPlay() override;
public:
virtual void Tick(float DeltaSeconds) override;
public:
ASTorch();
private:
UPROPERTY(VisibleAnywhere, Category="Troch")
TObjectPtr<class UBoxComponent> BoxComponent;
UPROPERTY(VisibleAnywhere, Category = "Troch")
TObjectPtr<class UStaticMeshComponent> BodyStaticMeshComponent;
UPROPERTY(VisibleAnywhere, Category = "Troch")
TObjectPtr<class UPointLightComponent> PointLightComponent;
UPROPERTY(VisibleAnywhere, Category = "Troch")
TObjectPtr<class UParticleSystemComponent> ParticleSystemComponent;
UPROPERTY(EditDefaultsOnly, Category = "Troch")
float RotationSpeed;
};
#include "WorldStatics/STorch.h"
#include "Components/BoxComponent.h"
#include "Components/PointLightComponent.h"
#include "Particles/ParticleSystemComponent.h"
void ASTorch::BeginPlay()
{
Super::BeginPlay();
RotationSpeed = 100.0f;
}
void ASTorch::Tick(float DeltaSeconds)
{
Super::Tick(DeltaSeconds);
AddActorWorldRotation(FRotator(0.f, RotationSpeed * DeltaSeconds, 0.f));
}
ASTorch::ASTorch()
{
PrimaryActorTick.bCanEverTick = true;
BoxComponent = CreateDefaultSubobject<UBoxComponent>(TEXT("RootBoxComponent"));
SetRootComponent(BoxComponent);
BodyStaticMeshComponent = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("My Static Mesh"));
BodyStaticMeshComponent->SetupAttachment(GetRootComponent());
BodyStaticMeshComponent->SetRelativeLocation(FVector(0.f, 0.f, -30.f));
static ConstructorHelpers::FObjectFinder<UStaticMesh> BodyStaticMesh(TEXT("/Script/Engine.StaticMesh'/Game/StarterContent/Architecture/Pillar_50x500.Pillar_50x500'"));
if (BodyStaticMesh.Succeeded())
{
BodyStaticMeshComponent->SetStaticMesh(BodyStaticMesh.Object);
}
PointLightComponent = CreateDefaultSubobject<UPointLightComponent>(TEXT("PointLight"));
PointLightComponent->SetupAttachment(GetRootComponent());
PointLightComponent->SetRelativeLocation(FVector(0.f, 0.f, 500.f));
ParticleSystemComponent = CreateDefaultSubobject<UParticleSystemComponent>(TEXT("ParticleSystem"));
ParticleSystemComponent->SetupAttachment(GetRootComponent());
ParticleSystemComponent->SetRelativeLocation(FVector(0.f, 0.f, 500.f));
static ConstructorHelpers::FObjectFinder<UParticleSystem> FireParticle(TEXT("/Script/Engine.ParticleSystem'/Game/StarterContent/Particles/P_Fire.P_Fire'"));
if (FireParticle.Succeeded())
{
ParticleSystemComponent->SetTemplate(FireParticle.Object);
}
}
URotatingMovementComponent 안에는 이미 Tick이 있기 때문에 Tick을 제거 해도 무방하다
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "STorch.generated.h"
UCLASS()
class TRACESOFTHEFOX_API ASTorch : public AActor
{
GENERATED_BODY()
protected:
virtual void BeginPlay() override;
/*
public:
virtual void Tick(float DeltaSeconds) override;
*/
public:
ASTorch();
private:
UPROPERTY(VisibleAnywhere, Category="Troch")
TObjectPtr<class UBoxComponent> BoxComponent;
UPROPERTY(VisibleAnywhere, Category = "Troch")
TObjectPtr<class UStaticMeshComponent> BodyStaticMeshComponent;
UPROPERTY(VisibleAnywhere, Category = "Troch")
TObjectPtr<class UPointLightComponent> PointLightComponent;
UPROPERTY(VisibleAnywhere, Category = "Troch")
TObjectPtr<class UParticleSystemComponent> ParticleSystemComponent;
UPROPERTY(EditDefaultsOnly, Category = "Troch")
float RotationSpeed;
UPROPERTY(VisibleAnywhere, Category = "Troch")
TObjectPtr<class URotatingMovementComponent> RotationMovementComponent;
};
#include "WorldStatics/STorch.h"
#include "Components/BoxComponent.h"
#include "Components/PointLightComponent.h"
#include "Particles/ParticleSystemComponent.h"
#include "GameFramework/RotatingMovementComponent.h"
/*
void ASTorch::Tick(float DeltaSeconds)
{
Super::Tick(DeltaSeconds);
AddActorWorldRotation(FRotator(0.f, RotationSpeed * DeltaSeconds, 0.f));
}
*/
ASTorch::ASTorch()
{
PrimaryActorTick.bCanEverTick = false;
BoxComponent = CreateDefaultSubobject<UBoxComponent>(TEXT("RootBoxComponent"));
SetRootComponent(BoxComponent);
BodyStaticMeshComponent = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("My Static Mesh"));
BodyStaticMeshComponent->SetupAttachment(GetRootComponent());
BodyStaticMeshComponent->SetRelativeLocation(FVector(0.f, 0.f, -30.f));
static ConstructorHelpers::FObjectFinder<UStaticMesh> BodyStaticMesh(TEXT("/Script/Engine.StaticMesh'/Game/StarterContent/Architecture/Pillar_50x500.Pillar_50x500'"));
if (BodyStaticMesh.Succeeded())
{
BodyStaticMeshComponent->SetStaticMesh(BodyStaticMesh.Object);
}
PointLightComponent = CreateDefaultSubobject<UPointLightComponent>(TEXT("PointLight"));
PointLightComponent->SetupAttachment(GetRootComponent());
PointLightComponent->SetRelativeLocation(FVector(0.f, 0.f, 500.f));
ParticleSystemComponent = CreateDefaultSubobject<UParticleSystemComponent>(TEXT("ParticleSystem"));
ParticleSystemComponent->SetupAttachment(GetRootComponent());
ParticleSystemComponent->SetRelativeLocation(FVector(0.f, 0.f, 500.f));
static ConstructorHelpers::FObjectFinder<UParticleSystem> FireParticle(TEXT("/Script/Engine.ParticleSystem'/Game/StarterContent/Particles/P_Fire.P_Fire'"));
if (FireParticle.Succeeded())
{
ParticleSystemComponent->SetTemplate(FireParticle.Object);
}
RotationMovementComponent = CreateDefaultSubobject<URotatingMovementComponent>(TEXT("RotatingMovementComponent"));
}
void ASTorch::BeginPlay()
{
Super::BeginPlay();
RotationSpeed = 100.0f;
RotationMovementComponent->RotationRate = FRotator(0.f, RotationSpeed, 0.f);
}
'Unreal' 카테고리의 다른 글
[Unreal] Pawn과 Character, EnhancedInput vs InputSystem (0) | 2023.11.24 |
---|---|
[Unreal] 플레이어 폰 세팅과 이동 애니메이션 (0) | 2023.11.24 |
[Unreal] 블루프린트를 이용한 캐릭터 hp/mp 상태바 위젯 구현 (1) | 2023.11.24 |
[Unreal] Line Trace 블루프린트와 C++로 구현 (1) | 2023.11.24 |
[Unreal] 언리얼 Json 직렬화 및 역직렬화 (0) | 2023.11.23 |