ユーセンブログ

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

【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キーを押します。

【Lumberyard】Script Canvas Tutorials(Creating a Controllable Entity)邦訳

LumberyardのScriptCanvasに関するドキュメントを自分用に邦訳しました。

Google翻訳に突っ込んだだけの雑翻訳です。

日本語化されるまでの短い命

コントロール可能なエンティティの作成
このチュートリアルでは、キーボード入力で制御できる単純な球を作成する手順を説明します。ノードの基本、入力、移動、およびロギングに加えて、以下の重要な概念を学びます。

  •  ノードの追加
  •  実行とデータ接続の作成 
  • イベントノードの追加 
  • アクションノードの追加

f:id:k_tachiban:20171117121443g:plain

Step 1:レベルを作成する

キーボード入力で制御できる球を作成する前に、レベルを作成する必要があります。

レベルを作成するには

  1. Lumberyard Editorで、File、Newを選択します。
  2. [新しいレベル]ダイアログボックスでfirstscriptcanvasと入力し、[OK]をクリックします。
  3. [地形のテクスチャを生成]ダイアログボックスで512x512を選択し、[OK]をクリックします。

Step 2:エンティティを作成し、コンポーネントを追加して制御可能なエンティティを作成する

キーボード入力で制御できる球を作成するには、エンティティを作成し、メッシュ、リジッドボディフィジックス、メッシュコライダー、および入力コンポーネントを追加します。また、WASDキーボード入力をx方向とy方向の動きに変換する入力マッピングを作成します。

制御可能なエンティティを作成するには

1. Perspectiveビューポートの任意の場所を右クリックし、Create entityを選択してエンティティを作成します。

2. エンティティインスペクタで、次の操作を行います。

    a. [名前]に「Player」と入力します。

f:id:k_tachiban:20171117122659p:plain

    b. コンポーネントの追加をクリックします。

    c.「レンダリング」で、「メッシュ」を選択します。

    d. Meshの下で、Meshアセットの場合は、参照(...)ボタンをクリックし、\ Game \ Objects \ defaultディレクトリに移動します。 primitive_sphere.cgfを選択し、「OK」をクリックします。

f:id:k_tachiban:20171117122707p:plain



3. ビューポートで、移動ツールを使用してz軸を選択し、エンティティを地面から移動します。

4. 「エンティティ」インスペクタで、「コンポーネントの追加」をクリックします。物理の下で、剛体物理をクリックします。

5. コンポーネントの追加をもう一度クリックします。 Physicsの下で、Mesh Colliderをクリックします。

6. コンポーネントの追加をもう一度クリックします。ゲームプレイで、入力を選択します。

7. エンティティインスペクタの[入力]で、[入力バインディングエディタ]アイコンをクリックします。


8. 入力バインディング・エディタで、「ファイル」→「新規資産の作成」→「Input to Event Bindings Asset」を選択します。 [ファイル名]にplayerと入力し、[保存]をクリックします。

9. アセットブラウザで、player.inputbindingsファイルに移動します。ファイルを右クリックし、[開く]を選択します。

10. [アセットの編集]ウィンドウで、次の操作を行います。

    a. 入力イベントグループでは、+をクリックして新しい入力イベントグループを追加します。

    b. 入力イベント・グループを展開します。イベント名にmove_xと入力します。

    c. イベントジェネレータの場合は、+をクリックしてイベントジェネレータを追加します。

    d. [作成するクラス]ダイアログボックスで、[OK]をクリックして入力クラスを追加します。

    e. move_x、イベントジェネレータ、gamepad_button_aに移動します。入力デバイスタイプでは、キーボードを選択します。

    f. 入力名にkeyboard_key_alphanumeric_Aを選択します。

    g. イベント値の乗数に-1を入力します。

    h. 手順C〜Eを繰り返します。次に、入力名としてkeyboard_key_alphanumeric_Dを選択します。イベント値乗数の場合は、デフォルト値の1を使用します。

    i. 次の図のように設定が表示されていることを確認します。


