UE5.3を使用したゲーム制作備忘録を作成中!

モバイル向けゲームを作るため日々奮闘中!
同じ悩みを持つ人たちの、解決の糸口になれば幸いです。

詳細はこちら
PR
スポンサーリンク

Unreal Engine コツコツ自習_スコア機能を実装する【2Dゲーム】

UEコツコツ自習シリーズ
スポンサーリンク

簡単な2Dゲームを作ろう

2Dゲーム制作の練習シリーズです。

アンリアルエンジンで2Dゲーム制作方法をまとめていきます。

説明を省略したり、細かな数値設定などの説明をしない場合もありますので、ご参考程度で確認ください。

※作業環境:UEバージョン5.3.2 Windows11 VSCode

スコア機能を実装する

敵を倒したときに、点数が追加されるスコアを実装していきます。

コードの移し替え

スコアを実装する前に、敵の追跡設定するコードを移設します。

敵が生成されたときに、敵の追跡行動をセットしたいので「EnemySpawner」のコードを編集していきます。

EnemySpawner.h

インクルードを追加します。

#include "Enemy.h"

// 追加↓
#include "PlayerCharacter.h"
// ここまで↑

「public:」内にコードを追加します。

	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	float DecreaseSpawnTimerByEveryInterval = 0.05f;

// 追加↓
	APlayerCharacter* Player;
// ここまで↑

関数も追加します。

	void OnSpawnTimerTimeout();
	void StartSpawning();
	void StopSpawning();
	void SpawnEnemy();

// 追加↓
	void SetupEnemy(AEnemy *Enemy);
// ここまで↑

EnemySpawner.cpp

インクルードを追加します。

#include "EnemySpawner.h"

// 追加↓
#include "Kismet/GameplayStatics.h"
// ここまで↑

「AEnemySpawner::BeginPlay(){}」にコードを追加します。

void AEnemySpawner::BeginPlay()
{
	Super::BeginPlay();

// 追加↓
	AActor *PlayerActor = UGameplayStatics::GetActorOfClass(GetWorld(), APlayerCharacter::StaticClass()); // プレイヤーを取得する
	if (PlayerActor) // プレイヤーが存在するなら
	{
		Player = Cast<APlayerCharacter>(PlayerActor); // キャストする
	}
// ここまで↑

	StartSpawning();
}

追加した関数の定義を作成します。

// 関数定義
void AEnemySpawner::SetupEnemy(AEnemy *Enemy)
{
	if (Enemy) // 敵が生成されたなら
	{
		Enemy->Player = Player; // 追跡対象をプレイヤーに設定する
		Enemy->CanFollow = true; // 追跡モードをオンにする
	}
}

「AEnemySpawner::SpawnEnemy(){}」内にコードを追加します。

    AEnemy *Enemy = GetWorld()->SpawnActor<AEnemy>(EnemyActorToSpawn, EnemyLocation, FRotator::ZeroRotator);

// 追加↓
    SetupEnemy(Enemy); // 敵の追跡機能を設定する
// ここまで↑

敵の追跡行動をセットするコードが作成できたので、「Enemy.cpp」にある類似コードを削除します。

削除するコード

Enemy.cpp

void AEnemy::BeginPlay()
{
	Super::BeginPlay();

// 削除↓
//	if (!Player) // プレイヤーをまだ取得していない場合
//	{
//      AActor *PlayerActor = UGameplayStatics::GetActorOfClass(GetWorld(), APlayerCharacter::StaticClass()); // プレイヤーを取得する
//		if (PlayerActor) // プレイヤーが存在するなら
//	    {
//          Player = Cast<APlayerCharacter>(PlayerActor); // キャストする
//		    CanFollow = true; // 追跡モードをオン
//	    }
//  }
// ここまで↑

}

これでコードの入れ替えは完了です。

デリゲートを実装する

スコアを実装していきます。

まずは、デリゲートを実装していきます。

デリゲート(DELEGATE)とは、通知を送るための仕組みです。

デリゲートを使って、関数を他の場所から呼び出したりできます。

Enemy.h

デリゲートを追加します。

#include "Enemy.generated.h"

// 追加↓
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FEnemyDiedDelegate);
// ここまで↑

UCLASS()
class PAPERGAME1_API AEnemy : public AActor
{

「public:」内にコードを追加します。

	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	float StopDistance = 20.0f;

// 追加↓
	FEnemyDiedDelegate EnemyDiedDelegate;
// ここまで↑

	AEnemy();

デリゲートを有効にするために、リフレッシュ&コンパイルします。

もしくは、VSCoodeからUEエディタを開いてください。

Enemy.cpp

「AEnemy::Die(){}」にコードを追加します。

