[Unreal] 14일차 - 블루프린트로 만들어진 것을 C++로 만들기 (StaticMeshComponent, Details, SubObject, RootComponent, 위치값)

2024. 8. 2. 02:39Unreal Engine

728x90
반응형

C++ 주의할 점

class SHOOTING_API ACPlayer : public APawn

콜론은 상속을 의미한다. A가 앞에 붙는 이유는 Actor이기 때문.

최상단 상속은 UObject이다.

 

 

#include "CoreMinimal.h"
#include "GameFramework/Pawn.h"
#include "CPlayer.generated.h"

"CPlayer.generated.h"는 항상 맨 아래에 있어야 한다. 순서를 바꾸면 에러가 발생한다.

 

 


 

 

BP_Player 하위의 Cube로 붙어있는 StaticMesh Component를 CPlayer C++에서 붙여본다.

 

 

CPlayer.h 헤더파일에서, 코드를 추가한다.

public:
	class UStaticMeshComponent* BodyMesh;

*은 포인터이다. UStaticMeshComponent는 자료형, BodyMesh는 그릇

 

전체 코드

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Pawn.h"
#include "CPlayer.generated.h"

UCLASS()
class SHOOTING_API ACPlayer : public APawn
{
	GENERATED_BODY()

public:
	// Sets default values for this pawn's properties
	ACPlayer();

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

public:	
	// Called every frame
	virtual void Tick(float DeltaTime) override;

	// Called to bind functionality to input
	virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;

public:
	class UStaticMeshComponent* BodyMesh;
};

 

 


 

 

CPlayer.cpp에서는, BodyMesh 이하의 코드줄을 추가한다.

// Sets default values
ACPlayer::ACPlayer()
{
 	// Set this pawn to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

	//BodyMesh 그릇에 StaticMeshComponent를 만들어서 담으려고 한다.
	BodyMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("BodyMesh"));
}

디폴트의 하위라서 서브 오브젝트를 만들어준다는 CreateDefaultSubobject를 사용. <> 안에는 만들고 싶은 컴포넌트 타입 자료형을 넣으면 된다. 저 위에 캡쳐사진에서 Cube 자리가 "BodyMesh"가 된다는 말이다.

 

 

Ctrl + B 눌러서 빌드.

 

 

잘 되었다면 다시 에디터로 돌아와서 Viewport에 Pawn을 올려놓았을 때 "BodyMesh" 이름의 하위 오브젝트가 생성된 것을 볼 수 있다. 

 

 

이렇게 바로 쓰지 않고 Blueprint로 바꿔서 사용한다.

Pawn에 우클릭 후 [Create Blueprint class based on CPlayer] 선택.

 

 

"BP_CPlayer" 이름으로 생성.

 

 

우측 Details 창에는 아무것도 나오지 않는다.

 

 


 

 

Details가 나오게 하기

헤더파일에서, URPOPERTY 부분을 추가한다.

VisibleAnywhere는 Class와 Instance 둘 다 특정 컴포넌트를 볼 수 있게 한다. 값 변경 불가능.

VisibleDefaultsOnly, VisibleInstanceOnly는 각각 Class, Instance 에서만 볼 수 있게 한다.

EditAnywhere은 값도 바꿀 수 있다.

public:
	UPROPERTY(VisibleAnywhere)
	class UStaticMeshComponent* BodyMesh;

 

 

전체 코드

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Pawn.h"
#include "CPlayer.generated.h"

UCLASS()
class SHOOTING_API ACPlayer : public APawn
{
	GENERATED_BODY()

public:
	// Sets default values for this pawn's properties
	ACPlayer();

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

public:	
	// Called every frame
	virtual void Tick(float DeltaTime) override;

	// Called to bind functionality to input
	virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;

public:
	UPROPERTY(VisibleAnywhere)
	class UStaticMeshComponent* BodyMesh;
};

 

 

빌드가 잘 되었다면 [Details] 부분이 나오는 것을 볼 수 있다.

 

 

