氷の床を作る

スクリプトから摩擦を調整して氷のように滑る床を作ります。動作環境はUnity 2022.3.10です。

# ステージを作る
キャラクターが移動するための床となるオブジェクトを作って配置します。Hierarchyビューで右クリックして3D ObjectでCubeを選択します。オブジェクトの名前はCubeにしておきます。CubeのInspectorビューでTagの名前をFloorに設定します。これで普通の床が出来ました。次に氷の床を作ります。普通の床を作った時と同じ要領で氷の床のオブジェクトを作ります。オブジェクトの名前はIceFloorにします。普通の床と異なる点は、InspectorビューのTagの名前をIceに設定しておくことです。また氷のような色にするために、氷っぽい色のマテリアルを作ってIceFloorオブジェクトの色を変えます。スクリプトから色を変えたい場合は、以下のコードを作ってIceFloorオブジェクトにアタッチすることによって出来ます。

```C#:IceColor.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class IceColor : MonoBehaviour
{
    void Start()
    {
        GetComponent<Renderer>().material.color = new Color32(175, 223, 228, 1);
    }
}
```
普通の床と氷の床が作れたら、比較できるように位置と大きさを調整して2つのオブジェクトを図のように並べて配置します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3644510/6ab8dbe8-bdfb-f97c-d393-89338b266685.png)

# 操作するキャラクターを用意する
無料アセットでも何でもよいので好きなキャラクターを置きます。InspectorビューのAdd Componentをクリックして、キャラクターのオブジェクトにBox Colliderをアタッチします。以下のコードを書いてキャラクターにアタッチします。

```C#:PlayerController.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[RequireComponent(typeof(Rigidbody))]
public class PlayerController : MonoBehaviour
{
    Rigidbody rigidbody;
    public float force; //キャラクターを移動させるために加える力
    public float jumpPower; //ジャンプ力
    private bool isJumping = false; //ジャンプ判定
    private BoxCollider col;
    PhysicMaterial material, iceMaterial;

    void Start()
    {
        rigidbody = gameObject.GetComponent<Rigidbody>(); //Rigidbodyを取得
        rigidbody.constraints = RigidbodyConstraints.FreezeRotation; //キャラクターを回転させない
        col = GetComponent<BoxCollider>(); //BoxColliderを取得
        material = new PhysicMaterial(); //普通の床用のPhysicマテリアルを生成
        iceMaterial = new PhysicMaterial(); //氷の床用のPhysicマテリアルを生成
        material.staticFriction = 1;  //普通の床の静止摩擦係数を設定する
        material.dynamicFriction = 1; //普通の床の動摩擦係数を設定する
        iceMaterial.staticFriction = 1;     //氷の床の静止摩擦係数を設定する
        iceMaterial.dynamicFriction = 0.1f; //氷の床の動摩擦係数を設定する
        col.material = material; //普通の床用PhysicマテリアルをColliderに追加する
    }

    void Update()
    {
        if (Input.GetKey(KeyCode.UpArrow))
        {
            rigidbody.AddForce(force * Vector3.forward); //上矢印を押すと奥に移動
        }

        if (Input.GetKey(KeyCode.DownArrow))
        {
            rigidbody.AddForce(force * Vector3.back); //下矢印を押すと手前に移動
        }

        if (Input.GetKey(KeyCode.RightArrow))
        {
            rigidbody.AddForce(force * Vector3.right); //右矢印を押すと右に移動
        }

        if (Input.GetKey(KeyCode.LeftArrow))
        {
            rigidbody.AddForce(force * Vector3.left); //左矢印を押すと左に移動
        }

        if (Input.GetKeyDown(KeyCode.Space) && isJumping == false)
        {
            rigidbody.AddForce(Vector3.up * jumpPower); //ジャンプ判定falseの時にスペースキー入力で上向きに力を加える
            isJumping = true; //ジャンプ判定をtrueにする
        }
    }

    void OnCollisionEnter(Collision collision)
    {
        if (collision.gameObject.CompareTag("Floor"))
        {
            isJumping = false; //ジャンプ判定をfalseにする
            col.material = material; //普通の床用Physicマテリアルに切り替える
        }

        if (collision.gameObject.CompareTag("Ice"))
        {
            isJumping = false; //ジャンプ判定をfalseにする
            col.material = iceMaterial; //氷の床用Physicマテリアルに切り替える
        }
    }
}
```

コードの解説を簡単にしておきます。クラスの宣言の前に[RequireComponent(typeof(Rigidbody))]と書いてありますが、これを書いておいたらオブジェクトにRigidbodyをアタッチし忘れても自動でアタッチしてくれます。
Start関数の中では、RigidbodxやBoxColliderの取得、Physicマテリアルの生成を行っています。Physicマテリアルは普通の床用と氷の床用の2種類を生成します。氷の床用のマテリアルのdynamicFrictionには普通の床用のマテリアルのdynamicFrictionよりも小さな値を代入します。こうすることで動摩擦係数が小さくなり氷の床の方が普通の床と比較して滑りやすくなります。
Update関数の中にはキャラクターの移動の処理を書きます。
OnCollisionEnter関数の中の1つ目のIf文には、TagがFloorのオブジェクトである普通の床と衝突した場合の処理を書きます。普通の床にキャラクターが乗ったらジャンプ判定がfalseになり、Colliderのマテリアルを普通の床用Physicマテリアルに切り替えます。
2つ目のIf文には、TagがIceのオブジェクトと衝突した判定を書きます。ジャンプ判定をfalseにするところは普通の床の場合と共通ですが、ColliderのマテリアルをiceMaterialに切り替えています。
最後にInspectorビューのPlayer Controller項目のforceやjumpPowerの値を設定すれば完成です。

# 参考
https://wiz.ooo/cg/2226