一直在学习,几乎边学边忘,再也不想打王者农药了,现在打卡学习持续写博客,现在在开发学习保卫萝卜,这篇文章关于地图编辑器的开发,在项目中不能是无限个场景,用读取xml文件的方法可以说是能实现无限关卡,同时节省很多开发时间缩短周期

一.目录结构

二.创建数据类(放置在Data目录)

  1. 首先看一下XML文件内容

  2. 根据xml文件节点创建一些数据类,首先创建Point.cs脚本,放置在Data目录中

using UnityEngine;
using System.Collections;//格子坐标
public class Point
{public int X;public int Y;public Point(int x, int y){this.X = x;this.Y = y;}
}

3.创建Tile.cs脚本

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;//格子信息
public class Tile
{public int X;public int Y;public bool CanHold; //是否可以放置塔public object Data; //格子所保存的数据public Tile(int x, int y){this.X = x;this.Y = y;}public override string ToString(){return string.Format("[X:{0},Y:{1},CanHold:{2}]",this.X,this.Y,this.CanHold);}
}

4.创建Round.cs脚本

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;public class Round
{public int Monster; //怪物类型IDpublic int Count;   //怪物数量public Round(int monster, int count){this.Monster = monster;this.Count = count;}
}

5.根据xml文件信息创建关卡类Level.cs

using UnityEngine;
using System.Collections;
using System.Collections.Generic;public class Level
{//名字public string Name;//背景public string Background;//路径public string Road;//金币public int InitScore;//炮塔可放置的位置public List<Point> Holder = new List<Point>();//怪物行走的路径public List<Point> Path = new List<Point>();//出怪回合信息public List<Round> Rounds = new List<Round>();
}

三.创建读写XML工具类

using UnityEngine;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Xml;public class Tools
{//读取关卡列表public static List<FileInfo> GetLevelFiles(){string[] files = Directory.GetFiles(Consts.LevelDir, "*.xml");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;}//填充Level类数据public static void FillLevel(string fileName, ref Level level){FileInfo file = new FileInfo(fileName);StreamReader sr = new StreamReader(file.OpenRead(), Encoding.UTF8);XmlDocument doc = new XmlDocument();doc.Load(sr);level.Name = doc.SelectSingleNode("/Level/Name").InnerText;level.Background = doc.SelectSingleNode("/Level/Background").InnerText;level.Road = doc.SelectSingleNode("/Level/Road").InnerText;level.InitScore = int.Parse(doc.SelectSingleNode("/Level/InitScore").InnerText);XmlNodeList nodes;nodes = doc.SelectNodes("/Level/Holder/Point");for (int i = 0; i < nodes.Count; i++){XmlNode node = nodes[i];Point p = new Point(int.Parse(node.Attributes["X"].Value),int.Parse(node.Attributes["Y"].Value));level.Holder.Add(p);}nodes = doc.SelectNodes("/Level/Path/Point");for (int i = 0; i < nodes.Count; i++){XmlNode node = nodes[i];Point p = new Point(int.Parse(node.Attributes["X"].Value),int.Parse(node.Attributes["Y"].Value));level.Path.Add(p);}nodes = doc.SelectNodes("/Level/Rounds/Round");for (int i = 0; i < nodes.Count; i++){XmlNode node = nodes[i];Round r = new Round(int.Parse(node.Attributes["Monster"].Value),int.Parse(node.Attributes["Count"].Value));level.Rounds.Add(r);}sr.Close();sr.Dispose();}//保存关卡public static void SaveLevel(string fileName, Level level){StringBuilder sb = new StringBuilder();sb.AppendLine("<?xml version=\"1.0\" encoding=\"utf-8\"?>");sb.AppendLine("<Level>");sb.AppendLine(string.Format("<Name>{0}</Name>", level.Name));sb.AppendLine(string.Format("<Background>{0}</Background>", level.Background));sb.AppendLine(string.Format("<Road>{0}</Road>", level.Road));sb.AppendLine(string.Format("<InitScore>{0}</InitScore>", level.InitScore));sb.AppendLine("<Holder>");for (int i = 0; i < level.Holder.Count; i++){sb.AppendLine(string.Format("<Point X=\"{0}\" Y=\"{1}\"/>", level.Holder[i].X, level.Holder[i].Y));}sb.AppendLine("</Holder>");sb.AppendLine("<Path>");for (int i = 0; i < level.Path.Count; i++){sb.AppendLine(string.Format("<Point X=\"{0}\" Y=\"{1}\"/>", level.Path[i].X, level.Path[i].Y));}sb.AppendLine("</Path>");sb.AppendLine("<Rounds>");for (int i = 0; i < level.Rounds.Count; i++){sb.AppendLine(string.Format("<Round Monster=\"{0}\" Count=\"{1}\"/>", level.Rounds[i].Monster, level.Rounds[i].Count));}sb.AppendLine("</Rounds>");sb.AppendLine("</Level>");string content = sb.ToString();StreamWriter sw = new StreamWriter(fileName, false, Encoding.UTF8);sw.Write(content);sw.Flush();sw.Dispose();}//加载图片public static IEnumerator LoadImage(string url, SpriteRenderer render){WWW www = new WWW(url);while (!www.isDone)yield return www;Texture2D texture = www.texture;Sprite sp = Sprite.Create(texture,new Rect(0, 0, texture.width, texture.height),new Vector2(0.5f, 0.5f));render.sprite = sp;}
}

