Unityを1ヶ月間勉強後、アプリを一つ製作したのでまとめ

##これは何
ゲーム開発がしたくて、Unityの勉強を一ヶ月間行った後、ゲームを一つ製作した。
iPhoneとAndroidの両方にbuildし、実機で遊べるようにした。
その中で詰まった点や学んだことについてまとめたもの。

##何で勉強したか？
・ドットインストール
・Unityの教科書2019

##学んだこと
- [Scriptファイルに元から記述されているメソッド二つの呼び出しタイミング](#scriptファイルに元から記述されているメソッド二つの呼び出しタイミング)
 - Start(): 起動時に一度呼ばれる
 - Update(): ワンフレーム毎に呼ばれる
- [publicをつけて変数を宣言すると、Unity上で触れるようになる](#publicをつけて変数を宣言するとunity上で触れるようになる)
- [Physics(Rigidbody, Collider)を使った衝突判定の実装方法](#physicsrigidbody-colliderを使った衝突判定の実装方法)
- [時間を遅らせてメソッドを呼ぶ方法2つ](#時間を遅らせてメソッドを呼ぶ方法2つ)
 - invoke
 - Coroutine

##詰まったところ
- [フリックした際に、フリック方向を上下左右の四方向で取得する方法](#フリックした際にフリック方向を上下左右の四方向で取得する方法)
- [onCollisionEnter内でinvokeを呼び出して、particleを発火させる方法](#oncollisionenter内でinvokeを呼び出してparticleを発火させる方法)
- [複数ある子オブジェクトを取得する方法](#複数ある子オブジェクトを取得する方法)
- AddForce()で横方向にPlayerを動かしたいのに、上下にブレる
- Playerが氷の上を滑っているような動きの実装
- iPhoneにbuildしようとした所、2つTheredが表示されできなかった

##ここから学んだ事の各詳細

###Scriptファイルに元から記述されているメソッド二つの呼び出しタイミング
- Start()メソッド: 起動時に一度呼ばれる
- Update(): ワンフレーム毎に呼ばれる

C#のscriptファイル製作時↓

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

public class NewBehaviourScript : MonoBehaviour
{
    // Start is called before the first frame update
    void Start() //起動時に一度呼ばれる
    {
        
    }

    // Update is called once per frame
    void Update() // ワンフレーム毎に呼ばれる
    {
        
    }
}

```

###publicをつけて変数を宣言すると、Unity上で触れるようになる
```
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class NewBehaviourScript : MonoBehaviour
{
    public GameObject Clear; //GameObject型のClear変数が宣言される
}

```
上記のように記述すると、下記スクショ赤枠のように、Clearという箇所が新しく表示される。
右側の枠にGameObjectをドラッグアンドドロップすると、選択したオブジェクトをscript上で簡単に使えるようになる。

![public.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/198412/ec1062e6-e8e0-f93b-769d-85a4010f2c9e.png)

Clearという名称のゲームオブジェクトを、上記の赤枠内右側にドラッグアンドドロップした場合、下記のように記述するとClearのRigidbodyを簡単に使える。

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

public class NewBehaviourScript : MonoBehaviour
{
    public GameObject Clear; //GameObject型のClear変数が宣言される

    // Start is called before the first frame update
    void Start()
    {
        Clear.GetComponent<Rigidbody>();
    }
}
```

###Physics(Rigidbody, Collider)を使った物理判定(今回は衝突判定)の実装方法
####Physicsとは？
Unityに標準で付属している物理エンジン。
Rigidbodyコンポーネントと、Colliderコンポーネントの二つからなる。今後ゲーム製作する上で滅茶苦茶よく使うと思う。
####Rigidbodyを使うと？
ゲームオブジェクトを物理特性によって制御する事ができるようになる。
詳しくはこちら→ [Rigidbody -Unity マニュアル](https://docs.unity3d.com/ja/2018.4/Manual/class-Rigidbody.html)
####Colliderを使うと？
物体の当たり判定の実装が出来る。

------------------
Playerと壁がある場合、下記のようにどちらかにrigidbodyをアタッチし、両方にcolliderをアタッチする必要がある。
Player: rigidbody + colllider
壁: collider

Physicsを使っている場合、onCollisionEnter()メソッドを使うことによって、衝突した時に処理を走らせる事が出来る。

onCollisionEnterやonCollisionExit等、一通りの衝突を検知するメソッドが見れる→ [【Unity】当たり判定を一通り!OnTrigger・OnCollisionをひとまとめ | 侍エンジニア塾ブログ（Samurai Blog） - プログラミング入門者向けサイト](https://www.sejuku.net/blog/83742)

###時間を遅らせてメソッドを呼ぶ方法2つ
####1. invoke
書き方

```
Invoke("呼び出すメソッド名", 秒数);
```

例: 宝箱のゲームオブジェクトに加えたscriptに記述しているのを想定。

```
    void OnCollisionEnter(Collision collision) 
    {
        if (collision.gameObject.tag == "Player") { // もし、衝突したゲームオブジェクトにPlayerというタグがついていた場合
            Invoke("open", 1.0f); // openメソッドを一秒後に読み込む
        }
    }

    // 宝箱が開いたときの音
    void open(){
        audSourse.PlayOneShot(openSE); //openSEという名称のaudioファイルを一度鳴らす処理
    }
```

Invokeの詳しい内容はこちら→ 
[【Unity】Invokeの使い方!実行タイミングを自在に操ろう | 侍エンジニア塾ブログ（Samurai Blog） - プログラミング入門者向けサイト](https://www.sejuku.net/blog/83762)

※豆知識: ちなみにInvokeは日本語に訳すと**呼び出す**という意味らしい。


####2. Coroutine
書き方

```
    // 呼び出す時
    StartCoroutine("ClearGame");
    
    //コルーチン関数を定義
    private IEnumerator ClearGame(){
        yield return new WaitForSeconds(秒数);
        SceneManager.LoadScene(0); //走らせたい処理
    }
```
例: 宝箱のゲームオブジェクトに加えたscriptに記述しているのを想定。

```
void OnCollisionEnter(Collision collision) 
    {
        if (collision.gameObject.tag == "Player") {
            StartCoroutine("ClearGame"); //ClearGameというコルーチン関数を呼ぶ
        }
    }
    
    private IEnumerator ClearGame() //ClearGameという名称のコルーチン関数を定義
    {
        yield return new WaitForSeconds(4.0f);//四秒後に以下に書いた処理が走る
        SceneManager.LoadScene(0); //0番のゲームシーンを読み込む
    }
```

コルーチンについての詳しい内容はこちら→ [Unityのコルーチンの使い方をまとめてみた - WonderPlanet Developers’ Blog](https://developers.wonderpla.net/entry/2014/09/02/205829)


詰まった所の、解決策や学んだことについてはこれから記載

##ここから詰まった所の各詳細

###フリックした際に、フリック方向を上下左右の四方向で取得する方法
3Dのゲームを製作したのですが、右斜め上や、左斜め下などの斜め方向のスワイプを上下左右のどれかに分類して取得するのにかなり詰まりました。
悩んみに悩み、ぐぐり倒して下記の記事に辿り着きかなり参考にさせていただきました。

参考にさせていただいた記事↓
[【Unity】フリックとスワイプ入力の同時取得方法【C#】](https://deve-cat.com/unity-flick-swipe/)

###onCollisionEnter内でinvokeを呼び出して、particleを発火させる方法

playerを操作して、宝箱に当たったらゲームクリアという内容で、**宝箱に当たったら二秒後に紙吹雪のパーティクルが発生する**ように処理を書いていました。

####何が原因だったのか？
particleにアタッチされているscriptに、下記のコードが記述されている事が原因だった。
ゲームスタートと同時に、三秒後に自分自身を破棄するメソッドが走っていた。

```
[SerializeField] private float timer = 3f;

    private void Start()
    {
        Destroy(gameObject, timer);
    }
```

このスクリプトのtimerの値を1000に変更することによって解決。

####ハマった理由
たまに宝箱に当たると、ちゃんと二秒後にパーティクルが発火する事があり、それにより原因の追求に紆余曲折時間がかかった。
#####悩んだ流れ
たまにパーティクル発火する事に気づき、発火する条件探しが始まる
↓
Clear(ゲームオブジェクト)
 ∟ clearParticle(パーティクルのアタッチされたゲームオブジェクト)
 ∟ clearParticle(パーティクルのアタッチされたゲームオブジェクト)
 
パーティクルは上記のようなヒエラルキーの構成にしており、clearParticleをforeachで取得する事によりパーティクルを発火させていた。foreachの既述の仕方がおかしいのかと思い探る。
Start()メソッドの中に既述するちゃんとパーティクルが発火したため、取得するためのコードに問題がない事を確認する。
↓
壁に一回当たった後だとパーティクルが発火し、二回当たるとパーティクルが発火しないという事に気づく。壁に当たった際にisKinematicをtrueにし、その後falseにする処理を書いていたのでそれが原因かと思い、playerのisKinematicのステータスをDebug.Logで確認しながらゲームをテストしたが問題なさそう。
ここでまず数時間溶けていた。
その後、壁に一回当たった後でもパーティクルが発火しない事がある事に気づく。
↓
壁に当たった回数ではなく、時間ではないか？と思い当たる。
5秒位経ってから宝箱に当たるとパーティクルが発火しない事に気づく。
ここら辺で色々いじっていたら新しくエラーログが出る。
ログの内容は、DestroyされているGameObjectを呼び出そうとしているよという内容だった。そこから、clearParticleオブジェクトor親オブジェクトのClearがDestroyされていると確認する。
しかしどこでパーティクルがDestroyされているのか分からず時間が溶けていく。
色々探った結果、clearParticleにscriptがアタッチされているのに気づき、中を見るとビンゴだった。

###複数ある子オブジェクトを取得する方法
Clear(ゲームオブジェクト)
 ∟ clearParticle(パーティクルのアタッチされたゲームオブジェクト)
 ∟ clearParticle(パーティクルのアタッチされたゲームオブジェクト )

上記のようなヒエラルキーの構成で、clearParticleを取得したい場合

####foreach文を使う
```
// Clear配下の、clearParticleにアタッチされたパーティクルを発火させたい場合のコード↓
Transform parentTransform = Clear.transform;
foreach (Transform child in parentTransform)
{
  child.GetComponent<ParticleSystem>().Play(); 
}
```

###AddForce()で横方向にPlayerを動かしたいのに、上下にブレる
これから記述
###Playerが氷の上を滑っているような動きの実装
これから記述
###iPhoneにbuildしようとした所、2つTheredが表示されできなかった
これから記述