ユーセンブログ

ゲーム開発に関することをたまに書きます

【Unity】選択したオブジェクトを強調表示するためのアウトラインシェーダーの作成

はじめに

ゲームを製作しているときに選んでいるオブジェクトをわかりやすくするために分かりやすいアウトラインを出して強調したいという場面は割とよくあるのですが、簡単に使えて綺麗にアウトラインを表示する方法がなかなか見つからなかったので作成して見ました。 単純にアウトライン部分のみを深度を無視して描画するシェーダーなので使い方は簡単でカメラにアウトライン表示用のスクリプト、オブジェクトに今回作成するシェーダをアタッチしたマテリアルを追加するだけでこんな感じに裏に回った部分もアウトラインだけ表示される形で強調表示ができるようになります。 f:id:k_tachiban:20180917151938p:plain

実装

今回のシェーダーの実装ですが方法としてはステンシルバッファにステンシルのみ書き込んで後からポストプロセスでアウトライン部分を描画しています。アウトラインの実装はよくある裏面を法線方向に拡大して描画する手法を使っています。

オブジェクト用のシェーダー

アウトラインをつけるオブジェクト用のシェーダーコードです。 今回は2Passを使って描画をしています。

1Pass目

1Pass目ではZWrite、ZTestをオフ、アルファを0にした状態でポリゴンの裏面を法線方向に伸ばした上で描画しています。この時あとでアウトラインとして描画するためのステンシルを書き込んでおきます。

2Pass目

2Pass目でもZWrite、ZTestをオフ、アルファを0にした状態に設定し、ステンシルの番号を変えて描画処理を行います。 これで法線方向が反転しているような特殊なモデル以外はアウトライン部分が1のStencilが書き込まれた状態になります。(深度テストを行わないため法線が反転していると表示がおかしくなりがち)

全文

ポストプロセス

ポストプロセス用スクリプト

続いては、アウトラインを実際に書き込むためにスクリプトを作成します。 本来ではOnRenderImage内でBlitを使ってポストプロセス処理を行うのですが、Blitを使ってポストプロセスを使ってステンシルを利用しようとするとかきこまれたステンシルを参照できないというバグ(?)がありました。 なので、この場合はCommandBuffer経由で描画してやる必要があるようです。 (今回はこちらのサイトのものをお借りしました)

[Unity]イメージエフェクトを特定のモデルだけにかける

using UnityEngine;
using UnityEngine.Rendering;

[ExecuteInEditMode]
[RequireComponent(typeof(Camera))]
public class ImageEffect : MonoBehaviour
{
    /// <summary>
    /// コマンドバッファ名
    /// </summary>
    private const string CommandBufferName = "StencilImageEffect";

    /// <summary>
    /// イメージエフェクトで使用するマテリアル
    /// </summary>
    [SerializeField] private Material material;

    /// <summary>
    /// イメージエフェクト用コマンドバッファ
    /// </summary>
    private CommandBuffer commandBuffer;


    private void OnEnable()
    {
        if (material == null) return;
        if (commandBuffer != null) return;

        var cam = GetComponent<Camera>();
        var cbs = cam.GetCommandBuffers(CameraEvent.BeforeImageEffects);
        foreach (var cb in cbs)
        {
            // 多重登録を回避するため、名前でチェック
            if (cb.name == CommandBufferName) return;
        }

        commandBuffer = new CommandBuffer();
        commandBuffer.name = CommandBufferName;

        // Blitでmaterialを適用してイメージエフェクトをかける
        commandBuffer.Blit(
            BuiltinRenderTextureType.CameraTarget,
            BuiltinRenderTextureType.CameraTarget,
            material);

        // カメラにコマンドバッファを登録
        cam.AddCommandBuffer(CameraEvent.BeforeImageEffects, commandBuffer);
    }

    private void OnDisable()
    {
        if (commandBuffer == null) return;

        var cam = GetComponent<Camera>();
        cam.RemoveCommandBuffer(CameraEvent.BeforeImageEffects, commandBuffer);
        commandBuffer = null;
    }
}