11. [アセットの編集]ウィンドウで、次の操作を行います。

    a. 入力イベントグループでは、+をクリックして新しい入力イベントグループを追加します。

    b. 入力イベント・グループを展開します。イベント名に「move_y」と入力します。

    c. イベントジェネレータの場合は、+をクリックしてイベントジェネレータを追加します。

    d. [作成するクラス]ダイアログボックスで、[OK]をクリックして入力クラスを追加します。

    e. move_y、イベントジェネレータ、gamepad_button_aに移動します。入力デバイスタイプでは、キーボードを選択します。

   f. 入力名として、keyboard_key_alphanumeric_Wを選択します。イベント値乗数の場合は、デフォルト値の1を使用します。

   g. 手順C〜Eを繰り返します。次に、入力名としてkeyboard_key_alphanumeric_Sを選択します。イベント値の乗数に-1を入力します。

   h. 次の図のように設定が表示されていることを確認します。


i. [保存して閉じる]をクリックします。

12. エンティティインスペクタの[入力]で、参照(...)ボタンをクリックし、player.inputbindingsファイルに移動します。 player.inputbindingsを選択し、[OK]をクリックします。

 

ステップ3:スクリプトキャンバスを使用して入力スクリプトを作成する

フィジカルと入力マッピングで球を設定したので、Script Canvasを使用して最初のスクリプトを作成できます。

入力スクリプトを作成するには
  1. Lumberyard Editorで、Tools、Script Canvasを選択します。
  2. スクリプトキャンバスエディタで、「ファイル」、「新規スクリプト」を選択します。
  3. 新しいキャンバスが読み込まれたら、[ファイル]、[名前を付けて保存]を選択します。
  4. [名前を付けて保存]ダイアログボックスの[ファイル名]にplayer.scriptcanvasと入力し、[保存]をクリックします。
  5. ノードパレットで、検索ボックスにinputと入力します。*1
  6. 入力パレットをノードパレットからキャンバスにドラッグします。入力ハンドラはイベントノードです。イベントが発生すると、イベントノードはスクリプトにメッセージを送信します。
  7. イベント名に「move_y」と入力します。これは、ノードに入力イベントをリッスンするように指示します。

    f:id:k_tachiban:20171117123738p:plain

  8. ノードパレットで、検索ボックスに「log」と入力します。
  9. ログをノードパレットからキャンバスにドラッグします。ログはアクションノードです。アクションノードを実行すると、データの要求、データの設定、データの操作、トリガなどのアクションが完了します。アクションノードはエディタコンソールにデータを出力し、スクリプトの実行中に値を確認することもできます。
  10. Input Handlerの保持ピン(白い矢印)を選択し、ドラッグしてLogのInピンに接続します。この接続は、入力ハンドラが保持されたイベントを受け取った後に実行するLogノードを指示します。*2
  11. Input HandlerのValueピン(黄色の円)を選択し、ドラッグしてLogのValueピンに接続します。この接続は、入力ハンドラノードから入力ハンドラからの入力イベント値をLogノードの最初の引数に渡すように指示します。*3
  12. スクリプトが次のイメージのようになっていることを確認します。

 

Step4:エンティティにスクリプトを割り当ててスクリプトをテストする

作成したスクリプトは、入力イベントの値を出力します。これで、エンティティにスクリプトを割り当て、スクリプトをテストできます。

スクリプトを割り当ててテストするには

  1. スクリプトキャンバスエディタで、ファイル、保存を選択します。 Ctrl + Sを押すこともできます。
  2. Lumberyard Editorで、手順2:エンティティの作成およびコンポーネントの追加で作成したエンティティを選択して、制御可能なエンティティを作成します。
  3. 「エンティティ」インスペクタで、「コンポーネントの追加」をクリックします。
  4. [スクリプト]の[スクリプトキャンバス]を選択します。
  5. スクリプトキャンバスで、参照(...)ボタンをクリックし、player.scriptcanvasファイルに移動します。 player.scriptcanvasを選択し、[OK]をクリックします。
  6. Ctrl + Gを押してゲームモードに入ります。
  7. 入力イベントをトリガーするには、Wを押してからSを押します。ランバーヤードエディターのコンソールペインでは、move_yイベントがトリガーされたときに入力イベントの値が出力されます。この場合、コンソールペインはWを押して1を出力し、Sを押すと-1を出力します。
  8. スクリプトのテストが終了したら、Escキーを押します。

