我的demo保卫萝卜中的技术要点

管理类:

GameManager(单例),GameController(单例);

一些其他的管理类(PlayerManager,AudioSourceManager,FactoryManager)作为GameManager的成员变量存在(这样也可以保证只有一个存在,并且初始化在GameManager之后)

使用到的多种设计模式

复盘一下我用过的设计模式-CSDN博客

:: Scoll View 结合 GridLayoutGroup 组件可以实现组件的整齐排列

RectTransform

RectTransform 和 Transfrom 的区别

Inspector,Awake,OnEnable与Start之间微妙的关系

Inspector 早于 Awake 早于 OnEnable 早于 Start

地图编辑器 编辑类

MapTool类

cs 复制代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.IO;

#if Tool
[CustomEditor(typeof(MapMaker))]
public class MapTool : Editor
{
    private MapMaker mapMaker;

    //关卡文件列表
    private List<FileInfo> fileList = new List<FileInfo>();
    private string[] fileNameList;

    //当前编辑的关卡索引
    private int selectIndex = -1;

    public override void OnInspectorGUI()
    {
        base.OnInspectorGUI();

        if(Application.isPlaying)
        {
            mapMaker = MapMaker.Instance; 
            EditorGUILayout.BeginHorizontal();
            //获取操作的文件名
            fileNameList = GetNames(fileList);

            int currentIndex = EditorGUILayout.Popup(selectIndex, fileNameList);
            if (currentIndex != selectIndex)  //当前选择对象是否改变
            {
                selectIndex = currentIndex;

                //实例化地图的方法
                mapMaker.InitMap();
                //加载当前选择的Level文件
                mapMaker.LoadLevelFile(mapMaker.LoadLevelInfoFile(fileNameList[selectIndex]));
            }

            if (GUILayout.Button("读取关卡列表"))
            {
                LoadLevelFiles();

            }
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.BeginHorizontal();
            if(GUILayout.Button("回复地图编辑器默认状态"))
            {
                mapMaker.RecoverTowerPoint();
            }

            if(GUILayout.Button("清除怪物路点"))
            {
                mapMaker.CLearMonsterPath();
            }

            EditorGUILayout.EndHorizontal();

            if(GUILayout.Button("保存当前关卡数据文件"))
            {
                mapMaker.SaveLevelFileByJson();
            }
        }
    }

    //加载关卡数据文件
    private void LoadLevelFiles()
    {
        CLearList();
        fileList = GetLevelFile();

    }

    //清楚文件列表
    private void CLearList()
    {
        fileList.Clear();
        selectIndex = -1;
    }

    //具体读取关卡列表的方法
    private  List<FileInfo> GetLevelFile()
    {
                                                                         //自动帮我们读后缀是.json的文件
        string[] files = Directory.GetFiles(Application.streamingAssetsPath + "/Json/Level/", "*.json");

        List<FileInfo> list = new List<FileInfo>();
        for (int i = 0; i < files.Length; i++)
        {
            FileInfo file = new FileInfo(files[i]);
            list.Add(file);
        }
        return list;
    }

    //获取关卡文件的名字
    private string[] GetNames(List<FileInfo> files)
    {
        List<string> names = new List<string>();
        foreach (FileInfo file in files)
        {
            names.Add(file.Name);
        }
        //将列表转成数组
        return names.ToArray();
    }


    
}
#endif

Mapmaker 类

cs 复制代码
using LitJson;
using System.Collections.Generic;
using System.IO;
using UnityEngine;

/// <summary>
/// 地图编辑工具,游戏中作为地图加载产生工具
/// </summary>

public class MapMaker : MonoBehaviour
{
#if Tool
    public bool drawLine;  //是否画线
    public GameObject gridGo;  //格子的预制体

    private static MapMaker _instance;

    public static MapMaker Instance { get => _instance; }
#endif

    //地图的有关属性
    private float mapWidth;  //地图宽
    private float mapHeight;  //地图高

    //格子
    [HideInInspector]
    public float gridWidth;
    [HideInInspector]
    public float gridHeight;

    //当前关卡索引
    //[HideInInspector]
    public int bigLevelID;
    //[HideInInspector]
    public int levelID;

    //全部的格子对象
    public GridPoint[,] gridPoints;

    //行列数
    public const int yRow = 8;
    public const int xCloumn = 12;

    //怪物路径点
    [HideInInspector]
    public List<GridPoint.GridIndex> monsterPath;

    //怪物路径点的具体位置
    [HideInInspector]
    public List<Vector3> monsterPathPos;

    //关卡的背景道路渲染
    private SpriteRenderer bgSR;
    private SpriteRenderer roadSR;

    //每一波次产生的怪物ID列表
    public List<Round.RoundInfo> roundInfoList;

    [HideInInspector]
    public Carrot carrot;

    private void Awake()
    {
#if Tool
        _instance = this;
        InitMapMaker();
#endif

    }