ポストプロセス用シェーダ

ポストプロセス用のシェーダーはシンプルにステンシルが書き込まれている場所に指定したカラーを描画するだけのシンプルなものになります。

StencilOutlinePostEffect.shader

この方法のメリット、デメリット

メリット

  • アウトラインの付け外しが楽
  • 半透明なものに対しても綺麗なアウトラインが描画できる
  • 既存のマテリアルに基本的に干渉しないため応用しやすい

デメリット

  • 通常の描画に加えて2Pass+ポストプロセス1Passなのでオーバヘッドが多い
  • アウトライン部分は深度チェックを行っていないため法線が反転しているものは相性が悪い
  • 鋭角なモデルに対してはポリゴンが浮いて見える

今回のスクリプト、シェーダはGitHubに上げておきました。 便利に使ってもらえると嬉しいです。 GitHub github.com

UnityPackerge Release StencilOutline.unitypackage · TachibanaKoki/StencilOutline · GitHub

参考サイト

ToonLitOutlineとステンシルによるOutlineの違い - AIプログラムとかUnityゲーム開発について

【Unity】【シェーダ】ステンシルバッファでアウトラインを描画する - LIGHT11

【Unity】ステンシルバッファをポストエフェクトで使う方法(と謎の挙動) - LIGHT11

[Unity]イメージエフェクトを特定のモデルだけにかける

Unity謎機能まとめ

なんとなくまとめたくなったのでUnityの存在しているがなんの為につかうのかよくわからない機能をまとめてみようと思います。

こう使うと便利だよ、とかこんな謎機能あるよだとか募集します。

Animator Parameter

使い方

  • Window>Animator Parameter

Animation Parametrsをみることが出来るwindow。普通のAnimatorWindowと同じ内容が表示される。 Animator見れば問題は無い。 用途は不明。

【Unity】Animator Parameterというウィンドウ - テラシュールブログ

Extract From Prefab

使い方

  • Project ビューでマテリアルが埋め込まれているモデルを右クリック>Extract From Prefab

モデルからマテリアルを抽出する機能。 マテリアル自体はインポート時に作成されるのでマテリアルを取得する機能として使うことはなさそう。データ容量が減らせたりする?

【Unity】Project ビューを右クリックした時に表示される「Extract From Prefab」とは - コガネブログ

まとめ

みんな気づいてないけど実は良い機能あったりしないかなーとか思ったり。 他にも謎機能があれば見つけ次第追加していきます。

【Lumberyard】Script Canvas入門

Lumberyard Advent Calendar 2017 の10日目です。 今回はLumberyard1.11.0から追加されたScriptCanvasの基本的な使い方と機能の紹介をします。

ScriptCanvasについて

