Unreal Engine 5 - Project Shooter (15): Convert to Cpp (2)

mingu Lee·2025년 9월 13일

1. 간단 요약


  • BP_Character의 일부 기능 C++로 전환 완료.
  • BP_GameMode의 일부 기능 C++로 전환 완료.
  • BP_PlayerController의 일부 기능 C++로 전환 완료.
  • BP_SaveGame의 기능 C++로 전환 완료.
  • BP_Bullet의 일부 기능 C++로 전환 완료.
  • BP_Weapon의 일부 기능 C++로 전환 완료.
  • BP_LaserPointer의 일부 기능 C++로 전환 완료.
  • BPW_GamePlayWidget과 BPW_ResultWidget의 일부 기능 C++로 전환 완료.

2. 세부 과정


  1. BP_Character
  2. BP_GameMode
  3. BP_PlayerController
  4. BP_SaveGame
  5. BP_Bullet
  6. BP_Weapon
  7. BP_LaserPointer
  8. BPW_GamePlayWidget
  9. BPW_ResultWidget

각 항목의 .Cpp 파일의 코드는 올리지 않고, .h 파일의 코드를 올려서 어떤 것들을 C++로 전환했는지에 대해서만 리뷰하겠음.

아래는 Migrate 하면서 Commit 했던 로그.

2-1. BP_Character


BP_Character의 Component와 Run, State와 관련된 일부 기능을 C++로 전환함.

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

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include <Camera/CameraComponent.h>
#include <InputAction.h>
#include "ProjectShooterCharacter.generated.h"

UENUM(BlueprintType)
enum class StateOfCharacterCpp : uint8
{
	Idle,
	Aiming,
	Reloading,
	Swapping,
	Running,
};

UCLASS()
class AProjectShooterCharacter : public ACharacter
{
	GENERATED_BODY()

public:
	// Sets default values for this character's properties
	AProjectShooterCharacter();

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

	virtual void OnTriggerRun(const FInputActionValue& Value);

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

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

	UFUNCTION(BlueprintCallable)
	virtual float GetSpeedCpp() const;

	UFUNCTION(BlueprintCallable)
	virtual bool CanRunCpp() const;

	UFUNCTION(BlueprintCallable)
	virtual void TickRunCpp();

	UFUNCTION(BlueprintCallable)
	virtual void OnFootStepLeftCpp();

	UFUNCTION(BlueprintCallable)
	virtual void OnFootStepRightCpp();

protected:
	UPROPERTY(Category = Character, VisibleAnywhere, BlueprintReadWrite)
	StateOfCharacterCpp StateCpp;

	UPROPERTY(Category = Character, EditAnywhere, BlueprintReadWrite)
	TObjectPtr<USoundBase> FootStepLeftSoundCpp;

	UPROPERTY(Category = Character, EditAnywhere, BlueprintReadWrite)
	TObjectPtr<USoundBase> FootStepRightSoundCpp;

	UPROPERTY(Category = Character, EditAnywhere, BlueprintReadWrite)
	TObjectPtr<UInputAction> RunInputActionCpp;

	UPROPERTY(Category = Character, VisibleAnywhere, BlueprintReadWrite)
	bool IsRunPressedCpp;

	UPROPERTY(Category = Character, VisibleAnywhere, BlueprintReadWrite)
	float MoveForwardValueCpp;

private:
	UPROPERTY(Category = Character, VisibleAnywhere, BlueprintReadOnly, meta = (AllowPrivateAccess = "true"))
	TObjectPtr<USkeletalMeshComponent> ShadowBodyCpp;

	UPROPERTY(Category = Character, VisibleAnywhere, BlueprintReadOnly, meta = (AllowPrivateAccess = "true"))
	TObjectPtr<UChildActorComponent> WeaponInBackCpp;

	UPROPERTY(Category = Character, VisibleAnywhere, BlueprintReadOnly, meta = (AllowPrivateAccess = "true"))
	TObjectPtr<USkeletalMeshComponent> LowerBodyCpp;

	UPROPERTY(Category = Character, VisibleAnywhere, BlueprintReadOnly, meta = (AllowPrivateAccess = "true"))
	TObjectPtr<UCameraComponent> CameraCpp;

	UPROPERTY(Category = Character, VisibleAnywhere, BlueprintReadOnly, meta = (AllowPrivateAccess = "true"))
	TObjectPtr<USkeletalMeshComponent> FirstPersonCpp;

