1. 程式人生 > >Unity 實現簡單的關卡管理系統

Unity 實現簡單的關卡管理系統

今天我們嘗試實現一個簡單的關卡管理系統。
先想想關卡都需要什麼功能?
在我基本的考慮下主要有:
1.投放物體(主角,道具,怪物)
2.控制關卡流程(比如,小關卡順序,怪物波次)
3.觸發各種事件(比如觸發劇情,啟用技能,啟用碰撞牆等等)

OK,知道我們需要什麼了,那我們就開始考慮要怎麼製作了。
在一個大關卡中,往往會劃分多個小的戰鬥區,玩家要控制角色依次通過戰鬥區域,獲得勝利,所以我們首要目標是要實現這些小的戰鬥區。
目標確定,那需要考慮一下戰鬥區一般的形狀:
1.矩形
2.圓形
3.不規則多邊形(這個實現較為複雜,暫且不考慮)
4.扇形(沒考慮到使用的地方,先繪製放一邊吧)
主要的還是矩形,和圓形。不規則多邊形,實現較為複雜,尚未研究。但是我們可以通過矩形實現不規則多變型的範圍管理。
那我們開始繪製戰鬥區
指令碼CheckPoint

//此指令碼為小戰鬥區控制指令碼
//首先實現戰鬥區範圍控制,我們採用 Gizmos.DrawMesh() 的方式來繪製戰鬥區範圍

public enum CheckRange
{
    Round, //圓形
    Fan, //扇形
    Rect //矩形
}
public class CheckPoint : MonoBehaviour {

