Unity3D+シューティングゲームのオブジェクトプールのチュートリアル

Blogをいつもご覧いただきありがとうございます。

シューティングゲームを作った時に、武器の弾のシステムは様々な書き方がありますが、一番シンプルな書き方は、恐らく弾のオブジェクトをインスタンスして、敵にヒットしたら(コード側ではコライダーやポジションでどちらでも可能です。)、敵と弾一緒に消滅すると思います。

弾を生成する場合の例:

using UnityEngine;
using System.Collections;

public class BulletInstance : MonoBehaviour {
public GameObject BulletPrefab;
// Update is called once per frame
void Update () {                                                                                                            
 GameObject bullet = Instantiate(BulletPrefab, Vector3.zero, Quaternion.identity) as GameObject;   //弾をインスタンス 
}

弾と敵を消滅する場合の例:

using UnityEngine;
using System.Collections;

public class Enemy : MonoBehaviour {

void OnTriggerEnter(Collider other)
 {
   if (other.tag.CompareTo("Bullet") == 0)
    {
       Destroy(other.gameObject);//弾が消される
       Destroy(this.gameObject);//敵自分が消される
    }
 }
}

この書き方は普通に動くはずですが、でも、常に弾のPrefabをインスタンスしたり、Destroyしたりしたら、メモリー上にとってあまり優しいとはいえません。正直に言うとPC用としてはまだしも、スマートフォンゲームの場合はかなりきびしいものになると思います。
オブジェクトをずっと増やし続けるとゲームのFPSが落ちたり、重くなったり、スマートフォンが熱くなったりするのもおかしくないです。

それをさける為に、考えを逆にするのはどうでしょうか?

プログラム側では、オブジェクトのInstanceやDestroyの場合にリソースを消費しているとしたら、なら、常にInstanceやDestroyしないシステムを作ればいいじゃんないか?

それでは、オブジェクトプールを勉強しましょう!

·オブジェクトプールの概念

オブジェクトプールとは、この先使えるオブジェクトを溜めておく用の倉庫のような存在で、オブジェクトが必要になったら取り出し、使い終わったら戻すことで、なるべく少数のオブジェクト使い回してオブジェクト数及び生成・消滅のコストを抑えるものです。

それでは、実際にUnity3D側で作っていきましょう。

·実装

Step1 Unityの環境作り

Step2 弾のプールシステム

ここで二つのスクリプトが必要です。