	EnemyFlipbook->SetFlipbook(DeadFlipbookAsset);
	EnemyFlipbook->SetTranslucentSortPriority(1);

// 追加↓
	EnemyDiedDelegate.Broadcast(); // デリゲートに関連付けた関数をすべて呼び出す
// ここまで↑

EnemySpawner.h

インクルードを追加します。

#include "PlayerCharacter.h"

// 追加↓
#include "GM_MyGameMode.h"
// ここまで↑

#include "EnemySpawner.generated.h"

「public:」内にコードを追加します。

	FTimerHandle SpawnTimer;

// 追加↓
	AGM_MyGameMode* MyGameMode;
// ここまで↑
	
	AEnemySpawner();

関数も追加します。

	void SetupEnemy(AEnemy *Enemy);

// 追加↓
	UFUNCTION()
	void OnEnemyDied();
// ここまで↑

EnemySpawner.cpp

追加した関数の定義を作成します。

// 関数定義
void AEnemySpawner::OnEnemyDied()
{
	GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::White, TEXT("Enemy died")); // デバック表示する
}

ここに、後でスコア換算コードを配置します。
今は、デバック表示のみにして、きちんと機能するか確認しています。

「AEnemySpawner::BeginPlay(){}」内のコードを追加します。

void AEnemySpawner::BeginPlay()
{
	Super::BeginPlay();

// 追加↓
	AGameModeBase *GameMode = UGameplayStatics::GetGameMode(GetWorld()); // ゲームモードを取得する
	if (GameMode) // ゲームモードが存在すれば
	{
		MyGameMode = Cast<AGM_MyGameMode>(GameMode); // キャストする
		check(MyGameMode); // 成功しているか確認
	}
// ここまで↑

「AEnemySpawner::SetupEnemy(){}」内にコードを追加します。

void AEnemySpawner::SetupEnemy(AEnemy *Enemy)
{
	if (Enemy)
	{
		Enemy->Player = Player;
		Enemy->CanFollow = true;

// 追加↓
		Enemy->EnemyDiedDelegate.AddDynamic(this, &AEnemySpawner::OnEnemyDied); // デリゲートに関数を関連付ける
// ここまで↑

	}
}

保存して、リフレッシュ&コンパイルします。

敵を倒したときにデバックが表示されればOKです。

スコアを設定する

敵を倒したときにスコアを加算させていきます。

スコア数はゲームモードで管理させます。

GM_MyGameMode.h

「public:」内にプロパティを追加します。

	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	float WinResetTime = 3.0f;

// 追加↓
	UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
	int Score = 0;
// ここまで↑

関数も追加します。

	FTimerHandle ResetGameTimer;

// 追加↓
	AGM_MyGameMode();
	virtual void BeginPlay() override;

	void SetScore(int NewScore);
	void AddScore(int AmountToAdd);
// ここまで↑

GM_MyGameMode.cpp

追加した関数の定義を作成します。

// 関数定義
AGM_MyGameMode::AGM_MyGameMode()
{
    PrimaryActorTick.bCanEverTick = true; // ティック機能をオンにする
    SetScore(0); // スコアを0にする
}

// 関数定義
void AGM_MyGameMode::BeginPlay()
{
    Super::BeginPlay();
    SetScore(0); // ゲーム開始時にも0にする
}

// 関数定義
void AGM_MyGameMode::SetScore(int NewScore)
{
    if (NewScore >= 0) // スコア数が0以上なら
    {
        Score = NewScore; // スコア更新
    }
}

// 関数定義
void AGM_MyGameMode::AddScore(int AmountToAdd)
{
    int NewScore = Score + AmountToAdd; // 新しいスコアを計算する
    SetScore(NewScore); // スコアを更新する

    GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::White, FString::Printf(TEXT("Score: %d"), Score)); // デバックでスコアを表示する
}

EnemySpawner.cpp

敵を倒したときにスコアを更新させます。

「AEnemySpawner::OnEnemyDied(){}」内のコードを編集します。

void AEnemySpawner::OnEnemyDied()
{

// 編集&追加↓
	// GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::White, TEXT("Enemy died")); // 消す

	int ScoreToAdd = 10; // 加算するスコア10点
	MyGameMode->AddScore(ScoreToAdd); // スコアを更新
// ここまで↑

}

保存して、リフレッシュ&コンパイルし、テストプレイします。

敵を倒すごとにスコアが増えていればOKです。

スコア機能の実装完了

今回はここまでです。

次回は「スコア表示するUIを作成する」の予定です。

前後記事

次回の記事
・作成中

他の記事を探す

他の記事も気になる方は、以下の記事の目次を確認ください。

タイトルとURLをコピーしました