    //初始化地图
    public void InitMapMaker()
    {
        Calculatesize();
        gridPoints = new GridPoint[xCloumn, yRow];
        monsterPath = new List<GridPoint.GridIndex>();
        for (int x = 0; x < xCloumn; x++)
        {
            for (int y = 0; y < yRow; y++)
            {
#if Tool
                GameObject itemGo = Instantiate(gridGo,transform.position,transform.rotation);
#endif

#if Game
                //问工厂要资源的方法
                GameObject itemGo = GameController.Instance.GetGameObjectResource("Grid");
#endif
                itemGo.transform.position = new Vector3(x * gridWidth - mapWidth / 2 + gridWidth / 2,
                    y * gridHeight - mapHeight / 2 + gridHeight / 2);
                itemGo.transform.SetParent(transform);
                gridPoints[x, y] = itemGo.GetComponent<GridPoint>();
                gridPoints[x, y].gridIndex.xIndex = x;
                gridPoints[x, y].gridIndex.yIndex = y;
            }
        }
        bgSR = transform.Find("BG").GetComponent<SpriteRenderer>();
        roadSR = transform.Find("Road").GetComponent<SpriteRenderer>();

    }

#if Game
    //加载地图
    public void LoadMap(int bigLevel, int level)
    {
        bigLevelID = bigLevel;
        levelID = level;
        LoadLevelFile(LoadLevelInfoFile("Level" + bigLevelID.ToString() + "_" + levelID.ToString() + ".json"));
        monsterPathPos = new List<Vector3>();
        for (int i = 0; i < monsterPath.Count; i++)
        {
            monsterPathPos.Add(gridPoints[monsterPath[i].xIndex, monsterPath[i].yIndex].transform.position);
        }

        //起始点与终止点
        GameObject startPointGo = GameController.Instance.GetGameObjectResource("startPoint");
        startPointGo.transform.position = monsterPathPos[0];
        startPointGo.transform.SetParent(transform);

        GameObject endPointGo = GameController.Instance.GetGameObjectResource("Carrot");
        endPointGo.transform.position = monsterPathPos[monsterPathPos.Count - 1] - new Vector3(0, 0, 1);
        endPointGo.transform.SetParent(transform);
        carrot = endPointGo.GetComponent<Carrot>();

    }


#endif

    //纠正位置
    public Vector3 CorrectPosition(float x, float y)
    {
        return new Vector3(x - mapWidth / 2 + gridWidth / 2, y - mapHeight / 2 + gridHeight / 2);
    }

    //计算地图格子宽高
    private void Calculatesize()
    {
        //视口坐标,左下角(0,0),右上角(1,1)
        Vector3 leftDown = new Vector3(0, 0);
        Vector3 rightUp = new Vector3(1, 1);

        //将视口转换为世界坐标
        Vector3 posOne = Camera.main.ViewportToWorldPoint(leftDown);
        Vector3 posTwo = Camera.main.ViewportToWorldPoint(rightUp);

        mapWidth = posTwo.x - posOne.x;
        mapHeight = posTwo.y - posOne.y;

        gridWidth = mapWidth / xCloumn;
        gridHeight = mapHeight / yRow;

    }

#if Tool
    //画格子用于辅助设计
    private void OnDrawGizmos()
    {
        if(drawLine)
        {
            Calculatesize();
            Gizmos.color = Color.green;

            //画行
            for(int y = 0; y <= yRow; y++)
            {
                Vector3 startPos = new Vector3(-mapWidth / 2, -mapHeight / 2 + y * gridHeight);
                Vector3 endPos = new Vector3(mapWidth / 2, -mapHeight / 2 + y * gridHeight);
                Gizmos.DrawLine(startPos, endPos);
            }

            //画列
            for(int x = 0;x <= xCloumn;x++)
            {
                Vector3 startPos = new Vector3(-mapWidth / 2 + x * gridWidth ,mapHeight / 2);
                Vector3 endPos = new Vector3(-mapWidth / 2 + x * gridWidth, -mapHeight / 2);
                Gizmos.DrawLine(startPos, endPos);
            }
        }
    }
#endif

    /// <summary>
    /// 有关地图编辑的方法
    /// </summary>

    //清除怪物路点
    public void CLearMonsterPath()
    {
        monsterPath.Clear();
    }

    //恢复地图编辑默认状态
    public void RecoverTowerPoint()
    {
        CLearMonsterPath();
        for (int x = 0; x < xCloumn; x++)
        {
            for (int y = 0; y < yRow; y++)
            {
                gridPoints[x, y].InitGrid();
            }
        }
    }