三.创建编辑器Editor类

1.创建常量类Consts.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;public static class Consts
{//目录public static readonly string LevelDir = Application.dataPath + @"\Game\Res\Levels";public static readonly string MapDir = Application.dataPath + @"\Game\Res\Maps";
}

2.创建Map.cs,此脚本挂在层级试图hierarchy中的Map上

先定义一些字段,属性,和方法

using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;public class Map : MonoBehaviour
{#region 常量public const int RowCount = 8;   //行数public const int ColumnCount = 12; //列数#endregion#region 字段float MapWidth;//地图宽float MapHeight;//地图高float TileWidth;//格子宽float TileHeight;//格子高List<Tile> m_grid = new List<Tile>(); //格子集合List<Tile> m_road = new List<Tile>(); //路径集合Level m_level; //关卡数据public bool DrawGizmos = true; //是否绘制网格#endregion#region 属性public Level Level{get { return m_level; }}public string BackgroundImage{set{SpriteRenderer render = transform.Find("Background").GetComponent<SpriteRenderer>();StartCoroutine(Tools.LoadImage(value, render));}}public string RoadImage{set{SpriteRenderer render = transform.Find("Road").GetComponent<SpriteRenderer>();StartCoroutine(Tools.LoadImage(value, render));}}public List<Tile> Grid{get { return m_grid; }}public List<Tile> Road{get { return m_road; }}//怪物的寻路路径public Vector3[] Path{get{List<Vector3> m_path = new List<Vector3>();for (int i = 0; i < m_road.Count; i++){Tile t = m_road[i];Vector3 point = GetPosition(t);m_path.Add(point);}return m_path.ToArray();}}#endregion#region 方法public void LoadLevel(Level level){//清除当前状态Clear();//保存this.m_level = level;//加载图片this.BackgroundImage = "file://" + Consts.MapDir + "/" + level.Background;this.RoadImage = "file://" + Consts.MapDir + "/" + level.Road;//寻路点for (int i = 0; i < level.Path.Count; i++){Point p = level.Path[i];Tile t = GetTile(p.X, p.Y);m_road.Add(t);}//炮塔点for (int i = 0; i < level.Holder.Count; i++){Point p = level.Holder[i];Tile t = GetTile(p.X, p.Y);t.CanHold = true;}}//清除塔位信息public void ClearHolder(){foreach (Tile t in m_grid){if(t.CanHold)t.CanHold = false;}}//清除寻路格子集合public void ClearRoad(){m_road.Clear();}//清除所有信息public void Clear(){m_level = null;ClearHolder();ClearRoad();}#endregion#region Unity回调//只在运行期起作用void Awake(){//计算地图和格子大小CalculateSize();//创建所有的格子for (int i = 0; i < RowCount; i++)for (int j = 0; j < ColumnCount; j++)m_grid.Add(new Tile(j, i));}//只在编辑器里起作用void OnDrawGizmos(){if (!DrawGizmos)return;//计算地图和格子大小CalculateSize();//绘制格子Gizmos.color = Color.green;//绘制行for (int row = 0; row <= RowCount; row++){Vector2 from = new Vector2(-MapWidth / 2, -MapHeight / 2 + row * TileHeight);Vector2 to = new Vector2(-MapWidth / 2 + MapWidth, -MapHeight / 2 + row * TileHeight);Gizmos.DrawLine(from, to);}//绘制列for (int col = 0; col <= ColumnCount; col++){Vector2 from = new Vector2(-MapWidth / 2 + col * TileWidth, MapHeight / 2);Vector2 to = new Vector2(-MapWidth / 2 + col * TileWidth, -MapHeight / 2);Gizmos.DrawLine(from, to);}foreach (Tile t in m_grid){if (t.CanHold){Vector3 pos = GetPosition(t);Gizmos.DrawIcon(pos, "holder.png", true);}}Gizmos.color = Color.red;for (int i = 0; i < m_road.Count; i++){//起点if (i == 0){Gizmos.DrawIcon(GetPosition(m_road[i]), "start.png", true);}//终点if (m_road.Count > 1 && i == m_road.Count - 1){Gizmos.DrawIcon(GetPosition(m_road[i]), "end.png", true);}//红色的连线if (m_road.Count > 1 && i != 0){Vector3 from = GetPosition(m_road[i - 1]);Vector3 to = GetPosition(m_road[i]);Gizmos.DrawLine(from, to);}}}#endregion#region 帮助方法//计算地图大小,格子大小void CalculateSize(){Vector3 leftDown = new Vector3(0, 0);Vector3 rightUp = new Vector3(1, 1);Vector3 p1 = Camera.main.ViewportToWorldPoint(leftDown);Vector3 p2 = Camera.main.ViewportToWorldPoint(rightUp);MapWidth = (p2.x - p1.x);MapHeight = (p2.y - p1.y);TileWidth = MapWidth / ColumnCount;TileHeight = MapHeight / RowCount;}//获取格子中心点所在的世界坐标Vector3 GetPosition(Tile t){return new Vector3(-MapWidth / 2 + (t.X + 0.5f) * TileWidth,-MapHeight / 2 + (t.Y + 0.5f) * TileHeight,0);}//根据格子索引号获得格子Tile GetTile(int tileX, int tileY){int index = tileX + tileY * ColumnCount;if (index < 0 || index >= m_grid.Count)return null;return m_grid[index];}//获取鼠标下面的格子Tile GetTileUnderMouse(){Vector2 wordPos = GetWorldPosition();int col = (int)((wordPos.x + MapWidth / 2) / TileWidth);int row = (int)((wordPos.y + MapHeight / 2) / TileHeight);return GetTile(col, row);}//获取鼠标所在位置的世界坐标Vector3 GetWorldPosition(){Vector3 viewPos = Camera.main.ScreenToViewportPoint(Input.mousePosition);Vector3 worldPos = Camera.main.ViewportToWorldPoint(viewPos);return worldPos;}#endregion
}

