[Unreal] 15일차 - C++ 플레이어 이동, 총알 생성 및 발사하기

2024. 8. 3. 15:49Unreal Engine

728x90
반응형

14일차 복습

메모리 관리가 필요한 부분은 U로 시작한다. UPROPERTY(), UStaticMeshComponent*

* 은 메모리 주소를 저장하는 변수이다.

:: 은 소속을 뜻한다. 왼쪽 안에 있는 오른쪽의~

F 붙으면 구조체나 표준 C++ 클래스를 만들어내는 오브젝트 (ex) FObjectFinder)

-> 는 기능에 접근하는 표시 (ex) SpaceShipMesh->SetStaticMesh()

 

 


 

 

BP_CPlayer 구성

헤더 파일 코드 추가

UPROPERTY(VisibleAnywhere)
class USceneComponent* FirePosition;

 

전체 코드

// 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;
	UPROPERTY(VisibleAnywhere)
	class USceneComponent* FirePosition;
};

 

 

C++ 코드 추가

//총구 컴포넌트 등록
FirePosition = CreateDefaultSubobject<USceneComponent>(TEXT("FirePosition"));
FirePosition->SetupAttachment(BodyMesh);
FirePosition->SetRelativeLocation(FVector(0, 0, 80));

 

전체 코드

// 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));
	}

	//총구 컴포넌트 등록
	FirePosition = CreateDefaultSubobject<USceneComponent>(TEXT("FirePosition"));
	FirePosition->SetupAttachment(BodyMesh);
	FirePosition->SetRelativeLocation(FVector(0, 0, 80));
}

// 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);
}

 

 

Ctrl + B로 빌드

 

 

Fire Position이 잘 붙었다.

 

 


 

 

C++로 이동 구현

오른쪽으로 향하게 만들기

헤더 파일 추가

public:
	//좌우, 상하 방향, 이동 속도 설정
	float h = 0;
	float v = 0;
	float speed = 500;

 

전체 코드

// 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;
	UPROPERTY(VisibleAnywhere)
	class USceneComponent* FirePosition;

public:
	//좌우, 상하 방향, 이동 속도 설정
	float h = 0;
	float v = 0;
	float speed = 500;
};

 

 

C++ 코드 추가

void ACPlayer::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

	//이동
	FVector dir = FVector::RightVector;
	FVector P0 = GetActorLocation(); //현재 위치 설정
	FVector vt = dir * speed * DeltaTime;
	FVector P = P0 + vt;
	SetActorLocation(P);
}

 

전체 코드

// 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));
	}

	//총구 컴포넌트 등록
	FirePosition = CreateDefaultSubobject<USceneComponent>(TEXT("FirePosition"));
	FirePosition->SetupAttachment(BodyMesh);
	FirePosition->SetRelativeLocation(FVector(0, 0, 80));
}

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

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

	//이동
	FVector dir = FVector::RightVector;
	FVector P0 = GetActorLocation(); //현재 위치 설정
	FVector vt = dir * speed * DeltaTime;
	FVector P = P0 + vt;
	SetActorLocation(P);
}

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

 

 

Viewport에 라이트, 카메라 추가

카메라 세팅

 

[Auto Activate for Player] - [Player 0] 설정

 

 

BP_CPlayer (0, 0, 0) 세팅

 

 

오른쪽으로 잘 움직인다.

 

 


 

 

사용자의 입력에 따른 이동

헤더 파일 코드 추가

public:
	//좌우, 상하 방향, 이동 속도 설정
	float h = 0;
	float v = 0;
	float speed = 500;

	void Horizontal(float value);
	void Vertical(float value);

 

 

헤더 전체 코드

// 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;
	UPROPERTY(VisibleAnywhere)
	class USceneComponent* FirePosition;

public:
	//좌우, 상하 방향, 이동 속도 설정
	float h = 0;
	float v = 0;
	float speed = 500;

	void Horizontal(float value);
	void Vertical(float value);
};

 

 

C++ 코드 추가

void ACPlayer::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

	//이동
	FVector dir(0, h ,v);
	FVector P0 = GetActorLocation(); //현재 위치 설정
	FVector vt = dir * speed * DeltaTime;
	FVector P = P0 + vt;
	SetActorLocation(P);
}

// Called to bind functionality to input
void ACPlayer::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);
	
	PlayerInputComponent->BindAxis(TEXT("Horizontal"), this, &ACPlayer::Horizontal);
	PlayerInputComponent->BindAxis(TEXT("Vertical"), this, &ACPlayer::Vertical);
}

void ACPlayer::Horizontal(float value) //좌우 입력 처리 함수
{
	h = value;
}
void ACPlayer::Vertical(float value) //상하 입력 처리 함수
{
	v = value;
}

 

