今天我们尝试实现一个简单的关卡管理系统
先想想关卡都需要什么功能?
在我基本的考虑下主要有:
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; 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);
        }
    }

2.检测玩家列表(为什么列表,考虑到会有多个玩家情况)是否进入当前战斗

 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>
 /// <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;
 }
注:我考虑的情况是,只要有一个玩家进入战斗区,则激活战斗区,其他玩家强制拉到战斗区中,当然你也可以让所有玩家进入战斗区才激活战斗区,这里也可以用碰撞体控制,我感觉都差不多,看心情吧

3.激活当前战斗区,并激活第一个波数管理器

 /// <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);
     }
 }
注:战斗区激活后,检测变会关闭
IsDetActor = false;

4.获取随机创建位置,GetRandomPos()这个方法是波数管理器调用的,随机创建只会在指定范围创建,而指定位置创建,是根据配置进行创建的。

    /// <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;

    }
这里经测试 圆形范围计算有问题,快过年了,我也不想去整了,你们有精力的自己写一下吧

5.战斗区结束控制,有始也有终,主要是结束事件能激活下一个战斗区得检测功能

    /// <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();
    }

5.当然这里也有两个事件列表

    [Header("当进入战斗开始时:")]
    public List<CpAction> OnStartAction = new List<CpAction>();
    [Header("当战斗区结束时:")]
    public List<CpAction> OnEndAction = new List<CpAction>();

恩,到这里战斗区,和波数控制我们基本上都完成了,那还需要什么呢?
我感觉我们还需要一个关卡管理器,用来控制战斗区的激活和战斗区得顺序,以便在后面我们要实现自动寻路时,能获取下一个战斗区或者当前战斗区等等功能。
OK,我们先看所有的代码

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

public class CheckPointManager : MonoBehaviour {

    /// <summary>
    /// 当角色创建
    /// </summary>
    public Action<Actor> OnActorCreate;

    /// <summary>
    /// 场景中所有动态元素
    /// </summary>
    [SerializeField]
    private List<Actor> ScenesActors = new List<Actor>();

    /// <summary>
    /// 编辑器
    /// </summary>
    private GUIAction FindGUI = null;
    private GUIAction ManagerGui = null;

    /// <summary>
    /// 关卡
    /// </summary>
    [SerializeField]
    private List<CheckPoint> CheckPoint = new List<global::CheckPoint>();
    /// <summary>
    /// 当前执行的管卡
    /// </summary>
    public CheckPoint CurPoint { get; private set; }
    /// <summary>
    /// 当执行的波数
    /// </summary>
    public CheckPointWave CurWave { get; private set; }
    /// <summary>
    /// 怪物检测列表
    /// </summary>
    public List<Actor> DetActor { get; private set; }

    /// <summary>
    /// 当关卡开始
    /// </summary>
    public List<CpAction> OnStartAction = new List<CpAction>();
    /// <summary>
    /// 当怪物结束
    /// </summary>
    public List<CpAction> OnEndAction = new List<CpAction>();

    void Awake()
    {

        //辅助UI
        FindGUI = GUITools.ResterWindowAction(new Rect(Screen.width - 500, 150, 200, Screen.height), delegate (GUIAction action1)
        {
            action1.Rect = GUI.Window(action1.Id, action1.Rect, delegate
            {

                List<PlayerTable> pts = PlayerTable.TryGet();
                for (int i = 0; i < pts.Count; i++)
                {
                    if (GUI.Button(new Rect(5, i * 20 + 20, 190, 20), pts[i].PlayerID + "-" + pts[i].PlayerName))
                    {
                        CreateActor(pts[i].PlayerID, new Vector3(float.Parse(ManagerGui.Param[2].Split(',')[0]), 10, float.Parse(ManagerGui.Param[2].Split(',')[1])));
                    }
                }

            }, "Find");
        });
        ManagerGui = GUITools.ResterWindowAction(new Rect(Screen.width-300,150,300,300),delegate(GUIAction action) {
            action.Rect = GUI.Window(action.Id,action.Rect,delegate {
                action.Param[0] = GUI.TextField(new Rect(5, 20, 150, 20), action.Param[0]);
                if (GUI.Button(new Rect(160, 20, 150, 20), "Find"))
                {
                    if (action.Param[1].Equals("1"))
                        action.Param[1] = "0";
                    else action.Param[1] = "1";
                }

                FindGUI.IsShow = action.Param[1].Equals("1");

                action.Param[2] = GUI.TextField(new Rect(5, 45, 150, 20), action.Param[2]);
                if (GUI.Button(new Rect(160,45,100,20),"Create"))
                    CreateActor(action.Param[0], new Vector3(float.Parse(action.Param[2].Split(',')[0]),10,float.Parse(action.Param[2].Split(',')[1])));

                if (GUI.Button(new Rect(5, 70, 80, 20), "Kill Wave"))
                {
                    CurWave.kill();
                }

                if (GUI.Button(new Rect(90, 70, 80, 20), "Kill Point"))
                {
                    CurWave.kill(true);
                    CurPoint.OnFinsh();
                }

                if (GUI.Button(new Rect(180, 70, 80, 20), "Kill All"))
                {
                    OnFinsh();
                }


                GUI.DragWindow();
            },"关卡管理器");
        },"0","0","69,44");
    }

