モンハンみたいな視点移動を10秒で実装するお話

#サマリー

「モンハンみたいにモデルの中心から一定の距離を置いてカメラが回転する」を実現します。
モンハンは水平面内の回転だけですが、この記事では鉛直面内の回転とズーム[^1]、回転中心の変更も含めて実装します。
釣りじゃなくマジで10秒でできます。
#ポイント

親子関係を持つオブジェクトでは、子のTransformの値は親からの相対座標になります。
これをうまく利用します。
#早速10秒で実装する
①4つのGameObjectを入れ子にし、最下層にCameraを配置
　Hierarchyはこんな感じ。
　ここではそれぞれRoot,HorizontalRotNode,VerticalRotNode,DollyNodeという名前にしています。
　（デモ用にユニティちゃんとPlaneを置いていますが気にしないでください）

![WS000000.JPG](https://qiita-image-store.s3.amazonaws.com/0/196069/6766d28d-85ea-c32f-5c5f-20f248292895.jpeg)

②以上。

これだけで完成です。
#動かしてみる
特にコードを書かなくても、Hierarchy上から値を入力することで動かすことができます。
何にどんな値を入力するかというと以下の通りです。

|GameObject|入力先|入力値|
|:-----------------:|:-----------------:|:-------------------------------------------:|
|RootNode  |transform.position  |被写体の位置|
|HorizontalRotNode  |transform.localRotation.y  |水平面内の回転量|
|VerticalRotNode  |transform.localRotation.x  |鉛直面内の回転量|
|DollyNode  |transform.localPosition.z  |被写体からの距離|

とりあえず動画で確認するのがわかりやすいかと思います。

![3dcamdemo.gif](https://qiita-image-store.s3.amazonaws.com/0/196069/c862ab1c-f4bf-1c2d-d889-0807e7e479a8.gif)


動画では以下のことを行っています。
①Gameビューに切り替えて
②上記に倣って値を変更

構造が簡単な割にはこんな風にかなり直感的に動きます。

#応用1. コントローラーと組み合わせる
この方法の利点の一つは、作りがシンプルなのでコードが複雑にならない点です。
下記はキー操作で動かせるようにしたスクリプトです。
適当なオブジェクトにアタッチしてください。


```C#:Camerawork.cs

using UnityEngine;

public class Comerawork : MonoBehaviour {

    public Transform horizontalRotNode;
    public Transform verticalRotNode;
    public Transform dollyNode;

    public const float DELTA_ANGLE = 1.0f;
    public const float DELTA_DOLLY = 0.05f;

    /**
     * 十字キーで回転 Z/Xキーでズーム
     */
    void Update () {
        RotateHorizontal();
        RotateVertical();
        Dolly();
	}

    private void RotateHorizontal()
    {
        float horizontalAngle = horizontalRotNode.localRotation.eulerAngles.y;

        if (Input.GetKey(KeyCode.RightArrow))
        {
            horizontalRotNode.localRotation = Quaternion.Euler(new Vector3(0, horizontalAngle + DELTA_ANGLE, 0));
        }
        else if (Input.GetKey(KeyCode.LeftArrow))
        {
            horizontalRotNode.localRotation = Quaternion.Euler(new Vector3(0, horizontalAngle - DELTA_ANGLE, 0));
        }
    }

    private void RotateVertical()
    {
        float verticalAngle = verticalRotNode.localRotation.eulerAngles.x;

        if (Input.GetKey(KeyCode.UpArrow))
        {
            verticalRotNode.localRotation = Quaternion.Euler(new Vector3(verticalAngle + DELTA_ANGLE, 0, 0));
        }
        else if (Input.GetKey(KeyCode.DownArrow))
        {
            verticalRotNode.localRotation = Quaternion.Euler(new Vector3(verticalAngle - DELTA_ANGLE, 0, 0));
        }
    }

    private void Dolly()
    {
        if (Input.GetKey(KeyCode.X))
        {
            dollyNode.transform.localPosition += new Vector3(0, 0, DELTA_DOLLY);
        }
        else if (Input.GetKey(KeyCode.Z))
        {
            dollyNode.transform.localPosition -= new Vector3(0, 0, DELTA_DOLLY);
        }
    }
}
```
publicプロパティはこのようにします。

![WS000002.JPG](https://qiita-image-store.s3.amazonaws.com/0/196069/ca2648e1-811c-1293-84fe-2d9ee0756ef2.jpeg)

これで入力を受け取って動くようになります。

スマホアプリを作っている方なら、上記スクリプトをタッチ操作に切り替えるだけで
めちゃくちゃ直観的に操作できますのでお試しあれ。

#応用2. Tweenと組み合わせる
直接Transformのプロパティを弄れるので、DOTweenなどのTween系Assetと相性が良いです。

#まとめ
誰かが書いてるような気もしますが見つけられなかったので。

[^1]: Cameraのズーム機能を使うわけではなく位置を変えるため、本当はズームではなくドリーです。ズームを使うとorthographicでは見栄えがよろしくないことになる場合があります。まぁでもその辺は好みで。