전체 코드

// 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));
	}

	//총구 컴포넌트 등록
	FirePosition = CreateDefaultSubobject<USceneComponent>(TEXT("FirePosition"));
	FirePosition->SetupAttachment(BodyMesh);
	FirePosition->SetRelativeLocation(FVector(0, 0, 80));
}

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

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

	//이동
	FVector dir(0, h ,v);
	FVector P0 = GetActorLocation(); //현재 위치 설정
	FVector vt = dir * speed * DeltaTime;
	FVector P = P0 + vt;
	SetActorLocation(P);
}

// Called to bind functionality to input
void ACPlayer::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);
	
	PlayerInputComponent->BindAxis(TEXT("Horizontal"), this, &ACPlayer::Horizontal);
	PlayerInputComponent->BindAxis(TEXT("Vertical"), this, &ACPlayer::Vertical);
}

void ACPlayer::Horizontal(float value) //좌우 입력 처리 함수
{
	h = value;
}
void ACPlayer::Vertical(float value) //상하 입력 처리 함수
{
	v = value;
}

 

 

Ctrl+B 빌드

 

 

BP_CPlayer에서 Possess 설정

 

 

잘 움직인다.

 

 


 

 

총알 새 C++ 클래스 만들기

우클릭 해서 생성

 

 

Actor 설정

 

 

솔루션 탐색기 보면 CBullet의 C++와 헤더 파일이 생성된 것을 볼 수 있다.

 

 


 

 

CPlayer에서 썼던 코드 복붙

헤더 파일

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

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "CBullet.generated.h"

UCLASS()
class SHOOTING_API ACBullet : public AActor
{
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	ACBullet();

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

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

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

 

C++ 파일

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


#include "CBullet.h"

// Sets default values
ACBullet::ACBullet()
{
 	// Set this actor 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;
}

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

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

}

 

 

이전에 블루프린트로 만들었던 BP_Bullet의 Cube 스케일 값을 사용하기 위해 값을 복사해서 가져온다.

	//스케일 값 설정
	BodyMesh->SetRelativeScale3D(FVector(1.0f, 0.25f, 0.75f));

 

 


 

 

만든 CBullet을 블루프린트로 만들기

 

 

스케일 값과 BodyMesh 하위 오브젝트가 잘 만들어진 것을 볼 수 있다.

 

 


 

 

StaticMesh 모델링 넣기

C++ 파일에 코드 추가

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

 

전체 코드

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


#include "CBullet.h"

// Sets default values
ACBullet::ACBullet()
{
 	// Set this actor 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;

	//스케일 값 설정
	BodyMesh->SetRelativeScale3D(FVector(1.0f, 0.25f, 0.75f));

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

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

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

}

 

 

에디터를 껐다 켜면, 큐브가 잘 들어온 것을 볼 수 있다.

 

 


 

 

메테리얼 적용하기

C++ 코드 추가

// 메테리얼 로드하기
ConstructorHelpers::FObjectFinder<UMaterial> TempMat(TEXT("/Script/Engine.Material'/Engine/BasicShapes/BasicShapeMaterial.BasicShapeMaterial'"));
//로딩 성공하면 BodyMesh에 사용할 Static Mesh로 TempMesh를 넣는다.
if (TempMat.Succeeded())
{
	BodyMesh->SetMaterial(0, TempMat.Object);
}

 

전체 코드

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


#include "CBullet.h"

// Sets default values
ACBullet::ACBullet()
{
 	// Set this actor 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;

	//스케일 값 설정
	BodyMesh->SetRelativeScale3D(FVector(1.0f, 0.25f, 0.75f));

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

	// 메테리얼 로드하기
	ConstructorHelpers::FObjectFinder<UMaterial> TempMat(TEXT("/Script/Engine.Material'/Engine/BasicShapes/BasicShapeMaterial.BasicShapeMaterial'"));
	//로딩 성공하면 BodyMesh에 사용할 Static Mesh로 TempMesh를 넣는다.
	if (TempMat.Succeeded())
	{
		BodyMesh->SetMaterial(0, TempMat.Object);
	}
}

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

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

}

 

 

Ctrl+B 빌드

 

 

메테리얼이 바로 적용이 안된다면,

Class Settings에서 Parent Calss를 Actor로 한 번 바꿔준 후 다시 CBullet으로 돌아오면 적용이 된다.

 

 

적용이 잘 되었다.

 

 


 

 

총알 이동 처리

헤더 파일 코드 추가

public:
	float speed = 500;

 

C++ 코드 추가

void ACBullet::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

	//이동
	FVector dir(0, 0, 1);
	FVector P0 = GetActorLocation(); //현재 위치 설정
	FVector vt = dir * speed * DeltaTime;
	FVector P = P0 + vt;
	SetActorLocation(P);
}

 