    void Start()
    {
        ///初始化关卡
        InitCheckPoint();
    }

    /// <summary>
    /// 关卡结束时
    /// </summary>
    public void OnFinsh()
    {
        if (OnEndAction.Count > 0)
        {
            for (int i = 0; i < OnEndAction.Count; i++)
                DoCpAction(OnEndAction[i].ActionType, OnEndAction[i].ActionParam);
        }

        ///接下来需要显示评分,和网络通信等等功能
    }


    /// <summary>
    /// 初始化关卡
    /// </summary>
    public void InitCheckPoint()
    {
        //设置检测列表
        DetActor = new List<Actor>();
        //添加主角
        if (MainActor.Instance != null)
            InsertActor(MainActor.Instance, 0);
        //获取所有的战斗区
        CheckPoint[] cps = transform.GetComponentsInChildren<CheckPoint>();
        if (cps.Length < 1) return;
        for (int i = 0; i < cps.Length; i++)
        {
            cps[i].SetCPManager(this);
            CheckPoint.Add(cps[i]);
        }
        ///战斗区排序
        CheckPoint.Sort((a1, a2) => { if (a1.Index > a2.Index) return 1; else if (a1.Index == a2.Index) return 0; return -1; });
        //设置下一关
        for (int i = 0; i < CheckPoint.Count; i++)
        {
            if (i != CheckPoint.Count - 1)
            {
                //没有手动指定关卡
                if (CheckPoint[i].NextIndex != -1)
                {
                    CheckPoint[i].SetNextCp(GetCheckPoint(CheckPoint[i].NextIndex));
                    continue;
                }
                CheckPoint[i].SetNextCp(CheckPoint[i + 1]);
            }
            else
                CheckPoint[i].SetNextCp(null);
        }
        ///第一个关卡开始检测玩家
        CheckPoint[0].IsDetActor = true;
        if (OnStartAction.Count > 0)
        {
            for (int i = 0; i < OnStartAction.Count; i++)
                DoCpAction(OnStartAction[i].ActionType, OnStartAction[i].ActionParam);
        }
    }

    /// <summary>
    /// 获取关卡
    /// </summary>
    /// <param name="index"></param>
    /// <returns></returns>
    public CheckPoint GetCheckPoint(int index)
    {
        for (int i = 0; i < CheckPoint.Count; i++)
        {
            if (CheckPoint[i].Index == index)
                return CheckPoint[i];
        }
        return null; 
    }

    /// <summary>
    /// 设置当前那个关卡
    /// </summary>
    /// <param name="point"></param>
    public void SetCurCheckPoint(CheckPoint point)
    {
        CurPoint = point;
    }

    /// <summary>
    /// 设置当前第几波
    /// </summary>
    /// <param name="wave"></param>
    public void SetCurWave(CheckPointWave wave)
    {
        CurWave = wave;
    }

