Unity出身者の為のUnrealC++使い方 初級編

  • 53
    いいね
  • 0
    コメント

対象人物

Unityを使った事が有り、
Blueprintを使ってみたけどやっぱりC#みたいな言語で書きたいと思ってる。
けどUnrealC++に手を出そうとしたら出来る事が多すぎて
全体的にボヤッとしてて何をすべきか分からない。
という人を対象にしています。

途中からチュートリアル形式になっており実際にプロジェクトを作りながら進めてゆきます。
完成するとこんな感じになります。
https://www.youtube.com/watch?v=gX87kcvKgA8

完成品ファイルはこちらになります。
7zipで圧縮してるので何とかして解凍してください。
https://bowlroll.net/file/114338

EpicさんのサイトでもUnity→UE4の引っ越し方法をもっと詳しく細かく解説しています。
https://docs.unrealengine.com/latest/JPN/GettingStarted/FromUnity/index.html

※C++用推奨図書
C++をある程度触ったことが有る事を前提としています。
10年くらいに前に仕入れた情報なので、書籍は古めです。
C++ の絵本 amazon

記事内では名前が長い物を下記のように省略する場合が有ります。
割と適当にやってるんであとは雰囲気で察してください。

省略
BluePrint BP
BluePrintEditor BPE
BluePrintClass BPClass
BluePrintVisualScript BPVS

UNITYのプレハブの構造

UNITYではGameObjectに様々なコンポーネントを付けてゆきました。
それがプレハブという入れ物に入って設定込みで保存されています。
プレハブ.jpg

UE4のBlueprint Classの構造

UE4では下の図のようになります。
ACTOR.jpg

UE4ではUNITYと名前は違いますが用途は同じです。
対応は下記の通り。

Unity UE4
プレハブ Blueprint Class
GameObect Actor
Component Actor Component

UE4でもActorComponentを追加していけば良いのです。

Unityと同じコンポーネント指向的なやり方で作ってみよう!

構造は違うようで似通っています。
ここからはチュートリアル形式になりますので、
Unityのコンポーネントの作り方を似てるポイントを掴みつつ進めてみてください。

以下の動画が完成品の動作になります。
https://www.youtube.com/watch?v=gX87kcvKgA8
ThirdPersonのサンプルを元にして、連射銃を持たせます。
ポイントとしては
・全てをC++で作ろうとするのではなく、部分的にはBPも使用する。
・既存のBluePrintClassを利用しコンポーネントを追加する形で拡張している。
 (他人のコードとの連携を上手くやっている。)
・ActorComponentで実装することにより再利用性の高い部品を作っている。
辺りになります。

テンプレートを元にTPSサンプルを作る

1、起動して
UE起動用.jpg

2、BluePrintの方のThirdPersonを選んで作成します。
尚、BluePrintの方を選択する理由は後述します。
テンプレート選択.jpg

3、こんな画面が表示されると思います。
今回はこの左側の灰色の人に連射銃を付けてみたいと思います。
mini.jpg

弾丸を作る

簡単なコードはBPVisualScriptで作るべきなのでここのコードはBPVisualScriptで作ります。
BPVisualScriptとC++のどちらで作るかの境目は決めておくべきなので
「For,While,Switchの制御文、またはローカル変数が必要になったらC++化する。」
と決めています。
このBluePrintVisualScriptの場合はこれらをどれも使わないため、
BluePrintVisualScriptで作成します。

1、フォルダーを準備します。
フォルダー準備.jpg

2、Bulletという名前でActorを作成します。
Bullet作成.jpg

3、BulletにSphereのSceneComponentを追加します。
AddComponentSphere2.jpg

4、Sphereをルートのノードにします
DragAndDrop.jpg

5、SphereのPhysics関連の設定を変更します。
チェックマーク入れる.jpg

5、こんな感じのBSVisualScriptを書きます。
  尚、UE4では+X方向が前方です。
  BPClassのエディター上ではあたかも-Y方向が前方であるかのように見えますがアレは罠です
BPVS bullet2.jpg

6、WorldOutlinerに配置し、Playしたら直ぐに前方へ飛んでいけば作成成功です。

C++ファイルを作る下準備

1、まずNewC++classで適当なファイルを作ります。
  これを行わないとC++ファイル保存用のフォルダが出てこないためになります。
createC++.jpg

2、なんでも良いのですが僕の場合はいつもSceneComponentのDummyを作ります。
  SceneComponentを選択して。
  ※Unityで言うところのEmptyObjectの代わりです。
  ※UE4では標準搭載ではないためこのタイミングでついでに作っておきます。
CreateSceneComp.jpg

3、Dummyという名前を付けます。
CreateDummy.jpg

4、するとプロジェクトのフォルダ内にSourceというフォルダが出来ます。
  この中にAComponentというフォルダを作成します。
folder.jpg

タイマーを作ってみよう

前と同じやり方でTimerというActorComponent
AComponentというフォルダ内に作りましょう。

C++内で出てくるマクロの機能表です。

マクロ名 内容
UFUNCTION(BlueprintCallable, Category = "Timer") BPVSへ関数が公開されます。
UPROPERTY(BlueprintReadWrite, EditAnywhere) 変数がBPVS,BPEへ公開されます。
UPROPERTY(BlueprintReadWrite) 変数がBPVSから読み書きできる
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FNoArg) デリゲートを使う前の呪文
UPROPERTY(BlueprintAssignable) デリゲートにBPEでBPVSを入れられるようにします。

デリゲートを作るとこんな感じのが出てきます。
中にBPVisualScriptを入れられるのでBPVisualScriptとの連携を
前提にしてる場合は必須アイテムになります。
Delegate.jpg