3.在Editor文件夹下创建编辑器类MapEditor.cs

using UnityEngine;
using UnityEditor;
using System.IO;
using System.Collections;
using System.Collections.Generic;[CustomEditor(typeof(Map))]
public class MapEditor : Editor
{[HideInInspector]public Map Map = null;//关卡列表List<FileInfo> m_files = new List<FileInfo>();//当前编辑的关卡索引号int m_selectIndex = -1;public override void OnInspectorGUI(){base.OnInspectorGUI();if(Application.isPlaying){//关联的Mono脚本组件Map = target as Map;EditorGUILayout.BeginHorizontal();int currentIndex = EditorGUILayout.Popup(m_selectIndex, GetNames(m_files));if (currentIndex != m_selectIndex){m_selectIndex = currentIndex;//加载关卡LoadLevel();}if (GUILayout.Button("读取列表")){//读取关卡列表LoadLevelFiles();}EditorGUILayout.EndHorizontal();EditorGUILayout.BeginHorizontal();if (GUILayout.Button("清除塔点")){Map.ClearHolder();}if (GUILayout.Button("清除路径")){Map.ClearRoad();}EditorGUILayout.EndHorizontal();if (GUILayout.Button("保存数据")){//保存关卡SaveLevel();}}if (GUI.changed)EditorUtility.SetDirty(target);}void LoadLevelFiles(){//清除状态Clear();//加载列表m_files = Tools.GetLevelFiles();//默认加载第一个关卡if (m_files.Count > 0){m_selectIndex = 0;LoadLevel();}}void LoadLevel(){FileInfo file = m_files[m_selectIndex];Level level = new Level();Tools.FillLevel(file.FullName, ref level);Map.LoadLevel(level);}void SaveLevel(){//获取当前加载的关卡Level level = Map.Level;//临时索引点List<Point> list = null;//收集放塔点list = new List<Point>();for (int i = 0; i < Map.Grid.Count; i++){Tile t = Map.Grid[i];if (t.CanHold){Point p = new Point(t.X, t.Y);list.Add(p);}}level.Holder = list;//收集寻路点list = new List<Point>();for (int i = 0; i < Map.Road.Count; i++){Tile t = Map.Road[i];Point p = new Point(t.X, t.Y);list.Add(p);}level.Path = list;//路径string fileName = m_files[m_selectIndex].FullName;//保存关卡Tools.SaveLevel(fileName, level);//弹框提示EditorUtility.DisplayDialog("保存关卡数据", "保存成功", "确定");}void Clear(){m_files.Clear();m_selectIndex = -1;}string[] GetNames(List<FileInfo> files){List<string> names = new List<string>();foreach (FileInfo file in files){names.Add(file.Name);}return names.ToArray();}
}