    //初始化地图
    public void InitMap()
    {
        bigLevelID = 0;
        levelID = 0;
        RecoverTowerPoint();
        roundInfoList.Clear();
        bgSR.sprite = null;
        roadSR.sprite = null;
    }

#if Tool
    //生成LevelInfo对象用来保存文件
    private LevelInfo CreateLevelInfoGo()
    {
        LevelInfo levelInfo = new LevelInfo
        {
            bigLevelID = this.bigLevelID,
            levelID = this.levelID,
        };
        levelInfo.gridPoints = new List<GridPoint.GridState>(); ;
        for (int x = 0; x < xCloumn; x++)
        {
            for (int y = 0; y < yRow; y++)
            {
                levelInfo.gridPoints.Add(gridPoints[x, y].gridState);
            }
        }
        levelInfo.monsterPath = new List<GridPoint.GridIndex>();
        for (int i = 0; i < monsterPath.Count; i++)
        {
            levelInfo.monsterPath.Add(monsterPath[i]);
        }
        levelInfo.roundInfo = new List<Round.RoundInfo>();
        for (int i = 0; i < roundInfoList.Count; i++)
        {
            levelInfo.roundInfo.Add(roundInfoList[i]);
        }
        Debug.Log("保存成功");
        return levelInfo;
    }

    //保存当前关卡的数据文件
    public void SaveLevelFileByJson()
    {
        LevelInfo levelInfoGo = CreateLevelInfoGo();
        string filePath = Application.streamingAssetsPath + "/Json/Level/" + "Level"
            + bigLevelID.ToString() + "_" + levelID.ToString() + ".json";
        string saveJsonStr = JsonMapper.ToJson(levelInfoGo);
        StreamWriter sw = new StreamWriter(filePath);
        sw.Write(saveJsonStr);
        sw.Close();
    }
    
#endif

    //读取关卡文件解析json转化为LevelInfo对象
    public LevelInfo LoadLevelInfoFile(string fileName)
    {
        LevelInfo levelInfo = new LevelInfo();
        string filePath = Application.streamingAssetsPath + "/Json/Level/" + fileName;
        if (File.Exists(filePath))
        {
            StreamReader sr = new StreamReader(filePath);
            string jsonStr = sr.ReadToEnd();
            sr.Close();
            levelInfo = JsonMapper.ToObject<LevelInfo>(jsonStr);
            return levelInfo;

        }
        Debug.Log("文件加载失败,加载路径是:" + filePath);
        return null;
    }

    //
    public void LoadLevelFile(LevelInfo levelInfo)
    {
        bigLevelID = levelInfo.bigLevelID;
        levelID = levelInfo.levelID;
        for (int x = 0; x < xCloumn; x++)
        {
            for (int y = 0; y < yRow; y++)
            {
                gridPoints[x, y].gridState = levelInfo.gridPoints[y + x * yRow];

                //更新格子的状态
                gridPoints[x, y].UpdateGrid();
            }
        }
        monsterPath.Clear();
        for (int x = 0; x < levelInfo.monsterPath.Count; x++)
        {
            monsterPath.Add(levelInfo.monsterPath[x]);
        }

        roundInfoList = new List<Round.RoundInfo>();
        for (int i = 0; i < levelInfo.roundInfo.Count; i++)
        {
            roundInfoList.Add(levelInfo.roundInfo[i]);
        }

        bgSR.sprite = Resources.Load<Sprite>("Pictures/NormalMordel/Game/"
            + bigLevelID.ToString() + "/" + "BG" + (levelID / 3).ToString());
        roadSR.sprite = Resources.Load<Sprite>("Pictures/NormalMordel/Game/"
            + bigLevelID.ToString() + "/" + "Road" + levelID.ToString());
    }
}
相关推荐
小春熙子15 小时前
Unity图形学之Shader结构
unity·游戏引擎·技术美术
Sitarrrr18 小时前
【Unity】ScriptableObject的应用和3D物体跟随鼠标移动:鼠标放置物体在场景中
3d·unity
极梦网络无忧18 小时前
Unity中IK动画与布偶死亡动画切换的实现
unity·游戏引擎·lucene
逐·風1 天前
unity关于自定义渲染、内存管理、性能调优、复杂物理模拟、并行计算以及插件开发
前端·unity·c#
_oP_i1 天前
Unity Addressables 系统处理 WebGL 打包本地资源的一种高效方式
unity·游戏引擎·webgl
Leoysq2 天前
【UGUI】实现点击注册按钮跳转游戏场景
游戏·unity·游戏引擎·ugui
_oP_i2 天前
unity中 骨骼、纹理和材质关系
unity·游戏引擎·材质
Padid2 天前
Unity SRP学习笔记(二)
笔记·学习·unity·游戏引擎·图形渲染·着色器
Tp_jh2 天前
推荐一款非常好用的C/C++在线编译器
linux·c语言·c++·ide·单片机·unity·云原生
dangoxiba2 天前
[Unity Demo]从零开始制作空洞骑士Hollow Knight第十八集补充:制作空洞骑士独有的EventSystem和InputModule
游戏·unity·c#·游戏引擎·playmaker