  • BulletPool.cs  このスクリプトはオブジェクトプールで、オブジェクトにドラッグドロップする必要はありません。
  • Bullets.cs     このスクリプトは弾のPrefabにドラッグドロップするスクリプトです,弾の方向やスピードをコントロールしています。
実装コード:

BulletPool.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BulletPool : MonoBehaviour {
    //オブジェクトのプールとしてのリストを作る
    List pools = new List();
    // start pos
    Vector3 firstPosition;
    //シングルトン
    private static BulletPool instance;
    private BulletPool() { }
    public static BulletPool GetInstance()
    {
        if (instance == null)
        {
          
            instance = new GameObject("BulletPool").AddComponent();
           
        }
        return instance;

    }
   
    //オブジェクトプールからオブジェクトを取得する
    public GameObject MyInstantiate(GameObject name)
    {
        //オブジェクトプールは空だから、インスタンスする
        if (pools.Count == 0)
        {
            return Instantiate(name, Vector3.zero, Quaternion.identity) as GameObject;
        }
        else 
        {
           
            //もしプールでは空じゃない場合は「0」を取る
            GameObject go = pools[0];
           
            go.SetActive(true);
            //オブジェクトプールから消される
            pools.Remove(go);
            return go;

        }
    }
    //オブジェクトプールを作成
    public void DelayInstantiate(GameObject name)
    {
        //オブジェクトを隠す
        name.SetActive(false);
        //オブジェクトプールに入れる
        pools.Add(name);
    }
}

Bullets.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Bullets : MonoBehaviour
{
    Transform target;
    private void OnEnable()
    {
        //ポジションを初期化する
        target = GameObject.Find("Hero").transform;
        transform.position = target.position;
        //二秒の後でCoroutineを実行する
        StartCoroutine(DelayObject(2f));
    }
    private void Update()
    {
        //弾の移動
        transform.Translate(Vector3.up * Time.deltaTime * 100);
    }
   
    IEnumerator DelayObject(float time)
    {
        yield return new WaitForSeconds(time);
        //弾のプールリストに入れる
        BulletPool.GetInstance().DelayInstantiate(gameObject);
    }

}

 

Step3 Playerのコントロール

弾のプールを実装完了したら、次は発砲の機能や移動の機能が入ってる”PlayerControlManager.cs”を「Hero」のオブジェクトにドラッグドロップしてください。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerControlManager : MonoBehaviour {

    float _hor_Speed = 1f;    //水平移動の速度
    float _ver_Speed = 1f;  //垂直移動の速度 
    float _topMax = 300f;//Player移動制御の変数
    float _bottomMax = -300f;//Player移動制御の変数
    float _sideMax =177f;//Player移動制御の変数
    float _turnAngle = 45;//回転の角度
    GameObject bulletPrefab;
    void Awake(){
        bulletPrefab = Resources.Load("Prefabs/Bullet") as GameObject;

    }
    void Update()
    {
        Move();
        TurnBody();
        Limit();
        Fire();
    }

    void Fire()//発砲
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            BulletPool.GetInstance().MyInstantiate(bulletPrefab);
        }
    }
    
    void Limit()//移動制御
    {
        if (transform.localPosition.x > _sideMax)
        {
            transform.localPosition = new Vector2(_sideMax, transform.localPosition.y);
        }
        if (transform.localPosition.x <  -_sideMax)
        { 
            transform.localPosition = new Vector2(-_sideMax, transform.localPosition.y); 
        } 
        if (transform.localPosition.y > _topMax)
        {
            transform.localPosition = new Vector2(transform.localPosition.x, _topMax);
        }
        if (transform.localPosition.y < _bottomMax)
        {
        transform.localPosition = new Vector2(transform.localPosition.x, _bottomMax);
        }
    }

    void TurnBody()//機体を回転する
    {
        if (Input.GetKeyDown(KeyCode.A) || Input.GetKeyDown(KeyCode.LeftArrow))
        {
            transform.Rotate(new Vector3(0, _turnAngle, 0));
        }
        if (Input.GetKeyDown(KeyCode.D) || Input.GetKeyDown(KeyCode.RightArrow))
        {
            transform.Rotate(new Vector3(0, -_turnAngle, 0));
        }
        if (Input.GetKeyUp(KeyCode.A) || Input.GetKeyUp(KeyCode.LeftArrow))
        {
            transform.Rotate(new Vector3(0, -_turnAngle, 0));
        }
        if (Input.GetKeyUp(KeyCode.D) || Input.GetKeyUp(KeyCode.RightArrow))
        {
            transform.Rotate(new Vector3(0, _turnAngle, 0));
        }
    }
    void Move()//Playerの移動
    {
        float ver = Input.GetAxis("Vertical");
        float hor = Input.GetAxis("Horizontal");
        transform.position +=new Vector3(hor * _hor_Speed, ver * _ver_Speed, 0);
    }

 }

   

上記の流れに沿って実装ができたら、プロジェクトをPlayしてください。

こんな感じですね

·注意点:

  • オブジェクトプールは非常に便利です。使う場面として繰り返し利用するオブジェクトを生成する場合に有効です。今回の場合は弾や敵などです。
  • 使う場合によっては逆効果が出る可能性もあります。実際にゲームのジャンルやシステム、オブジェクトの特徴などによって、どのような形式のオブジェクトプールを使うのか考える必要があると思います。
  • オブジェクトを破棄する代わりに隠す(表示しないようにする)ことで、表示的には破棄と同等の効果実現してます。そのおかげでオブジェクトをインスタンス化する際のリソースの無駄な消費を抑えられると思います。

※補足情報としてオブジェクトプールを利用することで、オブジェクトのインスタンス化をできるだけ削減しましたが、既にインスタンスされたオブジェクトはSetActive(false)になっても、まだメモリーの中に存在し、メモリーの容量を占有しています。メモリの占有が完全になくなるわけではありません。

ご覧いただきありがとうございました。

カスタムビルド解像度設定がリビルドで変更されない場合の対処

Unityでカスタム解像度を使ってビルドするとき、選択された会社名とアプリ名にリンクされたその解像度でプレーヤー設定ファイル を作ります。 問題は、その後そのカスタム解像度を変更してプロジェクトを再構築したい場合でも、古いプレーヤー設定ファイルがあるコンピューターに表示されるものが一度設定した解像度になることです。