    //戰鬥區形狀
    [Space(20)]
    public CheckRange CheckRange = CheckRange.Round;
    //圓形半徑
    [Header("Round:")]
    public float
RoundRadio = 0; //扇形引數 [Header("Fan")] //角度 public float FanEnagle = 0; //最小距離 [Range(0,1)] public float FanMinRange = 0; //最大劇情 public float FanMaxRange = 0; //獲取最小距離 public float GetFanMinRange { get { return FanMaxRange * FanMinRange; } } //矩形範圍
[Header("Rect")] //長度 public float RectWidth = 0; //寬度 public float RectHeight = 0; //是否繪製Gizmos public bool IsGzimos = false; void OnDrawGizmos() { if (!IsGzimos) return; DrawGizmos(); } //繪製mesh void DrawGizmos() { switch (CheckRange) { case CheckRange.Round: Mesh round = MeshTools.MeshRound(RoundRadio,60); Gizmos.color = new Color(1,0,0,0.5f); Gizmos.DrawMesh(round,transform.position); break; case CheckRange.Fan: Mesh fan = MeshTools.MeshFan(FanEnagle, FanMaxRange, GetFanMinRange); Gizmos.color = new Color(1, 0, 0, 0.5f); Gizmos.DrawMesh(fan, transform.position); break; case CheckRange.Rect: Mesh rect = MeshTools.MeshRect(transform.position, RectWidth, RectHeight); Gizmos.color = new Color(1, 0, 0, 0.5f); Gizmos.DrawMesh(rect, transform.position); break; } } }

指令碼:MeshTools 此指令碼主要是繪製mesh

//此指令碼主要是繪製mesh
using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class MeshTools {

    /// <summary>
    /// 圓形
    /// </summary>
    /// <param name="radio"></param>
    /// <param name="pointAmount"></param>
    /// <returns></returns>
    public static Mesh MeshRound(float radio,int pointAmount)
    {
        float eachAngle = 360f / pointAmount;
        List<Vector3> vertices = new List<Vector3>();
        for (int i = 0; i <= pointAmount; i++)
        {
            Vector3 pos = Quaternion.Euler(0f, eachAngle * i, 0f) * Vector3.forward * radio;
            vertices.Add(pos);
        }
        int[] triangles;
        Mesh mesh = new Mesh();

        int trangleAmount = vertices.Count - 2;
        triangles = new int[3 * trangleAmount];

        for (int i = 0; i < trangleAmount; i++)
        {
            triangles[3 * i] = 0;
            triangles[3 * i + 1] = i + 1;
            triangles[3 * i + 2] = i + 2;
        }
        mesh.vertices = vertices.ToArray();
        mesh.triangles = triangles;
        mesh.RecalculateNormals();
        mesh.RecalculateBounds();
        return mesh;
    }

    /// <summary>
    /// 矩形
    /// </summary>
    /// <param name="target"></param>
    /// <param name="width"></param>
    /// <param name="height"></param>
    /// <returns></returns>
    public static Mesh MeshRect(Transform target,float width, float height)
    {

        List<Vector3> vertices = new List<Vector3>();
        vertices.Add(new Vector3(0, 0, 0) - target.right * (width / 2));
        vertices.Add(new Vector3(0, 0, 0) - target.right * (width / 2) + target.forward * height);
        vertices.Add(new Vector3(0, 0, 0) + target.right * (width / 2) + target.forward * height);
        vertices.Add(new Vector3(0, 0, 0) + target.right * (width / 2));

        int[] triangles;
        Mesh mesh = new Mesh();

        int trangleAmount = vertices.Count - 2;
        triangles = new int[3 * trangleAmount];

        for (int i = 0; i < trangleAmount; i++)
        {
            triangles[3 * i] = 0;
            triangles[3 * i + 1] = i + 1;
            triangles[3 * i + 2] = i + 2;
        }

        mesh.vertices = vertices.ToArray();
        mesh.triangles = triangles;
        mesh.RecalculateNormals();
        mesh.RecalculateBounds();

        return mesh;
    }

    /// <summary>
    /// 矩形
    /// </summary>
    /// <param name="pos"></param>
    /// <param name="width"></param>
    /// <param name="height"></param>
    /// <returns></returns>
    public static Mesh MeshRect(Vector3 pos, float width, float height)
    {
        List<Vector3> vertices = new List<Vector3>();
        vertices.Add(new Vector3(width / 2, pos.y,height / 2));
        vertices.Add(new Vector3( width / 2, pos.y, -height / 2));
        vertices.Add(new Vector3(-width / 2, pos.y, -height / 2));
        vertices.Add(new Vector3(-width / 2, pos.y, height / 2));

        Mesh mesh = new Mesh();
        int[] triangles = new int[3 * 2];
        triangles[0] = 0;
        triangles[1] = 1;
        triangles[2] = 2;
        triangles[3] = 0;
        triangles[4] = 2;
        triangles[5] = 3;

        mesh.vertices = vertices.ToArray();
        mesh.triangles = triangles;
        mesh.RecalculateNormals();
        mesh.RecalculateBounds();
        return mesh;
    }

    /// <summary>
    /// 扇形
    /// </summary>
    /// <param name="angle"></param>
    /// <param name="maxRadio"></param>
    /// <param name="minRadio"></param>
    /// <returns></returns>
    public static Mesh MeshFan(float angle,float maxRadio,float minRadio)
    {
        //因為vertices(頂點)的個數與triangles(索引三角形頂點數)必須匹配
        int vertices_count = 60 * 2 + 2;            
        Vector3[] vertices = new Vector3[vertices_count];
        float angleRad = Mathf.Deg2Rad * angle;
        float angleCur = angleRad;
        float angledelta = angleRad / 60;
        for (int i = 0; i < vertices_count; i += 2)
        {
            float cosA = Mathf.Cos(angleCur);
            float sinA = Mathf.Sin(angleCur);

            vertices[i] = new Vector3(maxRadio * cosA, 0, maxRadio * sinA);
            vertices[i + 1] = new Vector3(minRadio * cosA, 0, minRadio * sinA);
            angleCur -= angledelta;
        }

        //triangles:
        int triangle_count = 60 * 6;
        int[] triangles = new int[triangle_count];
        for (int i = 0, vi = 0; i < triangle_count; i += 6, vi += 2)
        {
            triangles[i] = vi;
            triangles[i + 1] = vi + 3;
            triangles[i + 2] = vi + 1;
            triangles[i + 3] = vi + 2;
            triangles[i + 4] = vi + 3;
            triangles[i + 5] = vi;
        }

        Mesh mesh = new Mesh();
        mesh.vertices = vertices;
        mesh.triangles = triangles;

        mesh.RecalculateNormals();
        mesh.RecalculateBounds();

        return mesh;
    }
}

如此在Unity的Scene視窗中可以看見我們繪製的範圍了。
顯示效果:
這裡寫圖片描述
好吧,範圍畫好了,我們接來需要考慮什麼呢?
戰鬥區,戰鬥區得需要有怪物吧,應該考慮投放怪物了,然而在一個戰鬥區中,往往會存在好幾波的怪物。這個要怎麼控制呢?
不然我們在戰鬥區得下面在建立一個指令碼 CheckPointWave,用來控制管理怪物或道具的投放。
那我們就需要考慮一下怪物的投放了
1.隨機投放(這個怎麼感覺用的應該都很少吧)
2.指定位置投放
還要考慮一下,我們怎麼控制著一波是否結束了呢?
我選擇最簡單的方式,那就沒死一隻怪物就會與當前投放的怪物數量進行比較,如果相等,那就代表著結束了。
指令碼:CheckPointWave 此指令碼為波數管理控制指令碼

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

public class CheckPointWave : MonoBehaviour {