    /// <summary>
    /// 创建actor
    /// </summary>
    public void CreateActor(string heroID, Vector3 Pos, Action<Actor> OnDeath = null,Action<Actor> OnCreate =null)
    {
        PlayerTable pt = PlayerTable.TryGet(heroID);
        Actor actor = null;
        ///加载资源
        ResourcesManager.Instance.AsnyLoadResources<GameObject>(GeneralTable.TryGet(pt.PlayerActor).GeneralValue,delegate(GameObject obj) {
            actor = obj.GetComponent<Actor>();
            actor.OnCreateEvent = OnCreate;
            ProfilerTools.BeginSample("InitActor",delegate {
                //创建模型
                actor.Init(pt.PlayerModelID, delegate {
                    actor.CharacterController.radius = pt.PlayerActorRadioAndHeight.x;
                    actor.CharacterController.height = pt.PlayerActorRadioAndHeight.y;
                    actor.CharacterController.center = pt.PlayerActorOffset;

                    actor.ActorAttr.Speed = pt.PlayerSpeed;
                    actor.ActorAttr.UpSpeed = pt.PlayerUpSpeed; 
                    actor.ActorAttr.JumpAbility = pt.PlayerJumpAbility;
                    actor.ActorAttr.FlyAbility = pt.PlayerFlyAbility;
                    actor.ActorAttr.BackAbility = pt.PlayerBackAbility;
                    actor.ActorAttr.ForwardAbility = pt.PlayerForwardAbility;
                    actor.ActorAttr.MaxHp = pt.PlayerMaxHp;
                    actor.OnDeathEvent = OnDeath;
                });
            });

            GeneralTools.SetTransfrom(actor.transform,Pos,Vector3.zero,Vector3.one);
            if (actor is MainActor && actor.ActorType == ActorType.Player)
                InsertActor(actor, 0);
            else
                AddActor(actor);

            if (OnActorCreate != null)
                OnActorCreate(actor);

        });
    }

    /// <summary>
    /// 插入actor 主角放在0的位置
    /// </summary>
    /// <param name="actor"></param>
    /// <param name="index"></param>
    void InsertActor(Actor actor,int index)
    {
        //玩家如家类型为玩家或友方则需要将其放入怪物检测列表中
        if (actor.ActorType == ActorType.Player)
            DetActor.Add(actor);
        ScenesActors.Insert(index,actor);
    }

    /// <summary>
    /// 添加Actor
    /// </summary>
    /// <param name="actor"></param>
    void AddActor(Actor actor)
    {
        ScenesActors.Add(actor);
    }


    /// <summary>
    /// 获取主角
    /// </summary>
    public Actor GetMainActor
    {
        get {
            if (ScenesActors.Count < 1)
                return null;
            return ScenesActors[0];
        }

    }

    /// <summary>
    /// 执行 动作
    /// </summary>
    public void DoCpAction(string command)
    {
        string[] data = command.Split(':');
        if (data.Length < 2) return;
        DoCpAction(data[0],data[1]);
    }
    /// <summary>
    /// 执行时间
    /// </summary>
    /// <param name="command"></param>
    /// <param name="comParams"></param>
    public void DoCpAction(string command,string comParams)
    {
        CheckPointAction cpa = CheckPointActionFactory.Create(command);
        if (cpa == null)
        {
            Debug.Log(string.Format("加载关卡事件 {0} 失败...", command));
            return;
        }
        cpa.ActionType = command;

        if (cpa.OnParse(comParams))
            cpa.DoAction(this);
    }



    /// <summary>
    /// 编辑器方法 添加关卡
    /// </summary>
    /// <returns></returns>
    public GameObject AddCheckPoint()
    {
        GameObject go = new GameObject("CheckPoint");
        go.AddComponent<CheckPoint>();
        GeneralTools.SetParent(transform,go.transform);

        GameObject waveGo = new GameObject("Wave");
        waveGo.AddComponent<CheckPointWave>();
        GeneralTools.SetParent(go.transform,waveGo.transform);
        return go;
    }

}

解析一下主要功能:
1.初始化关卡,并且获取检测列表(这个里只添加主角),并且获取所有的战斗区进行排序,并且激活第一个战斗进行玩家检测


    /// <summary>
    /// 初始化关卡
    /// </summary>
    public void InitCheckPoint()
    {
        //设置检测列表
        DetActor = new List<Actor>();
        //添加主角
        if (MainActor.Instance != null)
            InsertActor(MainActor.Instance, 0);
        //获取所有的战斗区
        CheckPoint[] cps = transform.GetComponentsInChildren<CheckPoint>();
        if (cps.Length < 1) return;
        for (int i = 0; i < cps.Length; i++)
        {
            cps[i].SetCPManager(this);
            CheckPoint.Add(cps[i]);
        }
        ///战斗区排序
        CheckPoint.Sort((a1, a2) => { if (a1.Index > a2.Index) return 1; else if (a1.Index == a2.Index) return 0; return -1; });
        //设置下一关
        for (int i = 0; i < CheckPoint.Count; i++)
        {
            if (i != CheckPoint.Count - 1)
            {
                //没有手动指定关卡
                if (CheckPoint[i].NextIndex != -1)
                {
                    CheckPoint[i].SetNextCp(GetCheckPoint(CheckPoint[i].NextIndex));
                    continue;
                }
                CheckPoint[i].SetNextCp(CheckPoint[i + 1]);
            }
            else
                CheckPoint[i].SetNextCp(null);
        }
        ///第一个关卡开始检测玩家
        CheckPoint[0].IsDetActor = true;
        if (OnStartAction.Count > 0)
        {
            for (int i = 0; i < OnStartAction.Count; i++)
                DoCpAction(OnStartAction[i].ActionType, OnStartAction[i].ActionParam);
        }
    }