たとえば、解像度を800×600のカスタムサイズに設定してビルドした場合は、このようになります:

後でカスタム解像度を1920×1080に変更して再ビルドしても、同じ800×600の解像度が表示されます。

その解像度を適切な解像度に設定するには、2つの方法があります:

最初の方法は、ビルドプレイヤー設定に新しい会社名を設定することです。 その後、その名前であなたのシステムに新しいプレイヤー設定フォルダを作成します。

二番目の方法は、レジストリファイル内の設定フォルダを見つけて削除することです。 そのようにあなたの新しい解像度設定のファイルを作成します。 そのファイルはレジストリエディタのHKCU / softwareの中にあります。

Unity_PostProcessing機能の有効化

あるシーンが、「PostProcessingのエフェクトが適用されているシーンのはずなのに自分のPCで開くと見た目が通常と変わらない。」
上記のような場合は、Unity PostProcessing Stackがインストールされているかをチェックしてみてください。

確認方法は下記のとおりです。
1.メニューバーのWindow->Package Manager をクリック。

inst_PostProcessing_Stack01_Image
inst_PostProcessing_Stack01_Image
Image_of_inst_PostProcessing_Stack02
inst_PostProcessing_Stack02_Image

2.Allのタブ(①)をクリックし、スクロールダウンしてPost Processing(②)を選択します。
3.右上のInstallボタン(③)を押してインストールします。

この手順でシーンのカメラに設定された、Post Processingの効果が確認できると思います。

Unity3D+IK(Inverse Kinematics)のAnima2Dチュートリアル

Blogをいつもご覧いただきありがとうございます。

前回は「Unity3D+Anima2Dチュートリアル」というテーマの記事を投稿しました。

今回はAnima2dのInverse Kinematicsについて説明したいと思います。

Inverse Kinematicsとは何ですか?

Anima2Dには、Inverse Kinematicsのコンポーネントがあります。これを使い、親関係のボーンオブジェクトの子供を動かすと、親も連動し動きます。

例を挙げると、腕と肩の関係のようなものです。(以下省略”IK”です)。

シンプルなアニメーションは、ボーンをいじるだけで充分ですが、もしアニメーションが複雑な場合はかなり時間がかかると思います。

そういう場合は「IK」が便利です。移動させたいボーンを「IK」と繋げればこのボーンのチェーンを丸ごと動かすことができとても便利です。

 

IKの種類は?

 

Anima2DのIKには,IK CCDIK Limb という2種類のIKがあります。

IL Limbは骨を2本しかコントロールできません、余弦定理ですので、今回の場合手足に利用します。

IK CCD は設定に応じて、最大コントロールできる本数がルートボーンまでの全部の骨をコントロールすることができます。今回の場合頭と尻尾に使います。

 

では、前回の引継き、IKの使い方を説明します。
IKをの使い方を説明する前に、先ずAnima2Dの効率をアップでさせる機能を紹介したいと思います。

「PoseManager」というものです。

使い方はとても簡単です。下記の画像のように、前回の「牛」のオブジェクトに「Pose Manager」を入れれば、使えるようになるはずです。

そして、「Create new pose」をクリックしたら、今のスプライトのポジションとローテーションがセーブできます。

一つの「Idle」のポーズを「Save」をクリックしてから、後はどんな調整しても、ただ「Load」ボタンをクリックしたら、最初設定のポーズに戻れます。(ちなみに、「Save」はオーバライドしますので、ご注意ください。)

「Pose Manager」の使い方はここまでです。

それでは、「IK」の使い方の説明に入りましょう。

Step 1: IKをクリエイトします

「牛」のオブジェクトの中に、もう一個の空のオブジェクトを作って、名付け「IK」です。

下記の画像のようにそのオブジェクトに右クリックして、「2D Object」→「IK Limb」をクリックしたら、「IK」が出ます。