    /// <summary>
    /// 波數 
    /// </summary>
    public int Index = 0;
    /// <summary>
    /// 當波數結束時
    /// </summary>
    public Action OnWaveFinsh;

    /// <summary>
    /// 所屬戰鬥區
    /// </summary>
    [SerializeField]
    private CheckPoint CheckPoint;

    /// <summary>
    /// 隨機建立
    /// </summary>
    public WaveRandomCreate RandomCreate;
    /// <summary>
    /// 指定位置建立
    /// </summary>
    public List<WavePosCreate> PosCreate = new List<WavePosCreate>();
    /// <summary>
    /// 下一波
    /// </summary>
    [SerializeField]
    private CheckPointWave NextWave;

    /// <summary>
    /// 怪物列表
    /// </summary>
    private List<Actor> MonsterActor = new List<Actor>();
    /// <summary>
    /// 怪物數量
    /// </summary>
    public int MonsterNum { get { return RandomCreate.CreateNum + PosCreate.Count; } }
    /// <summary>
    /// 死亡數量
    /// </summary>
    public int DeathNum = 0;
    /// <summary>
    /// 開始事件
    /// </summary>
    public List<CpAction> OnStart = new List<CpAction>();
    /// <summary>
    /// 結束事件
    /// </summary>
    public List<CpAction> OnEnd = new List<CpAction>();

    /// <summary>
    /// 設定所屬戰鬥區
    /// </summary>
    /// <param name="cp"></param>
    public void SetCheckPoint(CheckPoint cp)
    {
        CheckPoint = cp;
    }

    /// <summary>
    /// 設定下一波
    /// </summary>
    /// <param name="nextWave"></param>
    public void SetNextWave(CheckPointWave nextWave)
    {
        NextWave = nextWave;
    }

    /// <summary>
    /// 當波數啟用
    /// </summary>
    public void OnActive()
    {
        //開始事件
        if (OnStart.Count > 0)
        {
            for (int i = 0; i < OnStart.Count; i++)
                CheckPoint.CpManager.DoCpAction(OnStart[i].ActionType, OnStart[i].ActionParam);
        }
        StartCoroutine(CreateActor());
        //設定當前正在進行的是那一撥
        CheckPoint.CpManager.SetCurWave(this);
    }

    /// <summary>
    /// 建立怪物
    /// </summary>
    /// <returns></returns>
    IEnumerator CreateActor()
    {
        if (RandomCreate.CreateNum != 0)
        {
            for (int i = 0; i < RandomCreate.CreateNum; i++)
            {
                yield return new WaitForSeconds(0.02f);
                int index = UnityEngine.Random.Range(0, RandomCreate.MonsterID.Count);
                CheckPoint.CpManager.CreateActor(RandomCreate.MonsterID[index], CheckPoint.GetRandomPos(), delegate(Actor actor) {
                    DeathNum++;
                    OnFinsh();
                },delegate(Actor actor) {
                    MonsterActor.Add(actor);
                });
            }
        }

        if (PosCreate.Count > 0)
        {
            for (int i = 0; i < PosCreate.Count; i++)
            {
                yield return new WaitForSeconds(0.02f);
                CheckPoint.CpManager.CreateActor(PosCreate[i].MonsterID, PosCreate[i].Postion, delegate(Actor actor) {
                    DeathNum++;
                    OnFinsh();
                }, delegate (Actor actor) {
                    MonsterActor.Add(actor);
                });
                DeathNum++;
                OnFinsh();
            }
        }
    }

    /// <summary>
    /// 殺死所有怪物
    /// </summary>
    /// <param name="isPoint"></param>
    public void kill(bool isPoint = false)
    {
        if (isPoint) NextWave = null;
        for (int i = 0; i < MonsterActor.Count; i++)
        {
            if (!MonsterActor[i].ActorAttr.IsDeath)
                MonsterActor[i].Kill();
        }
    }

