【制作100个unity游戏之27】使用unity复刻经典游戏《植物大战僵尸》,制作属于自己的植物大战僵尸随机版和杂交版6(附带项目源码)

最终效果

在这里插入图片描述

系列导航

文章目录

  • 最终效果
  • 系列导航
  • 前言
  • 方法一、使用excel配置表
    • excel转txt文本
    • 读取txt数据
    • 按配置信息生成僵尸
  • 方法二、使用ScriptableObject 配置关卡信息
  • 源码
  • 结束语

前言

本节主要是推荐两种实现配置关卡信息,并按表生成僵尸和关卡波次

方法一、使用excel配置表

前面我们只是简单的随机生成僵尸,实际关卡编辑肯定不可能按这种方式,这里教大家一个读取excel配置表的方法,具体可以参考我之前的文章,这里就不过多介绍了:【unity小技巧】unity读excel配置表操作,excel转txt文本,并读取txt文本内容,实例说明

excel转txt文本

比如配置表大概样式
level.xlsx
在这里插入图片描述

转换为txt文本后效果
在这里插入图片描述

读取txt数据

新增GameConfigData游戏配置表类,每个对象对应一个txt配置表

public class GameConfigData
{// 存储配置表中的所有数据private List<Dictionary<string, string>> dataDic;// 构造函数,参数为字符串public GameConfigData(string str){// 初始化数据字典dataDic = new List<Dictionary<string, string>>();// 按换行符切割字符串string[] lines = str.Split('\n');// 第一行是存储数据的类型string[] title = lines[0].Trim().Split('\t');//tab切割// 从第三行(下标为2)开始遍历数据,第二行数据是解释说明for (int i = 2; i < lines.Length; i++){// 创建新的字典存储每行数据Dictionary<string, string> dic = new Dictionary<string, string>();// 按tab切割每行数据string[] tempArr = lines[i].Trim().Split("\t");// 将切割后的数据添加到字典中for (int j = 0; j < tempArr.Length; j++){dic.Add(title[j], tempArr[j]);}// 将字典添加到数据列表中dataDic.Add(dic);}}// 获取所有行的数据public List<Dictionary<string, string>> GetLines(){return dataDic;}// 根据ID获取一行数据public Dictionary<string, string> GetOneById(string id){// 遍历数据列表for (int i = 0; i < dataDic.Count; i++){// 获取当前字典Dictionary<string, string> dic = dataDic[i];// 如果字典中的ID与参数相同,返回该字典if (dic["Id"] == id){return dic;}}// 如果没有找到,返回nullreturn null;}// 根据levelId获取数据public List<Dictionary<string, string>> GetListByLevelId(string levelId){List<Dictionary<string, string>> levelList = new List<Dictionary<string, string>>();// 遍历数据列表for (int i = 0; i < dataDic.Count; i++){// 获取当前字典Dictionary<string, string> dic = dataDic[i];// 如果字典中的levelID与参数相同if (dic["levelID"] == levelId){// 将字典添加到数据列表中levelList.Add(dic);}}return levelList;}
}

新增GameConfigManager代码如下

// 游戏配置管理类
public class GameConfigManager
{public static GameConfigManager Instance = new GameConfigManager();private GameConfigData levelData;//关卡数据// 文本资源private TextAsset textAsset;// 初始化配置文件(txt文件 存储到内存)public void Init(){// 加载关卡数据textAsset = Resources.Load<TextAsset>("Data/level");levelData = new GameConfigData(textAsset.text);}// 获取关卡行数据public List<Dictionary<string, string>> GetLevelLines(){return levelData.GetLines();}// 根据ID获取关卡数据public Dictionary<string, string> GetLevelById(string id){return levelData.GetOneById(id);}//根据关卡id获取数据public List<Dictionary<string, string>> GetLevelList(string levelId){return levelData.GetListByLevelId(levelId);}
}

按配置信息生成僵尸

修改GameManager,初始化配置表信息并获取当前关卡数据

