タイプ別TPS視点の作り方（in Unity3D with C#)

# 前書き
今回紹介する議題は他のサイトや、他Qiitaユーザーの皆様も紹介されている「Unity3dでTPS視点操作をどのように実装するか？」です。今回紹介する視点操作は以下のとおりです。

 - シューティング系
 - メタルギアソリッド系

注意：正規表現があまりキレイなコードではありません。ご指摘いただけますと幸いです。
gif内でカメラ操作がカクついているのは、トラックボールマウスを使用しているからです。

# Unity3Dでの視点操作の種類別コード
## シューティング系
良くTPSシューティングゲームに採用されているカメラ操作方法です。PUBGやFortnightの標準操作はこれですね。マウスをY軸（上下）方向に動かすとはカメラは上下に動き、X軸に動かすと__**キャラクターの向きが左右に動きます**__

参考画像
![Desktop 2018.11.09 - 16.31.35.07.DVR-60-6-1541755929085.1.gif](https://qiita-image-store.s3.amazonaws.com/0/313407/c8865341-4681-2064-9571-0645fade7214.gif)

```c#:MouseController.cs
using UnityEngine;

public class MouseController : MonoBehaviour
{
    [SerializeField]
    private Transform character;    //キャラクターをInspectorウィンドウから選択してください
    [SerializeField]
    private Transform pivot;    //キャラクターの中心にある空のオブジェクトを選択してください

    void Start()
    {
        //エラーが起きないようにNullだった場合、それぞれ設定
        if(character == null)
            character = transform.parent;
        if(pivot == null)
            pivot = transform;
    }
    //カメラ上下移動の最大、最小角度です。Inspectorウィンドウから設定してください
    [Range(-0.999f, -0.5f)]
    public float maxYAngle = -0.5f;
    [Range(0.5f, 0.999f)]
    public float minYAngle  = 0.5f;
    // Update is called once per frame
    void Update()
    {
        //マウスのX,Y軸がどれほど移動したかを取得します
        float X_Rotation = Input.GetAxis("Mouse X");
        float Y_Rotation = Input.GetAxis("Mouse Y");
        //Y軸を更新します（キャラクターを回転）取得したX軸の変更をキャラクターのY軸に反映します
        character.transform.Rotate(0, X_Rotation, 0);

        //次はY軸の設定です。
        float nowAngle = pivot.transform.localRotation.x;
        //最大値、または最小値を超えた場合、カメラをそれ以上動かない用にしています。
        //キャラクターの中身が見えたり、カメラが一回転しないようにするのを防ぎます。
        if (-Y_Rotation != 0)
        {
            if (0 < Y_Rotation)
            {
                if (minYAngle <= nowAngle)
                {
                    pivot.transform.Rotate(-Y_Rotation, 0, 0);
                }
            }
            else
            {
                if (nowAngle <= maxYAngle)
                {
                    pivot.transform.Rotate(-Y_Rotation, 0, 0);
                }
            }
        }
    }
}
```
上記のスクリプトを動かしたいカメラにアタッチし、unitychanの胴体の中心部分に空のオブジェクトを作成（Pivotと呼びます）し、カメラをその子要素にしてください。↓
<img width="318" alt="キャプチャ.JPG" src="https://qiita-image-store.s3.amazonaws.com/0/313407/7e68501f-d1bd-def9-04a0-5ae53782249b.jpeg">

その後Inspectorウィンドウから```Character```と```Pivot```にそれぞれのオブジェクトを設定してください。
上のGifでは**unitychan本体**を```Character```に、**上で作ったPivot**を```pivot```に設定しました。↓
<img width="512" alt="キャプチャ.JPG" src="https://qiita-image-store.s3.amazonaws.com/0/313407/fb20b631-bcf1-e6b7-32d5-636488581a7c.jpeg">

Pivotがあることで、カメラが上下に移動しても、しっかりとキャラクターを映す様になっています。TPSの目的は可愛い/カッコいいキャラクターが画面に映ることも利点の一つですからね。**多くの紹介サイトではこれを忘れています。**

```Min Y Angle```と```Max Y Angle```ですが、これを調整することで、カメラの上下移動範囲を広げることが出来ます。カメラ操作でもっと上まで見えるようにしたかったら、```Max Y Angle```を大きく設定するといいでしょう。


## メタルギア・ソリッド系
メタルギア・ソリッドVを参考にしたカメラ操作方法です。スニーキングミッションは隠れることが重要で、後ろに敵が居るか確認したいときなどに視点を移動すると体の向きが変わり、物音を発したりや体が物陰からはみ出てしまうと大問題です。そのため、このカメラ操作で
はマウスをY軸（上下）方向に動かすとはカメラは上下に動き、X軸に動かすと__**カメラがキャラクターの周りを回ります**__

参考画像
![Desktop 2018.11.09 - 17.26.21.10.DVR-9-7-1541759252669.1.gif](https://qiita-image-store.s3.amazonaws.com/0/313407/86a51e5b-339a-a80b-212b-43d0f10e8f9d.gif)

```c#:MetalGearMouseController.cs
using UnityEngine;

public class MetalGearMouseController : MonoBehaviour
{

    [SerializeField]
    private Transform pivot = null;
    void Start()
    {
        if (pivot == null)
            pivot = transform.parent;
    }

    [Range(-0.999f, -0.5f)]
    public float minYAngle = -0.5f;
    [Range(0.5f, 0.999f)]
    public float maxYAngle = 0.5f;
    void Update()
    {
        //マウスのX,Y軸がどれほど移動したかを取得します
        float X_Rotation = Input.GetAxis("Mouse X");
        float Y_Rotation = Input.GetAxis("Mouse Y");
        //Y軸を更新します（キャラクターを回転）取得したX軸の変更をキャラクターのY軸に反映します
        pivot.transform.Rotate(0, X_Rotation, 0);

        //次はY軸の設定です。
        float nowAngle = pivot.transform.localRotation.x;
        //最大値、または最小値を超えた場合、カメラをそれ以上動かない用にしています。
        //カメラが一回転しないようにするのを防ぎます。
        if (-Y_Rotation != 0)
        {
            if (0 < Y_Rotation)
            {
                if (minYAngle <= nowAngle)
                {
                    pivot.transform.Rotate(Y_Rotation, 0, 0);
                }
            }
            else
            {
                if (nowAngle <= maxYAngle)
                {
                    pivot.transform.Rotate(Y_Rotation, 0, 0);
                }
            }
        }
        //操作していると、Z軸がだんだん動いていくので、0に設定してください。
        pivot.eulerAngles = new Vector3(pivot.eulerAngles.x, pivot.eulerAngles.y, 0f);
    }
}
```
Inspectorウィンドウからの設定方法は上記シューティング系コードとほぼ同じです。ですが、今回は```Character```を回転させる必要がないので、```Pivot```のみとなっております。


## 終わりに
QiitaのMDってアンダーライン出来ないんですね…。また、マウスX,YがTransformのX,yと逆になっているのに、なぜ正しく動くのか謎です…ご存知の方はぜひ教えてください。