    /// <summary>
    /// 拍段當前這波是否結束
    /// </summary>
    public void OnFinsh()
    {
        if (DeathNum != MonsterNum) return;
        MonsterActor.Clear();
        //結束事件
        if (OnEnd.Count > 0)
        {
            for (int i = 0; i < OnEnd.Count; i++)
                CheckPoint.CpManager.DoCpAction(OnEnd[i].ActionType,OnEnd[i].ActionParam);
        }
        //拍段是否進行下一波
        if (NextWave != null)
        {
            NextWave.OnActive();
            return;
        }
        //如果是最後一波控制當前戰鬥區結束
        CheckPoint.OnFinsh();
    }

}

/// <summary>
/// 隨機建立
/// </summary>
[System.Serializable]
public class WaveRandomCreate
{
    public int CreateNum;
    public float MinDis = 1;
    public List<string> MonsterID = new List<string>();
}
/// <summary>
/// 固定位置建立
/// </summary>
[System.Serializable]
public class WavePosCreate
{
    public string MonsterID;
    public Vector3 Postion;
}

主要功能:
1.波數管理器啟用

 /// <summary>
    /// 當波數啟用
    /// </summary>
    public void OnActive()
    {
        //開始事件
        if (OnStart.Count > 0)
        {
            for (int i = 0; i < OnStart.Count; i++)
                CheckPoint.CpManager.DoCpAction(OnStart[i].ActionType, OnStart[i].ActionParam);
        }
        StartCoroutine(CreateActor());
        //設定當前正在進行的是那一撥
        CheckPoint.CpManager.SetCurWave(this);
    }

2.建立怪物或道具

    /// <summary>
    /// 建立怪物
    /// </summary>
    /// <returns></returns>
    IEnumerator CreateActor()
    {
        if (RandomCreate.CreateNum != 0)
        {
            for (int i = 0; i < RandomCreate.CreateNum; i++)
            {
                yield return new WaitForSeconds(0.02f);
                int index = UnityEngine.Random.Range(0, RandomCreate.MonsterID.Count);
                CheckPoint.CpManager.CreateActor(RandomCreate.MonsterID[index], CheckPoint.GetRandomPos(), delegate(Actor actor) {
                    DeathNum++;
                    OnFinsh();
                },delegate(Actor actor) {
                    MonsterActor.Add(actor);
                });
            }
        }

        if (PosCreate.Count > 0)
        {
            for (int i = 0; i < PosCreate.Count; i++)
            {
                yield return new WaitForSeconds(0.02f);
                CheckPoint.CpManager.CreateActor(PosCreate[i].MonsterID, PosCreate[i].Postion, delegate(Actor actor) {
                    DeathNum++;
                    OnFinsh();
                }, delegate (Actor actor) {
                    MonsterActor.Add(actor);
                });
                DeathNum++;
                OnFinsh();
            }
        }
    }

3.結束,開始下一波,還是結束戰鬥區

 /// <summary>
    /// 拍段當前這波是否結束
    /// </summary>
    public void OnFinsh()
    {
        if (DeathNum != MonsterNum) return;
        MonsterActor.Clear();
        //結束事件
        if (OnEnd.Count > 0)
        {
            for (int i = 0; i < OnEnd.Count; i++)
                CheckPoint.CpManager.DoCpAction(OnEnd[i].ActionType,OnEnd[i].ActionParam);
        }
        //拍段是否進行下一波
        if (NextWave != null)
        {
            NextWave.OnActive();
            return;
        }
        //如果是最後一波控制當前戰鬥區結束
        CheckPoint.OnFinsh();
    }

恩恩,注意了,在程式碼中的Actor 類,為我想專案的演員物件,這個地方應該替換為你們自己演員物件

恩波數也有了,注意了,我們在程式碼中加入了兩個事件列表

    /// <summary>
    /// 開始事件
    /// </summary>
    public List<CpAction> OnStart = new List<CpAction>();
    /// <summary>
    /// 結束事件
    /// </summary>
    public List<CpAction> OnEnd = new List<CpAction>();

分別控制著當這波啟用觸發的事件和當這波結束後觸發的事件。這個咋們下面再說,你只要注意到了就好…

現在好了,戰鬥區有了,波數控制也有了。那接下來呢?
現在我們來補充一下控制區部分的程式碼,因為我們需要獲取到波數控制器啊,並且還要管理波數控制器的先後順序呢?在這裡我放出完整的CheckPoint 指令碼:
指令碼:CheckPoint

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

public enum CheckRange
{
    Round,
    Fan,
    Rect
}

public class CheckPoint : MonoBehaviour {