	UPROPERTY(Category = Character, VisibleAnywhere, BlueprintReadOnly, meta = (AllowPrivateAccess = "true"))
	TObjectPtr<UChildActorComponent> WeaponInHandCpp;
};

2-2. BP_GameMode


UpdateRanking 함수에 관련된 변수와 EndGame Delegate를 C++로 전환함.

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

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/GameModeBase.h"
#include "ProjectShooterGameMode.generated.h"

DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE(FProjectShooterGameModeEndGame, AProjectShooterGameMode, OnEndGameCpp);

UENUM(BlueprintType)
enum class StateOfGameCpp : uint8
{
	Ready,
	Running,
	End,
};

/**
 * 
 */

UCLASS()
class AProjectShooterGameMode : public AGameModeBase
{
	GENERATED_BODY()
	
public:
	UFUNCTION(BlueprintCallable)
	void UpdateRankingCpp();

	UFUNCTION(BlueprintCallable)
	StateOfGameCpp GetStateCpp() const;

	FDateTime GetStartTimeCpp() const;

	UFUNCTION(BlueprintCallable)
	int32 GetRankingCpp() const;

	UFUNCTION(BlueprintCallable)
	TArray<float> GetRankingScoresCpp() const;

	UFUNCTION(BlueprintCallable)
	TArray<FString> GetRankingTimesCpp() const;

public:
	UPROPERTY(BlueprintAssignable, BlueprintCallable)
	FProjectShooterGameModeEndGame OnEndGameCpp;

protected:
	UPROPERTY(Category = GameMode, VisibleAnywhere, BlueprintReadWrite)
	FDateTime StartTimeCpp;

	UPROPERTY(Category = GameMode, VisibleAnywhere, BlueprintReadWrite)
	FDateTime EndTimeCpp;

	UPROPERTY(Category = GameMode, VisibleAnywhere, BlueprintReadWrite)
	TArray<float> RankingScoresCpp;

	UPROPERTY(Category = GameMode, VisibleAnywhere, BlueprintReadWrite)
	TArray<FString> RankingTimesCpp;

	UPROPERTY(Category = GameMode, VisibleAnywhere, BlueprintReadWrite)
	int32 RankingCpp;

	UPROPERTY(Category = GameMode, VisibleAnywhere, BlueprintReadWrite)
	float ScoreCpp;

	UPROPERTY(Category = GameMode, VisibleAnywhere, BlueprintReadWrite)
	StateOfGameCpp StateCpp;
};

2-3. BP_PlayerController


IMC와 Widget 추가에 관련된 로직만 C++로 전환함.

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

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/PlayerController.h"
#include <InputMappingContext.h>
#include "ProjectShooterPlayerController.generated.h"

/**
 * 
 */
UCLASS()
class AProjectShooterPlayerController : public APlayerController
{
	GENERATED_BODY()
	
public:
	UFUNCTION()
	void OnEndGameCpp();

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

protected:
	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	TObjectPtr<UInputMappingContext> ProjectShooterInputMappingContextCpp;

	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	TSubclassOf<UUserWidget> GamePlayWidgetCpp;

	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	TSubclassOf<UUserWidget> ResultWidgetCpp;
};

2-4. BP_SaveGame


기존에 가지고 있던 Scores와 Times 변수를 C++로 전환함.

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

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/SaveGame.h"
#include "ProjectShooterSaveGame.generated.h"

/**
 * 
 */
UCLASS()
class UProjectShooterSaveGame : public USaveGame
{
	GENERATED_BODY()
	
protected:
	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	TArray<float> ScoresCpp;

	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	TArray<FString> TimesCpp;
};

2-5. BP_Bullet


OnHitComponent Event와 Set Speed 함수에 관련된 기능들을 C++로 전환함.

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

#pragma once

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

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

	UFUNCTION(BlueprintCallable)
	void SetSpeedCpp(float Value);

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

	UFUNCTION()
	void OnHitCallback(UPrimitiveComponent* HitComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit);

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

protected:
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
	float SpeedCpp;

private:
	UPROPERTY(EditAnywhere, BlueprintReadOnly, meta = (AllowPrivateAccess = "true"))
	TObjectPtr<UStaticMeshComponent> BulletCpp;
};

2-6. BP_Weapon


