Unityでスマホのジャイロを使ってアレコレ

### ご注意
注意！この記事の筆者はいろいろよくわかってないです
なんかよくわからんけど動いたからヨシ！となってます

# 準備
### スマホ側
###### AndroidにUnity Remote 5 をインスコ
https://play.google.com/store/apps/details?id=com.unity3d.mobileremote

###### USBデバッグを有効化(例：シャオミ製スマホの場合)
<img width=49% src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3719521/a8739e28-60e3-48e8-5469-aa3d0398a79c.png>
<img width=49% src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3719521/75c53428-28fc-0d59-2e4c-b6550fd4d599.png>]
Unity Remoteアプリを開いて、PCとUSB接続して待機させておく。「USBデバッグを許可しますか？」には はい と答える。

### PC側
Unity Hub > インストール > 任意のバージョンの右の歯車をクリック > 「モジュールを加える」 で Android Build Support を入れる
<img width=60% src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3719521/e0c62851-0293-fb8d-9620-dbc22d00c09e.png>
適当にプロジェクトを作り、File > Build Settings... から Android で「Switch Platform」(時間かかる)
Edit > Project Settings... から Editor タブ "Unity Remote" 以下 Device を「Any Android Device」にする(元はNone)。
<img width=40% src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3719521/0f6a7d43-9250-e557-6d4c-a50b779bb00d.png> <img width=49.5% src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3719521/6b472c5c-551b-271f-7f77-0db6a41478da.png>


# スマホをunity上に出現させる
完成図
![unity_gyro.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3719521/2da39075-e15f-4e3f-848f-687ccbac989d.gif)

手に持っているスマホの傾きをUnity上で再現します。
まずはこんな感じに適当にスマホっぽい形の3Dオブジェクトを作ります。このとき、画面がカメラの方を向くように作ったほうがいいです(1敗)。つまりz方向に薄く、y方向に長くします。そのほうがなんかやりやすいです(小並感)。(最初画面が空を向くように設計したら、全く思った方向に回転できなくて挫折しました)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3719521/ced14ffb-9520-55b5-90eb-07abd0cf4f66.png)

スクリプトを書く前に、パソコンのモニタがスマホからみてどっちの方角を向いているのか調べておきます。
スマホをモニタのほうに向けて、方位磁針アプリを起動します(Playストアに沢山あるので一つ選んでインストールします。位置情報へのアクセス許可を求められても拒否で構いません。)
<img width=50% src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3719521/6dc86a17-7347-eef4-2d9b-00353bb6c24c.png>
例えば僕の環境では**277**°でした。

次にスクリプトを書きます。Scriptsフォルダを作って create > C# Script から"sumaho_gyro.cs"と名付けてダブルクリックします。次のコードをコピペしてもいいですが、下の方の`Quaternion.Euler(90, 0, 277)`となっているところの第三引数`277`はさっき得た数値にしてください。
```cs:sumaho_gyro.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//            ↓ここはファイル名と一致させる必要がある(1敗)
public class sumaho_gyro : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        //ジャイロを有効にする
        Input.gyro.enabled = true;
    }

    // Update is called once per frame
    void Update()
    {
        //クォータニオンとかいう4次元のベクトル。"ジンバルロック"が発生しないらしい(よくわかってない)
        Quaternion attitude = Input.gyro.attitude;
        //3D Object を回転させる。                         ↓この値は方位磁針アプリで測定した数値にする
        transform.localRotation = Quaternion.Euler(90, 0, 277) * new Quaternion(-attitude.x, -attitude.y, attitude.z, attitude.w);
    }
}

```
<details><summary>注意点</summary>

```cs
//            ↓ここはファイル名と一致させる必要がある(1敗)
public class sumaho_gyro : MonoBehaviour
```
について、最初ファイル名を変更せずに書き始めて、後からファイル名をつけていなかったことに気づきリネームしました。「スマホ」の3D Objectにスクリプトを適用しようとしたら
```
Can't add script component 'ファイル名' because the script class cannot be foumd.
```
な感じのエラーが出てちょっと悩みました。通常はファイル作成時のファイル名と同じクラス名になるのですが、うっかりリネームするとエラーになります。(例：NewBehaviourScript)
```cs
public class ファイル名 : MonoBehaviour
```
であることをしっかり確認しておきましょう。

また、(90,0,??)*new Quaternion(-x,-y,z,w) な感じに、90だったりxとyがマイナスだったりするのは、

https://vr-cto.hateblo.jp/entry/2016/05/02/070000

この記事にそう書いてあったからです。詳しく理解してないです。
</details>
書けたらHierarchyでスマホな3D Objectを選択し、Inspectorの空いてるところにスクリプトをドラッグ&ドロップして適用させます。Play(▶)ボタンを押すと、現実のスマホとunity内のスマホの傾きが同期していると思います。

# スマホを傾けてARゲームみたいにする①
完成図
![sumahoAR.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3719521/f8512b5f-876c-4f54-1845-5ebe1b6a3a62.gif)
これは自身が中心に立っていてまわりをぐるぐる見回している様子です。「FPS」ですね。
こんな感じに適当にフィールドを作ります。座標(0,0,0)を中心に各方向へ±1の2x2x2の立方体です。中心がわかりやすいようにSphereを置いています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3719521/6579d6f6-1540-4734-4ebf-5c9b88baff6a.png)
Sphereと同じ位置にMain Cameraを持ってきます。これに、先程の**sumaho_gyroのスクリプトを適用しただけ**で、AR(VR)な感じになります。

# スマホを傾けてARゲームみたいにする②
分かりづらかったのでテーブルをつけてみました。
![sumahoAR2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3719521/acebf77e-5666-6870-c2e2-ee57ec1bbeb9.gif)
先ほどと違い、カメラ自体の位置が変化しています。「TPS」ですね。中心のSphereをに追従するように、なめ回すような視点で観察できます。カメラを俯瞰で見るとこんな感じです。
![sumahoAR2_shousai.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3719521/e5eaf26c-0f60-4e64-5c67-2af64e2dda32.gif)
イメージとしては見えない球体表面に沿って移動している感じでしょうか。
新たに`camera_gyro.cs`を作って次を書き込みます。
```cs:camera_gyro.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class camera_gyro : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        Input.gyro.enabled = true;
    }

    // Update is called once per frame
    void Update()
    {
        Quaternion attitude = Input.gyro.attitude;
        transform.localRotation = Quaternion.Euler(90, 0, 277) * new Quaternion(-attitude.x, -attitude.y, attitude.z, attitude.w);
        //ここまで同じ

        //UnityのInspectorに出てくるRotationと同じ値を取得
        float rotx = transform.localRotation.eulerAngles.x;
        float roty = transform.localRotation.eulerAngles.y;
        float rotz = transform.localRotation.eulerAngles.z;

        //y軸まわり(左右)について、中心からの位置を一定にする
        float x = -Mathf.Sin(roty * Mathf.PI / 180);
        float z = -Mathf.Cos(roty * Mathf.PI / 180);

        //x軸まわり(上下)について、中心からの位置を一定にする
        float y = Mathf.Sin(rotx * Mathf.PI / 180);
        x *= Mathf.Cos(rotx * Mathf.PI / 180);
        z *= Mathf.Cos(rotx * Mathf.PI / 180);

        //カメラの位置を変更して中心を見つめる
        transform.localPosition = new Vector3(x, y, z);
    }
}
```
Main Cameraに適用します。
先ほどは一人称でVRっぽかったですが、こちらは三人称でARっぽいですね。
今回はジャイロだけを使っていくつか作ってみました。
加速度とかカメラとかと組み合わせて使うと面白そうですね