ScriptCanvasはLumberryard1.11から追加された目玉機能の一つで新しいビジュアルスクリプト((UE4のBPのようなスクリプト環境環境になります。 CryEngineからの流れでFlow Graphというビジュアルスクリプト環境はあったのですが今後はScriptCanvasに置き換えられていく流れになると思います。 使用感としては機能縮小版BPといった感じでした。 今回はScriptCanvasの紹介とキーの入力でオブジェクトを動かすところまでやりたいと思います。  

ScriptCanvasのエディタ基本機能

ScriptCanvasエディターの基本構成の説明です。 といっても基本構成はシンプルで、左にノードを一覧できるNode Palleteとノードをつなげたり、管理するCanvasがあるだけです。 この画面はtools>Script Canvsから開けます。

image.png

ノードの追加は左のビューからドラッグアンドドロップか右クリックから検索で行います。

追加のウィンドウ

基本構成以外の追加可能なウィンドウもあります。 追加可能なウィンドウはNode InspectorNode OutLinerの二つです。

image.png

右上のNode Inspectorはノードが設定している定数が見れるようです(今後増える?) 右下のNode OutLinerではキャンバスに配置されているノードを一覧することができる機能です。

コメント

ScriptCanvasではコメント機能もありました。 コメントの追加方法はノードと同じようにcommentを探して追加するか、右クリック時に出てくるAdd Commentで追加できます。 使用感としてはキャンバスに置けるメモといった感じでサイズの変更もできずUE4のようにグループ化するために使うといったことはできなさそうです。 f:id:k_tachiban:20171203201702p:plain

ScriptCanvasの作成

Script Canvasを作成するには

  • Tools>Script CanvasまたはEntiityのScriptCanvasからScript Canvasのウィンドウを開く
  • File>New Scriptで作成
  • Ctrl+SまたはFile>Saveで名前を付けて保存 成功すると.scariptcanvasファイルが作成されます。

ユーザーからの入力を取得する

それではいよいよScriptCanvasの記述方法についてです。 まずはユーザーからの入力を受け取るスクリプトから書いていきます。

Input Bindingの作成

Script Canvasで入力を行うためにはまず初めに.inputBindingsを作成する必要があります。 手順は以下の通りです。

  • Tools>Input EditorでInput Binding Editorを開く
  • File>Create New Asset>Input to Event Bindings Assetで.inputbindingsを作成
  • Input Event Groupsの横の+ボタンを押す
  • 作成されたUnspecified EventにEvent Nameを入力
  • 作成したイベントのEvent Generatorsの+をクリック
  • Input Device TypeとInput Nameをイベントに合わせて入力
  • 以降Input Eventに必要な数のイベントを作成する
  • 入力が終わったらSave&Closeで保存

WASDでのキー入力をこんな感じで登録しました。

image.png

これでScriptCanvasでキーの入力がイベント名で取れるようになります。

入力を取得する

それでは作成したInput Bindingを使ってキーの入力を取得します。 Inputの取得にはInput Handlerノードを使用します。

 image.png

Event Nameのところに先ほど作成したInput Bindingのイベント名を入力してその入力時にログを出します。 ログを出すにはUtilities>Debug下のLogノードとVariables>CreateVariablesのStringからStringのVariableノードを作成することで実現できます。

image.png

出力を確認する

出力を確認するためにEntityに作成したScriptCanvasをAddします。 今回は入力をするためScrpit Canvas ComponentのほかにInput Componentの追加します。

image.png

そのあとCtrl+Gでゲームを実行。 登録したDを押したら無事Consoleにログが出ました。

image.png

オブジェクトの移動操作

ユーザーからの入力が取れたところでオブジェクトを移動させてみます。 オブジェクトの移動はMoveEntityノードで行えます。

image.png

キーの入力に合わせてこんな感じで作成。

キャプチャ.PNG

f:id:k_tachiban:20171203195120g:plain

これで動くようになりましたがノードが少々汚いのでもう少し改善します。 具体的にはInputBindingを編集して、S(Down)、A(Left)を押したときに-1が帰るように変更し、ノードを減らします。

f:id:k_tachiban:20171203200044p:plain

イベントをmove_X、move_Yの二つに減らしてS、Aの入力時のEvent value multiplierの値を-1.0にしています。 こうすることでノードがすっきりしました。

f:id:k_tachiban:20171203200404p:plain

まとめ

現時点でのScript Canvasを簡単に使ってみた感触ですが機能も少なく、シンプルなビジュアルスクリプティングといえると思いました。 UE4のブループリントのようにがっつり作るのには向いていませんがシンプルな機能の実装や、短期間での高速な開発には向いているようにかんじました。 シンプルなものにはScript Canvas、複雑なものにはC++luaを使うといった住み分けができるので状況に合わせて何を使ってスクリプティングするのか選択して使うのがよさそうです。

参考

Getting Started with Script Canvas - Lumberyard

Script Canvas Tutorials - Lumberyard

script canvas - Game Dev Forum

【Lumberyard】箱に物理を導入する

Lumberyardアドカレの6日目です。 Lumberyardで箱を出して物理を導入するだけの簡単な記事です。 使用したエンジンは1.11.1です。

Lumberyardで箱を出す

Lumberyardで単純な箱などのオブジェクトをを出すのはちょっとわかりにくいので紹介します。 LumberyardではUnityやUE4のように箱やカプセルなどの単純なオブジェクトをEntityの作成時に作れません。 しかし、単純なメッシュ自体はデフォルトで存在しているのでそれをアサインしてやれば使えるようになります。 手順は以下の通りです。

  • エンティティを作成
  • MeshをAdd Component
  • MeshのMesh Assetの「…」をクリックしてGame/Objects/Primitives/Box1x1.cgfを選択

f:id:k_tachiban:20171205222847p:plain

箱が表示されるようになりました!

primitivesには箱以外にもいくつかあるのでそれらをアサインすればとりあえず表示するオブジェクトには困らずに済みます。

面白いところだと「egg_001.cgf」「egg_proxy_001.cgf」なるモデルがありました。

f:id:k_tachiban:20171205223217p:plain
マジタマゴ

箱に物理をつける

作成した箱が物理挙動をするように設定するやり方です。 なんとなくで結構進む気がしたんですがそんなことはなく。 作成した箱のエンティティに以下の操作をしてください。

  • RigidBodyPhysics をAdd Component
  • Mesh ColliderをAdd Component
    • この時、~Shapeとprimitive colliderを代わりにAddすることでシンプルなコリジョンで動かせるようになります・
  • (1.10以前)RigidBodyPhysicsの「at rest initially」のチェックを外す。

f:id:k_tachiban:20171205230908g:plain

物理で動いた!

はまりポイント

オブジェクトの表示から物理を入れるまでは比較的簡単にいくのですが一部のモデルはMeshColliderをつけて物理を効かせようとすると動きません。

Primitivesの中だとproxyと書かれているものセットのモデルはproxyと書かれているモデル以外は動かなくなります。

どうしても動かしたい場合はShape系とprimitive colliderでシンプルに動かす必要があります。

あと、検証はしてませんが自前のモデルもMesh Colliderを使いたい場合はMaya、blenderの専用プラグイン通さないとダメな気がします。

まとめ

Lumberyardで物理をやる場合、UnityやUE4と比較して若干制約があるっぽいので何も見ずやったら案外はまりました。 今回の記事がにぎやかしくらいにはなればと思います。

【Unity】Compute Shaderでグローバルなテクスチャを使う方法

 UnityのCompute ShaderでGbufferをどうにか頑張ってRenderTextureに変換して使っていたのですが、もっと簡単に扱えることにあとで気がつきました。

 自分と似たような状態の人がいないとも限らないのでちょっと記事にしてみようかと思います。

概要

 _CameraGBufferTexture0などのグローバルなテクスチャをCompute Shaderで使いたい場合は

cs.SetTextureFromGlobal(index, "Albedo", "_CameraGBufferTexture0");

のようにCompute ShaderのインスタンスSetTextureFromGlobal関数を使ってセットすることでCompute Shaderで扱えるようになります。

今回の話はこれで終わりです。

説明

UnityではデフォルトではForwardに設定されているのですが設定を変更することでDeferredレンダリングに変更することができます。

Defferdレンダリングに設定すると

  • _CameraGBufferTexture0
  • _CameraGBufferTexture1
  • _CameraGBufferTexture2
  • _CameraGBufferTexture3
  • _CameraDepthTexture

などのGBuffer及びBufferがグローバルで定義されています。

通常のシェーダーでは_CameraGBufferTexture0などをsampler2Dとして定義することで使用することができるのですが、Compute Shaderでは使用することができませんでした。

これらのグローバルなテクスチャをCompute Shaderで扱う場合、Compute Shaderクラスのインスタンスから先述のSetTextureFromGlobal関数を呼び出して引数にカーネルのインデックスCompute Shaderで定義されているTextureSampler2Dの名前グローバルなテクスチャの名前をそれぞれ渡すことでCompute Shaderでもグローバルなテクスチャを扱うことができるようになります。

【Unity】Google Spreadsheetsでリアルタイムにパラメーター調整する話

初めに

まず、チームでゲームを制作する際、一つ問題になるのがゲームのバランス調整をどのように行うのかということです。

基本的にチームのプランナーが行うと思うのですが、例えばデータをエクセルに書いてプログラマーに渡すといったやり方はデータの受け渡しやデータの差し替えなどが非常に大きなコストになります。

UnityやUE4などのゲームエンジンを使って直接調整していたり、gitなどを使ってデータを管理している場合もビルドやそもそもツールを起動するなど手間がかかります。

なのでそれらの反映をできる限り簡単したいということで、GoogleのSpreadsheetsとGoogle Action Script(以下GAS)を使ってリアルタイムに実機で調整できるようにします。

f:id:k_tachiban:20171114213026g:plain
今回は起動時のみ取って来るようにしていますが更新ボタンを用意したり定期的に取得するようにしたりもっと使いやすくすることは十分可能です。

Google Spreadsheetsとは

ざっくり言ってしまうとGoogleが提供しているブラウザ版のExcelです。

  • 複数人での同時編集が可能
  • 共有が楽ちん
  • 通信で取得することが可能   大体この辺が特徴でしょうか。

ここで提供されているGASというAPIを活用することでデータを取得したり逆にデータを書き込むといったことも可能です。(超便利!)

実際にGoogle SpreadSheetのデータを取れるようにする

  1. スプレッドシートを作成する
  2. ツールからスクリプトエディタを開く
function test() {
Logger.log(SpreadsheetApp.getActiveSpreadsheet().getId());
}
  1. ↑の処理を走らせてスプレッドシートのログからID取得*1

  2. 上の処理を消して本番の処理を書く

function doGet(e) {
  var sheetName = e.parameter.sheetName;
  var sheet = SpreadsheetApp.openById('調べたID');  
  if (sheet.getSheets().some(function(s) {
    return s.getSheetName() === sheetName;
  })) {

    var ss = sheet.getSheetByName(sheetName);
   //シートに書かれている情報をすべてJSONにして投げる
   var json = ss.getDataRange().getValues();
    return ContentService
      .createTextOutput(JSON.stringify(json))
      .setMimeType(ContentService.MimeType.JSON);
  }
}
  1. これを新たに書き込んだら公開→webアプリケーションとして導入
  2. アプリケーションにアクセスできるユーザーを全員(匿名ユーザーを含む)に設定して公開

これでスプレッドシートの情報が取れるようになりました。

Unity上でデータを扱う

Unity上でデータを取得するにはWWWかUnityWebRequestを使ってデータを取得し、その取得したデータをJSONからクラスなどにパースして扱います。

この際、やり方はとてもたくさんあるのですが今回はUnityWebRequestとminiJSONを使っています。

このやり方はお手軽かついろいろなバージョンで動くのですが処理的にはかなり無駄が多いのでもし調整以外の目的で使う場合はUnityWebRequestやJSONUtilityなどを使ったり取得するデータの範囲をきちんと指定するなどして最適化してください。

using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using MiniJSON;

public class SpreadsheetsManager : MonoBehaviour
{
    //ダウンロードしたデータを格納する。
    [SerializeField]
    List<Character> downloadData = new List<Character>();

    private IEnumerator LoadGoogleSpreadSheet(string _sheetName)
    {
        string URL = "https://script.google.com/macros/s/AKfycbyj8ZQoHjnnxii_KH2Wj1NmNRdMn0mRNAgfSXYqhQHb5UtiAmY/exec";
        var download = UnityEngine.Networking.UnityWebRequest.Get(URL + "?sheetName=" + _sheetName);
        
        yield return download.SendWebRequest();

        //JSONの読み込みにはminiJSONを使用
        var json = (List<object>)Json.Deserialize(download.downloadHandler.text);
        if (json != null)
        {
            //先頭一行目は無視、本来は無視しないようにデータを送るべき
            for (int i = 1; i < json.Count; i++)
            {
                var tex = (List<object>)json[i];
                string[] str = tex.Select(n => n.ToString()).ToArray();

                Character chara = downloadData[i - 1];
                //先頭一列目は無視
                chara.charaID = str[1];
                chara.charaName = str[2];
                chara.hp = int.Parse(str[3]);
                chara.Attack = int.Parse(str[4]);
            }

        }
        else
        {
            Debug.LogError(download.downloadHandler.text);
        }

        for(int i=0;i< downloadData.Count;i++)
        {
            downloadData[i].ReflectState();
        }
    }

    void Start ()
    {
        StartCoroutine(LoadGoogleSpreadSheet("Sheet1"));
    }
}

とりあえずの例としては

  1. UnityWebRequestからjsonのデータを取得
  2. 取得したjsonを何らかの形でパース(今回はminiJSON)
  3. ゲームに使用する

大体このような流れになるかと思います。 データの扱い方はゲームによってさまざまだと思うのでそこらへんは各自応用してみてください。

参考

Google Spreadsheetに書いたシナリオをUnityのScriptableObjectにする - Qiita

Google Apps Script で spreadsheet のデータを JSON として読み込む - プログラマってこんなかんじ??

*1:ログは表示タブから開けます。

【Lumberyard】Script Canvas Tutorials(Opening and Closing a Door with Trigger Areas and Variables)邦訳

前回の続きです。

tachis.hatenablog.com

 トリガーエリアと変数でドアを開閉する

このチュートリアルは、「スクリプトキャンバスチュートリアル:制御可能なエンティティの作成」で学んだことを基にしています。 次のチュートリアルでは、制御可能な球体がトリガー領域に入ったり出たりすると開閉するドアを作成します。 これを行うには、次のようにします。

  • トリガー領域を作成する
  • イベントノードを追加する
  • 変数を追加する

始める前に、スクリプトキャンバスチュートリアル:制御可能なエンティティの作成を完了する必要があります。

 

ステップ1:ドアとトリガーエリアを作成する

ドアとトリガー領域を作成するには、子エンティティを持つエンティティを作成し、子エンティティにコンポーネントを追加します。

ドアとトリガーエリアを作成するには
  1. Lumberyard Editorで、コントロール可能な球の近くのPerspectiveビューポートを右クリックし、Create entityを選択してエンティティを作成します。

  2. エンティティインスペクタで、名前に「Door Group」と入力します。

  3. ドアを作成するには、次の手順を実行します。

    1. エンティティアウトライナで、[Door Group]を右クリックし、[子エンティティの作成]を選択します。この子エンティティはあなたのドアです。

    2. エンティティインスペクタの「名前」に「Door Mesh」と入力します。

    3. Asset Browserで、Game \ Objects \ Primitivesに移動します。

    4. ビューポートでドアメッシュエンティティを選択した状態で、box_1x1.cgfをアセットブラウザからエンティティインスペクタにドラッグしてメッシュコンポーネントを作成します。

    5. 「エンティティ」インスペクタで、「コンポーネントの追加」をクリックします。 物理の下で、静的物理をクリックします。 これにより、Static PhysicsコンポーネントがDoor Meshエンティティに追加されます。

    6. コンポーネントの追加をもう一度クリックします。 Physicsの下で、Mesh Colliderをクリックします。 このコンポーネントは、Door Meshエンティティの衝突シェイプを定義します。

    7. エンティティインスペクタのTransform、ScaleでXを2.5、Yを0.5、Zを4.0に設定します。

  4. トリガ領域を作成するには、次の手順を実行します。

    1. エンティティアウトライナで、[Door Group]を右クリックし、[子エンティティの作成]を選択します。この子エンティティはトリガー領域です。

    2. エンティティインスペクタで、名前に「Door Trigger」と入力します。

    3. コンポーネントの追加をクリックします。 [スクリプト]の下の[Trigger Area]をクリックします。

    4. [Trigger Area]で、[必須コンポーネントの追加]をクリックします。図形の下のボックス図形をクリックします。

    5. Box Shapeの下で、DimensionsでXを3.0に、Yを9.0に、Zを6.0に設定します。

    6. コンポーネントの追加をもう一度クリックします。 [スクリプト]の[スクリプトキャンバス]をクリックします。

    7. Lumberyard Editorで、Tools、Script Canvasを選択します。

    8. スクリプトキャンバスエディタで、「ファイル」、「新規スクリプト」を選択します。

    9. 新しいキャンバスが読み込まれたら、[ファイル]、[名前を付けて保存]を選択します。

    10. [ファイル名]に「door」と入力し、[保存]をクリックします。保存したファイルのディレクトリパスをメモしてください。これは後で必要になります。

    11. ランバーヤードエディタのエンティティインスペクタのスクリプトキャンバスで、参照(...)アイコンをクリックし、door.scriptcanvasfileに移動します。 door.scriptcanvasを選択し、[OK]をクリックします。

ステップ2:ドアを開閉するためのスクリプトを作成する

ドアとトリガエリアを設定したら、別のエンティティがトリガエリアに出入りするときにドアを開閉するスクリプトを作成できます。

ドアを開閉するスクリプトを作成するには
  1. スクリプトキャンバスエディタで、door.scriptcanvasファイルがまだ開いていない場合は、ステップ1:ドアとトリガ領域を作成して開きます。

  2. ノードパレットで、検索ボックスに「Vector3」と入力します。

  3. 変数、変数の作成で、ノードパレットからVector3をキャンバスにドラッグします。変数を使用して、スクリプト内の永続的な値を格納および変更できます。

  4. #Variable 1ノードで、次の操作を行います。

    1. 表示名に「opened_position」と入力します。

    2. デフォルト値の場合、Zを2に設定します。z軸の正の値は、ドアをスライドさせます。ドアエンティティはドアグループの子であるため、ローカル相対位置を使用してドアの開閉位置を制御できます。

  5. ノードパレットから別のVector3をキャンバスにドラッグします。

  6. #Variable 2ノードのDisplay Nameに「closed_position」と入力します。閉じた位置はデフォルト値の0,0,0を使用できます。

  7. ノードパレットから別のVector3をキャンバスにドラッグします。

  8. #Variable 3ノードのDisplay Nameに「destination_position」と入力します。この変数は、エンティティがトリガ領域に出入りするときにドアの目的地位置を設定します。

  9. ノードパレットで、検索ボックスに「trigger」と入力します。

  10. 「ゲームプレイ」の「トリガーエリア」で、「ノードパレット」から「入力エリア」をキャンバスにドラッグします。このイベントノードを使用すると、Lumberyard EBusメッセージングシステムを簡単に使用できます。

  11. [トリガーエリア]ノードで、[イベントの追加と削除]をクリックし、[エリア終了時にオン]チェックボックスをオンにします。トリガーエリアEBusからの入力イベントと終了イベントを公開します。

  12. ノードパレットで、検索ボックスにpositionと入力します。

  13. Node Paletteから2つの#destination_positionノードをキャンバスにドラッグします。変数を作成した後、ノードパレットでGetおよびSetノードを使用できます。これらのノードを使用すると、動的変数値を扱うことができます。コア変数ノードは変数を初期化します。

  14. キャンバスで、以下の接続を行います:

    1. On Area EnteredのOutピンを選択し、ドラッグしてSet#destination_positionノードのInピンに接続します。

    2. On Area ExitedのOutピンを選択し、それをドラッグして他のSet#destination_positionノードのInピンに接続します。

    3. #opened_positionのGetピンを選択し、それをドラッグして、On Area Enteredに接続されているSet#destination_positionノードのVector 3ピンに接続します。

    4. #closed_positionのGetピンを選択し、それをドラッグしてOn Area Exitedに接続されているSet#destination_positionノードのVector 3ピンに接続します。

    5. スクリプトが次のイメージのようになっていることを確認します。

  15. Door Meshエンティティの位置を取得し、目的地に補間するには、次の操作を行います。

    1. ノードパレットで、検索ボックスに「get local」と入力します。

    2. ノードパレットからローカル変換をキャンバスにドラッグします。このノードを使用して、Door Meshentityの現在の位置を取得し、宛先に補間することができます。現地通訳は、その親に対するエンティティの翻訳に適用されます。

    3. [ローカル変換を取得]ノードで、[ソース]テキストボックスで一時停止し、ターゲットボタンをクリックします。選択すると、ターゲットボタンの輪郭はオレンジ色になります。

    4. Entity Outlinerで、Door Meshを選択して、Door MeshエンティティをGet Local TranslationノードのSourceプロパティに割り当てます。

      注意

      エンティティ参照をリセットするには、[ソース]テキストボックスを右クリックし、[Set to Self]を選択します。

    5. スクリプトキャンバスエディタで、以下の接続を行います。

      1. Set #destination_positionノードのOutピンを選択し、それをドラッグしてGet Local TranslationのInピンに接続します。

      2. 他のSet#destination_positionノードのOutピンを選択し、それをドラッグしてGet Local TranslationのInピンに接続します。

        複数の接続が1つの論理ピンに入ると、いずれかの実行がトリガされるたびにノードが実行されます。複数の実行が同時にトリガーされた場合、ノードは同じゲームティックで複数回実行されます。

  16. 指定した時間(秒)でノードを実行するには、次の操作を行います。

    1. ノードパレットで、検索ボックスにdurationと入力します。

    2. ノードパレットから長さをキャンバスにドラッグします。

    3. Get Local TranslationのOutピンを選択し、ドラッグしてDurationのStartピンに接続します。 Durationノードをトリガーすると時間がリセットされます。

    4. 期間ノードで、期間に1.0(秒)を入力します。

  17. 現在の位置と目的地の間の補間を設定するには、以下を実行します。

    1. ノードパレットで、検索ボックスに「lerp」と入力します。

    2. 数学、Vector3の下で、ノードパレットからLerpをキャンバスにドラッグします。このノードは、Percentageプロパティに基づいて2つの値をブレンドします。

    3. S持続時間のOutピンを選択し、ドラッグしてLerpのInピンに接続します。

    4. 期間のElapsedピンを選択し、ドラッグしてLerpのPercentageピンに接続します。

    5. Get Local TranslationのTranslationピンを選択し、ドラッグしてLerpのStartピンに接続します。

    6. ノードパレットで、検索ボックスにdestinationを入力します。

    7. ノードパレットから#destination_positionをキャンバスにドラッグします。

    8. Get_destination_positionのVector 3ピンを選択し、ドラッグしてLerpのEndピンに接続します。

    9. スクリプトが次のイメージのようになっていることを確認します。

  18. Durationノードが現在の位置と目的地の位置の間でブレンドされているときに、ドアの位置を設定するには、次の操作を行います。

    1. ノードパレットで、検索ボックスに「set local translation」と入力します。

    2. ノードパレットからSet Local Translationをキャンバスにドラッグします。

    3. LerpのOutピンを選択し、それをドラッグして、Set Local TranslationのInピンに接続します。

    4. LerpのVector 3ピンを選択してドラッグし、Set Local TranslationのTranslationピンに接続します。

    5. [Set Local Translation]ノードで、[Source]テキストボックスで一時停止し、ターゲットボタンをクリックします。選択すると、ターゲットボタンの輪郭はオレンジ色になります。

    6. Entity Outlinerで、Door Meshを選択して、Set Local TranslationノードのSourceプロパティにDoor Meshエンティティを割り当てます。

  19. スクリプトが次のイメージのようになっていることを確認します。

  20. スクリプトキャンバスエディタで、ファイル、保存を選択します。 Ctrl + Sを押すこともできます。

  21. ランバーヤードエディタで、Ctrl + Gキーを押してゲームモードに入り、スクリプトをテストします。

  22. 球をドアトリガーエリアに移動してドアをスライドさせて開くには、W、A、Dキーを押します。

  23. トリガーエリアの外に球を移動してドアを閉じてスライドさせるには、Sキーを押します。

  24. スクリプトのテストが終了したら、Escキーを押します。