[C++] Unreal Engine 4ゲームプログラミング for Ultra Beginners [基本][Actor]

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

世の数多の3DCGソフトやゲームエンジンに手を出しては心を砕かれてきた、不肖小室が、Unreal Engine 4のゲームプログラミングに挑戦してみます。

ここ最近ではメジャータイトルのゲームエンジンに採用される など色々と話題なゲームエンジンです。

背景

私が今住んでいる札幌は、ゲーム開発会社がとても活発な印象です。昨年自分が参加したGlobal Game Jam Sapporoでもプログラマー、3DCGのデザイナー、プランナーやサウンド・エンジニアの方などの方々が数多く参加されていました。そのため、ゲームに関する開発情報などが東京に居た時以上に身近に見聞きすることが多くなっています。

そして、Global Game Jamの中で強烈に高いクオリティのゲームを作り上げていた Unreal Engineチーム があり、そこで初めてUnreal Engineの開発を間近で見ることができました。そこが始まりです。

学習素材について

スクリーンショット 2015-08-31 16.55.09

Unreal Engineは基本的に公式ドキュメントが非常に充実しています。これらほとんどのドキュメントは日本語化されています。そのため、初心者の人は公式ドキュメントを参照しながら学習していくのが良いようです。またTutorialのための動画もYoutubeにアップロードされていたりするため、基本を学ぶ上での学習素材にはあまり困らないのではないでしょうか。 *1

開発環境について

ワタシの開発環境はこちらです。

  • OS: Windows 7 Professional 64bit
  • CPU: Intel Core i5-4590 3.30GHz
  • メモリ: 8GB
  • IDE: Visual Studio Community 2013
  • Unreal Engine: Unreal Engine 4.8.3 *2
  • グラフィックカード: nVidia GeForce GTX 750 Ti

SteamでFPSをやることが多いため *3、エントリーミドルレンジあたりのコスパの良いグラフィックカードを搭載しています。開発環境としては少々メモリが貧弱かもしれません。

プロジェクトの作成

Unreal Engineを立ち上げます。Unreal Editorと呼ばれる開発環境が立ち上がります。

2015-09-01 12_33_55-エピックゲームズランチャー

「C++の基本コード」を選択します。

2015-09-01 15_11_00-プロジェクトブラウザ

Unreal EditorとVisual Studioが立ち上がるのでしばらく待ちます。

2015-09-01 15_11_45-プロジェクトブラウザ

起動しました。準備完了。

2015-09-01 15_36_10-QuickStart - Microsoft Visual Studio

2015-09-01 15_25_19-QuickStart - アンリアルエディタ

Actorを拡張する

QuickStartにそって進めていきましょう。まずは Actor というクラスを拡張した独自のクラスを作成します。 Actor はオブジェクトとしての特性を持った基本的なオブジェクトのクラスです。位置情報などワールド内に存在するための情報は持たず、あくまでその物体の特徴のみを記載できるようサポートしているようです。

作り方はEditor上からポチポチと作成していきます。今回はQuickStartの通りに「FloatingActor」という名前で作成しましょう。

2015-09-01 15_38_28-QuickStart - アンリアルエディタ

2015-09-01 15_38_49-C++ クラスを追加

2015-09-01 15_39_56-QuickStart - アンリアルエディタ

2015-09-01 15_40_14-QuickStart - Microsoft Visual Studio

Editorにオブジェクトが追加されると同時に、Visual Studioのプロジェクト内に以下のファイルが追加されているのが確認できます。

  • FloatingActor.h
  • FloatingActor.cpp

ざっと中身を確認してみます。

ヘッダファイルを読む

#include "GameFramework/Actor.h"
#include "FloatingActor.generated.h"

UCLASS()
class QUICKSTART_API AFloatingActor : public AActor
{
    GENERATED_BODY()

public: 
    // Sets default values for this actor's properties
    AFloatingActor();

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

    // Called every frame
    virtual void Tick( float DeltaSeconds ) override;   
};

UCLASS() という表記が見えます。

後半にも出てきますが、どうやらこの U から始まるマクロは、Unreal Editorで見たり、編集したりするために公開する変数などのための宣言に使うようです。この場合は、クラス名をUnreal Editorへ公開しているという意味で捉えれば良さそうです。

public セクションを見ていきます。

  • AFloatingActor() コンストラクタ。生成時に呼ばれます。
  • virtual void BeginPlay() override 開始時に一度呼ばれるメソッド。
  • vertual void Tick (float DeltaSeconds) override 1フレーム毎に呼ばれるメソッドです。オプションの設定によって、これが1フレーム毎に呼ばれるのを抑止することも出来ます。時間によってオブジェクトの情報を変化させたい場合は、ここに処理を記述していきます。

ソースファイルを読む

ソースファイルを確認します。ここにはヘッダファイルで定義した各メソッドの実装を記述されています。

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

#include "QuickStart.h"
#include "FloatingActor.h"


// Sets default values
AFloatingActor::AFloatingActor()
{
    // 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;

}

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

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

コンストラクタ内部で PrimaryActorTick.bCanEverTicktrue に設定している箇所が見えます。これが true に設定されている場合は、 AFloatingActor::Tick() は1フレーム毎に呼ばれます。このオプションを false にすることで時間変化による情報の更新が必要のないものや、高速に処理する必要のないものを定義することができるようです。

秒単位で更新すれば良いオブジェクトなどは1フレーム毎に更新する必要はないので、このオプションは false に設定されるようです。

定義したActorを可視コンポーネントに結びつける