public int curLevelId = 1; //当前关卡
public int curProgressId = 1;//当前进度
public List<Dictionary<string, string>> listData;//当前关卡数据private void Awake()
{Instance = this;//初始化配置表GameConfigManager.Instance.Init();//获取当前关卡数据listData = GameConfigManager.Instance.GetLevelList(curLevelId.ToString());
}

修改GenerateZombies,调用配置表信息并使用

public class GenerateZombies : MonoBehaviour
{public static GenerateZombies Instance { get; private set; }public List<GameObject> curProgressZombie;//保存当前进度的敌人int zOrderIndex = 0;//排序private void Awake(){Instance = this;}private void Start(){curProgressZombie = new List<GameObject>();TableCreateZombie();}//生成僵尸private void TableCreateZombie(){//判断是否是最后一波敌人,如果表格中当前进度没有可以创建的敌人,及游戏胜利bool canCreate = false;//获取当前关卡数据GameManager.Instance.listData.ForEach(data =>{//属于当前进度的僵尸if (data["progressId"] == GameManager.Instance.curProgressId.ToString()){//延迟一段时间创建僵尸StartCoroutine(ITableCreateZombie(data));//代表当前进度有敌人canCreate = true;}});if(!canCreate){StopAllCoroutines();//停止所有的携程//TODO:游戏胜利处理Debug.Log("游戏胜利");}}IEnumerator ITableCreateZombie(Dictionary<string, string> levelItem){yield return new WaitForSeconds(float.Parse(levelItem["createTime"]));//加载预制件:从Resources文件夹中加载,例如Zombie1GameObject zombiePrefab = Resources.Load("Prefabs/Enemy/Zombie" + levelItem["zombieType"]) as GameObject;//生成僵尸实例GameObject zombie = Instantiate(zombiePrefab);//根据配表的生成位置,找到父物体Transform zombieLine = transform.GetChild(int.Parse(levelItem["bornPos"]));zombie.transform.parent = zombieLine;zombie.transform.localPosition = Vector3.zero;zombie.GetComponent<SpriteRenderer>().sortingOrder = zOrderIndex;zOrderIndex ++;curProgressZombie.Add(zombie);}//消灭敌人public void ZombieDied(GameObject gameObject){if(curProgressZombie.Contains(gameObject)){curProgressZombie.Remove(gameObject);}//当前进度的僵尸全部消灭了,开启下一个进度if(curProgressZombie.Count == 0){GameManager.Instance.curProgressId += 1;TableCreateZombie();}}
}

修改Zombie里的OnDie方法,消灭敌人时调用下面代码,控制游戏进度变化

GenerateZombies.Instance.ZombieDied(gameObject);

记得配置敌人信息
在这里插入图片描述

效果,可以看到僵尸按配置表在指定位置逐渐生成
在这里插入图片描述

方法二、使用ScriptableObject 配置关卡信息

前面的excel转txt配置表使用比较方便,如果你觉得太复杂,并不理解他的用法。那也没关系,这里推荐另一种方法使用ScriptableObject 做配置关卡信息,省去了读excel和txt的步骤,也能实现一样的效果

新增LevelData

using System.Collections.Generic;
using UnityEngine;[CreateAssetMenu(fileName = "LevelData", menuName = "LevelData", order = 0)]
public class LevelData : ScriptableObject {// 存储关卡数据的列表public List<LevelItem> levelDataList = new List<LevelItem>();
}// 表示单个关卡的数据
[System.Serializable]
public class LevelItem {public int id;           // 关卡IDpublic int levelId;      // 等级IDpublic int progressId;   // 进度IDpublic int createTime;   // 创建时间public int zombieType;   // 僵尸类型public int bornPos;      // 出生位置// 自定义的ToString方法,用于返回关键信息的字符串表示overridepublic string ToString(){return "[id]: " + id.ToString();}
}

配置和excel表基本一样,然后再去获取这个LevelData 使用即可,使用方法和前面类似,这里就不多介绍了
在这里插入图片描述

源码

源码不出意外的话我会放在最后一节

结束语

赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注,以便我第一时间收到反馈,你的每一次支持都是我不断创作的最大动力。当然如果你发现了文章中存在错误或者有更好的解决方法,也欢迎评论私信告诉我哦!

