[Unity] ゲームパッドで視点操作とカメラ移動の同期２(FPS的操作)

#はじめに
\***注意**\*この記事はプログラミングの基礎知識がある前提で進みます。
レベルとしては**C++でちょっと書いたことあるよ**とか、**Javaならいじったことあるぜ**、って人ならば十分に理解できるでしょう。
あと**高校数学の知識**を必要とします。
それと、**その１を見ないと多分意味わからないから見てね。**

#視点操作とカメラ移動の同期編
やっとタイトルが出てきましたね。
前回はこんなコードで終了しましたね。

```C#:move
void update(){
    float dx = Input.GetAxis("Horizontal");
    float dz = Input.GetAxis("Vertical");

    transform.Translate(dx, 0, dz, 0.0F);
}
```
さあ、何故ダメなのかを答え合わせしよう。
実際にやってみた人ならばわかるだろうが、**カメラの視点とカメラの移動が同期されていない**のです。

さて**ここからは最も重要な範囲であり、最も退屈な理論の時間**です。

###同期の理論
カメラの移動は**カメラの視点に同期する必要がある**と思いました。
じゃあどうして同期してやればいいでしょう。
私が思いついた方法を説明します。

実はその１で **sight_x の範囲を 0 ～ 360**にしましたね。
その理由が今回、**その値を利用して方角を決めるから**なのです。
**sight_x は z軸方向を正方向つまり 0度と定めた角度**なのです。

####上下入力があった場合
ではまず左スティックの上下入力があった場合を考えてみましょう。
![zahyo1.JPG](https://qiita-image-store.s3.amazonaws.com/0/393071/16210cdb-c4a2-2f12-16ce-62bca8046cb5.jpeg)
**カメラが向いている方向が sight_x度方向である**として、ベクトルの移動量が１であるとすると

```math
1^2 = x方向の移動量^2 + y方向の移動量^2
```
　　　　　　　　　　　　　　　　　　　　　つまり

```math
1 = sin(sight\_x)^2 + cos(sight\_x)^2
```
　　　　　　入力量は常に**1または-1であるとは限らない**ので、入力量を両辺にかける

```math
z^2 = (zsin(sight\_x))^2 + (zcos(sight\_x))^2
```
　　　　　　　したがって各成分を分解してみると、**z軸方法**の移動量を**dz1**とすると

```math
dz1 = zcos(sight\_x)
```
　　　　　　　　　　　　　　　　　**x軸方法**の移動量を**dx1**とすると

```math
dx1 = zsin(sight\_x)
```
　　　　　　　　　　　　　　　　　となることがわかりました。
####左右入力があった場合
これは**カメラが向いている方向から右に90度方向に進めばいい**ということになります。
ということは気づいた方もいると思いますが、**sight_x**に**90**を足せばいいということです。

```math
1 = sin(sight\_x+90)^2 + cos(sight\_x+90)^2
```
　　　　　　　　　　　　先ほどの理論より、x軸方向の移動量を掛けると

```math
x^2 = (xsin(sight\_x+90))^2 + (xcos(sight\_x+90))^2
```
　　　　　　　したがって各成分を分解してみると、**z軸方法**の移動量を**dz2**とすると

```math
dz2 = xcos(sight\_x+90)
```
　　　　　　　　　　　　　　　　　**x軸方法**の移動量を**dx1**とすると

```math
dx2 = xsin(sight\_x+90)
```
　　　　　　　　　　　　　　　　　となることがわかりました。
#結果
上下左右の入力から求めた移動量をあわせると**z軸方向の移動量をdz**、**x軸方向の移動量をdx**とすると、

```math
dz = dz1 + dz2 = zcos(sight\_x) + xcos(sight\_x+90)
```

```math
dx = dx1 + dx2 = zsin(sight\_x) + xsin(sight\_x+90)
```

となります。お疲れさまでした、理論は終わりです。

#実行
さあ、長い理論にお付き合いいただきましたので、さっそく使っていただきましょう。
先ほどの移動量の式をコードに変換すると

```C#:
float dx = Mathf.Sin(sight_x * Mathf.Deg2Rad) * z + Mathf.Sin((sight_x + 90f) * Mathf.Deg2Rad) * x;
float dz = Mathf.Cos(sight_x * Mathf.Deg2Rad) * z + Mathf.Cos((sight_x + 90f) * Mathf.Deg2Rad) * x;
```

このコードを追加して、コードを完成させると

```C#:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class クラス名 : MonoBehaviour
{

    void Start()
    {

    }

    float sight_x = 0;
    float sight_y = 0;

    void controller()
    {
        float x = Input.GetAxis("Horizontal");
        float z = Input.GetAxis("Vertical");
        float angleH = Input.GetAxis("Horizontal2") * 5.0f;
        float angleV = Input.GetAxis("Vertical2") * 5.0f;

        if (sight_x >= 360)
        {
            sight_x = sight_x - 360;
        }
        else if (sight_x < 0){
            sight_x = 360 - sight_x;
        }
        sight_x = sight_x + angleH;

        if (sight_y > 80)
        {
            if (angleV < 0)
            {
                sight_y = sight_y + angleV;
            }
        }
        else if (sight_y < -90)
        {
            if (angleV > 0)
            {
                sight_y = sight_y + angleV;
            }
        }
        else
        {
            sight_y = sight_y + angleV;
        }

        float dx = Mathf.Sin(sight_x * Mathf.Deg2Rad) * z + Mathf.Sin((sight_x + 90f) * Mathf.Deg2Rad) * x;

        float dz = Mathf.Cos(sight_x * Mathf.Deg2Rad) * z + Mathf.Cos((sight_x + 90f) * Mathf.Deg2Rad) * x;

        transform.Translate(dx, 0, dz, 0.0F);

        transform.localRotation = Quaternion.Euler(sight_y, sight_x, 0);

        //Debug.Log("sight_x:sight_y \n" + sight_x + " : " + sight_y);
        Debug.Log("dx:dz \n" + dx + " : " + dz);
    }

    void Update()
    {
        controller();
    }
}

```

よく頑張りました、これで**視点操作とカメラ移動の同期**を終了します。
何かわからないことがあればコメントで遠慮せずに尋ねてください。
私はすべてのプログラマーの味方でありたいと思っていますので。　　　それではさようならっ！！

#あとがき(自己紹介です、読まなくてもいいです)
私は**Vonlet**と申します。
プログラミング、電子工作、作曲などを生きがいにしています。
一番わかりやすいものでしたら、

**マクドナルド(シオンタウン店)**
https://www.nicovideo.jp/watch/sm34895662

**FutureHouse神社(bootleg).dondiablo**
https://www.nicovideo.jp/watch/sm34666016

などを作って恥を晒しています。よろしければ見に行ってやってください。

最後に自分のSNSを載せておきます
**YouTube** : https://www.youtube.com/channel/UCvL2cxUWsnBDT95jSq1G9QQ
**Twitter** : https://twitter.com/Vonlet
**ニコニコ動画** : https://www.nicovideo.jp/user/87637963
**Sound Cloud** : https://soundcloud.com/8yve6bc8icio