4.自此完成了读取XML文件,显示地图和放塔点,接着要做的是完成在编辑器模式下鼠标左键添加或清除放塔点,右键添加或清除路径点

在map.cs脚本中添加一个事件类TileClickEventArgs,继承EventArgs

//鼠标点击参数类
public class TileClickEventArgs : EventArgs
{public int MouseButton; //0左键,1右键public Tile Tile;public TileClickEventArgs(int mouseButton, Tile tile){this.MouseButton = mouseButton;this.Tile = tile;}
}

定义事件

    #region 事件public event EventHandler<TileClickEventArgs> OnTileClick;#endregion

接着在map类中添加事件回调代码

    #region 事件回调void Map_OnTileClick(object sender, TileClickEventArgs e){if (Level == null)return;//处理放塔操作if (e.MouseButton == 0 && !m_road.Contains(e.Tile)){e.Tile.CanHold = !e.Tile.CanHold;}//处理寻路点操作if (e.MouseButton == 1 && !e.Tile.CanHold){if (m_road.Contains(e.Tile))m_road.Remove(e.Tile);elsem_road.Add(e.Tile);}else { }}#endregion

在Awake()方法中监听鼠标点击事件

       监听鼠标点击事件OnTileClick += Map_OnTileClick;

然后在Update中检测触发