では、「IK」のパラメータを説明しましょう。

  • Record:アニメーションモードの間,ボーンのキーフレームを記録します。
  • Target: IKが適用されるボーン。
  • Weight:​IKのポーズに対する影響度。
  • Restore Default Pose: 計算を実行する前に最初のポーズを設定します。
  • Orient Child:ターゲットの子ボーン(使用可能な場合)をIKローテーションに回転させます。
  • Num bonesIKの影響を受けるボーンの数.最大はルートボーンまで。
  • Iterations solverの反復回数。
  • Dampingソルバのステップ速度を制御する.値が小さいと変化が見やすい,大きいと変化が見にくいです。Dampingの値が大きければ、もっと自然に見えるかもしれません。

 

Step 2:「IK」をコントロールしたい関節に配置します

下記の画像のように、三つの「IK」をクリエイトして、分かりやすい名前を付けてから、それぞれにコントロールしたいところに置いてください。

上記の説明の通り、「頭」の部分には、使っているのはIK CCDです。

お気付きだとおもいますが、このグレーのリングを自分が望んでいる所に配置しても、スプライトはまだコントロールできません。

なぜかというと、下記の画像表示の通りに、右側の「Inspector」の「Target」はまだ「None」になっていますので、コントロールできるオブジェクトはまだありません。

では、「Target」に相応の「Bone」オブジェクトに入れてみてください。

設定が終了したら、グレーのリングは青のリングに変わります。

では、下記の画像の手順通りにすれば、左側のコントロールしたい「IK」のオブジェクトをクリックして、右側のリングを移動したら、「牛」全身が一緒に動きます。

注意点:偶にリングを移動しても、欲しい角度に合わせられない場合があったら、下記の画像の状態で「IK」の「Inspector」の「Filp」のチェックを入れてから、もう一度調整すれば、合わせられると思います。

適用後の図:

これで、「IK」のリングを弄れば、簡単に関節が調整できるようになりました。

複雑なボーンが入っているスプライトでは、「IK」はとても役に立ちます。

今回のインバース キネマティクス(IK)の使い方はここまでになります。

では皆さん、次回の内容をご期待ください!

Unity3D+Anima2Dチュートリアル

Blogをいつもご覧いただきありがとうございます。
先日、「Unity+Myo(ジェスチャーを活用して牛乳を搾るゲームを作りました)」というテーマのブログを発表しました。

下記のURLはゲームの映像です。
https://www.youtube.com/watch?v=4Jz7y1n3Iec

その中の「牛」はAnima2Dプラグインを利用して制作しました。Anima2Dの使い方のチュートリアルとして今回はAnima2Dを利用して「牛」を動かしてみましょう!

Anima2Dのメリットは?
  • Unity3Dのアニメーションと同じ感覚で2Dキャラクターが動かせます。
    • スキニングとBoneが付くアニメーションを作ることができます。
    • Spriteの各頂点編集することができます。
    • 全部アニメーション(Unity3Dの標準機能)でコントロールすることができます
Step1 Anima2Dをインストール
  • AssetStoreからAnima2Dを検索し、ダウンロードしてから、インポートをしてください。
Step2 「牛」の画像を分割

上記の画像はまだ分割していない状態です。

ゲームでは「頭」、「足」二本、「体」を分けたいので、こちらで「Gimp2」でこの4つの部分を分割しました。

そして、分割した画像をUnityにインポートして、下記の状態になりました。

画像のInspectorのTexture TypeSprite (2D and UI)に変更するのを忘れないで下さい。

これで、下準備は完了です。

Step3 SpriteMeshを作る

ここから本番ですね。先用意した画像を選択して、右クリックしてSpriteMeshが作れます。( Create→Anima2D→SpriteMesh)

上記のステップで、拡張子が「asset」のファイルができると思います。保存先が分からなくなってしまわぬよう独立のフォルダーを入れるとよいと思います。

Step4 SpriteMeshをSceneに配置

これから、作り上げたSpriteMeshをシーンに配置します。

まず、シーンにempty GameObjectを作って、この中で二つ空のGameObjectを作ります。下記の画像ご参考までに。

そして、SpriteMeshを一個ずつBodyのGameObjectに入れます。(一気に全部選択しても一個ずつしか入りませんので)

全部入れて、元「牛」の四肢のようにポジションを調整したら、下記の画像のようになるかと思います。

Step5 SortingLayer、OrderLayerの調整

ですが、牛の頭が体に隠れてしまってるように見えますので、そこで、OrderLayerの順位を調整します。

  • 先ず、SpriteMeshのSortingLayerを全部同じにします。SpriteMeshのオブジェクトを選択して、右側は下記のようにします。

