※ これは 2016/11/20 時点の情報です
最新版では動作が異なる可能性がありますのでご注意ください
前回 は Surface Dial を UWP で利用してみました
今回はさらに Unity で作った UWP アプリから使ってみたいと思います
※ 今回のサンプルコードは下記にアップしています
何を作るかというと、みなさんおなじみのブロック崩しゲームを Unity で作り、操作に Surface Dial を利用しようと思います
ブロック崩しゲーム本体の作りはサンプルコード等をご覧いただき、今回は Surface Dial の連携の部分を取り上げます
といっても、基本的には以前下記の記事に書いた方法でいけました!
こんな感じで Unity のプロジェクト以外に、Windows 10 UWP の API を利用するライブラリプロジェクトと、このライブラリと Unity の間を取り持つライブラリのインタフェースプロジェクトを用意しました
InputManager というのが Surface Dial の入力を管理するクラスで下記のようなコードです
using System; #if NETFX_CORE using Windows.Storage.Streams; using Windows.UI.Input; #endif namespace BreakoutSample.UwpPlugin { /// <summary> /// 入力管理クラス /// </summary> public class InputManager { /// <summary> /// ダイアルボタンクリックフラグ /// </summary> public bool IsButtonClicked { get; set; } /// <summary> /// 水平移動量 /// </summary> public float AxisXDelta { get; set; } /// <summary> /// インスタンス /// </summary> private static InputManager instance; /// <summary> /// インスタンス /// </summary> public static InputManager Instance { get { return instance ?? (instance = new InputManager()); } } /// <summary> /// 加速度係数 /// </summary> private const float Accel = 0.5f; #if NETFX_CORE // <summary> /// Surface Dial 管理クラス /// </summary> private RadialController control; #endif /// <summary> /// コンストラクタ /// </summary> private InputManager() { } /// <summary> /// コンストラクタ /// </summary> static InputManager() { } /// <summary> /// 初期化処理 /// </summary> public void Initialize() { #if NETFX_CORE this.control = RadialController.CreateForCurrentView(); // オリジナルのメニューを追加 var icon = RandomAccessStreamReference.CreateFromUri(new Uri("ms-appx:///Assets/CatHand.png")); var item = RadialControllerMenuItem.CreateFromIcon("Play Game", icon); this.control.Menu.Items.Add(item); // イベントの購読 this.control.ButtonClicked += this.OnButtonClicked; this.control.RotationChanged += this.OnRotationChanged; #endif } #if NETFX_CORE /// <summary> /// ダイアル回転イベントハンドラ /// </summary> /// <param name="sender">イベント発行者</param> /// <param name="args">イベント引数</param> private void OnRotationChanged(RadialController sender, RadialControllerRotationChangedEventArgs args) { this.AxisXDelta = ((float)args.RotationDeltaInDegrees) * Accel; } /// <summary> /// ダイアルボタンクリックイベントハンドラ /// </summary> /// <param name="sender">イベント発行者</param> /// <param name="args">イベント引数</param> private void OnButtonClicked(RadialController sender, RadialControllerButtonClickedEventArgs args) { this.IsButtonClicked = true; } #endif } }
Windows 10 固有の API に触れる部分は #if NEXTFX_CORE
のディレクティブで囲んで Unity Editor から見えないようにしています
また、Unity → UWP ライブラリは簡単に呼び出せますが、逆は Unity のメインスレッドを直接呼び出せずかんたんにはいきません
そのため、IsButtonClicked や AxisXDelta などの値型プロパティを下記のように Unity 側から参照することにしました
using BreakoutSample.UwpPlugin; using UnityEngine; /// <summary> /// メインシーン /// </summary> public class MainScene : MonoBehaviour { /// <summary> /// ラケット /// </summary> [SerializeField] private GameObject racket; /// <summary> /// ボール /// </summary> [SerializeField] private GameObject ball; /// <summary> /// プレイ中フラグ /// </summary> private bool isPlaying = false; /// <summary> /// 入力管理クラス /// </summary> public InputManager InputManager { get; private set; } /// <summary> /// 初期処理 /// </summary> public void Awake() { this.InputManager = InputManager.Instance; UnityEngine.WSA.Application.InvokeOnUIThread(() => { this.InputManager.Initialize(); }, false); this.isPlaying = false; } /// <summary> /// 更新処理 /// </summary> public void Update() { if (!this.isPlaying) { this.ball.transform.position = new Vector3(this.racket.transform.position.x, 0, this.racket.transform.position.z + 0.25f); // 開始前に Surfave Dial がクリックされたらボールに力を与えて動かし始める if (Input.GetButtonDown("Submit") || this.InputManager.IsButtonClicked) { this.ball.SendMessage("AddFource"); this.isPlaying = true; // クリックフラグは降ろしておく this.InputManager.IsButtonClicked = false; } } } /// <summary> /// ミスイベントハンドラ /// </summary> public void Miss() { this.ball.GetComponent<Rigidbody>().velocity = Vector3.zero; this.InputManager.IsButtonClicked = false; this.isPlaying = false; } }
あまりスマートなやり方ではないですが、取り急ぎやりたい場合ならこれで十分かもしれません
本格的にやるには Dispacher を用意して Unity のメインスレッドから呼び出す仕組みが必要になりそうですね
さてこれで動くかな?
ちゃんと動きましたね!