void Update(){//鼠标左键检测if (Input.GetMouseButtonDown(0)){Tile t = GetTileUnderMouse();if (t != null){//触发鼠标左键点击事件TileClickEventArgs e = new TileClickEventArgs(0, t);if (OnTileClick != null){OnTileClick(this, e);}}}//鼠标右键检测if (Input.GetMouseButtonDown(1)){Tile t = GetTileUnderMouse();if (t != null){//触发鼠标右键点击事件TileClickEventArgs e = new TileClickEventArgs(1, t);if (OnTileClick != null){OnTileClick(this, e);}}}}

地图编辑器到这里就完成了。第一次写博客完全不知道怎么写,只知道贴代码,就当是自己的学习笔记鼓励自己继续学下去,总比沉迷王者农药要好得多,农药伤身不益智 。mmp—-

Unity3d开发——保卫萝卜学习笔记一地图编辑器开发相关推荐

  1. 【嵌入式系统开发】学习笔记四:嵌入式开发的基本概念与工具链

    提示:本文内容参考慕课课程:<ARM微控制器与嵌入式系统> 嵌入式开发的基本概念与工具链 前言 一.电路板 1.开发板:EVB(Evaluation board) 2.最小系统板 二.开发 ...

  2. HaaS600物联网开发板学习笔记(一)---开发板硬件资源

    摘要:2020年9月阿里云HaaS100物联网开发板发布,紧接着600开发板也发布了.二者不同之处有很多,最明显的是100是wifi联网,600是gprs联网,也就是"wifi和插卡&quo ...

  3. iTOP-RK3568开发板学习笔记(1)编译+烧录系统

    迅为 RK3568 开发板学习笔记 文章目录 准备开发环境 复制 Linux SDK 编译 Buildroot 烧录固件 准备开发环境 将 ITOP-RK3568 资料包中的虚拟机开发环境解压到自己的 ...

  4. Python学习笔记:Day13 提升开发效率

    前言 最近在学习深度学习,已经跑出了几个模型,但Pyhton的基础不够扎实,因此,开始补习Python了,大家都推荐廖雪峰的课程,因此,开始了学习,但光学有没有用,还要和大家讨论一下,因此,写下这些帖 ...

  5. 华清远见fs4412开发板学习笔记(四)

    fs4412开发板学习笔记(四) 今天的课程安排 1.复习 1.1 VIM 编辑器 [1] vim + filename 打开 [2] 工作模式 命令模式 编辑模式 底行模式 [3] 模式切换 命令- ...

  6. springmvc学习笔记(10)-springmvc注解开发之商品改动功能

    springmvc学习笔记(10)-springmvc注解开发之商品改动功能 springmvc学习笔记(10)-springmvc注解开发之商品改动功能 标签: springmvc springmv ...

  7. ASP.Net MVC开发基础学习笔记(5):区域、模板页与WebAPI初步

    http://blog.jobbole.com/85008/ ASP.Net MVC开发基础学习笔记(5):区域.模板页与WebAPI初步 2015/03/17 · IT技术 · .Net, Asp. ...

  8. Android:日常学习笔记(8)———探究UI开发(2)

    Android:日常学习笔记(8)---探究UI开发(2) 对话框 说明: 对话框是提示用户作出决定或输入额外信息的小窗口. 对话框不会填充屏幕,通常用于需要用户采取行动才能继续执行的模式事件. 提示 ...

  9. 微信小程序开发:学习笔记[8]——页面跳转及传参

    微信小程序开发:学习笔记[8]--页面跳转及传参 页面跳转 一个小程序拥有多个页面,我们可以通过wx.navigateTo推入一个新的页面.在首页使用2次wx.navigateTo后,页面层级会有三层 ...

最新文章

  1. Maven 学习Tips
  2. 卷积的定义及其物理意义_高等数学入门——高阶导数的定义及其物理意义
  3. php无法将值传入数据库,PHP-无法将句子插入数据库
  4. python代码基础题-python3的基础练习题
  5. Python__封装
  6. 微信小程序实现文件下载 以及微信小程序保存Excel
  7. labview当前vi路径_对于LabVIEW程序为什么生成EXE后,涉及到路径的输出不正确了?...
  8. 高等数学下-赵立军-北京大学出版社-题解-练习9.3
  9. 利用React/anu编写一个弹出层
  10. 【OpenCV】图像的内存分配与释放以及复制图像
  11. LaTeX 安装及环境配置
  12. 离线缓存与客户端存储总结
  13. 从认知负荷理论看语音交互设计
  14. redis实现分布式锁(乞丐版)
  15. DNS基础之使用dig查询DNS解析过程
  16. DFS序——树链剖分前驱知识
  17. Android调查问卷的创建与提交
  18. 美通社企业新闻汇总 | 2019.2.14 | 燃石医学完成8.5亿融资;伊蒂之屋情人节携手中国区品牌大使黄明昊...
  19. 读刘润《底层逻辑》摘录
  20. oracle clear buffer,Out 对象的 clearBuffer() 方法用来清除缓冲区里的数据,但并不把数据写到客户端。...

热门文章

  1. BZOJ2594 水管局长数据加强版LCT
  2. vs2022提示”解决方案尚未完成分析”或加载过慢问题的解决方法
  3. CentOS防火墙查看关闭和禁止启动
  4. 基于Json.net的省市县三级联动WinForm制作
  5. (转) shiro real的理解,密码匹配等
  6. python 深度学习-数学基础-3-微积分
  7. word2vec需要去标点吗_word2vec学习笔记(应用篇)(金庸武侠)
  8. 【我的Android进阶之旅】异常:java.lang.NoSuchFieldError: No static field xxx of type I in class Lcom/xxx/R$id;
  9. ODOO15如何简易查看产品历史交易价格和采购价格【免费分享OCA模块】
  10. 华为荣耀309升级鸿蒙,将更新鸿蒙 HarmonyOS 2,华为 Mate 10 Pro/P20/P30 系列老机型可升级存储:309 元起...