Unityの物理エンジンを使ってブロック崩しを作ってみた

# 作るもの
Unityをつかってブロック崩しを作成する。
仕様は以下の通り。

* プログラム実行と同時にボールが右上に向かって発射
* バーはキーボード矢印で操作。（面白そうなので上下にも動くようにする）
* ボールがバーより下の壁に当たると壁が消える
* ボールが、消えた壁の上を通過するとゲームオーバー
* ブロックに当たるとブロックが消える（ブロックは６つ）
* ブロックをすべて消してもクリア画面等は用意しない


# 開発環境

* Unity 2020.3.2f1
* Visual Studio Code 1.55.0

# 開発スタート

### １．ブロック崩しに必要なものを配置

* 床、壁、ボールなどのブロック崩しに必要なオブジェクトを画面に配置する。
* 追加は画面上部のバーから「アセット」>「作成」を選択して行う
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1035894/626c14bd-f5f4-49d1-fdf0-2c7250f9b3ef.png)

いろいろなアセットがありますが、今回配置するオブジェクトに使うのは「マテリアル」のみ！

↓マテリアルを追加するとボール状のものがプロジェクトに追加されます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1035894/6f17bb3b-a65b-99ce-7630-510f04187afc.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1035894/4925bdac-1683-4899-e7a3-21e8edda6d8a.png)

### ２．ボールに物理演算（物理エンジン）を付与する

Unityには様々な物理演算機能が用意されています
今回はその中でも

* Rigidbody （重力付与及び動作制御）
* Sphere Collider （球体の衝突に関する設定） 

#### Rigidbodyの追加

「コンポーネント>物理>リジットボディ」からプロパティを追加します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1035894/b540fc7f-7f78-e652-7674-3faf81ef5c18.png)

今回Y軸（高さ）方向に動いてほしくないので、Constraintsの位置を固定にてYをチェックします。
また、回転も特に必要ないのですべてにチェックをします。

#### Sphere Colliderの追加

「アセット>作成>物理マテリアル」からプロジェクトにアセットを追加します

↓こんなアセットが追加されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1035894/36e485b1-03ba-fb2e-8f84-9f86668bd44a.png)

ボールは等速でシンプルな動作をしてほしいので。
`摩擦ゼロ`  `物体に当たったら跳ね返る` 設定をします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1035894/aed6c60e-7c16-efb3-5586-4549bc02731b.png)

プロパティー説明

| プロパティー | 機能 |
|:-----------|:------------|
| Dynamic Friction | 移動している物体に対する摩擦。通常は、0 から 1 の間の値を使用します。0 の場合、氷のような感じになります。1 の場合、強い力や重力がオブジェクトを押さない限り、すぐに止まります。|
| Static Friction | 面上で静止しているオブジェクトに使用される摩擦。通常は、0 から 1 の間の値を使用します。0 の場合、氷のような感じになります。1 の場合、強い力を加えないとオブジェクトは動きません。|
| Bounciness | 表面にどれだけ弾性があるか。0 の場合は弾性がありません。1 の場合はエネルギーが減ることなく跳ねます。シミュレーションには少量のエネルギーを加えるかもしれませんが、ある程度の近似が予想されます。|
| Friction Combine | 衝突するオブジェクト間の摩擦をどう処理するか。|
| Bounce Combine | 衝突するオブジェクト間の跳ね返し度合いをどう処理するか。Friction Combineと同じです。|

以上の設定が完了したら、この物理マテリアルをボールの「Sphere Collider」に設定します。（マテリアルに設定した物理マテリアル名が表示されればOK）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1035894/23fa26cd-7635-bb71-0d04-a852516eb6ef.png)

### ３．スクリプトでものを動かす

物理エンジンでボールの動きは設定できたので、後は下記の動きをスクリプトで実装します。

①ゲームスタートでボールを右上に発射
②キーボードでバーを操作
③ボールがブロックにあたったらブロックを消す
④(おまけ)ボールが、バーより下を２回通過するとゲームオーバーの文字を表示

①④

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

public class ball : MonoBehaviour
{

    public float speed = 1.0f;
    private Rigidbody myRigid;
    private bool OutFlg = false; 

    public GameObject lightObj;
    public GameObject gameOverObj;

    light script; //UnityChanScriptが入る変数

    // ゲームスタートでボールを右上に発射
    void Start () {
        myRigid = this.GetComponent<Rigidbody>();
        myRigid.AddForce((transform.forward + transform.right) * speed, ForceMode.VelocityChange);
    }

    // (おまけ)ボールが、バーより下を２回通過するとゲームオーバーの文字を表示
    void Update()
    {
        if (this.transform.position.z < -7 && !OutFlg){
            OutFlg = true;
            lightObj.GetComponent<light>().removeLight();
            
            Rigidbody rd;
            rd = gameOverObj.GetComponent<Rigidbody>();
            rd.useGravity = true;
            Destroy(this.gameObject);
        }
    }
}
```

②

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

public class player : MonoBehaviour
{
    public float speed = 1.0f;

    // Start is called before the first frame update
    void Start()
    {
        
    }

    // キーボードでバーを操作
    void Update()
    {
        if (Input.GetKey(KeyCode.LeftArrow)){
            if(this.transform.position.x > -4)
                this.transform.position += Vector3.left * speed * Time.deltaTime;
        }

        if (Input.GetKey(KeyCode.RightArrow)){
            if(this.transform.position.x < 4)
                this.transform.position += Vector3.right * speed * Time.deltaTime;
        }

        if(Input.GetKey(KeyCode.UpArrow)){
            if(this.transform.position.z < 5.5)
                this.transform.position += Vector3.forward * speed * Time.deltaTime;
        }
        
        if(Input.GetKey(KeyCode.DownArrow)){
            if(this.transform.position.z > -5.5)
                this.transform.position += Vector3.back * speed * Time.deltaTime;
        }
    }

}
```

③

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

public class block : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }

    // ボールがブロックにあたったらブロックを消す
    private void OnCollisionEnter(Collision collision){
        Destroy(this.gameObject);
    }
}
```

### 以上で完成です

出来上がったものがこちら

<iframe width="560" height="315" src="https://www.youtube.com/embed/x2RAvcERf1Q" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>