SpawnActor, TimerHandler, FireRelease, Recoil에 관련된 함수와 변수를 C++로 전환함.

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

#pragma once

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

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

	UFUNCTION(BlueprintCallable)
	void FireCpp(UClass* BulletClass, FTransform Transform);

	UFUNCTION(BlueprintCallable)
	void RegisterNextFireCpp(float Duration);

	UFUNCTION(BlueprintCallable)
	void FireReleasedCpp();

	UFUNCTION(BlueprintCallable)
	bool IsFiringCpp() const;

	UFUNCTION(BlueprintCallable)
	void MakeRecoilCpp();

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

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

protected:
	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	float BulletSpeedCpp;

	UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
	FTimerHandle TimerFireCpp;

	UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
	bool IsFirePressedCpp;
};

2-7. BP_LaserPointer


LineTrace에 관련된 기능을 C++로 전환함.

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

#pragma once

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

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

	UFUNCTION(BlueprintCallable)
	float GetEndPointOfLaserCpp(FVector Start, FVector End) const;

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

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

};

2-8. BPW_GamePlayWidget


Designer에서 사용하고 있는 TextBlock들을 C++로 전환함.

UPROPERTY로 BindWidget을 추가하여 C++로 선언한 것들을 Hierarchy에서 생성한 것처럼 사용할 수 있도록 함.

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

#pragma once

#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include <Components/TextBlock.h>
#include "ProjectShooterGamePlayWidget.generated.h"

/**
 * 
 */
UCLASS()
class UProjectShooterGamePlayWidget : public UUserWidget
{
	GENERATED_BODY()
	
public:
	UFUNCTION(BlueprintCallable)
	void TickTimeCpp();

protected:
	UPROPERTY(BlueprintReadOnly, meta = (BindWidget))
	TObjectPtr<UTextBlock> PlayTimeText;

	UPROPERTY(BlueprintReadOnly, meta = (BindWidget))
	TObjectPtr<UTextBlock> RemainBulletText;

	UPROPERTY(BlueprintReadOnly, meta = (BindWidget))
	TObjectPtr<UTextBlock> MaxBulletText;

	UPROPERTY(BlueprintReadOnly, meta = (BindWidget))
	TObjectPtr<UTextBlock> WeaponNameText;

	UPROPERTY(BlueprintReadOnly, meta = (BindWidget))
	TObjectPtr<UTextBlock> FireModeText;
};

2-9. BPW_ResultWidget


Designer에서 사용하고 있는 TextBlock들과 InitRanking 함수를 C++로 전환함.

UPROPERTY로 BindWidget을 추가하여 C++로 선언한 것들을 Hierarchy에서 생성한 것처럼 사용할 수 있도록 함.

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

#pragma once

#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include <Components/TextBlock.h>
#include <Components/GridPanel.h>
#include "ProjectShooterResultWidget.generated.h"

/**
 * 
 */
UCLASS()
class UProjectShooterResultWidget : public UUserWidget
{
	GENERATED_BODY()
	
protected:
	virtual void NativeConstruct() override;

	UFUNCTION(BlueprintCallable)
	void InitRankingCpp();

protected:
	UPROPERTY(BlueprintReadOnly, meta = (BindWidget))
	TObjectPtr<UTextBlock> YourScoreText;

	UPROPERTY(BlueprintReadOnly, meta = (BindWidget))
	TObjectPtr<UTextBlock> YourRankingText;

	UPROPERTY(BlueprintReadOnly, meta = (BindWidget))
	TObjectPtr<UGridPanel> Rankingtable;
};

3. 구현 중 발생한 문제 및 해결방안


  • Blueprint에서 사용했던 함수, 변수들이 실제 C++ 코드에서는 어떤 타입이고, 어떻게 사용하고, 어떤 헤더에 포함되어 있는지 확인하는 것이 상당히 어려웠음.
    내가 선언 및 사용하고자 하는 기능에 대해서 Ctrl + Left Shift + F, Left Shift + F12, Ctrl + T 등 다양한 방법으로 참조되고 있는 코드, 사용하고 있는 코드를 찾아보면서 작성함.

4. 오늘의 결과물


기능을 추가하는 작업은 아니라서 결과물에 차이가 없기 때문에 C++로 전환하는 과정에 대해서는 따로 결과물을 올리지 않겠음.

profile
Github: https://github.com/dlalsrn

0개의 댓글