Learn how create 2D Idle Clicker Game in Unity Section4 学習メモ

# 概要
Learn how create 2D Idle Clicker Game in Unity Section4の学習メモです。
動きを把握するため、クラス図を書いたり実際に動かした際の試行錯誤を記録に残しています。


# 開発環境
IDE:Rider
Unity:2019.4.40
OS:Windows10

# 図
## 実現したい動き
新たにelevatorを作成しShaftのDepositに溜まっている金を集めElevatorのdepositに集約します。
以下イメージ
![twoMode1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/08f38280-29d7-4e8b-6ea6-c822571ccf6e.gif)

## クラス図

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/91b7526c-e902-ff60-1073-91d155ee217a.png)





クラス名|説明
---|---
Elevator|elevatorのDeposit そのLocationを定義しているクラス。
ElevatorUI| elevatorのuGuiを管理するクラス。Canvasオブジェクト以下のオブジェクトに作用。
ElevatorMiner|メインの処理が入っている。具体的にElevatorMinerが絡む金の授受、移動に関する処理を定義している
BaseMiner| ElevatorMinerの継承元



# 実装

## UnityEditor上の設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/53e0e3f9-7939-ba43-868f-055281e742ad.png)


オブジェクト名|説明
-----------|-----
Elevator|Elevatorスクリプト、ElevatorUIスクリプトがアタッチされている。
Canvas|uGuiのオブジェクトを配置。elevatorのdepositの所持金のラベルと　アップグレードボタン（未実装）の２つ
DepositLocation| Elevator側のDepositの座標。金をもったElevatorMinerはこの座標に到着するとelevatorのdepositに金を渡す。
Deposit|Depositスクリプトがアタッチされている。
ElevatorSprite|ElavatorMinerのアバター、エレベータの枠部分も含まれている。ElevatorMinerスクリプトがアタッチされている。



## コード部分
変数宣言のみでシンプルな構成です。
### Elevator.cs
```csharp:Elevator.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Elevator : MonoBehaviour
{
    [SerializeField] private Transform depositLocation;
    [SerializeField] private Deposit elevatorDeposit;

    public Deposit ElevatorDeposit => elevatorDeposit;
    public Transform DepositLocation => depositLocation;
}

```

### ElevatorUI.cs
これも短いしわかりやすいです。

```csharp:ElevatorUI.cs
public class ElevatorUI : MonoBehaviour
{
    [SerializeField] private TextMeshProUGUI elevatorDepositGoldText;

    private Elevator _elevator;
    
    private void Start()
    {
        _elevator = GetComponent<Elevator>();
    }

    
    private void Update()
    {
        elevatorDepositGoldText.text = _elevator.ElevatorDeposit.CurrentGold.ToString();
    }
}

```



