以前のチュートリアルでUnityで作成したコンテンツをOculus Riftで表示できるところまで進みました。Oculus RiftでもOculus Questでも便利なOculusコントローラーを使います。Unityの従来の入力システムが、なんといえばいいでしょうか、まあ、あまりよくないです。そのために全く新しいInput Systemが導入されました。パワフルで柔軟性がありますが、その分、複雑になりました。ドキュメントもまだ不十分で使いにくい印象を与えてしまいますが、基本を理解すれば、むしろ従来のシステムより非常に使い勝手がいいです。
Input Systemの準備
新しいInput Systemは標準でプロジェクトに追加されないので、パッケージマネージャでインストールする必要があります。
最初はプロジェクトに追加されているパッケージしか表示されないので、「Unityレジストリ」を選択して、インストール可能な標準パッケージを表示します。
「Input System」をインストールします。
そこで、重要なお知らせが表示されます。旧入力システムから新システムに移行するためにプロジェクトの設定を変える必要がありますとの事です。必ず、絶対に「Yes」を押してください。
そうするとなんとUnityが再起動します。クラッシュではなく正常の動作です。
アクションの登録
新しいInput Systemは同じゲームがさまざまなデバイスで、さまざまなコントローラで遊べるように設計されています。設定を簡単に切り替えるためにアセットとして保存されます。シンプルなコンテンツなら一つのインプット設定ファイルで十分です。
アセットメニューから新規の「Input Actions」ファイルを作成します。(Input Systemパッケージがインストールされていないと表示されません。)
「DefaultActions」など、分かりやすい名称を付けます。
このアセットをダブルクリックして編集します。
プレーヤーが引き起こすイベントをアクション(Action)といいます。アクションは基本的に自分で必要に応じて追加して定義します。Move(移動)、Jump(ジャンプ)、Fire(撃つ)などなど。複雑なゲームので、操作方法を切り替えたい場合、アクションを複数のアクションマップ(Action Map)でまとめる事ができます。例えば、戦闘の時のアクション、会話の時のアクション、メニューの時のアクションなどを別々のアクションマップで設定することができます。
今回は単純なゲームを作るので一つだけのアクションマップを使います。新しいアクションマップを追加して、「Oculus Actions」という名称を付けます。(アクションマップの名称は自由です。)
次は新しいアクションを追加します。今回は動作確認のためにキューブを落下させたいですので、「Drop」アクションを追加します。
デフォルトのアクションの「New action」の名称を変えるだけでいいです。
アクションをもっと追加したい時は「+」ボタンを押して追加していきます。
次の重要な概念はバインドです。分かりにくいプログラミング用語ですが、単純にこのアクションを引き起こす時にプレーヤーはどうすればいいのかという設定です。一つのアクションに複数のバインドを登録する事ができます。例えば、「弾を撃つ」というアクションはキーボードのCtrlキー、エンターキー、マウスの左ボタン、ゲームコントローラーのトリガーボタンなど、いくつもの操作方法を登録することができます。今回はプレーヤーが右手のOculusコントローラーのトリガーボタンを押したらキューブが落下するという風に登録します。
「Drop」アクションの表示を展開して、「<No Binding>」を選択します。
「Binding」の「Path」でプレーヤーの操作を選びます。「XR Controller」でAR・VRコントローラーを選択します。
「Oculus Touch Controller」を選ぶと…
左手(LeftHand)と右手(RightHand)のどちらかを選びます。
ここにいくつもの操作がリストアップされます。「Button」で終わる操作はボタンが押された時を意味します。「Touched」で終わる操作はプレーヤーが該当の入力を触れるだけで反応します。スティックだけ押す操作が「Clicked」になっています。コントローラーの入力デバイスの名称とそのバインドはこちらです。
「triggerPressed」を選択しますが、他の操作でも登録してもいいです。
入力設定の編集が終わったら忘れずに設定を保存します。
保存すれば設定画面を閉じます。
アクションを受け取る
登録したアクションに反応してほしいゲームオブジェクトに「PlayerInput」というコンポーネントを追加します。今回のチュートリアルではCubeになります。
PlayerInputコンポーネントに使用する設定を指定しないと動作しません。Actionsパラメータで先ほど作成した設定アセットを選択します。
初期値になっているので変更する必要はありませんが、Behaviorパラメータを必ず「Send Messages」をしておきましょう。アクションが起きた時に様々な形で通知を受け取る事ができますが、「メッセージを送信」という方法から説明します。この方法ではC#のスクリプトで通知を受け取ります。
プロジェクトでスクリプト用のフォルダーを用意します。(整理整頓!)
この中に「ObjectDrop」というスクリプトを作成します。
この「ObjectDrop」をCubeに追加します。まだ書いていませんが、ObjectDropスクリプトはPlayerInputと連動するので必ずセットで使います。
スクリプトをダブルクリックしてコード編集ソフトウェアで必要なスクリプトを書きます。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ObjectDrop : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
// ここにアクションに反応するメソッドを書きます。
void OnDrop()
{
gameObject.AddComponent<Rigidbody>();
}
}
void OnDrop()
から始まる部分だけを追加します。このOnDrop
というのは「On
」(起きた時に)と自分で設定したアクション名で構成されています。波括弧の中にアクションが起きた時に実行するコードを書きます。ここは自分自身のゲームオブジェクト(gameObject)に「Rigidbody」という種類のコンポーネントを追加する指示をします。Rigidbodyは物理演算を影響を受けるようにするので、追加することで重力で落下します。
Unityに戻って、再生ボタンを押すと右手のトリガーボタンを押したらキューブが落下します。
これから、左手コントローラや他の動作、Dropアクションのバインドを変えてみましょう。
Unity Eventsの使い方
もう一つのアクションの反応方法として、Unity Eventがあります。こちらはC#を書かなくても使えるので、プログラミングに自信がない人にとって嬉しい選択肢ですが、できる事が非常に制限されています。
簡単な例として、オブジェクトを非表示にするアクションを追加しましょう。入力設定を編集して、新しい「Hide」アクションを追加します。そして、好きな操作にバインドしておきます。
入力設定を保存して、ウィンドウを閉じます。Cubeの隣に球体(Sphere)を追加します。
SphereにもPlayerInputコンポーネントを追加して、アクションのアセットを指定します。今回はBehaviorを「Invoke Unity Events」にします。
イベント、そして「Oculus Actions」を展開すると登録したアクションを見えます。(DropとHideです。)
「Hide」のところにイベントを追加します。いつも困る事ですが、初期値の「Runtime Only」を必ず「Editor And Runtime」に変えます。(そうしないと書き出した時にしか動作しません。)
反応するオブジェクトをSphereにして、呼び出される関数(Function)をMeshRendererのenabledにします。
MeshRendererのenabledをオフにするとオブジェクトが非表示になります。
この状態で動かしてみると、キューブの落下、スフィアの非表示が可能になります。
ボタンを押した時、離した時に反応するスクリプトの書き方
Unityの旧入力システムではボタンが押されているかどうかの確認が簡単でした。新しいシステムでも簡単にできますが、どうもドキュメントが分かりにくいです。キューブのスクリプトを編集して、プレーヤーが「グリップ」ブタンを押した時にキューブを大きくして、離した時に通常のサイズに戻すプログラムを書きましょう。
まず、入力設定に新しいアクションを追加します。
操作をバインドする前に、GrowのInteractions設定を変えます。
「+」ボタンを押して「Press」を選択します。これは「押して」操作する意味です。ボタンの場合、わざわざ指定しなくてもいいですが、押したときも離した時も反応したい場合、明示的に指定します。他に長押し(Hold)、やタップがあります。
Trigger Behaviorを「Press And Release」に変えます。そして、以前と同様にコントローラの動作にアクションをバインドします。
保存して、ウィンドウを閉じます。次はコードエディターに戻って、ObjectDropスクリプトを編集します。
ファイルの冒頭に次の一行を追加します。
using UnityEngine.InputSystem;
他の「using
」で始まる行の前後なら大丈夫です。これでスクリプトの中で新しいInput Systemの機能(クラス)を使う事ができます。
OnDrop
が定義されている後に新しいメソッドを追加します。同様にOn
+アクション名で名称を指定しますが、ボタンが押されているかどうかを教えてくれる引数も追加します。
void OnGrow(InputValue input)
{
if (input.isPressed) // 入力が押されているかどうかを確認する
{
transform.localScale = Vector3.one * 2; // オブジェクトのスケジュールを2にする
}
else // 押されていない(離された)
{
transform.localScale = Vector3.one; // オブジェクトのスケジュールを1にする
}
}
実行してみると、コントローラを握った時にキューブが大きくなります。
スティックでオブジェクトを動かす
Input Systemで今までボタンしか使っていませんが、Oculusコントローラにスティックが付いています。使いたい場合、アクションの設定を調整する必要があります。
今まで同様に、「Move」という新しいアクションを追加します。
しかし、Action Typeを「値」に変えます。
Control TypeをButtonからVector2に変えます。これはOculusコントローラだけでなく、2次元データを返すすべての入力デバイス共有の設定になります。以前、ボタンにPressインタラクションを追加しましたが、新しいアクションを追加すると受け継がれてしまうようですが、要らないので削除します。
操作をバインドするとボタンがリストから消えて代わりに「thumbstick」が表示されます。これを選択します。
設定を保存してウィンドウを閉じます。
またObjectDropスクリプトを編集します。Growと同様なOnMove
メソッドを追加します。
Vector2 moveDirection = Vector2.zero;
void OnMove(InputValue input)
{
moveDirection = input.Get<Vector2>();
}
他のメソッドで使いたいので、moveDirection
を<code>OnMove
の外に宣言します。input.Get<Vector2>()
で入力のデータから2次元の移動を取り出します。これを記憶して、後で使います。
Update
メソッドを編集して、移動入力でオブジェクトを動かします。
// Update is called once per frame
void Update()
{
transform.position += (Vector3)moveDirection * 0.5f * Time.deltaTime;
}
ここの「0.5」を変えるとキューブの移動速度が変わります。
これでおそらくほとんどすべてのVRアプリで必要なユーザー操作に対応することができるでしょう。
Leave a Reply