このチュートリアルでは、変数と関数のエディタへの公開方法、タイマーを利用したコード実行の遅延またはリピート方法、アクタ間のコミュニケーションでのイベント使用方法を説明します。
1.タイマーを使用したアクタの作成
Unreal Engine にまだ慣れていない場合は、最初に
まず「HowTo_VTE」という名前のスターターコンテンツを使用して、新規で Basic Code (基本コード) プロジェクトを作成し、 Actor クラスを追加します。このチュートリアルでは「Countdown」と名前を付けます。
ゲームに表示するシンプルなカウントダウンタイマーの作成から始めます。「Countdown.h」ファイルで、クラス定義の最後に以下の行を追加します。
int32 CountdownTime; UTextRenderComponent* CountdownText; void UpdateTimerDisplay();
Countdown.cpp
に、レンダリング可能なテキスト Component を作成して、カウントダウン時間を 3 秒に初期化します。このタイプの アクタ には必要ないため、Ticking をオフにすることもできます。まず最初にファイルの一番上にコンポーネント用のヘッダを追加します。"include" セクションはこのようになります。#include "GameFramework/Actor.h" #include "Components/TextRenderComponent.h" #include "Countdown.generated.h"
ヘッダをインクルードすると、
ACountdown::ACountdown
を書き込むことができます。このようになります。ACountdown::ACountdown() { // Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it. PrimaryActorTick.bCanEverTick = false; CountdownText = CreateDefaultSubobject<UTextRenderComponent>(TEXT("CountdownNumber")); CountdownText->SetHorizontalAlignment(EHTA_Center); CountdownText->SetWorldSize(150.0f); RootComponent = CountdownText; CountdownTime = 3; }
ACountdown::UpdateTimerDisplay
はテキスト表示を更新して、残り時間、または時間切れの場合はゼロを表示します。ゲームにACountdown
を初めてスポーンした時にこのコードを実行して、CountdownTime
変数がゼロになるまで 1 秒に一回コードを実行します。void ACountdown::UpdateTimerDisplay() { CountdownText->SetText(FString::FromInt(FMath::Max(CountdownTime, 0))); }
関数の実行に Timer を割り当てると、必ず Timer Handle が与えられます。カウントダウン終了時に Timer をシャットダウンできるようにこのハンドルをしっかりと維持します。時間をカウントダウンする関数と、この関数をコントロールするために必要な Timer Handle を
Countdown.h
のクラス定義に追加しましょう。この作業を行うついでに、カウントダウン終了時に何か特別なことを行う関数も追加しましょう。void AdvanceTimer(); void CountdownHasFinished(); FTimerHandle CountdownTimerHandle;
Countdown.cpp
ファイルにACountdown::AdvanceTimer
とACountdown::CountdownHasFinished
のボディを記述することもできます。void ACountdown::AdvanceTimer() { --CountdownTime; UpdateTimerDisplay(); if (CountdownTime < 1) { //We're done counting down, so stop running the timer. GetWorldTimerManager().ClearTimer(CountdownTimerHandle); CountdownHasFinished(); } } void ACountdown::CountdownHasFinished() { //Change to a special readout CountdownText->SetText(TEXT("GO!")); }
新しく更新した関数の呼び出しを追加して
ACountdown::BeginPlay
のテキスト表示を初期化します。そして 1 秒に一回カウントダウンを進め、更新を行うタイマーを設定します。UpdateTimerDisplay(); GetWorldTimerManager().SetTimer(CountdownTimerHandle, this, &ACountdown::AdvanceTimer, 1.0f, true);
ACountdown::ACountdown
ではなく、ACountdown::BeginPlay
の表示を更新しています。Unreal Editor で変数に設定されている値は、コンストラクタの後で、BeginPlay の前に割り当てられるからです。後でエディタへCountdownTime
を公開する時にこれらの値に従います。Unreal Editor へ移動して Compile (コンパイル) を押して、これまでの作業進捗を確認しましょう。
更新した
ACountdown
クラスを、コンテンツ ブラウザ から レベル エディタ へドラッグできます。カウントダウン テキストは
ACountdown::ACountdown
ではなくACountdown::BeginPlay
中に設定するため、デフォルトの "Text" が レベルエディタ に表示されます。Play (再生) を押すと、予定通りカウントダウンが始まって、 "3"、 "2"、 "1"、 最後に "GO!" となります。
この時点で、タイマーを使用するシンプルなクラスが出来上がりました。プログラミングをしないユーザーは、カウントダウン時間を設定したり、カウントダウン終了時の挙動を変更するとさらに活用できます。次にこうした機能をエディタに公開します。
開発途中のコード
Countdown.h
// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.
#pragma once
#include "GameFramework/Actor.h"
#include "Countdown.generated.h"
UCLASS()
class HOWTO_VTE_API ACountdown : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
ACountdown();
protected:
// Called when the game starts or when spawned (ゲーム開始時またはスポーン時に呼び出されます)
virtual void BeginPlay() override;
public:
// Called every frame (フレーム毎に呼び出されます)
virtual void Tick( float DeltaSeconds ) override;
//How long, in seconds, the countdown will run
int32 CountdownTime;
UTextRenderComponent* CountdownText;
void UpdateTimerDisplay();
void AdvanceTimer();
void CountdownHasFinished();
FTimerHandle CountdownTimerHandle;
};
Countdown.cpp
// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.
#include "HowTo_VTE.h"
#include "Components/TextRenderComponent.h"
#include "Countdown.h"
// Sets default values
ACountdown::ACountdown()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = false;
CountdownText = CreateDefaultSubobject<UTextRenderComponent>(TEXT("CountdownNumber"));
CountdownText->SetHorizontalAlignment(EHTA_Center);
CountdownText->SetWorldSize(150.0f);
RootComponent = CountdownText;
CountdownTime = 3;
}
// Called when the game starts or when spawned
void ACountdown::BeginPlay()
{
Super::BeginPlay();
UpdateTimerDisplay();
GetWorldTimerManager().SetTimer(CountdownTimerHandle, this, &ACountdown::AdvanceTimer, 1.0f, true);
}
// Called every frame
void ACountdown::Tick( float DeltaTime )
{
Super::Tick( DeltaTime );
}
void ACountdown::UpdateTimerDisplay()
{
CountdownText->SetText(FString::FromInt(FMath::Max(CountdownTime, 0)));
}
void ACountdown::AdvanceTimer()
{
--CountdownTime;
UpdateTimerDisplay();
if (CountdownTime < 1)
{
// We're done counting down, so stop running the timer.
GetWorldTimerManager().ClearTimer(CountdownTimerHandle);
//Perform any special actions we want to do when the timer ends.
CountdownHasFinished();
}
}
void ACountdown::CountdownHasFinished()
{
//Change to a special readout
CountdownText->SetText(TEXT("GO!"));
}
2. 変数と関数をエディタに公開する
現時点のカウントダウン タイマーは値 3 (秒) にハード コーディングされています。エディタでカウントダウン時間に希望する値を設定できるとより実用的になります。しかもこの変更は簡単にできます。Visual Studio で、「
Countdown.h
」ファイルを開いて以下の行を探します。int32 CountdownTime;
この変数を Unreal Engine に公開するには、
UPROPERTY
に変更する必要があります。変更後は、ゲームの起動時や保存レベルのロード時に変数の値をエンジンに保存できるようになります。影響を与える変数のすぐ上に以下のように空の丸括弧を付けてUPROPERTY
タグを追加します。UPROPERTY() int32 CountdownTime;
UPROPERTY
は Unreal Engine がどのように変数を使用するかを変更する引数をサポートします。変数を編集可能に設定したいため、EditAnywhere
引数を追加します。UPROPERTY(EditAnywhere) int32 CountdownTime;
C++ コードの変数にコメントを追加することもできます。コメントは以下のように Unreal Editor で変数の説明として表示されます。
//How long, in seconds, the countdown will run UPROPERTY(EditAnywhere) int32 CountdownTime;
UPROPERTY
でさらに多くの設定が可能です。BlueprintReadWrite
とCategory
など他の指定子を今後調査すると良いでしょう。現時点で必要なものはそろっています。Unreal Editor に戻って [Compile (コンパイル)] ボタンを押すと、配置した
ACountdown
の変数が [Details(詳細)] パネルに表示されます。タイマー値を変更して [Play] を押して様々な値で試してみてください。タイマー値の変更に加えて、プログラマーでない方もタイマー終了時に起こることを変更できるようにしましょう。Visual Studio で
Countdown.h
ファイルを開いて以下の行を探します。void CountdownHasFinished();
この関数を以下のように
UFUNCTION
にすると Unreal Engine にこの関数を公開できます。UFUNCTION() void CountdownHasFinished();
UPROPERTY
マクロのように、より多くの機能を有効にしたりプログラマーではないデベロッパーが利用できるように、何ができるかについての情報を追加する必要があります。考えられるオプションは以下の 3 つです。BlueprintCallable
関数は C++ コードで記述されていて ブループリントグラフ で呼び出しが可能ですが、C++コードを編集せずに変更またはオーバーライドすることができません。このようにマークされた関数は、通常はプログラマー以外の方が使用するためにプログラミングされた機能ですが、変更を想定していなかったり、変更する意味がありません。例えば分かりやすい例として math 関数を見てみましょう。BlueprintImplementableEvent
関数は C++ ヘッダ (".h") ファイルに設定されていますが、関数のボディ全体は C++ コードではなくブループリント グラフに記述されます。期待していたデフォルト アクションや標準のビヘイビアが存在しないなど、特殊な状況でプログラマー以外の方がカスタム仕様のリアクションを作成して対応できるようになっています。この例としては、スペースシップゲームでパワーアップがプレイヤーのシップに触れた時のイベントなどがあります。BlueprintNativeEvent
関数はBlueprintCallable
関数とBlueprintImplementableEvent
関数の組み合わせのようなものです。デフォルトのビヘイビアは C++ でプログラミングされていますが、ブループリント グラフ でオーバーライドして追加や置換が可能です。こうしたプログラミングをする場合、以下のように C++ コードは名前の最後に _Implementation を追加して常に仮想関数にします。これが最も柔軟性のあるオプションなため、このチュートリアルではこのオプションを使用します。
プログラマー以外の方が C++ 関数を呼び出したり ブループリント でオーバーライドできるように、
Countdown.h
ファイルに以下の変更を加えます。UFUNCTION(BlueprintNativeEvent) void CountdownHasFinished(); virtual void CountdownHasFinished_Implementation();
「Countdown.cpp」で次の行を探します。
void ACountdown::CountdownHasFinished()
変更後:
void ACountdown::CountdownHasFinished_Implementation()
C++ コードに独自の値と機能を記述しながら、プログラマー以外の方がアクセスおよび変更可能な変数と関数を作成しました。プログラマー以外の方の使用方法を確認するために、ACountdown
クラスのブループリント拡張を作成して自身でこれを修正します。
完成コード
Countdown.h
// Copyright 1998-2018 Epic Games, Inc.All Rights Reserved.
#pragma once
#include "GameFramework/Actor.h"
#include "Countdown.generated.h"
UCLASS()
class HOWTO_VTE_API ACountdown : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
ACountdown();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick( float DeltaSeconds ) override;
//How long, in seconds, the countdown will run
UPROPERTY(EditAnywhere)
int32 CountdownTime;
UTextRenderComponent* CountdownText;
void UpdateTimerDisplay();
void AdvanceTimer();
UFUNCTION(BlueprintNativeEvent)
void CountdownHasFinished();
virtual void CountdownHasFinished_Implementation();
FTimerHandle CountdownTimerHandle;
};
Countdown.cpp
// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.
#include "HowTo_VTE.h"
#include "Components/TextRenderComponent.h"
#include "Countdown.h"
// Sets default values
ACountdown::ACountdown()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = false;
CountdownText = CreateDefaultSubobject<UTextRenderComponent>(TEXT("CountdownNumber"));
CountdownText->SetHorizontalAlignment(EHTA_Center);
CountdownText->SetWorldSize(150.0f);
RootComponent = CountdownText;
CountdownTime = 3;
}
// Called when the game starts or when spawned
void ACountdown::BeginPlay()
{
Super::BeginPlay();
UpdateTimerDisplay();
GetWorldTimerManager().SetTimer(CountdownTimerHandle, this, &ACountdown::AdvanceTimer, 1.0f, true);
}
// Called every frame
void ACountdown::Tick( float DeltaTime )
{
Super::Tick( DeltaTime );
}
void ACountdown::UpdateTimerDisplay()
{
CountdownText->SetText(FString::FromInt(FMath::Max(CountdownTime, 0)));
}
void ACountdown::AdvanceTimer()
{
--CountdownTime;
UpdateTimerDisplay();
if (CountdownTime < 1)
{
// We're done counting down, so stop running the timer.
GetWorldTimerManager().ClearTimer(CountdownTimerHandle);
//Perform any special actions we want to do when the timer ends.
CountdownHasFinished();
}
}
void ACountdown::CountdownHasFinished_Implementation()
{
//Change to a special readout
CountdownText->SetText(TEXT("GO!"));
}
3. ブループリントで C++ コードを拡張およびオーバーライドする
このチュートリアルでは、 ブループリント を使用した C++ クラスの機能拡張方法を紹介します。ブループリントのチュートリアルとしてではなく、C++ コードの記述にミスがないことを確認するテストを目的としています。ブループリント の導入に関しては
「Countdown1」と名付けられた ACountdown インスタンスのビヘイビアを変更するには、まず編集可能な「Countdown1」のブループリント バージョンをエディタで作成しなくてはいけません。これを行うには、ワールド アウトライナー で「Countdown1」を選択して [Details (詳細)] パネル の [Blueprint/Add Script] ボタンをクリックします。
ここで修正する ACountdown クラスを格納する Blueprint アセットにパスを割り当てて名前を付けることができます。
"Countdown1" のブループリント バージョンを表す新規アセットが作成されます。Countdown1 もこの新規ブループリントのインスタンスと置き換えられるため、ブループリントを変更するとゲーム内の Countdown1 に影響を及ぼします。
Unreal Editor は コンテンツ ブラウザ に表示される新規アセットへ自動的に移動します。アセットを 右クリック し、[Edit (編集) ...] を選択して、 Blueprint Graph (ブループリントグラフ)、 Component (コンポーネント) 階層、 Default Values (デフォルト値) を修正します。
関数とイベントは [Event Graph] タブに表示されます。最初にこれを選択します。
Event Graph ウィンドウの任意の場所を 右クリック して、ビヘイビアを決定するイベントノードとして CountdownHasFinished 関数を追加することができます。
新規ノードの右側にある白い (実行) ピンを左クリックしてドラッグし、機能を追加することができます。
左マウス ボタンを放すと、実行したい関数またはイベント名の入力が促されます。このチュートリアルでは、カウントダウン終了時に パーティクル システム をスポーンしましょう。Spawn Emitter At Location ノードが必要なので、このノードをリストから選択します。例えば「spawn loc」など名前の一部を検索欄に入力すると時間を短縮できます。次に黄色の「Location」ピンを左クリックしてドラッグし、 Get Actor Location 関数にアタッチします。
後は作成したいエフェクトを選択するだけです。Emitter Template で Select Asset をクリックすると、適切なエフェクト アセットのリストを取得できます。この場合、P_Explosion が適切であるため、これを選択します。
ブループリント エディタ の左上にある [Compile (コンパイル)] ボタンをクリックして変更を保存します。
ここで [Play (再生)] を押すと、カウントダウンが始まり、カウントダウン数がゼロになると爆発します。
しかし、カウントダウンは最後に「0」ではなく「GO!」となるようにプログラミングしました。C++ の機能を ブループリント ビジュアルスクリプティングに完全に置きかえたため、これはもう起こりません。この状況は意図したものではないため、この関数の C++ バージョンへの呼び出しを追加しなくてはいけません。Countdown Has Finished ノードを右クリックして、コンテキスト メニューから Add call to parent function を選択します。
これが完了すると、Parent: Countdown Has Finished というラベルの付いたノードが イベントグラフ に配置されます。 一般的に親ノードはこの場所に直接接続します。ここで行いますが、これは必須ではありません。親の呼び出しノードは他のノードと同様であり、好きな場所で何度でも呼び出すことができるためです。
これにより Spawn Emitter At Location への接続が置換されるため、 **Parent: programming-and-scripting/programming-language-implementation/cpp-in-unreal-engine/tutorials
これでゲームの実行時にカウントダウンが終了すると "GO!" (C++ コードから) という文字と爆発 (ブループリント グラフから) が表示されます。
4.応用編
ここまでで学んだ知識を活かして、以下を行ってみます。
イベント 実行時にターゲットのトランスフォームへ移動または回転する アクタ を作成します。ゲームでプラットフォームやドアを移動するために使用します。このイベントが 2 番目のイベントをトリガーする タイマー を開始するようにします。この 2 番めのイベントはアクタを元の位置に戻します。ハードコードされた値の代わりに公開された変数 (
UPROPERTY
を用いて) を適切な場所に使用します。タイマー ハンドルといくつかのカスタム イベント を使用して、燃え尽きる (火の Particle System Component を非アクティブにするなど) 火のついたトーチを作成します。例えば AddFuel Event でトーチの燃焼時間を延長することができます。DouseWithWater Event はトーチを瞬時に消火して、今後 AddFuel が機能しないように設定します。こうした機能は両方とも ティック を使用しないで記述できます。ハンドルで実行しているタイマーを単に修正するだけです。
以下はこのチュートリアルの内容の詳しい情報のリンク先です。
タイマーに関する詳細は ゲームプレイ タイマー ページをご覧ください。
クラスまたは構造体の変数と合わせて
UPROPERTY
タグを使用した一通りのリファレンスは、[変数、タイマー、イベント](programming-and-scripting/programming-language-implementation/cpp-in-unreal-engine/Properties)ページをご覧ください。UFUNCTIONS
とイベントの作成について学ぶには、[変数、タイマー、イベント](programming-and-scripting/programming-language-implementation/cpp-in-unreal-engine/Functions)ページをご覧ください。詳しいチュートリアルは「C++ プログラミングのチュートリアル」を参照してください。