Unreal Editorに戻ります。コンテンツブラウザ の「C++クラス」という箇所の「QuickStart」を選択しましょう。「FloatingActor」という球体のサムネイルが確認できます。

2015-09-01 16_04_33-QuickStart - アンリアルエディタ

これをドラッグしてプレビュー画面の中へ持っていきます。レベルエディタと呼ばれるのはこれのようです。

2015-09-01 16_05_17-QuickStart - アンリアルエディタ

すると右上にある「アウトライナ」に「FloatingActor1」 が追加されます。

2015-09-01 16_02_45-QuickStart - アンリアルエディタ

これを選択し、下の緑色のボタン「コンポーネントを追加」 をクリックするとオブジェクトの選択肢が出てきます。ここでは「コーン」を選択しましょう。

2015-09-01 16_03_04-

すると画面上にコーンがにょきっと出現します。が、見えない!カメラの位置を動かします。右クリックをしながらドラッグするとカメラの方向を変えました。

2015-09-01 16_06_16-QuickStart - アンリアルエディタ

地面にめり込んでしまってるので位置を補正してテーブルの上に配置します。ロケーション のパラメータを設定します。

  • x: -200.0
  • y: 0.0
  • z: 200.0

2015-09-01 16_08_13-QuickStart - アンリアルエディタ

これでテーブルの上にふわりと浮いたコーンが出現します。

2015-09-01 16_08_34-QuickStart - アンリアルエディタ

コンパイルと実行

Unreal Editor上からコンパイルできます。上部に並んでいるメニューから「コンパイル」を選択します。編集された全てのリソースをもりもりコンパイルしてくれます。Visual Studio上のコンパイルは特に実行する必要がないのかもしれません。但し、エラーが発生した場合は比較的見づらいログになるので要注意です。

2015-09-01 21_19_11-

コンパイル中は「C++コードをコンパイル中。。。」という表示がされます。 正常に完了すると「コンパイルが完了しました」というメッセージが通知されます。

2015-09-01 21_18_05-QuickStart - アンリアルエディタ

その隣の「プレイ」を押すと、実際のゲーム画面のプレビューをプレイすることができます。 いわゆるFPSゲームと同じ動きなので、前後左右の動きはキーボードの「WSAD」、視点移動はマウスで行います。

3D酔いするひとは程よいゲロゲロ感が味わえるかと思います。

2015-09-01 21_20_28-QuickStart - アンリアルエディタ

コーンを上下に浮遊させる

このままでは、単に自動生成されたコードをポチポチ配置しただけで動きがありません。さきほど画面に登場させたコーン型のコンポーネントは、定義したActorと結びついています。そのため、FloatingActor.h, FloatingActor.cpp を編集することでコンポーネントの動きが定義できます。QuickStartにそって、フワフワと浮遊させてみます。

フレームごとに呼び出されるメソッドの中に実装を記述していきます。引数として渡されている DeltaTime はその名の通りフレームごとの差分時間が記録されているものと想像できます。

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

これらの情報を利用してオブジェクトの動作を記述していきます。まずはオブジェクトの現在位置を取得しましょう。

FVector NewLocation = GetActorLocation();

GetActorLocation() というメソッドが親クラスの Actor には宣言されているようです。こちらを呼び出します。

余談なのですが、宣言する変数名が大文字始まりというのが個人的にかなり違和感があります。Unreal EngineのC++文化特有のものなのでしょうか。一応、郷に入れば郷に従えの精神でこのまま進みます。

さて一度Unreal Editorに戻ってワールドの座標系を確認してみましょう。

どうも上下方向が Z軸 方向にあたるようです。ということで上下にオブジェクトを動かすためには、オブジェクトのZ座標を操作します。経過時間ごとに上下に行き来させるためには、 sin関数 を利用し 1.0f ~ -1.0f の領域を行ったり来たりするようにします。

float DeltaHeight = (FMath::Sin(RunningTime + DeltaTime) - FMath::Sin(RunningTime));

RunningTime という変数が唐突に出てきました。これは累計経過時間を表します。クラスのメンバー変数としてヘッダに宣言します。実装については後述。

public: 
    // Sets default values for this actor's properties
    AFloatingActor();
    // Called when the game starts or when spawned
    virtual void BeginPlay() override;
    // Called every frame
    virtual void Tick( float DeltaSeconds ) override;
    // 累計経過時間
    float RunningTime =0.0f;

DeltaHeight はそのままでは、当然 1~-1の値の領域しか変化しません。変化させたい高さをかけてオブジェクトのZ座標へ適用します。

NewLocation.Z += DeltaHeight * 20.0f;

これにより物体は上下に 20~-20 変化することになります。最後に自分自身の位置情報を更新させます。

SetActorLocation(NewLocation);
RunningTime += DeltaTime;

累計経過時間に差分時間を足し合わせるのもお忘れなく。

実行結果

早速実行してみます。ふわりふわりとテーブルの上にコーンが上下する謎の世界が出来上がりました。

おまけ

この Hello World 的チュートリアル後、発展課題が有るのですがそこに書いてあるのが

Particle System Component を FloatingActor に追加します。プロジェクトの中には、ビルド済みの パーティクル システム が幾つか含まれています。

唐突に登場するParticle System Component!後半のドキュメントを読めば使い方が書いてありました。が、Hello World直後の自分にとってはもう泳げるよ!とポーンと海のど真ん中に投げ出された感がありました。

参照

脚注

  1. まだ自分が困るところまで到達していないだけかもしれませんが。
  2. 執筆中に4.9が出ました。
  3. ただし、激重と言われるCryEngine系はやっていない。