2.我们把角色创建的代码也放置在这里了,并且我们将主角始终放置在第一位

    /// <summary>
    /// 创建actor
    /// </summary>
    public void CreateActor(string heroID, Vector3 Pos, Action<Actor> OnDeath = null,Action<Actor> OnCreate =null)
    {
        PlayerTable pt = PlayerTable.TryGet(heroID);
        Actor actor = null;
        ///加载资源
        ResourcesManager.Instance.AsnyLoadResources<GameObject>(GeneralTable.TryGet(pt.PlayerActor).GeneralValue,delegate(GameObject obj) {
            actor = obj.GetComponent<Actor>();
            actor.OnCreateEvent = OnCreate;
            ProfilerTools.BeginSample("InitActor",delegate {
                //创建模型
                actor.Init(pt.PlayerModelID, delegate {
                    actor.CharacterController.radius = pt.PlayerActorRadioAndHeight.x;
                    actor.CharacterController.height = pt.PlayerActorRadioAndHeight.y;
                    actor.CharacterController.center = pt.PlayerActorOffset;

                    actor.ActorAttr.Speed = pt.PlayerSpeed;
                    actor.ActorAttr.UpSpeed = pt.PlayerUpSpeed; 
                    actor.ActorAttr.JumpAbility = pt.PlayerJumpAbility;
                    actor.ActorAttr.FlyAbility = pt.PlayerFlyAbility;
                    actor.ActorAttr.BackAbility = pt.PlayerBackAbility;
                    actor.ActorAttr.ForwardAbility = pt.PlayerForwardAbility;
                    actor.ActorAttr.MaxHp = pt.PlayerMaxHp;
                    actor.OnDeathEvent = OnDeath;
                });
            });

            GeneralTools.SetTransfrom(actor.transform,Pos,Vector3.zero,Vector3.one);
            if (actor is MainActor && actor.ActorType == ActorType.Player)
                InsertActor(actor, 0);
            else
                AddActor(actor);

            if (OnActorCreate != null)
                OnActorCreate(actor);
        });
    }

3.另外这里还有事件的解析部分

  /// <summary>
    /// 执行 动作
    /// </summary>
    public void DoCpAction(string command)
    {
        string[] data = command.Split(':');
        if (data.Length < 2) return;
        DoCpAction(data[0],data[1]);
    }
    /// <summary>
    /// 执行时间
    /// </summary>
    /// <param name="command"></param>
    /// <param name="comParams"></param>
    public void DoCpAction(string command,string comParams)
    {
        CheckPointAction cpa = CheckPointActionFactory.Create(command);
        if (cpa == null)
        {
            Debug.Log(string.Format("加载关卡事件 {0} 失败...", command));
            return;
        }
        cpa.ActionType = command;

        if (cpa.OnParse(comParams))
            cpa.DoAction(this);
    }

4.当然还有结束的部分

    /// <summary>
    /// 关卡结束时
    /// </summary>
    public void OnFinsh()
    {
        if (OnEndAction.Count > 0)
        {
            for (int i = 0; i < OnEndAction.Count; i++)
                DoCpAction(OnEndAction[i].ActionType, OnEndAction[i].ActionParam);
        }

        ///接下来需要显示评分,和网络通信等等功能
    }

OK,大体上完成了,接下来,我们主要来看一下事件的部分。
主题思想还是,所有事件继承一个积累,再用一个工厂类来创建事件的实例,调用事件,解析参数,执行事件
这个跟我前面几篇文章的事件大体上相似,直接看一下代码吧!
工程类:CheckPointActionFactory

