総コン Advent Calendar 2022 19日目の記事です。
今回目指すもの
JoyconLibの導入からポインターのUIの表示まで行います。
環境
JoyconLib06 2018.2
Unity 2021.3.8 (2019以降なら問題ない気はします)
MacOS Big Sur ver 11.6
対象読者
Unity初心者
JoyconLibの導入
JoyconLibのダウンロード
Joy-ConをUnityで使えるようにパッケージを製作してくださっている方がいるので、これを用います。上のリンクから、JoyConLibのpackageをダウンロードします。
Unityプロジェクトの作成
UnityプロジェクトへPackageの導入
画面左上から Assets -> Import Package -> Custom Package を選択します。
先ほどダウンロードしたパッケージファイルを選択して、Openしましょう。
Unity側で新しくウィンドウが出るので、Importをクリックします。
これでPackageが導入できました。
Joy-ConをPCに接続する
Macのシステム環境設定を開いて、Bluetoothの項目を開きます。
Joy-Con側面のペアリングボタンを長押ししてペアリングモードにします。
出てきたデバイス一覧から「Joy-Con(R)」をクリックして接続します。
「Joy-Con(L)」も同じように接続します。
接続済み表記になれば問題なく接続できていると思います。
サンプルシーンの起動
ProjectビューからAssets -> ScenesをクリックしてScenesフォルダを開きます。
Scene1をクリックして、JoyconLibのサンプルシーンに切り替えます。
Unityの実行ボタンを押してサンプルシーンを実行します。
このような感じで青いCubeがJoy-Conに連動して動けば問題ないと思われます。
ちょっとした解説
今回動かした青色の立方体を動かしているのは、JoyconDemo.csというスクリプトです。
JoyconDemo.csを見てみましょう。
画面左のCubeオブジェクトをクリックして、画面右のInspectorビューにあるJoyconDemoをダブルクリックする。もしくは画面下のAssetsフォルダ内にあるJoyconDemo.csをダブルクリックすることで、c#ファイルを編集できます。
VisualStudioで開くと、このようなコードが書かれています。
静的に定義したJoyconManagerクラスのインスタンスから、接続しているJoy-Conのリストを取得し、Joy-Conの右と左をそれぞれJoyconクラスの変数jに代入して、Joy-Conからの情報を受け取る。のようなコードが書いてあるようです。
JoyconManagerクラスのインスタンスを静的に定義しているので、Hierarchyビューにもあるように、どうやら、JoyconManagerスクリプトを付けたオブジェクトがシーン内に1つ必要そうですね。
今回はこれを参考に進めていきます。
ポインタデバイスの実装(この記事の肝)
ポインターを実現するためには、
「あるオブジェクトの向きベクトルと、垂直な平面との交点を求めれば良い」です。
先ほどのサンプルの実行でJoy-Conの傾きが取得できそうなことはわかったと思います。
Joy-Conの傾きを反映させたオブジェクトの向きベクトルを利用して実装します。
これから、実際にJoyconをポインタとして使うためのコードと設定を書いていきます。
Sceneの作成
Assets/Sceneフォルダに移動して、右クリック
Create -> Scene をクリックして、新しくSceneを作成します。名前はPointerとしました。
Sceneアイコンをダブルクリックして新しく作ったSceneの編集に切り替えます。
JoyConManagerオブジェクトの作成
Hierarchyビューの何もないところを右クリックして、CreateEmptyを選択します。
オブジェクト名を「JoyConManager」として、空のオブジェクトを作成します。
HierarchyビューにできたJoyConManagerをクリックして、InspectorビューのAddComponentからJoyConManager.csをアタッチします。
Cube,Plane,Sphereオブジェクトの作成
先ほどと同じようにオブジェクトを作成します。
create -> 3DObject -> Cube を選択してCube(JoyConCube)を作成します。
同様にPlane(JoyConPlane), Sphere(JoyConPlane)を作成します。
Cubeオブジェクト用のスクリプト JoyConCube.cs を作成
JoyConCubeオブジェクトを選択して、AddComponentをします。
New Scriptをクリックして、名前はJoyConCubeなどにして、スクリプトを作成&アタッチします。
JoyconDemo.csを参考にして、以下のような必要最低限のコードを書きます。
傾きの回転がCubeオブジェクトに反映されればOKです。
using UnityEngine;
using System.Collections.Generic;
public class JoyConCube : MonoBehaviour
{
private List<Joycon> joycons;
// Values made available via Unity
public float[] stick;
public Vector3 gyro;
public Vector3 accel;
public int jc_ind = 0;
public Quaternion orientation;
void Start()
{
gyro = new Vector3(0, 0, 0);
accel = new Vector3(0, 0, 0);
joycons = JoyconManager.Instance.j;
if (joycons.Count < jc_ind + 1)
{
Destroy(gameObject);
}
}
// Update is called once per frame
void Update()
{
// make sure the Joycon only gets checked if attached
if (joycons.Count > 0)
{
Joycon j = joycons[jc_ind];
// Bボタンでセンター位置のリセット
if (j.GetButtonDown(Joycon.Button.DPAD_DOWN))
{
j.Recenter();
}
gyro = j.GetGyro();
accel = j.GetAccel();
orientation = j.GetVector();
gameObject.transform.rotation = orientation;
}
}
}
JoyConSphere.csの作成
Joy-Conのポインターの先で面との交点となるSphereを動かすJoyConSphere.csを作ります。
先ほどと同様にして、JoyConSphereオブジェクトにJoyConSphere.csを作成&アタッチします。
以下の記事を参考にして、コードを書きます。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class JoyConSphere : MonoBehaviour
{
public GameObject StartPoint;
public GameObject Plane;
// Update is called once per frame
void Update()
{
var n = Plane.transform.up;
var x = Plane.transform.position;
var x0 = StartPoint.transform.position;
var m = StartPoint.transform.forward;
var h = Vector3.Dot(n, x);
var intersectPoint = x0 + ((h - Vector3.Dot(n, x0)) / (Vector3.Dot(n, m))) * m;
transform.position = intersectPoint;
}
}
unityエディタに戻って、JoyConSphereオブジェクトのInspectorビューで、
上のコードでpublicとして定義したStartPointとPlaneを設定します。
StartPointに、JoyConCubeオブジェクトを
Planeに、JoyConPlaneオブジェクトをドラッグ&ドロップしてアタッチします。
オブジェクトの位置の微修正
このまま実行するとJoyConCubeオブジェクトはデフォルトで真上を向いているので、それに合わせて各オブジェクトの位置を変えます。
JoyConSphereオブジェクトのtransformのPositionのYの座標を10にします。
JoyConPlaneオブジェクトのtransformのPositionのYの座標を10にします。
transformのRotationのXの座標を180にします。
実行してみる
ここで一度実行してみましょう。SphereがCubeの向きの延長上に動けばOKです。
次に、Sphereの座標を利用してUIに組み込みます。
UI用の画像の作成と、ポインタに同期して動かす
UIとして画面に表示させるようにします。
UI画像の作成
Hierarchyビューの何もないところで右クリックをして、UI->RawImage を選択してポインタ用の画像を作ります。
RawImageのRectTransfromからWidth,Heightをそれぞれ25くらいで、色は赤色などにしましょう。
ポインタに同期して動かす
RawImageにPointerImage.csなどのスクリプトを作成・アタッチします。以下のようなコードを書きます。
using UnityEngine;
public class PointerImage : MonoBehaviour
{
public Transform SphereTransfrom;
private RectTransform rectTransform;
// 任意の倍率、大きくすると小さい動きで大きく動く
private float scale = 50.0f;
void Start()
{
rectTransform = GetComponent<RectTransform>();
}
void Update()
{
float x = SphereTransfrom.position.x * scale;
float y = SphereTransfrom.position.z * -scale;
rectTransform.anchoredPosition = new Vector3(x, y, 0);
}
}
untiyエディタでPointerImage(Script)のSphereTransform欄に、JoyConSphereオブジェクトをドラッグ&ドロップしてアタッチします。これで全ての工程が終わりました。
完成
こんな感じで上手く動けばポインタデバイスとしての表示までできました。
感度はPointerImage.csのscaleの値をいじるか、JoyConPlaneのy座標をもっと遠くに設定するかなどすれば変えられます。
あとは、ボタンを押して決定できたりすればゲームに組み込めますね!!
おまけ
実はこの記事は僕が作ったゲーム「一限侍」の実装解説でもありました。
ゲーム内では、このような感じでUIボタンを配置してポインタで選択・決定をできるようにしました。
また時間があれば斬る動作の実装の記事も書こうと思います。
参考にした記事