VisibleAnywhere 뒤에 BluprintReadOnly라고 추가로 붙이면, 드래그 앤 드랍으로 블루프린트에 가져와도 오직 Get으로만 가져올 수 있다. (BlueprintReadWrite 하면 Get Set 가능)

public:
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
	class UStaticMeshComponent* BodyMesh;
};

 

 

참고로, 블루프린트에서 [Show Inherited Variables]를 활성화하면 부모의 Variables도 가져올 수 있다.

 

 


 

 

이제 블루프린트로만 만들었던 Cube 이하의 서브 오브젝트를 C++에서 만들어본다.

 

 

헤더파일에서 코드를 추가한다.

UPROPERTY(VisibleAnywhere)
class UStaticMeshComponent* SpaceShipMesh;

 

 

전체 코드

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Pawn.h"
#include "CPlayer.generated.h"

UCLASS()
class SHOOTING_API ACPlayer : public APawn
{
	GENERATED_BODY()

public:
	// Sets default values for this pawn's properties
	ACPlayer();

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

public:	
	// Called every frame
	virtual void Tick(float DeltaTime) override;

	// Called to bind functionality to input
	virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;

public:
	UPROPERTY(VisibleAnywhere)
	class UStaticMeshComponent* BodyMesh;
	UPROPERTY(VisibleAnywhere)
	class UStaticMeshComponent* SpaceShipMesh;
};

 

 

C++ 파일에서도 코드 추가

SpaceShipMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("SpaceShipMesh"));

 

 

전체 코드

// Fill out your copyright notice in the Description page of Project Settings.


#include "CPlayer.h"

// Sets default values
ACPlayer::ACPlayer()
{
 	// Set this pawn to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

	//BodyMesh 그릇에 StaticMeshComponent를 만들어서 담으려고 한다.
	BodyMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("BodyMesh"));
	SpaceShipMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("SpaceShipMesh"));
}

// Called when the game starts or when spawned
void ACPlayer::BeginPlay()
{
	Super::BeginPlay();
	
	int32 number1 = 205;
	int32 number2 = 5;
	UE_LOG(LogTemp, Warning, TEXT("%d"), number1 + number2);
}

// Called every frame
void ACPlayer::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

}

// Called to bind functionality to input
void ACPlayer::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);

}

 

 

Ctrl + B로 빌드

 

 

에디터로 돌아가면 SpaceShipMesh가 생성되어 있는 것을 볼 수 있다.

 

 


 

 

BodyMesh를 루트 컴포넌트로 등록하고, SpaceShipMesh는 자식 컴포넌트로 변경

C++ 코드 추가

//BodyMesh를 Root로 등록
RootComponent = BodyMesh;
SpaceShipMesh->SetupAttachment(BodyMesh);

 

 

전체 코드

// Fill out your copyright notice in the Description page of Project Settings.


#include "CPlayer.h"

// Sets default values
ACPlayer::ACPlayer()
{
 	// Set this pawn to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

	//BodyMesh 그릇에 StaticMeshComponent를 만들어서 담으려고 한다.
	BodyMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("BodyMesh"));

	//BodyMesh를 Root로 등록
	RootComponent = BodyMesh;

	SpaceShipMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("SpaceShipMesh"));
	SpaceShipMesh->SetupAttachment(BodyMesh);
}

// Called when the game starts or when spawned
void ACPlayer::BeginPlay()
{
	Super::BeginPlay();
}

// Called every frame
void ACPlayer::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);
}

// Called to bind functionality to input
void ACPlayer::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);
}

 

 

에디터로 돌아가면 BodyMesh가 루트 컴포넌트가 되어있는 것을 볼 수 있다.

 

 


 

 

동적으로 SpaceShipMesh에 모델링 넣기

C++ 코드 추가

//사용할 Static Mesh 데이터를 읽어서 컴포넌트에 할당하기
ConstructorHelpers::FObjectFinder<UStaticMesh> TempMesh(TEXT("/Script/Engine.StaticMesh'/Game/SpaceShip/Spaceship_ARA.Spaceship_ARA'"));
//로딩 성공하면 SpaceShipMesh에 사용할 Static Mesh로 TempMesh를 넣는다.
if (TempMesh.Succeeded())
{
	SpaceShipMesh->SetStaticMesh(TempMesh.Object);
}

 