public class CheckPointActionFactory
{
    private static Hashtable lookUpType = new Hashtable();
    public static CheckPointAction Create(string name)
    {
        CheckPointAction c = null;
        try
        {
            var type = (Type)lookUpType[name];
            lock (lookUpType)
            {
                if (type == null)
                {
                    //Assembly curAssembly = Assembly.GetEntryAssembly();
                    type = Type.GetType(name);
                    //type = Type.GetType();
                    lookUpType[name] = type;
                }
            }
            if (type != null)
                c = Activator.CreateInstance(type) as CheckPointAction;
        }
        catch (Exception ex)
        {
            Debug.Log(string.Format("创建关卡事件,失败!!", ex.Message));
        }
        return c;
    }
}

基类:CheckPointAction

/// <summary>
/// 关卡事件
/// </summary>
public abstract class CheckPointAction
{
    public string ActionType;
    public abstract bool OnParse(string command);
    public abstract bool DoAction(CheckPointManager cm);
}

实体类:CpActive
现在只实现了一个,其他类型根据自己需要来进行创建

/// <summary>
/// 激活或显示物体 CpActive:UI,TipPanel,true
/// </summary>
public class CpActive : CheckPointAction
{
    /// <summary>
    /// UI,Cp,
    /// </summary>
    public string targetType;
    public string targetName;
    public bool IsActive;
    public override bool OnParse(string command)
    {
        try
        {
            string[] data = command.Split(',');
            targetType = data[0];
            targetName = data[1];
            IsActive = bool.Parse(data[2]);
            return true;
        }
        catch { return false; }
    }

    public override bool DoAction(CheckPointManager cm)
    {
        switch (targetType.ToLower())
        {
            case "ui":
                break;
            case "cp":
                Transform target = cm.transform.Find(targetName);
                if (target != null)
                    target.gameObject.SetActive(IsActive);
                break;
        }
        return true;
    }
}

这个类主要实现的功能是,隐藏或显示物体,有三个参数,隐藏物体类型(ui或者关卡下的内容,这个可以分开写,我只是测试随意了),物体名称,状态(显示或隐藏)

具体配置方法:
这里写图片描述

好,基本的都介绍完了,具体需要实现的一些功能,还得需要在项目需要的进行添加,当然这些数据你都可以配置到配置表中,然后根据配置进行创建,也可以将关卡直接存储为一个预制体,在需要的时候进行加载。

哦对了,主要注意啊,在CheckPointManager 的Awake位置,我创建了ui创建方便进行测试,类似于这样:
这里写图片描述

写了一个window的管理类:

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

/// <summary>
/// GUI工具
/// </summary>
public class GUITools : MonoBehaviour {

    public static GUITools _instance;
    public static GUITools Instance
    {
        get { return _instance; }
    }
    /// <summary>
    /// 是否显示GUI
    /// </summary>
    public bool IsShowGUI = false;

    public bool IsShowSystemInfo = false;
    /// <summary>
    /// GUI
    /// </summary>
    private static List<GUIAction> GUIActions = new List<global::GUIAction>();
    /// <summary>
    /// 注册GUI Window
    /// </summary>
    /// <param name="rect"></param>
    /// <param name="func"></param>
    /// <param name="param"></param>
    /// <returns></returns>
    public static GUIAction ResterWindowAction(Rect rect, Action<GUIAction> func,params string[] param)
    {
        GUIAction ga = new global::GUIAction(func);
        ga.Rect = rect;
        ga.Param = param;
        GUIActions.Add(ga);
        return ga;
    }
    /// <summary>
    /// 绘制GUI
    /// </summary>
    void OnGUI()
    {
        if (IsShowGUI)
        {
            GUI.color = Color.yellow;
            for (int i = 0; i < GUIActions.Count; i++)
                if(GUIActions[i].IsShow)
                    GUIActions[i].DoAction();
        }
    }

}

/// <summary>
/// GUI功能
/// </summary>
public class GUIAction
{
    public static int NextID = 0;
    public int Id { get; private set; }
    public Rect Rect;
    public string[] Param;
    public Action<GUIAction> Func { get; private set; }

    public bool IsShow = true;

    public GUIAction(Action<GUIAction> func)
    {
        Id = NextID++;
        Func = func;
    }

    public void DoAction()
    {
        if (Func != null)
            Func(this);
    }

}

方便对GUI进行管理,不过现在只有一个window。使用时,挂载到一个预制体就行了。

最终结果
这里写图片描述

快过年,给种无动力奔袭而来,最后一个周,让我混混日子吧…

Logo

快速构建 Web 应用程序

更多推荐