ステップ5:あなたの球を動かすためのスクリプトを作成する

最初のスクリプトが正常に作成されたので、スクリプトにノードを追加して球を移動することができます。また、入力イベント値を変更して移動速度を制御します。

球を動かすには
  1. スクリプトキャンバスエディタのノードパレットで、検索ボックスに「multiply」と入力します。
  2. Node PaletteからキャンバスにMultiplyをドラッグします。
  3. Input HandlerのHeldピンを選択し、ドラッグしてMultiplyのInピンに接続します。この接続は、入力ハンドラが保持イベントを受け取った後に乗算ノードを実行します。
  4. 入力ハンドラのValueピンを選択し、それをドラッグしてMultiplyのArg1ピンに接続します。
  5. Multiplyノードで、Arg2に0.1と入力します。入力イベントのこの小さな値は、移動速度を抑制します。
  6. ノードパレットで、検索ボックスに「move」と入力します。
  7. エンティティをノードパレットからキャンバスにドラッグしてドラッグします。
  8. ノードパレットで、検索ボックスに「vector 3」と入力します。
  9. ノードパレットからキャンバスに値からコンストラクタをドラッグします。このノードを使用して、番号からvector 3を構築します。
  10. MultiplyのOutピンを選択し、ドラッグして値から構築するInピンに接続します。
  11. MultiplyのResultピンを選択し、ドラッグして値から構築するためにYピンに接続します。 y方向のみが必要なので、XとZにはデフォルト値(0)を使用します。
  12. 「値から構築」のOutピンを選択し、ドラッグしてMove EntityのInピンに接続します。
  13. 値から構成するためのvector 3ピンを選択し、ドラッグして移動エンティティの方向ピンに接続します。
  14. スクリプトが次のイメージのようになっていることを確認します。

    f:id:k_tachiban:20171117124407p:plain

  15. [ファイル] - [保存]を選択します。 Ctrl + Sを押すこともできます。
  16. ランバーヤードエディタで、Ctrl + Gキーを押してゲームモードに入り、スクリプトをテストします。
  17. 球を前方に移動するには、Wを押します。球を後方に移動するには、Sを押します。
  18. スクリプトのテストが終了したら、Escキーを押します。

ステップ6:あなたの球のX軸に動きを加える

エンティティをy軸に移動する方向に入力イベント値を変換したので、x軸に移動を追加できます。

x軸に動きを加えるには
  1. スクリプトキャンバスエディタでキャンバスをドラッグして、入力ハンドラ、掛け算、値から構築、およびエンティティノードの移動を選択します。選択したノードの周りにオレンジ色のアウトラインが表示されます。
  2. Ctrl + Cを押して、選択したノードをコピーします。
  3. Ctrl + Vを押して、コピーしたノードとその接続を貼り付けます。これにより、既存のスクリプトを複製して、x軸上の移動に適した設定で複製されたバージョンを変更することができます。
  4. 選択したまま、コピーされたノードと重ならないようにノードを移動します。

     

  5. 重複する入力ハンドラノードで、イベント名に「move_x」と入力します。
  6. Duplicate MultiplyノードのResultピンとDuplicate Valuesノードの重複するYピンを結ぶ黄色の線を探します。値から構築ノードのYピンの近くの接続をクリックし、Xピンに移動します。*4
  7. スクリプトが次のイメージのようになっていることを確認します。
  8. [ファイル] - [保存]を選択します。 Ctrl + Sを押すこともできます。
  9. ランバーヤードエディタで、Ctrl + Gキーを押してゲームモードに入り、スクリプトをテストします。
  10. 以下をせよ:
  1. 球体を前方に移動するには、Wキーを押します。
  2. 球体を後ろに移動するには、Sキーを押します。
  3. 球を左右に動かすには、AとDを押します。

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

 

*1:また、キャンバスの空の領域を右クリックして、ノードのリストにアクセスすることもできます。

*2:ノードの実行は、常にノードの左側から右側に向かって行われます。詳細については、「ピンと接続」を参照してください。

*3:データは常にノードの左側に入力され、ノードの右側から出力されます。詳細については、「ピンと接続」を参照してください。

*4:接続を切断するには、接続をキャンバスの空の部分にドラッグします。接続を削除するには、Altキーを押しながら接続をクリックします。

