文章目录

  • 目标
  • Excel 解析工具
  • 配置文件
  • 读取配置文件
  • 最终效果

目标

本章主要实现通过 Excel 配置关卡数据, Unity 解析 Excel 生成关卡,实现自动刷新敌人。

Excel 解析工具

在 Unity 中解析 Excel 需要使用 Excel.dll 和 ICSharpCode.SharpZipLib.dll ,这里附上下载链接:Unity 解析Excel工具:Excel.dll 和 ICSharpCode.SharpZipLib.dll。

解压后直接放到Plugins文件夹下即可:

配置文件

用 Excel 写一个配置文件,上面预留两行,左侧预留一列方便后期做填写说明。

读取配置文件

首先根据配置文件写了两个匹配配置文件的类:LevelConfig、EnemyConfig。代码如下:

LevelConfig.cs

using System.Collections.Generic;namespace TDGameDemo.GameLevel{    public class LevelConfig    {        private string _levelCode;        private int _count;        private float _cristalHP;        private List<EnemyConfig> _enemyConfigs;        public string LevelCode { get => _levelCode; set => _levelCode = value; }        public int Count { get => _count; set => _count = value; }        public float CristalHP { get => _cristalHP; set => _cristalHP = value; }        public List<EnemyConfig> EnemyConfigs { get => _enemyConfigs; set => _enemyConfigs = value; }    }}

EnemyConfig.cs

using System.Collections;namespace TDGameDemo.GameLevel{    public class EnemyConfig    {        private int _roundNum;        private string _prefabPath;        private int _enemyCount;        private int _GenInterval;        private float _enemyHP;        private float _enemyAttack;        private float _enemySpeed;        public int RoundNum { get => _roundNum; set => _roundNum = value; }        public string PrefabPath { get => _prefabPath; set => _prefabPath = value; }        public int EnemyCount { get => _enemyCount; set => _enemyCount = value; }        public int GenInterval { get => _GenInterval; set => _GenInterval = value; }        public float EnemyHP { get => _enemyHP; set => _enemyHP = value; }        public float EnemyAttack { get => _enemyAttack; set => _enemyAttack = value; }        public float EnemySpeed { get => _enemySpeed; set => _enemySpeed = value; }    }}

然后再创建一个 LevelManager 脚本来读取配置,这个 LevelManager 后期将会实现关卡的加载、开始、结束,以及生成敌人等功能。目前代码如下:

LevelManager.cs

using Excel;using System.Collections.Generic;using System.IO;using TDGameDemo.Enemy;using TDGameDemo.Game;using UnityEngine;namespace TDGameDemo.GameLevel{    ///     /// 关卡管理器    /// 加载关卡数据、加载场景、生成敌人    ///     public class LevelManager : MonoBehaviour    {        private GameMain _gameMain;        private EnemyGenerator _enemyGenerator;        public Transform _generatePoint;        public Transform _target;        private LevelConfig _levelConfig;        private int currRound = 0;        //private int currEnemyIndex = 0;        private float lastEnemyGenTim = 50f;        private int genEnemyCount = 0;        // Start is called before the first frame update        void Start()        {            _gameMain = GetComponent<GameMain>();            _enemyGenerator = GetComponent<EnemyGenerator>();        }        // Update is called once per frame        void Update()        {            //Debug.Log("99999999999999----------" + Time.deltaTime);            // 游戏开始,生成敌人            if (_gameMain.GameStart)            {                // 如果当前为第0回合,证明游戏刚开始                if (currRound == 0)                {                    currRound = 1;                }                // 累加生成时间                lastEnemyGenTim += Time.deltaTime;                // 如果上一个敌人的生成时间大于本轮的生成间隔,则生成新的敌人                if (_levelConfig.EnemyConfigs[currRound - 1].GenInterval < lastEnemyGenTim)                {                    _enemyGenerator.GenerateEnemy(                        _generatePoint,                        Level.ENEMY_PREFAB_PREFIX + _levelConfig.EnemyConfigs[currRound - 1].PrefabPath,                        _target                    );                    // 生成数量+1                    genEnemyCount++;                    // 生成时间重置                    lastEnemyGenTim = 0;                    // 如果生成数量大于等于本轮生成总量,则进行下一轮                    if (genEnemyCount >= _levelConfig.EnemyConfigs[currRound - 1].EnemyCount)                    {                        currRound++;                        genEnemyCount = 0;                    }                }            }        }        public void InitLevel(string configPath)        {            // 创建关卡配置对象            _levelConfig = new LevelConfig();            // 解析Excel            FileStream fs = new FileStream(Application.dataPath + configPath, FileMode.Open, FileAccess.Read);            // 创建Excel读取类            IExcelDataReader excelReader = ExcelReaderFactory.CreateOpenXmlReader(fs);            // 读取            int index = 0;            // 移动到第四行            for (; index < 4; index++)            {                excelReader.Read();            }            _levelConfig.LevelCode = excelReader.GetString(1);            _levelConfig.Count = excelReader.GetInt32(2);            //Debug.Log(_levelConfig.Count + "======================" + _levelConfig.LevelCode);            // 跳过空白行和标题行            excelReader.Read();            excelReader.Read();            _levelConfig.EnemyConfigs = new List<EnemyConfig>();            for (; index <= 4 + _levelConfig.Count; index++)            {                excelReader.Read();                EnemyConfig emConfig = new EnemyConfig();                emConfig.RoundNum = excelReader.GetInt32(1);                emConfig.PrefabPath = excelReader.GetString(2);                emConfig.EnemyCount = excelReader.GetInt32(3);                emConfig.GenInterval = excelReader.GetInt32(4);                emConfig.EnemyHP = excelReader.GetFloat(5);                emConfig.EnemyAttack = excelReader.GetFloat(6);                emConfig.EnemySpeed = excelReader.GetFloat(7);                _levelConfig.EnemyConfigs.Add(emConfig);            }        }    }}

GameMain.cs

using TDGameDemo.GameLevel;using UnityEngine;namespace TDGameDemo.Game{    ///     /// 游戏主程序    /// 加载关卡、游戏的开始、暂停、通关、失败    ///     public class GameMain : MonoBehaviour    {        private LevelManager _levelManager;        private bool gameStart = false;        public bool GameStart { get => gameStart; set => gameStart = value; }        void Start()        {            _levelManager = GetComponent<LevelManager>();            _levelManager.InitLevel("/Resources/Level/LevelConfig/Level_1001.xlsx");        }        // Update is called once per frame        void Update()        {            // 按 B 键开始游戏            if (Input.GetKeyDown(KeyCode.B))            {                GameStart = true;            }        }    }}

附上脚本:

注意,EnemyGeneratePoint 的位置要放在地图上合理的位置上,不然导航将会报错。

最终效果

由于 GIF 大小有限制,只能少生成几个敌人了。前面三个小的是第一轮的,中间两个大的是第二轮的,后面小的是第三轮的。


更多内容请查看总目录【Unity】Unity学习笔记目录整理