【Unity】【講座】カードゲーム学習まとめ

# はじめに
・シャドウバース風ゲーム開発講座を見て、新しく学んだ知識をまとめます。
参考サイト : [シャドバ風！？カードゲームの作り方](https://www.youtube.com/watch?v=CHIwhExGIxs&list=PLEkX-p0oUs8zRR4MNH1gJuWTmni60IGVm)

# 第1回 UIの実装
### 要素を等間隔に配置する。
・親要素のUI(PanelやImage)でAddComponentを選択し、「〇〇〇Layout Group」を追加する。
・PaddingやSpacingなどはHTMLと同じ使い方をする。

### UIのサイズを親に合わせる。
・子要素のAnchorの種類を「stretch」にして,PosXYZ, Width, Heightの値を0にする。

### 疑問点★
#### TextとTextMesh Proの違い

# 第2回 カードの生成
### 親を指定したインスタンス生成
```csharp:Generator.cs
        // ヒエラルキー上で親子関係を持たせたい場合に，第2, 3引数を指定する。
        // 第2引数は親となる要素のTransform
        // 第3引数はfalseであればプレハブの座標は親からの相対座標, trueであれば絶対座標
        // として使われる。
        Instantiate(cardPrefub, hand, false);
```

# 第3回 カードデータの生成
### ScriptableObjectによる外部データの管理
・外部データはcsv, txt, dbなどあるが,Unity上から値の変更が容易にできるものとして「ScriptableObject」を利用できる。
・1件/1ファイルとなるので，ファイル管理は煩雑になる。

①データの定義

```CSharp:Entity.cs
// fileName : デフォルトで生成されるファイル名
// menuName : メニュ上で表示されるテキスト
[CreateAssetMenu(fileName = "CardEntity", menuName = "Card Entity")]
// MonoBeheiverでなくScriptableObjectを継承する。
public class CardEntity : ScriptableObject
{
    public string name; // 名前
    public Sprite icon; // 画像
}
```

②データの作成
　ScriptやShaderなどと同様にProjectビューからCreateを選択し、CardEntityを選択する。
　データを入力する。

③データのロード

```Csharp:Model.cs
    CardEntity entity = Resources.Load<CardEntity>("★Pass★");
```
　Resourcesクラスを用いて、②で生成したファイルへのパスを設定する。
### 疑問点
#### ScriptableObjectを複数件あつかえないか。


# 第4回 カードの表示
### MVCモデルの利用
・MVCモデルを利用することで、データの更新処理(Model)と見た目の処理(View)が分割され、管理が容易となる。
・実装としてはControllerクラスの中に、Viewクラス及びModelクラスを保持する。

# 第5回 カードの移動

### イベントの実装
#### ① Rayを用いた処理
・カメラから飛ばしたRayがオブジェクトと衝突しているかを判定する。
・前提条件として衝突判定をするオブジェクトには「Collider(2D / 3D)」コンポーネントの付与が必要。
##### ①-1 2Dの場合
```CSharp:HitCheck2D
        if (Input.GetMouseButtonDown(0))
        {
            // マウスのクリックされたスクリーン上の座標をワールド座標に変換する。
            Vector2 worldPoint = Camera.main.ScreenToWorldPoint(Input.mousePosition);
            // 座標をもとに衝突情報を取得する。
            // 2Dのためdirectionは常にVector2.zeroで問題ないはず。
            RaycastHit2D hit2d = Physics2D.Raycast(worldPoint, Vector2.zero);
            // 衝突しているかどうか
            if (hit2d.collider != null) { // 衝突時の処理 }
        }
```
##### ①-2 3Dの場合
```CSharp:HitCheck3D
        if (Input.GetMouseButtonDown(0))
        {
            // マウスのスクリーン座標をRayに変換する。
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            // Ray情報をもとに衝突情報を取得する。 
            RaycastHit hit = new RaycastHit();
            if (Physics.Raycast(ray.origin, ray.direction, out hit, Mathf.Infinity)) { // 衝突時の処理 }
        }
```
#### ② EventSystemを用いた処理
・Unity4.6で登場し、Unity5.0からは標準になっている。
・Unityによって発行されるさまざまなイベント(マウスクリックなど)をトリガーとして、コールバック関数が実行される。
##### ②-1 Unity上から操作する。
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/505426/cfd0f2ad-64e5-c42d-5f49-bb79fa299cb4.png)
・イベント対象のオブジェクトに対してEvent Triggerコンポーネントを追加する。
　　- イベント種類
　　- イベント伝達先のオブジェクトと、それに付属するスクリプトのメソッド
　　- メソッドに渡すパラメタ(プリミティブ型1つ)
・メインカメラにRayCasterコンポーネントを追加する。
　　- 2D オブジェクトの場合、「Physics 2D Raycaster」を追加する。
　　- 3D オブジェクト または UIの場合、「Physics Raycaster」を追加する。

##### ②インターフェースを実装する。
```CSharp:EventListenerSample.cs
public class EventListenerSample : MonoBehaviour, IDragHandler
{
    // ドラッグ時のイベント
    public void OnDrag(PointerEventData eventData { // 処理あれそれ }
}
```
・イベント対象のオブジェクトに対して、イベントのインターフェースを実装したスクリプトをアタッチする。
・イベントの一覧については「参考サイト : サポートされているイベント」参照