### ElevatorMiner.cs
ぱっと見難しいですね。
全メソッドにDebug.Logを入れて処理を追ってきます。
```csharp:ElevatorMiner.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ElevatorMiner : BaseMiner
{
    [SerializeField] private Elevator elevator;
    public Vector3 DepositLocation => new Vector3(transform.position.x, elevator.DepositLocation.position.y);

    private Deposit _currentShaftDeposit;
    private int _currentShaftIndex = -1;

    public override void OnClick()
    {
        Debug.Log("<color=yellow>ElevatorMinerクラスのOnClickが実行されました。</color>");
        MoveToNextLocation();
        
    }

    private void MoveToNextLocation()
    {
        Debug.Log("<color=orange>ElevatorMinerクラスのMoveToNextLocationが実行されました。</color>");
        _currentShaftIndex++;
        Shaft currentShaft = ShaftManager.Instance.Shafts[_currentShaftIndex];
        _currentShaftDeposit = currentShaft.ShaftDeposit;
        Vector3 shaftDepositPos = currentShaft.DepositLocation.position;
        Vector3 fixedPos = new Vector3(transform.position.x, shaftDepositPos.y);
        MoveMiner(fixedPos);
    }

    protected override void CollectGold()
    {
        Debug.Log("<color=red>ElevatorMinerクラスのCollectGoldが実行されました。</color>");
        if (_currentShaftIndex == ShaftManager.Instance.Shafts.Count - 1 && !_currentShaftDeposit.CanCollectGold)
        {
            ChangeGoal();
            MoveMiner(DepositLocation);
            _currentShaftIndex = -1;
            return;
        }

        float amountToCollect = _currentShaftDeposit.CollectGold(this);
        float collectTime = amountToCollect / CollectPerSecond;
        StartCoroutine(IECollect(amountToCollect, collectTime));
    }

    protected override IEnumerator IECollect(float gold, float collectTime)
    {
        Debug.Log("<color=purple>ElevatorMinerクラスのIECollectが実行されました。</color>");
        yield return new WaitForSeconds(collectTime);

        if (CurrentGold < CollectCapacity && gold <= (CollectCapacity - CurrentGold))
        {
            CurrentGold += gold;
            _currentShaftDeposit.RemoveGold(gold);
        }

        yield return new WaitForSeconds(0.5f);

        if (CurrentGold < CollectCapacity && _currentShaftIndex != ShaftManager.Instance.Shafts.Count - 1)
        {
            MoveToNextLocation();
        }
        else
        {
            ChangeGoal();
            MoveMiner(DepositLocation);
            _currentShaftIndex = -1;
        }
    }

    protected override void DepositGold()
    {
        Debug.Log("<color=olive>ElevatorMinerクラスのDepositGoldが実行されました。</color>");
        if (CurrentGold <= 0)
        {
            ChangeGoal();
            MoveToNextLocation();
            return;
        }

        float depositTime = CurrentGold / CollectPerSecond;
        StartCoroutine(IEDeposit(depositTime));
    }

    protected override IEnumerator IEDeposit(float depositTime)
    {
        Debug.Log("<color=cyan>ElevatorMinerクラスのIEDepositが実行されました。</color>");
        yield return new WaitForSeconds(depositTime);
        
        elevator.ElevatorDeposit.DepositGold(CurrentGold);
        CurrentGold = 0;
        
        ChangeGoal();
        MoveToNextLocation();
    }
}

```

# 動かして確認

## Shaftの数を一つにした時
### 動かしている様子（gifアニメ）
ShaftのDepositにある金をElavatorのDepositに渡しているまでの様子です。

![OneMode1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/4c97b89f-189c-bbf3-bd2f-3f059cbf182c.gif)

### Shaft側に金がある時のログ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/eef51261-a9e5-f5b5-975d-23ae59e52d68.png)

MoveToNextLocation→CollectGold→IECollect→DepositGold→IEDepositの順で実行される。

### Shaft側に金がない時のログ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/9419b049-68c0-63a4-9a2f-aa47b7f51cf9.png)

MoveToNextLocation→CollectGold→DepositGold→ToNextLocationの順で実行される。
お金がある時と比べると、IEDepositの処理は抜けます。


## Shaftの数を2にした時の動き
### 動き（gifアニメ）
![twoMode1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/b24c92f5-3260-b8a2-11d1-583744701650.gif)


gifアニメの説明
以下の処理が行われています。

1.初期時点から１段目のshaftに移動しElevatorMinerがdepositに入っている金800を受け取る
2.２つ目のshaftに移動しElevatorMinerがdepositに入っている金200を受け取る
3.Elevatorのdepositに移動し、ElevatorMinerが持っている金1000をElevatorのdepositに渡す。


### コンソールログでの動き
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/bbbe04bd-41e1-4a76-663d-e957f918ca44.png)

上のログから以下のことがわかります。
下に行く動作（shaft側のdepoistから金を集める動き）
MoveToNextLocation→CollectGold→IECollectで実行される。
今回はshaftが２個あるため、MoveToNextLocation→CollectGold→IECollectを２周実行する。

上に行く動作（elevatorのdepositに金を渡す動く動作）
DepositGold→IEDepositの順で実行する。


# 感想
Section2のShaftMinerの応用だと思いました。
ElevatorMinerクラスが重要です。全メソッドにConsole.Logを加えて処理が追いやすくなります。

# 参考

Section4 Elevator

https://www.udemy.com/course/learn-how-to-create-a-2d-idle-clicker-game-in-unity-2021/