    /// <summary>
    /// 戰鬥區ID
    /// </summary>
    public int Index = 0;
    /// <summary>
    /// 戰鬥區下一個ID
    /// </summary>
    public int NextIndex = -1;
    /// <summary>
    /// 是否啟用
    /// </summary>
    public bool IsActive = false;
    /// <summary>
    /// 是否檢測玩家
    /// </summary>
    public bool IsDetActor = false;
    /// <summary>
    /// 關卡管理器
    /// </summary>
    [SerializeField]
    public CheckPointManager CpManager { get; private set; }
    /// <summary>
    /// 下一個戰鬥區
    /// </summary>
    [SerializeField]
    private CheckPoint NextCheckPoint;
    /// <summary>
    /// 當前戰鬥區所有的波數管理器
    /// </summary>
    [SerializeField]
    private List<CheckPointWave> Waves = new List<CheckPointWave>();
    /// <summary>
    /// 當戰鬥區結束事件
    /// </summary>
    public Action OnCheckFinsh;

    [Header("當進入戰鬥開始時:")]
    public List<CpAction> OnStartAction = new List<CpAction>();
    [Header("當在戰鬥區時:")]
    public List<CpAction> OnInsertAction = new List<CpAction>();
    [Header("當戰鬥區結束時:")]
    public List<CpAction> OnEndAction = new List<CpAction>();

    //戰鬥區形狀
    [Space(20)]
    public CheckRange CheckRange = CheckRange.Round;
    //圓形半徑
    [Header("Round:")]
    public float RoundRadio = 0;
    //扇形引數
    [Header("Fan")]
    //角度
    public float FanEnagle = 0;
    //最小距離
    [Range(0, 1)]
    public float FanMinRange = 0;
    //最大劇情
    public float FanMaxRange = 0;
    //獲取最小距離
    public float GetFanMinRange
    {
        get
        {
            return FanMaxRange * FanMinRange;
        }
    }

    //矩形範圍
    [Header("Rect")]
    //長度
    public float RectWidth = 0;
    //寬度
    public float RectHeight = 0;
    //是否繪製Gizmos
    public bool IsGzimos = false;

    /// <summary>
    /// 設定關卡管理器
    /// </summary>
    /// <param name="cpManager"></param>
    public void SetCPManager(CheckPointManager cpManager)
    {
        CpManager = cpManager;
    }
    /// <summary>
    /// 設定下一個戰鬥區
    /// </summary>
    /// <param name="cp"></param>
    public void SetNextCp(CheckPoint cp)
    {
        NextCheckPoint = cp;
    }

    void Start()
    {
        //獲取所有的波數管理器
        CheckPointWave[] wave = transform.GetComponentsInChildren<CheckPointWave>();
        for (int i = 0; i < wave.Length; i++)
        {
            wave[i].SetCheckPoint(this);
            Waves.Add(wave[i]);
        }
        //根據波數管理器id進行排序
        Waves.Sort((r1,r2)=> { if (r1.Index > r2.Index) return 1; else if (r1.Index == r2.Index) return 0;return -1; });
        //設定波數
        for (int i = 0; i < Waves.Count; i++)
        {
            if (i != Waves.Count - 1)
                Waves[i].SetNextWave(Waves[i + 1]);
            else
                Waves[i].SetNextWave(null);
        }
    }

    void Update()
    {
        if (CpManager == null) return;
        if (Waves.Count < 1) return;
        if (!IsDetActor) return;
        ///檢測玩家是否進入管戰鬥區
        for (int i = 0; i < CpManager.DetActor.Count; i++)
        {
            if (DetActor(CpManager.DetActor[i]))
            {
                OnActive();
                IsDetActor = false;
            }
        }
    }

    /// <summary>
    /// 啟用戰鬥區
    /// </summary>
    public void OnActive()
    {
        IsActive = true;
        ///設定當前戰鬥區
        CpManager.SetCurCheckPoint(this);
        //第一波啟用
        Waves[0].OnActive();
        if (OnStartAction.Count > 0)
        {
            for (int i = 0; i < OnStartAction.Count; i++)
                CpManager.DoCpAction(OnStartAction[i].ActionType, OnStartAction[i].ActionParam);
        }
    }