#### OnDropとOnEndDragの違い
OnEndDrag : ドラッグが終了した時
OnDrop : ドラッグが終了した際、イベントを持つオブジェクトとドラッグのオブジェクトが異なる(オブジェクトが重なった時)

### カード移動の実装
カード移動の実装は3つのイベントで構成する。
①マウスがクリックされた際
・現在の親を保存する。
②マウスがクリックされている最中
・カードの座標にマウスの座標を設定する。
③マウスが離れた際
・その際選択中の要素を、カードの親にする。

### レイキャストのブロックとイベント実行
・GUI要素が複数重なっている場合，イベントは一番手前の要素に対してしか実行されない。
　なぜなら一番手前の要素がレイを遮断してしまうから。
　(イベントに使用されるレイはCanvasオブジェクトのGraphic Raycasterが使われていると推測。)
・後ろの要素でイベントを発生させるには、レイの遮断をさせないようにする必要がある。
・手前の要素に対して「Canvas Group」コンポーネントを追加し、「Blocks Raycasts」をfalseにする。
・詳細については「参考サイト : Canvas Group」を参照。
### 疑問点
・Dragしたものがカード以外に存在した場合、それらを見分ける方法。
 (TEPPENを例にするとロックマンのライフアップなど)

# 第8回 敵カードの移動
### 親子のコンポーネント取得
```csharp
  // 単一子要素からコンポーネント取得
  // 複数ある場合、深さ優先探索
  gameObject.GetComponentInChildren<TestScript>();
  
  // 複数子要素からコンポーネントの配列を取得
  gameObject.GetComponentsInChildren<TestScript>();
  
  // 親要素からコンポーネント取得
　// コンポーネントが見つかるまで再帰的に親をたどる。
  gameObject.GetComponentInParent<CardController>();

  // 複数親要素からコンポーネントの配列を取得
  gameObject.GetComponentInParent<CardController>();
　　
``` 

# 第11回 Playerカードの攻撃
### 疑問点★
unityにおけるシングルトン

# 第22回 ターン時間のカウントダウン
### コルーチンの停止
```CSharp
  // 同一スクリプト内のすべてのコルーチンを停止する。
  StopAllCoroutines();
```

# 第24回 敵AIの修正
```CSharp
  // 条件を満たす要素で新しい配列を作成する。
  Arrays.FindAll(配列, Predicate)
  
  // 配列の中で条件を満たす要素が存在するかどうか。
  Arrays.Exists(配列, Predicate)
```

# 第25回 敵AIのアニメーション
### Dotweenアセット
・Dotweenというアニメーションに特化した無料アセットを使用する。
[ドキュメント](http://dotween.demigiant.com/documentation.php)

```CSharp:animation.cs
transform.DOMove(field.position, 0.25f);
```

### アニメーションの考え方

```CSharp:animation.cs
IEnumerator DoMove() {

  // 移動前に必要なロジック　~~~

  // アニメーション処理
  transform.DOMove(new Vector3(3.0f, 3.0f, 3.0f, 0.25f);
  yield return new WaitForSeconds(0.25f);

  // 移動後に必要なロジック ~~~
}
```
・コルーチンを利用する。
・アニメーション処理とWait処理をセットで定義する。

### アニメーション時の操作の無効化
```csharp
  eventSystem.enable = false;
```
・イベントシステムごと無効化してあげる。

### 修正点
・フィールドのカードをつかんだままターンがタイムアップした場合、
そのカードが宙ぶらりんになってしまうため、タイムアップ時に
置きなおす処理が必要。(仮に設定した親のカードに対して、フィールドを親に付けなおす処理が必要　＆　ドラッグをPG上から解除させる処理が必要？)

# 特記事項なし
第6回 ターンの実装
第7回 ドローの実装
第9回 敵カードの攻撃
第10回 ステータス変更反映
第12回 攻撃可能カードの可視化
第13回 攻撃回数と表示の修正 
第14回 デッキの作成
第15回 Heroへの攻撃
第16回 敵カードがHeroへの攻撃
第17回 Result画面の表示
第18回 マナコスト
第19回 マナコストの修正
第20回 敵マナコストの実装
第21回 マナコストの増加
第23回 敵AIの時間制御
第26回 カードの並びを修正

# まとめ
・UI作成時は自動レイアウトコンポーネントを利用するとよい。
・アニメーションをする際はコルーチンとWait()を合わせて使用する。
・MVCを意識してロジックと見た目を分離するとよい。
・カードの移動などはEventSystemを利用して実装する。

# 参考サイト
[シャドバ風！？カードゲームの作り方](https://www.youtube.com/watch?v=CHIwhExGIxs&list=PLEkX-p0oUs8zRR4MNH1gJuWTmni60IGVm)

■ 第5回
[[Unity初心者Tips]オブジェクトがクリックされたか検知する方法、よく見かける？あの方法と比較](https://qiita.com/JunShimura/items/4547563fbb2691f40626)
[RaycastHit2D.collider](https://docs.unity3d.com/ja/2017.4/ScriptReference/RaycastHit2D-collider.html)
[サポートされているイベント](https://docs.unity3d.com/jp/current/Manual/SupportedEvents.html)
[Canvas Group](https://docs.unity3d.com/ja/current/Manual/class-CanvasGroup.html)

■ 第25回
[UnityのEventSystemを操る](http://chungames.hateblo.jp/entry/2015/11/21/234241)