好了,我是向宇,https://xiangyu.blog.csdn.net

一位在小公司默默奋斗的开发者,出于兴趣爱好,最近开始自学unity,闲暇之余,边学习边记录分享,站在巨人的肩膀上,通过学习前辈们的经验总是会给我很多帮助和启发!php是工作,unity是生活!如果你遇到任何问题,也欢迎你评论私信找我, 虽然有些问题我也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/846642.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PCIe总线-事物层之TLP路由介绍(七)

1.概述 下图是一个PCIe总线系统示意图。此时RC发出一个TLP&#xff0c;经过Switch访问EP&#xff0c;TLP的路径为红色箭头所示。首先TLP从RC的下行OUT端口发出&#xff0c;Switch的上行IN端口接收到该TLP后&#xff0c;根据其路由信息&#xff0c;将其转发到Switch的下行OUT端…

Google力作 | Infini-attention无限长序列处理Transformer

更多文章&#xff0c;请关注微信公众号&#xff1a;NLP分享汇 原文链接&#xff1a;Google力作 | Infini-attention无限长序列处理Transformerhttps://mp.weixin.qq.com/s?__bizMzU1ODk1NDUzMw&mid2247485000&idx1&sne44a7256bcb178df0d2cc9b33c6882a1&chksm…

Linux的shell脚本:如何用bash脚本从mysql数据库中直接读取用户数据,并直接显示出来(一条命令查看数据库信息)

目录 一、要求 二、脚本和解释 三、脚本执行 1、 脚本保存为sh文件 2、给脚本赋予执行权限 3、运行脚本 四、Bash脚本中&#xff0c;可以使用哪些MySQL语句 1、连接到MySQL数据库 2、执行SQL语句 3、查询并显示结果 4、脚本中执行SQL文件 5、数据库操作 …

Vue.js 动态组件与异步组件

title: Vue.js 动态组件与异步组件 date: 2024/6/2 下午9:08:50 updated: 2024/6/2 下午9:08:50 categories: 前端开发 tags:Vue概览动态组件异步加载性能提升路由管理状态控制工具生态 第1章 Vue.js 简介 1.1 Vue.js 概述 Vue.js 是一个渐进式的JavaScript框架&#xff0c;…

《论文阅读》通过顺序不敏感的表示正则化实现稳健的个性化对话生成 ACL 2023

《论文阅读》通过顺序不敏感的表示正则化实现稳健的个性化对话生成 ACL 2023 前言 相关个性化生成论文推荐简介问题定义方法损失函数实验结果 前言 亲身阅读感受分享&#xff0c;细节画图解释&#xff0c;再也不用担心看不懂论文啦~ 无抄袭&#xff0c;无复制&#xff0c;纯手…

中间件模版引擎

文章目录 中间件1.自定义中间件1&#xff09;全局2&#xff09;局部中间件 2.内置中间件(静态资源目录&#xff09; Art-template1.模板语法1&#xff09;输出2&#xff09;原文输出3&#xff09;条件判断4&#xff09;循环5&#xff09;子模版6&#xff09;模版继承7&#xff…

vue-Dialog 自定义title样式

展示结果 vue代码 <el-dialog :title"title" :visible.sync"classifyOpen" width"500px" :showClose"false" class"aboutDialog"> <el-form :model"classifyForm" :rules"classifyRules">…

【OJ】C++ | 二叉树进阶 · 合集(2)

摘要&#xff1a;根据二叉树创建字符串、二叉树的最近公共祖先、二叉树的层序遍历 前言&#xff1a;承接上文&#xff0c;本文继续提供二叉树进阶有关题目的解法。如有错误&#xff0c;烦请指正。 目录 1. 根据二叉树创建字符串 题解及代码 2. 二叉树的最近公共祖先 题解及…

Java | Leetcode Java题解之第121题买卖股票的最佳时机

题目&#xff1a; 题解&#xff1a; public class Solution {public int maxProfit(int prices[]) {int minprice Integer.MAX_VALUE;int maxprofit 0;for (int i 0; i < prices.length; i) {if (prices[i] < minprice) {minprice prices[i];} else if (prices[i] -…