Slackの/feedでUnityまとめの投稿を超簡単に通知する

Unityの最新の情報を集めたいときにいちいちネットサーフィンとかtwitterとかで情報探すのめんどくさいなーSlackさん教えてくれないかなーと思って探してみたらか簡単にできる方法があったので紹介です。

今回はSlackのスラッシュコマンド機能の/feedという機能を使います。

 

f:id:k_tachiban:20171113222717p:plain

使いたいchannelに  

 /feed https://unity-matome.com/feed

と書いてEnter押して終わり
これで新しい投稿があってから20分程度でSlackにリンクが投稿されます。便利。

説明

/feed コマンドはRSSAtomのリンクを登録することでwebサイトの最新の投稿を所得して投稿する機能です。

/feed [RSSのURL]

で登録し

 /feed remove [IDナンバー]

で削除できます。

IDナンバーは登録した後

/feed list

で取得できます。

ちなみに、わからなくなったら

 /feed help

 でこれらの使い方が見れます。

 

おまけ

自分が使っている便利なRSSリンクです。

「Unityまとめ」

https://unity-matome.com/feed

「UnityのタグがつけられたQiitaの投稿」

http://qiita.com/tags/Unity/feed

UE4のタグがつけられたQiitaの投稿」

http://qiita.com/tags/UE4/feed

「東京周辺のゲームが含まれるイベントの情報」

http://api.atnd.org/events/?keyword_or=ゲーム,game&keyword=東京&format=atom

 

QiitaやATNDのリンクにあるUnityやらゲームやらの名前を変えれば好きなタグやキーワードで投稿を監視できます。

RSSのリンクはサイトごとに取り方がいろいろあるので探してみてください。

例えばGoogleアラートというものを使えばGoogleで検索して出るサイトを監視することもできます。

参考

スラッシュコマンド – Slack

Slack に RSS フィードを追加する – Slack

GoogleアラートをRSSフィードで受信する | Googleアラートの使い方 | ぼくらのハウツーノート

 

 

 

【Unity】UNETを本格的に導入する前に知っておいたほうが良かったこと

お久しぶりの記事です。

今回はUnityの5.1から実装されたUnityのネットワーク機能「UNET」を実装する上で予め知っておいたほうが良かったと思ったことや、結局調べるはめになるであろうことを書いていこうと思います。

 

とはいえ基本的な部分はこちらの記事を読んだほうが早いです。

 

