Unityで3Dモデルを駆け回る。(インポートされた3Dモデルへの当たり判定付与、一人称視点、視点移動、向いてる方向に進む)

# 1.はじめに
## 1.1 経緯
夏休みの自由研究という名のお遊び。(僕たちはもう夏休みです！)
## 1.2 やりたいこと
大きく分けて問題が三つ
1. Cinema4D(モデリングソフト、有料版)等で作った3DモデルをUnityにインポート。当たり判定を付ける。
2. カメラについてマウスでFPSゲームみたいに視点を移動(一人称視点)
3. プレイヤーオブジェクトについて向いてる方向に移動
こんなんでゲームは作れそうです。

# 2.インポートしたモデルに当たり判定を付ける。
## 2.1 モデリングソフト側の設定(割と重要)
モデリングソフト、ツールは問いませんが、オブジェクトファイルにエクスポートできると思います。```Blender```で作ったモデルだと```Unity```はプロジェクトファイルのままでも読み込んでくれますがこれは使用しません。必ず**一つのオブジェクトとしてエクスポート**してください。一つのオブジェクトとしてというのは一つのメッシュとしてというのと同義です。後でUnityに配置したときに以下のように子オブジェクトが一つであれば大丈夫です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/263233/7723e57e-69ed-80e9-b73b-1e0a50b890ce.png)

ファイル形式は.objを推奨します。(マテリアルは適応されません)
## 2.2 当たり判定の付与
### 2.2.1 アセット「SAColliderBuilder」を導入
このままではオブジェクトがすり抜けてしまいますので当たり判定を付けましょう。しかし、Unityではこの当たり判定の設定、勝手にやってくれないんです。そこで使うのが```SAColliderBuilder```というアセットです。アセットストアから「SAColliderBuilder」と検索すれば出てきます。```Dawnload```して```import```しましょう。

### 2.2.2 モデルの配置
``Scene``ディレクトリ内に.objファイルをドラッグアンドドロップして、```Hierarchy```にそれを配置しましょう。この時2.1の画像のようになってればオッケーです。子オブジェクトが複数あるときは設定しなおしてください。

### 2.2.3 適応
子オブジェクト(2.1の画像では```default```)を選択してください。右の```Inspector```に```Mesh Filter```もしくは```Mesh Render```という項目がなければエクスポートからやり直してください。あれば```SAColliderBuilder```は適応できます。選択した状態で```Inspector```の一番最後、```Add Component```をおして検索窓から``SA``まで入れると何個かに絞られます。そこで``SA Mesh Collinder Builder``を選択しましょう。
![聖光学院立体モデル案内計画 - SampleScene - PC, Mac & Linux Standalone - Unity 2019.2.0b10 Personal _DX11_ 2019_07_26 19_18_57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/263233/1e19b778-a5ff-31ff-93c9-d5290666e837.png)
追加されたコンポーネント内の``Shape Type``を``Mesh``に、``Mesh Type``を``Convex Hull``にしたら``Process``を押して適応を始めましょう。**しばらくかかるので少し待ちましょう。**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/263233/6b370ab1-aef4-2eac-23f0-1c0c2e2cecef.png)
これで完了です。モデリングの仕方によって当たり判定の範囲が異なりました。特に階段など、一部を切り取る感じでモデリングすると変な当たり判定になります。ですが、当たり判定が想像していた形より小さくなることはないので、メッシュに埋まることはないと思います。

# 3.視点移動
一人称視点(追従)とマウスによる視点移動を実装します。まとめて``CameraSetter.cs``というファイルにしてしまいましょう。

```c#:CameraSetter.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CameraSetter : MonoBehaviour
{
    // 追従先
    public GameObject Player;
    // 視点回転スピード
    public float RotateSpeed = 0.1f;

    // 追従先との距離ベクトル
    private Vector3 OffsetVector;
    // 追従先のTransform
    private Transform PlayerTransform;

    void Start()
    {
        // 一番最初に一回だけ呼ばれる。
        // 追従先との距離を覚える。
        OffsetVector = transform.position - Player.transform.position;
        // 追従先のTransformを取る。(カメラが向いた方向に追従先も回転させるため)
        PlayerTransform = Player.GetComponent<Transform>();
    }

    void Update()
    {
        // 追従先との距離を保つ
        transform.position = Player.transform.position + OffsetVector;
        
        // マウスの回転を感知して回転ベクトル化
        Vector3 angle = new Vector3(
            Input.GetAxis("Mouse X") * 1.0f,
            Input.GetAxis("Mouse Y") * -1.0f,
            0
        );
        // 回転ベクトルをカメラのもとのベクトルに加算
        transform.eulerAngles += new Vector3(angle.y, angle.x);
        // 追従先も加算して回転させる。
        PlayerTransform.transform.eulerAngles += new Vector3(0, angle.x, 0);
        
    }
}
```

# 4.向いてる方向に進む
Wキーで前に、Sキーで後ろに移動しましょう。三角関数を使うのでわからない人はggってね★

```c#:PlayerSetter.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerSetter : MonoBehaviour {

    // 自分のオブジェクト
    public GameObject Player;
    // X軸への移動スピード
    public float MoveSpeedX = 20.0f;
    // Z軸への移動スピード
    public float MoveSpeedZ = 20.0f;

    // ジャンプの高さ
    private float MoveSpeedY = 10f;
    private Rigidbody rb;

    void Start()
    {
        // プレイヤーオブジェクトの物理演算数を取得。
        rb = Player.GetComponent<Rigidbody>();
    }

    // 毎フレームごとに実行される。
    void FixedUpdate() { 

        // wを押したとき
        if (Input.GetKey(KeyCode.W))
        {
            rb.AddForce(Mathf.Cos(transform.localEulerAngles.y * Mathf.Deg2Rad) * MoveSpeedX, 0, -Mathf.Sin(transform.localEulerAngles.y * Mathf.Deg2Rad) * MoveSpeedX);
        }
        
        // sを押したとき
        if (Input.GetKey(KeyCode.S))
        {Pla
            rb.AddForce(-Mathf.Cos(transform.localEulerAngles.y * Mathf.Deg2Rad) * MoveSpeedX, 0, Mathf.Sin(transform.localEulerAngles.y * Mathf.Deg2Rad) * MoveSpeedX);
        }

        // スペースを押したとき
        if (Input.GetKeyDown(KeyCode.Space))
        {
            Vector3 go = new Vector3(0, MoveSpeedY, 0);
            rb.velocity = go;

        }
    }
}
```

# 5.適応
カメラをプレイヤーオブジェクトの目の位置に設置して、```CameraSetter.cs```をカメラに``PlayerSetter.cs``をプレイヤーオブジェクトに適応しましょう。あとはそれぞれの``Inspector``で適応したファイルの設定をすませばOKです。**あ、プレイヤーオブジェクトにリジッドボディのコンポーネントを付けるのを忘れないようにしてください。**

# 6.まとめ
ということでこんなちょっとしたコードでFPSで大地を駆け回ることができました。


キャラクターの動かし方ですが、``AddForce``でよかったのでしょうか？ちょっと違和感を感じます。(特にジャンプとか)
**どなたか教えていただけると幸いです。**


ではよい夏休みを！
Twitter: https://twitter.com/Cyber_Hacnosuke (フォローしてくださいお願いします。)