전체 코드

// Fill out your copyright notice in the Description page of Project Settings.


#include "CPlayer.h"

// Sets default values
ACPlayer::ACPlayer()
{
 	// Set this pawn to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

	//BodyMesh 그릇에 StaticMeshComponent를 만들어서 담으려고 한다.
	BodyMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("BodyMesh"));

	//BodyMesh를 Root로 등록
	RootComponent = BodyMesh;

	SpaceShipMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("SpaceShipMesh"));
	SpaceShipMesh->SetupAttachment(BodyMesh);

	//사용할 Static Mesh 데이터를 읽어서 컴포넌트에 할당하기
	ConstructorHelpers::FObjectFinder<UStaticMesh> TempMesh(TEXT("/Script/Engine.StaticMesh'/Game/SpaceShip/Spaceship_ARA.Spaceship_ARA'"));
	//로딩 성공하면 SpaceShipMesh에 사용할 Static Mesh로 TempMesh를 넣는다.
	if (TempMesh.Succeeded())
	{
		SpaceShipMesh->SetStaticMesh(TempMesh.Object);
	}
}

// Called when the game starts or when spawned
void ACPlayer::BeginPlay()
{
	Super::BeginPlay();
}

// Called every frame
void ACPlayer::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);
}

// Called to bind functionality to input
void ACPlayer::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);
}

 

 

우측 Static Mesh에 모델링이 들어와 있는 것을 볼 수 있다.

 

 


 

 

위치 값 세팅하기

C++ 코드 추가

//로딩 성공하면 SpaceShipMesh에 사용할 Static Mesh로 TempMesh를 넣는다.
if (TempMesh.Succeeded())
{
	SpaceShipMesh->SetStaticMesh(TempMesh.Object);

	//부모 기준 상대적 위치값 세팅. 회전 순서는 Y, Z, X 순서임
	SpaceShipMesh->SetRelativeRotation(FRotator(0, 90, 90));
	//크기 세팅
	SpaceShipMesh->SetRelativeScale3D(FVector(6));
}

 

회전 값은 Copy해서 코드에 붙여넣는다.

 

전체 코드

// Fill out your copyright notice in the Description page of Project Settings.


#include "CPlayer.h"

// Sets default values
ACPlayer::ACPlayer()
{
 	// Set this pawn to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

	//BodyMesh 그릇에 StaticMeshComponent를 만들어서 담으려고 한다.
	BodyMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("BodyMesh"));

	//BodyMesh를 Root로 등록
	RootComponent = BodyMesh;

	SpaceShipMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("SpaceShipMesh"));
	SpaceShipMesh->SetupAttachment(BodyMesh);

	//사용할 Static Mesh 데이터를 읽어서 컴포넌트에 할당하기
	ConstructorHelpers::FObjectFinder<UStaticMesh> TempMesh(TEXT("/Script/Engine.StaticMesh'/Game/SpaceShip/Spaceship_ARA.Spaceship_ARA'"));
	//로딩 성공하면 SpaceShipMesh에 사용할 Static Mesh로 TempMesh를 넣는다.
	if (TempMesh.Succeeded())
	{
		SpaceShipMesh->SetStaticMesh(TempMesh.Object);

		//부모 기준 상대적 위치값 세팅. 회전 순서는 Y, Z, X 순서임
		SpaceShipMesh->SetRelativeRotation(FRotator(0, 90, 90));
		//크기 세팅
		SpaceShipMesh->SetRelativeScale3D(FVector(6));
	}
}

// Called when the game starts or when spawned
void ACPlayer::BeginPlay()
{
	Super::BeginPlay();
}

// Called every frame
void ACPlayer::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);
}

// Called to bind functionality to input
void ACPlayer::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);
}

 

 

회전과 스케일 값이 잘 들어온 것을 볼 수 있다.

728x90
반응형