UPROPERTYの引数にBlueprintReadWriteが入っているとBPVisualScriptでアクセス出来るようになります。
UPROPERTYの引数にEditAnywhereが入っているとBPEditor上で設定できるようになります。

クラス作成を行ったらコードは下記のようにしてください。
名前がTimerで一致してればコピペで大丈夫です。
中身については上のマクロ機能表を参考に読んで頂ければと思います。
機能としては下記のようになっています。
・一定時間ごとに所定のBlueprintVisualScriptを実行する。
・Start(bool)でスタートさせたり停止させたりする。
・スタートしたらとりあえず一発実行しておく(実行するかの切り替え有り)

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

#pragma once

#include "Components/ActorComponent.h"
//追加ヘッダを書く場合はここに書きます。
//今回は使いません。
#include "Timer.generated.h"

//デリゲートを使う場合の儀式です。
//通常はどこか適当なヘッダに呼び出す用に書いておくのですが今回はヘッダ内に書きます。
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FNoArg);


UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class FIRST_API UTimer : public UActorComponent
{
    GENERATED_BODY()

public: 
    // Sets default values for this component's properties
    UTimer();

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

    // Called every frame
    virtual void TickComponent( float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction ) override;

    //停止中でもこれを実行するとスタートします。
    //引数次第では停止ボタンにもなります。
    //動作中にもう一回実行するとタイマーがリセットされます。
    UFUNCTION(BlueprintCallable, Category = "Timer")
        void Start(bool enable);

    //この変数の感覚でデリゲートの関数を実行します。
    UPROPERTY(BlueprintReadWrite, EditAnywhere)
        float m_TimeSpan = 1.0f;

    //現在アクティブか保存しておきます。
    //UE4標準のやつは動作を把握してないのであえて使いません。
    UPROPERTY(BlueprintReadWrite, EditAnywhere)
        bool m_ActiveNow = false;

    //スタートした時に一回実行する設定
    UPROPERTY(BlueprintReadWrite, EditAnywhere)
        bool m_StartFile = true;

    //現在の時間です。
    UPROPERTY(BlueprintReadWrite)
        float m_TimeNow = 0.0f;

    //デリゲートになります。
    //こう書いておくと、BP側から好きな関数を入れたりできます。
    UPROPERTY(BlueprintAssignable)
        FNoArg m_TimerFire;

};
Timer.cpp
// Fill out your copyright notice in the Description page of Project Settings.

#include "first.h"
#include "Timer.h"


// Sets default values for this component's properties
UTimer::UTimer()
{
    // Set this component to be initialized when the game starts, and to be ticked every frame.  You can turn these features
    // off to improve performance if you don't need them.
    bWantsBeginPlay = true;
    PrimaryComponentTick.bCanEverTick = true;

    // ...
}


// Called when the game starts
void UTimer::BeginPlay()
{
    Super::BeginPlay();
    if (m_ActiveNow)
    {
        //スタート直後に一回実行
        m_TimerFire.Broadcast();
    }
    // ...

}


// Called every frame
void UTimer::TickComponent( float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction )
{
    Super::TickComponent( DeltaTime, TickType, ThisTickFunction );

    //アクティブ状態だったら時間を加算する。
    if (m_ActiveNow)
    {
        m_TimeNow += DeltaTime;

        //時間積算が一定以上になったらデリゲート関数を実行
        if (m_TimeNow > m_TimeSpan )
        {
            m_TimeNow -= m_TimeSpan;
            m_TimerFire.Broadcast();
        }
    }
    else
    {
        // 時間計算中じゃないのにアクティブだった場合は非アクティブにする。
        if ( this->IsActive() )
        {
            this->Activate( false );
        }

    }

    // ...
}

void UTimer::Start(bool enable)
{
    this->Activate(enable);
    m_ActiveNow = enable;
    m_TimeNow = 0.0f;

    if(m_ActiveNow)
    {
        //スタート時に一回デリゲート関数を実行
        m_TimerFire.Broadcast();
    }
}

連射ショットを作ってみよう

この人にショット連射機能を付けます。
CharaSelect.jpg

3、Arrowを追加します。
AddArrow.jpg

4、Arrow位置調整します。
ArrowHaichi.jpg

5、先ほど作ったActorComponentのTimerを追加します。
timer追加.jpg

6、Timerの設定をします。
TimerSetting.jpg

7、こんな感じのBPVisualScriptを作ります。
CharaBPVScript.jpg
m_TimerFileは以下をクリックすると出てきます。
Delegate.jpg

8、完成
  以上で完成します。
  Playすると「完成品」の動きになります。

操作方法:
A 左へ歩く
S 下へ歩く
D 右へ歩く
W 上へ歩く
Space ジャンプ
左クリック ショット

完成品

https://bowlroll.net/file/114338

おまけ、今回使用したBlueprintClass(Character)の構造

Character.jpg
前回の図で「Actor自体が機能を持っている」と書いていましたが
Actorの追加機能版であるCharacterでは多くの標準機能を持っています。
全て書くと大変になるので端折っていますが代表格は下記の通り。
・Ai機能
・アニメーション機能
・キャラクターコントローラ
特にAi機能、アニメーション機能についてはCharacter自体に組み込まれた機能で
コンポーネントにはなってません。
これらはUnityには無い機能で作られています。

次回予告

次の投稿では今回の内容をもう少し詳しくいきます。
具体的にはまだ書いてませんが、下記みたいな感じになると思います。
・何故UE4では迷ってしまうのか?の正体
・Actor継承も出来るけど、触れるべからず