文章目录
目标
本章主要实现通过 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
{
/// <summary>
/// 关卡管理器
/// 加载关卡数据、加载场景、生成敌人
/// </summary>
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
{
/// <summary>
/// 游戏主程序
/// 加载关卡、游戏的开始、暂停、通关、失败
/// </summary>
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学习笔记目录整理