デフォルトの状態で全部のSpriteMeshのOrderLayerは0になっていますので、一番前に表示したい物のLayerの順位を0より大すると前面に表示できます。

今回の場合は牛の頭を体の前に表示しようと思いますので、頭のオブジェクトを選択して、OrderLayerは1にすれば、一番前に表示できるようになると思います。

これで、SortingLayerとOrderLayerの説明は維持上です。

Step6 Boneを入れる

これがAnima2Dのとても大事な機能です。スプライトに骨を付けることができます。

先ず、先ほど作ったBoneというゲームオブジェクトに右クリックしてください。

下記の画像のように選択します。

こうすれば、新しいBoneオブジェクトがインスタンスされます。自分が分かりやすい名前を決めてください。

そして、「Torso」の中で頭、両足の2DBoneを作って、針みたいなものを相応の所に配置します。

注意点:上記の赤い箇所で示している所は「骨」の長さです、スプライトの大きさに相応して決めてください。

そして、BoneとSpriteMeshを繋げましょう!

下記の画像の通りにそれぞれのBoneオブジェクトをSpriteMeshのSet bonesの所に入れます。

注意点:繋げたくない部分があれば、右クリックで削除してください。

これで、BoneとSpriteMeshは繋がりました。

とは言え、Boneを動かしてみたら、Meshの方は全然ついて来きません。それはなぜでしょうか?次のステップで解決していきます。

Step7 SpriteMeshはBoneと一緒に動かす

SpriteMeshはBoneと一緒に移動できるようにする場合は、先ず、移動させたいSpriteMeshを選択したまま、「Window」をクリックしてください。そして、「Anima2D」→「Sprite Mesh Editor」を押してください。

開いたら、下記の画面が表示します。

注意点:赤い箇所は頂点の数がコントロールできます。今回はデフォルトの設定で十分だと思いますので、デフォルトのままで行きます。

次は「Bind」の方に進みましょう。

設定する前に、先ず右下の「Overlay」をチェックしてください。そして、影響範囲が可視化されてもっとわかりやすくなるのでしょう。

次は右上の「Apply」を押したら、MeshとBoneは一緒に動かすことができるはずです。

全部上記の設定が完了すると、牛の頭を移動しても体のSpriteMeshも一緒に連動して動きます。

次回はインバース キネマティクス(IK)の使い方を説明したいと思います。

Flowの基礎について


前回は、Stingrayの基本と、テストプレイまで紹介しました。
今回はStingrayによる開発で、最も重要になると思われる
『Flow』についてご紹介します。


1.Flowとは何か

『Flow』とは、Stingrayに基本搭載されているビジュアルスクリプティング機能です。
そもそも、ビジュアルスクリプティングとは『視覚的にプログラムが組める機能』といった感じです。
有名なものでいえば、UnrealEngine4の『Blueprint』や、初心者向けのプログラミング言語の『Scratch』などがありますね。

ビジュアルスクリプティングの利点として、
『プログラムに触れたことのない初心者に優しい』『一目でどのような処理かわかりやすい』という点があります。
もちろん、普通のプログラムができないわけではなく、StingrayではLuaにてプログラミングが行えます


2.フローの開きかた

今回はまず、前回に作成したプロジェクトのFlowを開いてみます。
VRテンプレートのエディタの『Level Viewport』のタブのすぐ右側にある『Level Flow』タブを開きましょう。
『Level Flow』タブが見つからない場合は、『Window』のドロップダウンメニューを開き、
『Level Flow』を選択してください。


画像1

すると、画像のようなエディタが開かれるはずです。
これは『レベルフロー』といい、Flowの一種です。

たくさんのブロックが線で繋がっているのが見えます。
これがビジュアルスクリプティングにおけるプログラムになります。


3.Flowの基礎(ピンとノード)

Flowにおけるブロックは『ノード』と呼ばれ、
『特定の値を拾う』『操作を受け付ける』等といった機能が、ブロックごとに設定されています。
Stingrayではこのブロックとブロックを線で繋ぎ、プログラミングをやっていきます。

今のままでは、画面がよく見えないため、Flowを拡大しましょう。
Flowの拡大/縮小はマウスホイールで行えます。
また、ホイールクリックでFlowの移動もできます。