    /// <summary>
    /// 戰鬥區結束
    /// </summary>
    public void OnFinsh()
    {
        IsActive = false;

        if (OnEndAction.Count > 0)
        {
            for (int i = 0; i < OnEndAction.Count; i++)
                CpManager.DoCpAction(OnEndAction[i].ActionType,OnEndAction[i].ActionParam);
        }

        if (NextCheckPoint != null)
        {
            NextCheckPoint.IsDetActor = true;
            return;
        }
        CpManager.OnFinsh();
    }

    /// <summary>
    /// 檢測玩家是否進入戰鬥區
    /// </summary>
    /// <param name="actor"></param>
    /// <returns></returns>
    bool DetActor(Actor actor)
    {
        bool IsActive = false;
        switch (CheckRange)
        {
            case CheckRange.Round:
                IsActive = Vector3.Distance(actor.position,transform.position)<= RoundRadio;
                break;
            case CheckRange.Fan:

                break;
            case CheckRange.Rect:
                Vector2 pos1 = new Vector2(transform.position.x+ RectWidth/2,transform.position.z+RectHeight/2);
                Vector2 pos2 = new Vector2(transform.position.x - RectWidth / 2, transform.position.z - RectHeight / 2);

                IsActive = actor.position.x <= pos1.x && actor.position.x >= pos2.x && actor.position.z <= pos1.y && actor.position.z >= pos2.y;
                break;
        }
        return IsActive;
    }
    /// <summary>
    /// 獲取隨機位置
    /// </summary>
    /// <returns></returns>
    public Vector3 GetRandomPos()
    {
        Vector3 pos = Vector3.zero;
        switch (CheckRange)
        {
            case CheckRange.Round:
                Vector2 pos3 = new Vector2(transform.position.x + RoundRadio / 2, transform.position.z + RoundRadio / 2);
                Vector2 pos4 = new Vector2(transform.position.x - RoundRadio / 2, transform.position.z - RoundRadio / 2);

                float rx = UnityEngine.Random.Range(pos4.x, pos3.x);
                float rz = UnityEngine.Random.Range(pos4.y, pos3.y);

                Vector3 dir = new Vector3(rx, transform.position.y, rz);

                float range = UnityEngine.Random.Range(0, RoundRadio);

                pos = dir.normalized * range + transform.position;


                break;
            case CheckRange.Rect:

                Vector2 pos1 = new Vector2(transform.position.x + RectWidth / 2, transform.position.z + RectHeight / 2);
                Vector2 pos2 = new Vector2(transform.position.x - RectWidth / 2, transform.position.z - RectHeight / 2);
                float x = UnityEngine.Random.Range(pos2.x, pos1.x);
                float z = UnityEngine.Random.Range(pos2.y, pos1.y);
                pos = new Vector3(x, 10, z);
                break;
        }
        return pos;

    }

    void OnDrawGizmos()
    {
        if (!IsGzimos) return;
        DrawGizmos();
    }

    /// <summary>
    /// 繪製戰鬥區
    /// </summary>
    void DrawGizmos()
    {
        switch (CheckRange)
        {
            case CheckRange.Round:
                Mesh round = MeshTools.MeshRound(RoundRadio,60);
                Gizmos.color = new Color(1,0,0,0.5f);
                Gizmos.DrawMesh(round,transform.position);
                break;
            case CheckRange.Fan:
                Mesh fan = MeshTools.MeshFan(FanEnagle, FanMaxRange, GetFanMinRange);
                Gizmos.color = new Color(1, 0, 0, 0.5f);
                Gizmos.DrawMesh(fan, transform.position);
                break;
            case CheckRange.Rect:
                Mesh rect = MeshTools.MeshRect(transform.position, RectWidth, RectHeight);
                Gizmos.color = new Color(1, 0, 0, 0.5f);
                Gizmos.DrawMesh(rect, transform.position);
                break;
        }
    }
}

現在這個指令碼主要實現的功能有:
1.獲取當前戰鬥區下的所有波數管理器,並進行排序,控制波數的先後順序

  void Start()
    {
        //獲取所有的波數管理器
        CheckPointWave[] wave = transform.GetComponentsInChildren<CheckPointWave>();
        for (int i = 0; i < wave.Length; i++)
        {
            wave[i].SetCheckPoint(this);
            Waves.Add(wave[i]);
        }
        //根據波數管理器id進行排序
        Waves.Sort((r1,r2)=> { if (r1.Index > r2.Index) return 1;