【Unity9】UNETでマルチプレイヤーなオンラインゲーム開発【UNET1】 - Unity5(C#)初心者・入門者向けチュートリアル ひよこのたまご

25回にわたって書かれているので導入としてとても良かったです。

Unity 5.1 から導入された新しいネットワーク機能の UNET について詳しく調べてみた - 凹みTips

こちらではUNETについて詳しく解説されています。

 

あと細かい仕様とかはここ

Unity - マニュアル: ネットワーキング リファレンス

 

 オープンソースを使う

さて、まずははじめに把握しておくべきだと思うことは、UNETはまだ未完成であるということです。

なのでこの段階で本格的に導入すると割りとめんどくさい事になります。

(そして圧倒的にUNETの日本語の記事は少なかった…)

なので、UNETをそのまま使わず基本的に中身はいじれるようにしておいたほうが吉です。

UNETはこちらのリポジトリオープンソースとして公開されているのでそれを改造しながら使うべき。

Unity-Technologies / Networking / source / — Bitbucket

 

エラーに注意

そしてもう一つめんどくさいのがサンプルなどでよく出てくるNetworkManagerとそのHUD、NetoworkTransformを使った超シンプルなサンプルで、ホストになる→ストップ→ホストになるという流れをなんどか繰り返すとエラーで止まります(8月12日現在

)。

どうやら作ったソケットか何かがきちんと破棄されていないらしく、StopServer、StopClientなどを呼ぶだけでは繰り返しのプレイに耐えられません。

ではどうするかというと

NetworkTransport.Shutdown();

NetoworkTransport.init();

の2つをセットで呼べばとりあえず正常に動くようになります。

 

ServerChangeSceneが謎だった

次に結構長い間挙動が謎だったのがこいつ。

NetworkManager.ServerChangeScene();

なにげに非同期読み込みです。

ロードシーンか何かを挟めば簡単に読み込み画面が作れます。

 

基本的にはいろいろ揃ってて便利

UNETはHLAPIなのでネットワークゲームを作る上で必要なものがある程度網羅されています。

LANで通信相手を探すNetworkDiscovery

マッチメイキング用のMatchmaker

ロビー用のNetworkLobbyManager

マッチングサーバーを提供してくれるServiceのUnityMultiplayer

この辺りを目的に合わせてうまく使えば結構つくりやすいかなと思います。

 

 

Unityのネットワーク機能が出てたので使ってみた現段階の感想としてまだ未完成ということ、日本語の資料がまだまだ少ないこともあって割りと大変でした。

ただ、基本的なところの実装はかなりはやくできるのでGameJamなんかでは結構使いどころがありそうな印象です。

 

 

大学でKPTを試してみた話

 

 初投稿。

 先日、大学のチーム制作の会議でKPT(けぷと)というものをやりました。

 KPTとはKeep、Problem、Tryの略称でアジャイル開発などで使われる振り返りのための会議のやり方です。

 

 このやり方は以前にも何度かやったことがあるのですが、今回ちゃんとやってみてかなり学校でのゲーム制作と相性がいいのでは? と感じたのでそこの所含めて書いていきたいと思います。

 

KPTってどうやるの?

 KPTのやり方は簡単です。

 ↓まずこんな感じでK、P、Tのそれぞれの枠をホワイトボードに書きます。

f:id:k_tachiban:20160410000938p:plain

 後はKeepの枠に良かったこと、Problemの枠に現在の問題点、そしてTryにこれからやっていくことをそれぞれふせんで書き出していきます。これをだいたい1、2週間くらいに一回やります。以上です。

 

 ……とだけ書いてしまうとあまりに雑なのでそれぞれの書くことを説明します。

「Keep」

 ここにはこれからも継続したいこと、良かったことを書いていきます。このKeep、他の2つと比べると割りと軽視されがちですがかなり重要なところ。

 ここでしっかりチームを褒め、雰囲気をよくすることでこの後のProblemで雰囲気が悪くなりにくくなります。これを怠るとただの反省会になってしまって良くない雰囲気になりやすくなります。

 とはいえはじめはそんなポンポン出てくるわけではないので開発の状況だけでなくプライベートであった良かったことなども書き出すようにすると楽しくなります。

「Problem」

 ここがメイン。これまで良くなかった問題点を書き出していきます。この時司会役の人はなるべくぶっちゃけてもらうように指示してください。

 チーム制作でありがちな「みんな何も言わないけど、なんとなくこれはヤバい気がする……」ということを共有します。自分がヤバいと思っていてほんとにヤバいことはだいたいみんなヤバいと思っています。

「Try」

 ここでは、まず、チームの人それぞれに自分が書き出したことについて話してもらってその人の意図を共有します。

 その後、Keep、Problemを踏まえてこれから実行していくことを書き出します。このとき「~を頑張る」などではなく、なるべく具体的にできたかどうかがはっきりわかるように書き出してください。

 あと、すぐに解決方法が出てこないし、時間で解決されそうな問題はスルーしても良いです。ほんとにヤバかったら次回やっても出てくるのでその時対処方法を考えるようにするとスムーズに進みます。

時間配分

時間配分ですが私は

Keep:3分

Problem:3分

Try:10分

くらいを目安にやっています。短く区切ったほうがダラダラしないし楽なので続けやすいです。

 

まとめ

 KPTを開発に使う上で大事な概念として、開発後ではなく、開発中、かつ頻繁にKPTを行うというのがあります。とはいえ朝会のように毎日やるというほどのものでもありません。大体1、2週間に一度位のペースで行います。

 そして、大学の授業でやっているなら週に一度は授業の日があり、サークルでも週に一度ミーティングをやるところは多く、それに合わせてKPTを行うと開発にリズムも生まれるしきちんと情報の共有ができるので、なんとなく発言しにくいといった問題を抱えているチーム開発におすすめの方法です。

 

 で、あってるよね? そうじゃねぇだろっていう意見があればコメント下さい。