画像は先ほどのFlowの左上の部分を拡大したものです。
ノードにいくつかの○があるのが見えます。
この○は『ピン』といい、ノードに入力する値(引数)か、
ノードから出力される値(返り値)を表します。
左側の○が引数、右側の○が返り値となります。
線はこのピンから伸び、また別のノードのピンに繋がります。

線とピンにはそれぞれ色がついています。
この色は、その線とピンが『何を表しているか』を示しています。
どの色が何を表すか、については今後必要に応じて説明するため、
現時点では、『白い線で繋がっているノードの順に実行される』ということだけ覚えておけば大丈夫です。


4.処理の始まりのノード

先ほどの画像では、『Level Update』というノードから白い線が始まっているのがわかります。
つまり、ここが処理の始まりの部分となるわけです。

『Level Update』というノードは『更新の度にout以降の処理を行う』というものです。
つまり、『Level Update』の『out』から繋がったノードは、一定の間隔で実行されるということです。
何度も実行したい処理はこのノードに繋げます。

この他にも、『処理の始まり』となるノードは幾つも存在します。
そのうちの一つが、『Level Loaded』ノードです。
このノードは『レベルのロード時のみ』に呼ばれます。
分かりづらいという方は『一番最初に一度だけ呼ばれる』と覚えておけば、今の時点では問題ありません。

また、その逆で『レベルの終了時』、つまり『一番最後に一度だけ呼ばれる』
『Level Shutdown』ノードも存在します。


5.Flowへのノード追加方法

さて、まずはFlowに慣れるために、非常に簡単なプログラムを作ってみます。
作成するプログラムは『終了時に”おしまい”とログに出力する』というものです。

『終了時』ということは先ほど説明した『Level Shutdown』ノードが必要ですね。
しかし、先ほど開いたレベルフローの中を探してみても、『Level Shutdown』ノードはどこにもありません。
自分で追加する必要があります。

レベルフローの中で右クリックをすると、ズラーっとたくさんの項目が出てきます。
ズラーっと出てこなかった場合はフローの四角形の外で右クリックをするようにしてください。

この項目の中から『Event』→『Level Shutdown』と選択します。
こうすることで、レベルフローの中に新たに『Level Shutdown』ノードが追加されます。
Flowへのノードの追加は、このように行います。

画像3


6.ログへの出力

続いては、『ログに出力する』という処理のノードを追加します。
先ほどと同じように右クリック、『Debug』→『Debug Print』の順に選択します。
『Debug Print』ノードは『Label』と『Text』に設定された値をログに出力します。
赤いピンは『文字列』を表しています。

画像4

それでは、『Level Shutdown』と『Debug Print』を繋いでみましょう。
白いピン同士を繋げると以下の画像のようになります。

画像5

これで、『終了時にログに文字列を出力する』という処理自体は完成です。


7.引数への設定

しかし、これではまだ”おしまい”というログを出力できません。
『Label』、もしくは『Text』に文字列を設定する必要があります。

文字列を設定する方法は、ピンに”おしまい”を出力するピンから線を繋げるという方法と、
直接”おしまい”という文字列を設定する方法の2種類がありますが、今回は後者の方法を利用します。

『Debug Print』ノードの『Label』か『Text』の右側にある四角をクリックしてください。
すると、画像のような編集画面が出てきます。
この編集画面に入力した値が、クリックした項目にセットされます。
ここで”おしまい”という文字を入力してからOKを押しましょう。

画像6

画像のように『Debug Print』内に”おしまい”の文字がセットされたのがわかるはずです。
(下の方の四角をクリックした場合はTextの横に”おしまい”と入ります)

画像8

これで処理は完成です。


8.実装の確認テスト

Ctrl+Sキーで保存してから、プレイを始めて動作を確認しましょう。
プレイ前に『Log Console』タブを開くのを忘れないでください。
『Log Console』タブはデフォルトでは画面下側にあります。
見つからない場合は『Window』→『Log Console』とクリックしてください。

また、コンソール画面は様々なチェックで用いられるため、常に開いておくようにしましょう。

ここまでの実装に問題がなければ、プレイの終了時(ESCキー入力時)にコンソール画面に画像のように”おしまい”と表示されるはずです。

画像7


これで、最初のFlowプログラミングは完了です。
次回は、いよいよ本格的なVR用のノードをご紹介します。