サイバーエージェント　プロトスプリントリーグで学んだことまとめてみた　第2弾

# はじめ
kigです．前回に引き続き，プロトスプリントリーグで学んだことを自分のメモと共にまとめます．この調子だと次回が最終回になるかも？？

# 再掲
今回のプロトスプリントリーグで開発したゲームは↓になります，ぜひプレイしてね．
[UnityRoom: ChargeCat](https://unityroom.com/games/chargecat)
#### 対象者
Unityの入門書を読み終えた後に，実際に何か開発したことがある方におすすめです．
まだ何も作ってないよという方でも，一度読んでみて，「これ実装したいけどなんかあの記事であったような...」となってもらえれば嬉しいです．

# 目次
[1. Switch文の応用](#1-switch文の応用)
[2. namespace](#2-namespace)
[3. シングルトン&instance](#3-シングルトンinstance)
[4. Prefab Variant](#4-prefab-variant)
[5. GameObject Brush](#5-gameobject-brush)
[6. NavMeshAgent](#6-navmeshagent)
[おわり](#7おわり)

# 1. Switch文の応用
参考サイト：[初心者でもわかるswitch case構文ガイド](https://yossy.penne.jp/wordpress/2024/02/07/c-switch-case/)

Switch文自体はみなさんご存知だと思いますが，チームメンバーが私の知らないSwitch文を書いていたので，ここで紹介します．
### whenキーワード
```cs:Capter1_when.cs
    switch(score)
    {   
        case int n when (n >= 60):      // scoreが60以上なら「合格」と表示
            Debug.Log("合格");
            break;
        case int n when (n >= 50 && n <= 59):       // scoreが50〜59なら...(本来 n <= 59 は不要)
            Debug.Log("再試を受けられます");
            break;
        default:
            Debug.Log("不合格");
            break;
    }
```
whenキーワードを使用することで，条件の範囲指定，複数条件分岐が可能になります．

:::note warn
注意
case int n when (n >= 50 && n <= 59): の n <= 59は冗長です．
今回は複数条件分岐もできるよという意味で書いてます．
:::

### enumの使用
```cs:Chapter1_enum
    enum GameState
    {
        BeforeStart,
        Playing,
        Finished
    }
    // Start is called before the first frame update
    void Start()
    {
        GameState state = GameState.Playing;
        switch (state)
        {
            case GameState.BeforeStart:     // stateがPlayingなら
                Debug.Log("開始前");
                break;
            case GameState.Finished:        // stateがFinishedなら
                Debug.Log("終了");
                break;
            default:
                break;
        }
    }
```
[第1弾の記事](https://qiita.com/kig/items/402b469cc1b8034d031d)で紹介したenumも，switch文と組み合わせて使用できます．

### switch式
```cs:Chapter1_switch_string.cs
    string inputText = "";
    var result = inputText switch       // ゲームに登場するキャラの名前を入力すると，そのキャラ名に応じて返事をくれる
    {
        "放浪者" => "放浪者，かっこいいよね",
        "フリーナ" => "フリーナ，可愛いよね",
        _ => "それは誰だい？"
    };
```
もしinputTextが放浪者なら，resultに「放浪者，かっこいいよね」が代入されます．inputTextが放浪者でもフリーなでもなければ．resultに「それは誰だい？」が代入されます．
```cs:Chapter1_switch_int.cs
    int score = 0;
    var resultText = score switch
    { 
        int n when (n >= 60) => "合格",          // 60以上
        59 => "ギリギリ不合格",    // 59ちょうど
        _ => "不合格"            // 58以下
    };
```
intバージョンです．

if文のelse ifを増やすよりかは，switch文を使用することでコードは短くなりそうですね．

# 2. namespace
namespaceとは名前空間のことで，複数のクラスなどを1つの領域にまとめる機能です．
参考サイト：[C# の 名前空間](https://csharp.keicode.com/basic/namespaces.php)
```Chapter2_difine.cs
namespace Player
{
    class Hoge
    {
    
    }
}

namespace Enemy
{
    class Hoge
    {
        
    }
}
```

```cs:Chapter2_use.cs
using Player
class Use
{
    static void Main(string[] args)
    {
        Hoge hoge = new Hoge();    // PlayerのHogeがhogeに代入される
        // Player.Hoge hoge = new Player.Hoge();    using Playerと書かない場合の使用方法
    }
}
```
例が雑なコードになってしまいましたが，こんな感じ．このクラス名，重複しやすそうと思ったら使う感じかな？個人開発規模ではあまり使わなそう．

たまに，これは曖昧な定義ですみたいなエラーを目にしませんか？おそらくあのエラーは，同じクラス名の関数or値を使用してるから，namespaceまで指定してくれっていうエラーなのかなと思いました．

# 3. シングルトン&instance
参考動画：[シーン間でのデータ共有（シングルトンなど）](https://www.youtube.com/watch?v=dq-fyCmmz40)

ゲームの開始から終了まで，いろんなシーンを渡り歩くと思いますが，その全てのシーンでずっと参照していたい値とかってありますよね．マリオで言えば残機とか．ソシャゲだと課金アイテム．ガチャ画面やクエスト画面のコンティニュー，ショップ画面でも所持数を参照したいですよね．こういった時にシングルトンが活躍します．(staticも使用できますが，どっちがいいのかいまいち分からない．)
staticかシングルトンどちらが良いか調べていると，staticやシングルトンが危険というのも言われていました．ですが，個人開発であったり，大規模でないチーム開発，時間が欲しいハッカソンであれば楽するためにstaticやらシングルトンを使うのは良いと思います．(個人的な考え)
```cs:GameManager.cs
public class Gamemanager : MonoBehaviour
{
    public int hp = 100;
    static public GameManager instance
    pruvate void Awake()
    {
        if (instance == null)
        {
            instance = this;
            DontDestroyOnLoad(this.gameObject);
        }
        else 
        {
            Destroy(this.gameObject);
        }
    }
}
```
```cs:GetHp.cs
public class GetHp : MonoBehaviour
{
    void Start()
    {
        Debug.Log(GameManager.instance.hp)    // シングルトンからhpを取得
    }
}
```
GameManagerをEmptyObjectにでもアタッチすることで，シーンを跨いでも値を共有することができます．

シングルトンは値の共有だけでなく，シーンを跨いでもBGMが中断されないや，シーン遷移するボタンを押した際に音を鳴らすこともできます．(通常，ボタンを押すと同時にシーン遷移するため，音を鳴らすコードも破壊されて，音が鳴らない．)

# 4. Prefab Variant
あるPrefabと，そのPrefabに何かしらAddComponentを設定したもの両方をPrefab化したい！こういう時はPrefab Variantが使用できます．
参考サイト：[プレハブバリアントを使う](https://www.ame-name.com/archives/12124)

元のPrefabの値と比較できたり，このPrefabを継承したオブジェクトということもわかりますね．

+α：[C#における継承とは？初心者向けに解説](https://zenn.dev/daichi_gamedev/articles/ecde26bdbca887)

# 5. GameObject Brush
タイルマップ関連のお話です．<font color="red">2Dゲームを作る方は知っておくべき！！</font>

マリオみたいにブロックを配置していく時は，必ずタイルマップを使いましょう．BoxColliderを付けたブロックをPrefabから1個1個引っ張ってきて配置して〜は大変すぎます．(経験談)
当たり判定がある(プレイヤーが乗るだけの)ブロックならタイルマップのDefault Brushで良いですが，何かスクリプトが付いているブロックもBrushで配置したい！という時にGameObject Brushが使えます．めちゃくちゃ楽にステージ制作できますよ．

参考サイト：[タイルマップにゲームオブジェクトをぺたぺた貼れるGameObject Brush](https://gamedev65535.com/entry/unity_tilemap_gameobjectbrush/)
公式：[GameObject ブラシ](https://docs.unity3d.com/ja/Packages/com.unity.2d.tilemap.extras@3.0/manual/GameObjectBrush.html)

:::note warn
Brushで貼りたいオブジェクトは，グリッドのマス目に沿って配置しないとスポイトできません．

↓タイルマップを複数作る場合↓
貼りたいオブジェクトが，指定したタイルマップ(親)の子になっていないとスポイトできません．(Tile Paletteツールバーの選択〜塗りつぶしアイコンの真下に，親タイルマップを選択できるところがあります．)
:::
オブジェクトを配置する→スポイトを選択し，貼りたいオブジェクトをシーン画面で選択→ペタペタする．

# 6. NavMeshAgent
NavMeshAgent(AI)を使用することで，対象のオブジェクトに向かって接近してくる敵を作ることができます．
参考サイト：[NavMeshAgentを使ってキャラクターを自動的に動かす](https://qiita.com/SDDev0228/items/e2632e525e4874323fc8)

他にも，障害物(壁や扉)を避けて移動したりもできそうです．
参考サイト：[かしこくエモい動きの敵キャラはNavMeshを使いこなせ。](https://zenn.dev/k1togami/articles/71519622146168)

また，プレイヤーが近づいた時のみ追いかけたりと，調べると色々出てきたので，できることは多そうです．

# おわり
前回より少し難易度が高かったかもしれません．気になるものがあれば，リンク先の動画やサイト，または他のサイトも見てみてください．
2Dゲーム好きならGameObject Brushはめっちゃおすすめです！！！！！
また次回．