用幻灯片讲解C++中的C语言风格数组

用幻灯片讲解C中的C语言风格数组 1.栈内存中的C风格数组 糟糕的可用性&#xff0c;但你将在遗留代码中看到它们。相同类型的对象块。大小必须是常量表达式。第一个元素的索引为0&#xff0c;即数组索引从0开始。 注意一下数组的初始化&#xff0c;使用了C11标准之后的统一初始…

数学建模--特殊的图

目录 1.二部图 &#xff08;1&#xff09;简单认识 &#xff08;2&#xff09;定义 &#xff08;3&#xff09;判定定理 &#xff08;4&#xff09;定理理解 2.匹配问题 &#xff08;1&#xff09;匹配 &#xff08;2&#xff09;完备&&完美匹配 &#xff08;3…

Python 入门教程详细版全集(两周速成)

一、初始Python 打开CMD&#xff08;命令提示符&#xff09;程序&#xff0c;输入Python并回车。然后&#xff0c;在里面输入代码回车即可立即执行。 Tip1:找不到“命令提示符”程序在哪里&#xff1f; 使用快捷键&#xff1a;win r;打开运行框&#xff0c;输入cmd后回车即可…

chat2-Client发送数据给Server

本文档描述了Client发送消息给Server&#xff0c; Server端打印接收的消息 一、Client 1.1.客户端的类Client.java中添加如下的start()方法 (表示启动客户端功能的方法)&#xff0c;并调用 /**start方法&#xff0c;作为客户端开始工作的方法*/ public void start(){ …

自然语言处理(NLP)—— 神经网络语言处理

1. 总体原则 1.1 深度神经网络&#xff08;Deep Neural Network&#xff09;的训练过程 下图展示了自然语言处理&#xff08;NLP&#xff09;领域内使用的深度神经网络&#xff08;Deep Neural Network&#xff09;的训练过程的简化图。 在神经网络的NLP领域&#xff1a; 语料…

深入解析Java中List和Map的多层嵌套与拆分

深入解析Java中List和Map的多层嵌套与拆分 深入解析Java中List和Map的多层嵌套与拆分技巧 &#x1f4dd;摘要引言正文内容什么是嵌套数据结构&#xff1f;例子&#xff1a; 遍历嵌套List和Map遍历嵌套List遍历嵌套Map 拆分嵌套数据结构拆分嵌套List拆分嵌套Map &#x1f914; Q…

排序-希尔排序

介绍 希尔排序属于那种没有了解过的直接看代码一脸懵逼的&#xff0c; 所以同学们尽量不要直接看代码&#xff0c;仔细阅读本篇博客内容。 插入排序本来算是一个低效排序&#xff0c; 一次只可以挪动一个数据&#xff0c; 但是&#xff0c;它的强来了&#xff01;&#xff01…

网吧|基于SprinBoot+vue的网吧管理系统(源码+数据库+文档)

网吧管理系统 目录 基于SprinBootvue的网吧管理系统 一、前言 二、系统设计 三、系统功能设计 1 管理员功能模块 2 网管功能模块 3 会员功能模块 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介绍&#…

Arduino 按钮及弹跳

所需元件 可插入面包板的按钮1个 220Ω电阻1个 10kΩ电阻1个 3mm或5mm LED 1个 面包板1块 Arduino Uno开发板1块 面包板连接线数条 使用外接电阻 将5V接到按钮&#xff0c;按钮的另一端串联1个10kΩ电阻再接地&#xff0c;这样的接法被称为下拉电阻(pull-down resistor)。若测…

【30天精通Prometheus:一站式监控实战指南】第14天:jmx_exporter从入门到实战:安装、配置详解与生产环境搭建指南,超详细

亲爱的读者们&#x1f44b;   欢迎加入【30天精通Prometheus】专栏&#xff01;&#x1f4da; 在这里&#xff0c;我们将探索Prometheus的强大功能&#xff0c;并将其应用于实际监控中。这个专栏都将为你提供宝贵的实战经验。&#x1f680;   Prometheus是云原生和DevOps的…