전체 코드

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


#include "CBullet.h"

// Sets default values
ACBullet::ACBullet()
{
 	// Set this actor 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;

	//스케일 값 설정
	BodyMesh->SetRelativeScale3D(FVector(1.0f, 0.25f, 0.75f));

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

	// 메테리얼 로드하기
	ConstructorHelpers::FObjectFinder<UMaterial> TempMat(TEXT("/Script/Engine.Material'/Engine/BasicShapes/BasicShapeMaterial.BasicShapeMaterial'"));
	//로딩 성공하면 BodyMesh에 사용할 Static Mesh로 TempMesh를 넣는다.
	if (TempMat.Succeeded())
	{
		BodyMesh->SetMaterial(0, TempMat.Object);
	}
}

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

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

	//이동
	FVector dir(0, 0, 1);
	FVector P0 = GetActorLocation(); //현재 위치 설정
	FVector vt = dir * speed * DeltaTime;
	FVector P = P0 + vt;
	SetActorLocation(P);
}

 

 

Ctrl+B 빌드

 

 

에디터에서 BP_CBullet 끌어다 놓고 위치 수정하고 실행하면 위로 올라가는 것을 볼 수 있다.

 

 

총알 속도 조절 가능하도록 코드 수정

public:
	UPROPERTY(EditAnywhere)
	float speed = 500;

 

 

블루프린트에서도 사용할 수 있게 수정

public:
	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	float speed = 500;

 

 

카테고리 추가도 가능하다.

public:
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="MySettings")
	float speed = 500

 

 


 

 

발사 버튼을 누를 때 총알이 발사 되도록 설정

CPlayer.h 코드 추가

//발사 버튼 입력 처리 함수
void Fire();
//총알 공장
UPROPERTY(EditAnywhere, Category = "Bullet")
TSubclassOf<class ACBullet> bulletFactory; //ACBullet의 하위 클래스

 

전체 코드

// 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;
	UPROPERTY(VisibleAnywhere)
	class USceneComponent* FirePosition;

public:
	//좌우, 상하 방향, 이동 속도 설정
	float h = 0;
	float v = 0;
	float speed = 500;

	void Horizontal(float value);
	void Vertical(float value);

	//발사 버튼 입력 처리 함수
	void Fire();

	//총알 공장
	UPROPERTY(EditAnywhere, Category = "Bullet")
	TSubclassOf<class ACBullet> bulletFactory; //ACBullet의 하위 클래스
};

 

 

빌드 후 에디터에서 보면 ACBullet의 하위 클래스만 뜨는 것을 볼 수 있고, BP_CBullet을 선택한다.

 

 

CPlayer.cpp 코드 추가

#include <CBullet.h>
//총알 발사 버튼 입력과 처리 함수 엮기
PlayerInputComponent->BindAction(TEXT("Fire"), IE_Pressed, this, &ACPlayer::Fire);
void ACPlayer::Fire()
{
	//총알 발사
	GetWorld()->SpawnActor<ACBullet>(bulletFactory, FirePosition->GetComponentLocation(), FRotator());
}

 

전체 코드

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


#include "CPlayer.h"
#include <CBullet.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));
	}

	//총구 컴포넌트 등록
	FirePosition = CreateDefaultSubobject<USceneComponent>(TEXT("FirePosition"));
	FirePosition->SetupAttachment(BodyMesh);
	FirePosition->SetRelativeLocation(FVector(0, 0, 80));
}

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

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

	//이동
	FVector dir(0, h ,v);
	FVector P0 = GetActorLocation(); //현재 위치 설정
	FVector vt = dir * speed * DeltaTime;
	FVector P = P0 + vt;
	SetActorLocation(P);
}

// Called to bind functionality to input
void ACPlayer::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);
	
	PlayerInputComponent->BindAxis(TEXT("Horizontal"), this, &ACPlayer::Horizontal);
	PlayerInputComponent->BindAxis(TEXT("Vertical"), this, &ACPlayer::Vertical);

	//총알 발사 버튼 입력과 처리 함수 엮기
	PlayerInputComponent->BindAction(TEXT("Fire"), IE_Pressed, this, &ACPlayer::Fire);
}

void ACPlayer::Horizontal(float value) //좌우 입력 처리 함수
{
	h = value;
}
void ACPlayer::Vertical(float value) //상하 입력 처리 함수
{
	v = value;
}

void ACPlayer::Fire()
{
	//총알 발사
	GetWorld()->SpawnActor<ACBullet>(bulletFactory, FirePosition->GetComponentLocation(), FRotator());
}

 

 

발사가 잘 된다.

728x90
반응형