这里使用的是unity2020.1

对于unity编辑器开发也不是很了解,这方面的教程也不多,也是慢慢摸索的

效果显示

首先简单

介绍下Unity编辑器开发

1:Editor下打开新窗口需要继承EditorWindow,然后使用获取窗口即可,注意放在Editor文件夹下

public class DrawGameLevel : EditorWindow
{[MenuItem("Maps/Create Map &M")]public static void OpenMapCreate(){DrawGameLevel window = EditorWindow.GetWindow<DrawGameLevel>("地图编辑器");window.Show();window.minSize = new Vector2(500, 800);window.maxSize = new Vector2(600, 1200);}
}

2:因为是在Scene视图下进行操作,所以注册SceneView.duringSceneGui事件,在OnEnable中

void OnEnable()2     {3         SceneView.duringSceneGui += OnSceneGUI;4         //初始化一些东西5     }6 7     void OnDestroy()8     {9         SceneView.duringSceneGui -= OnSceneGUI;
10     }

3:unity 编辑器开发,需要在GUI中写,使用EditorGUILayout或者GUILayout来显示ui,基本的组件都是有的

这是我实现的界面和代码

 #region GUI显示private string brushY = "";// 刷新的y坐标private string brushX = "";// 刷新的x坐标private string brushDisY = "0";// 刷新的y坐标间距private string brushDisX = "0";// 刷新的x坐标间距private string zIndex = "-0.2";// 显示的层级private string fixCount = "0";// 固定生成个数,设置0,一直生成private float _lastBrushY = -10000;// 保持Y合理间距 上次刷的y的坐标private float _lastBrushX = -10000;// 保持X合理间距 上一个刷的x的坐标private int _curImgIndex = -1;//当前正在使用的图private int _curFixCount = 0;// 当前已经生成的个数private bool _drag = false;// 鼠标拖拽?private int _select = 0;// 当前选择的图片 indexprivate string ck = "1";// 关卡private Texture[] _items = null;// 地形基础图 要使用的地块private GameObject parentMap = null;// 地图节点的父节点private GameObject bgParent = null;// 背景图挂点private string[] bgNames = { "Forest", "Night", "Winter" };// 背景图名字private int selectMapIndex = 0;// 选择的地图背景图indexprivate int lastSelectMapIndex = -1;// 上次选择的地图背景图indexprivate int funcTypeIndex = 0;//  功能类型的indexprivate string[] funcTypeArry = { "无","橡皮擦","选中单个物体"};// 选择单个物体private int selectTypeIndex = 0;private int lastSelectTypeIndex = 0;// 上次选择的类型private string[] typeArry = {"不显示选图", "地形图","障碍物",};// Update is called once per framevoid OnGUI(){GUI.skin.label.normal.textColor = Color.yellow;GUI.skin.label.fontSize = 15;GUIStyle popStyle = new GUIStyle("Popup");popStyle.fontSize = 15;// 选择地图EditorGUILayout.Space();EditorGUILayout.BeginHorizontal();GUILayout.Label("1.选择地图", GUILayout.Width(200));this.selectMapIndex = EditorGUILayout.Popup(this.selectMapIndex, bgNames, popStyle, GUILayout.MaxWidth(100));EditorGUILayout.EndHorizontal();EditorGUILayout.Space();LoadBg(); ck = EditorGUILayout.TextField("2.设置关卡", ck);// 输入数据EditorGUILayout.Space();GUILayout.Label("设置坐标,批量坐标保持一致的时候使用,不输入是按照鼠标位置刷新");brushY = EditorGUILayout.TextField("3.固定Y的坐标(从左到右刷)", brushY);brushX = EditorGUILayout.TextField("4.固定X的坐标(从上到下刷)", brushX);brushDisY = EditorGUILayout.TextField("5.固定Y间距(从左到右刷)", brushDisY);brushDisX = EditorGUILayout.TextField("6.固定X间距(从上到下刷)", brushDisX);fixCount = EditorGUILayout.TextField("7.固定生成的个数", fixCount);EditorGUILayout.Space(10);zIndex = EditorGUILayout.TextField("8.物体显示层级,小的靠前显示", zIndex);EditorGUILayout.Space();EditorGUILayout.BeginHorizontal();GUILayout.Label("9.选择橡皮擦 或者 选中一个场景物体", GUILayout.Width(250));this.funcTypeIndex = EditorGUILayout.Popup(this.funcTypeIndex, funcTypeArry, popStyle, GUILayout.MaxWidth(100));EditorGUILayout.EndHorizontal();EditorGUILayout.Space();EditorGUILayout.BeginHorizontal("box");GUIStyle btnStyle = new GUIStyle("Button");btnStyle.fontSize = 15;btnStyle.padding = new RectOffset(10, 10, 10, 10);if (GUILayout.Button("10.清除当前地图数据",btnStyle)){RemoveParentChild(parentMap);_lastBrushY = -10000;// 防止后面刷新跟着这个位置_lastBrushX = -10000;_curFixCount = 0;}if (GUILayout.Button("11.导出json数据",btnStyle)){DataMgr.Instance.OutFile(parentMap,ck);EditorUtility.DisplayDialog("导出数据成", "导出关卡数据成功"+ck, "确定");}if (GUILayout.Button("12.导入json数据",btnStyle)){DataMgr.Instance.ImportFile(parentMap,ck);EditorUtility.DisplayDialog("导入数据成功","导入关卡数据成功"+ck,"确定");}EditorGUILayout.EndHorizontal();// 选择图片类型GUILayout.Label("13.显示选图", GUILayout.Width(200));this.selectTypeIndex = EditorGUILayout.Popup(this.selectTypeIndex,typeArry, popStyle, GUILayout.MaxWidth(100));if (selectTypeIndex>0)  LoadChooseImg();// 加载选图}#endregion

4:unity 编辑器开发,资源加载可以使用Resources,前提是需要把资源放到Editor->Resources中

5:地图文件导出和导入,通过FileStream和LitJson的解析实现的

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using LitJson;
using UnityEngine;
using UnityEditor;// 障碍物
public class Obstacle
{public int id;public string name;public int type;
}
// 导出的地图json文件数据格式
public class DataFile
{public int id;public string name; // 预制体名字public string path; // 加载路径public string tag;// 预制体的tagpublic string posX;// 坐标xpublic string posY;// 坐标ypublic string posZ;// 坐标zpublic string scaX;//  scale xpublic string scaY;//  scale ypublic string scaZ;// scale zpublic string rotX;//  rotate xpublic string rotY;//  rotate y  public string rotZ;// rotate z// Todo,后面还可以加障碍物id,用于实现障碍物的功能public DataFile() { }public DataFile(int id1,string path1,string tag1, float px, float py, float pz, float sx, float sy, float sz, float rx, float ry, float rz){id = id1;path = path1;string[] p = path.Split('/');name = p[p.Length - 1];tag = tag1;posX = px.ToString();posY = py.ToString();posZ = pz.ToString(); // 使用string类型,是因为转json不识别float和double scaX = sx.ToString();scaY = sy.ToString();scaZ = sz.ToString();rotX = rx.ToString();rotY = ry.ToString();rotZ = rz.ToString();}
}public class DataMgr:Editor
{private static DataMgr instance = null;public static DataMgr Instance{get{if (null == instance) instance = new DataMgr();return instance;}}public readonly List<Obstacle> m_table = null;public  DataMgr(){// 注册json类型转换方法LitJson.JsonMapper.RegisterImporter<int, string>((int input) => { return input.ToString(); });LitJson.JsonMapper.RegisterImporter<string, int>((string input) => { return Convert.ToInt32(input); });// 加载障碍物表 //TextAsset ts = Resources.Load<TextAsset>("jsonTable/config_obstacle");//m_table = JsonMapper.ToObject<List<Obstacle>>(ts.text);}// 导出文件json// ck 关卡idpublic void OutFile(GameObject parent,string ck){int childCount = parent.transform.childCount;if (childCount <= 0){Debug.Log("没有可以导出的数据节点");}List<DataFile> list = new List<DataFile>();for (int i = 0; i < childCount; i++){GameObject obj = parent.transform.GetChild(i).gameObject;DataFile file = new DataFile(i+1,obj.name,obj.tag,obj.transform.localPosition.x, obj.transform.localPosition.y, obj.transform.localPosition.z, obj.transform.localScale.x, obj.transform.localScale.y,obj.transform.localScale.z, obj.transform.localRotation.x, obj.transform.localRotation.y,obj.transform.localRotation.z);list.Add(file);}string jsons = JsonMapper.ToJson(list);FileStream fs = new FileStream(Application.dataPath + "/OutMap/mapCk_"+ck+".json", FileMode.Create);//存储时时二进制,所以这里需要把我们的字符串转成二进制byte[] bytes = new UTF8Encoding().GetBytes(jsons);fs.Write(bytes, 0, bytes.Length);//每次读取文件后都要记得关闭文件fs.Close();Debug.Log("导出成功"+ "/OutMap/mapCk_"+ck +".json");}// 导入文件 实例化数据public void ImportFile(GameObject parent,string ck){if (!parent) return;FileStream fs = new FileStream(Application.dataPath + "/OutMap/mapCk_" + ck + ".json", FileMode.Open);byte[] bytes = new byte[fs.Length];fs.Read(bytes, 0, bytes.Length);//将读取到的二进制转换成字符串string s = new UTF8Encoding().GetString(bytes);List<DataFile> list = JsonMapper.ToObject<List<DataFile>>(s);if (list.Count <= 0){Debug.Log("没有可导入的数据" + "/OutMap/mapCk_" + ck + ".json");return;}UnityEngine.Object a = Resources.Load<GameObject>(list[0].path);for (int i = 0; i < list.Count; i++){if (a.name != list[i].path){// 实例化新的a = Resources.Load<GameObject>(list[i].path);}GameObject obj = Instantiate(a) as GameObject;obj.tag = list[i].tag;obj.name = list[i].path;obj.transform.parent = parent.transform;obj.transform.localPosition = new Vector3(Convert.ToSingle(list[i].posX), Convert.ToSingle(list[i].posY), Convert.ToSingle(list[i].posZ));obj.transform.localRotation = Quaternion.Euler(Convert.ToSingle(list[i].rotX), Convert.ToSingle(list[i].rotY), Convert.ToSingle(list[i].rotZ));obj.transform.localScale = new Vector3(Convert.ToSingle(list[i].scaX), Convert.ToSingle(list[i].scaY), Convert.ToSingle(list[i].scaZ));}Debug.Log("导入成功" + "/OutMap/mapCk_" + ck + ".json");}
}

6:地图编辑器面版的全部代码

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEditor.SceneManagement;
using System;public class DrawGameLevel : EditorWindow
{[MenuItem("Maps/Create Map &M")]public static void OpenMapCreate(){DrawGameLevel window = EditorWindow.GetWindow<DrawGameLevel>("地图编辑器");window.Show();window.minSize = new Vector2(500, 800);window.maxSize = new Vector2(600, 1200);}#region 初始化和关闭界面private void OnEnable(){// 在scene下操作,所以要注册,屏蔽scene原有事件SceneView.duringSceneGui += OnSceneGUI;InitUI();}private void OnDestroy(){// 取消事件,恢复sceneSceneView.duringSceneGui -= OnSceneGUI;EndUI();}//初始化ui,判断是否需要创建挂点private void InitUI(){bgParent = GameObject.Find("BgCamera");// 判断有没有quad平面GameObject pa = GameObject.Find("Quad");if (!pa){GameObject obj = GameObject.CreatePrimitive(PrimitiveType.Quad);obj.transform.localScale = new Vector3(1000, 10, 1);obj.transform.position = new Vector3(0, 0, 0);pa = obj;}pa.tag = "Plane";// 判断地图的父节点 要刷的地形的父节点GameObject map = GameObject.Find("MapInfo");if (!map){map = new GameObject("MapInfo");map.transform.position = Vector3.zero;}parentMap = map;}// 关闭界面的时候private void EndUI(){// 删除背景图RemoveParentChild(bgParent);// 保存数据道json  再//DataMgr.Instance.OutFile(parentMap,ck);// 删除parentMap下的RemoveParentChild(parentMap);// 保存场景 原始场景EditorSceneManager.SaveScene(UnityEngine.SceneManagement.SceneManager.GetActiveScene());}#endregion#region 点击事件和射线检测刷地形private void OnSceneGUI(SceneView sceneView){// 替换Scene视图以前的相应事件,发射线检测要绘制的地图,射线必须要要有碰撞体,所以在场景中准备一个plane,整对着屏幕,只要射线碰撞到plane才进行绘制HandleUtility.AddDefaultControl(GUIUtility.GetControlID(FocusType.Passive));// 添加默认响应,来屏蔽以前的if (Event.current.type == EventType.MouseDown && Event.current.button == 0)// 点击{}else if (Event.current.type == EventType.MouseUp && Event.current.button == 0)// 抬起{if (!_drag){OnMouseEvent();}_drag = false;// 清楚上次记录的 拖动位置,上次记录的刷出数量_lastBrushY = -10000;_lastBrushX = -10000;_curFixCount = 0;}else if (Event.current.type == EventType.MouseDrag && Event.current.button == 0){OnMouseEvent();_drag = true;}}// 检测射线private void OnMouseEvent(){Vector2 mousePos = Event.current.mousePosition;mousePos.y = Camera.current.pixelHeight - mousePos.y;// 这里的鼠标原点在左上,而屏幕空间原点在左下,翻转他Ray ray = Camera.current.ScreenPointToRay(mousePos);RaycastHit hit;if (Physics.Raycast(ray, out hit, 3000f)){//  检测是不是要选中一个已经铺设的物体 if (this.funcTypeIndex == 2){// 选择了铺设的地图点if (hit.transform.parent == parentMap.transform){// 选中场景中物体EditorGUIUtility.PingObject(hit.transform);Selection.activeGameObject = hit.transform.gameObject;}return ;}// 固定生成的个数够了,不生成了if (Convert.ToInt32(fixCount) > 0 && Convert.ToInt32(fixCount) <= _curFixCount) return;// if ((hit.transform.tag == "Plane" || hit.transform.tag == "Ground") && this.funcTypeIndex!=1){// 实例化图 点击的是地面,或者点击的是groundGameObject obj = GetBrushName();float x = 0;// 这里使用临时的,是为了防止引用变量带来的错误float y = 0;Vector3 pos = Camera.current.ScreenToWorldPoint(mousePos);if (brushX != ""){// x一致 刷的物体 ,记录本次的y坐标,下次方便调整间距pos.x = Convert.ToSingle(brushX);if (_lastBrushY != -10000){// 前面有刷的同物体,计算本次位置var box = obj.GetComponent<BoxCollider>();if (box){// 必须从上往下刷_lastBrushY -= (box.size.y * obj.transform.localScale.y) + Convert.ToSingle(brushDisY);y = _lastBrushY;}}else _lastBrushY = pos.y;}else if (brushY != ""){// 刷的物体y一致 ,记录本次的x坐标,下次方便调整间距pos.y = Convert.ToSingle(brushY);if (_lastBrushX != -10000){// 前面有刷的同物体,计算本次位置var box = obj.GetComponent<BoxCollider>();if (box){// 必须从左往右刷_lastBrushX += box.size.x * obj.transform.localScale.x + Convert.ToSingle(brushDisX);x = _lastBrushX;}}else _lastBrushX = pos.x;}obj.transform.localPosition = new Vector3(x != 0 ? x : pos.x, y != 0 ? y : pos.y,Convert.ToSingle(zIndex));if (Convert.ToInt32(fixCount) > 0 && (brushY != "" || brushX != "")){// 有刷x或者y,并且固定个数,数量加_curFixCount++;}}else if ((hit.transform.tag == "Ground" || hit.transform.tag == "Obstacle") && this.funcTypeIndex == 1){// 选择了橡皮擦,擦除地面 或者 障碍物UnityEngine.Object.DestroyImmediate(hit.transform.gameObject);}}}#endregion#region GUI显示private string brushY = "";// 刷新的y坐标private string brushX = "";// 刷新的x坐标private string brushDisY = "0";// 刷新的y坐标间距private string brushDisX = "0";// 刷新的x坐标间距private string zIndex = "-0.2";// 显示的层级private string fixCount = "0";// 固定生成个数,设置0,一直生成private float _lastBrushY = -10000;// 保持Y合理间距 上次刷的y的坐标private float _lastBrushX = -10000;// 保持X合理间距 上一个刷的x的坐标private int _curImgIndex = -1;//当前正在使用的图private int _curFixCount = 0;// 当前已经生成的个数private bool _drag = false;// 鼠标拖拽?private int _select = 0;// 当前选择的图片 indexprivate string ck = "1";// 关卡private Texture[] _items = null;// 地形基础图 要使用的地块private GameObject parentMap = null;// 地图节点的父节点private GameObject bgParent = null;// 背景图挂点private string[] bgNames = { "Forest", "Night", "Winter" };// 背景图名字private int selectMapIndex = 0;// 选择的地图背景图indexprivate int lastSelectMapIndex = -1;// 上次选择的地图背景图indexprivate int funcTypeIndex = 0;//  功能类型的indexprivate string[] funcTypeArry = { "无","橡皮擦","选中单个物体"};// 选择单个物体private int selectTypeIndex = 0;private int lastSelectTypeIndex = 0;// 上次选择的类型private string[] typeArry = {"不显示选图", "地形图","障碍物",};// Update is called once per framevoid OnGUI(){GUI.skin.label.normal.textColor = Color.yellow;GUI.skin.label.fontSize = 15;GUIStyle popStyle = new GUIStyle("Popup");popStyle.fontSize = 15;// 选择地图EditorGUILayout.Space();EditorGUILayout.BeginHorizontal();GUILayout.Label("1.选择地图", GUILayout.Width(200));this.selectMapIndex = EditorGUILayout.Popup(this.selectMapIndex, bgNames, popStyle, GUILayout.MaxWidth(100));EditorGUILayout.EndHorizontal();EditorGUILayout.Space();LoadBg(); ck = EditorGUILayout.TextField("2.设置关卡", ck);// 输入数据EditorGUILayout.Space();GUILayout.Label("设置坐标,批量坐标保持一致的时候使用,不输入是按照鼠标位置刷新");brushY = EditorGUILayout.TextField("3.固定Y的坐标(从左到右刷)", brushY);brushX = EditorGUILayout.TextField("4.固定X的坐标(从上到下刷)", brushX);brushDisY = EditorGUILayout.TextField("5.固定Y间距(从左到右刷)", brushDisY);brushDisX = EditorGUILayout.TextField("6.固定X间距(从上到下刷)", brushDisX);fixCount = EditorGUILayout.TextField("7.固定生成的个数", fixCount);EditorGUILayout.Space(10);zIndex = EditorGUILayout.TextField("8.物体显示层级,小的靠前显示", zIndex);EditorGUILayout.Space();EditorGUILayout.BeginHorizontal();GUILayout.Label("9.选择橡皮擦 或者 选中一个场景物体", GUILayout.Width(250));this.funcTypeIndex = EditorGUILayout.Popup(this.funcTypeIndex, funcTypeArry, popStyle, GUILayout.MaxWidth(100));EditorGUILayout.EndHorizontal();EditorGUILayout.Space();EditorGUILayout.BeginHorizontal("box");GUIStyle btnStyle = new GUIStyle("Button");btnStyle.fontSize = 15;btnStyle.padding = new RectOffset(10, 10, 10, 10);if (GUILayout.Button("10.清除当前地图数据",btnStyle)){RemoveParentChild(parentMap);_lastBrushY = -10000;// 防止后面刷新跟着这个位置_lastBrushX = -10000;_curFixCount = 0;}if (GUILayout.Button("11.导出json数据",btnStyle)){DataMgr.Instance.OutFile(parentMap,ck);EditorUtility.DisplayDialog("导出数据成", "导出关卡数据成功"+ck, "确定");}if (GUILayout.Button("12.导入json数据",btnStyle)){DataMgr.Instance.ImportFile(parentMap,ck);EditorUtility.DisplayDialog("导入数据成功","导入关卡数据成功"+ck,"确定");}EditorGUILayout.EndHorizontal();// 选择图片类型GUILayout.Label("13.显示选图", GUILayout.Width(200));this.selectTypeIndex = EditorGUILayout.Popup(this.selectTypeIndex,typeArry, popStyle, GUILayout.MaxWidth(100));if (selectTypeIndex>0)  LoadChooseImg();// 加载选图}#endregion#region 加载图片和删除// 加载地形需要图 选择使用private void LoadChooseImg(){// 根据类型,加载相应地形图,障碍,还是金币,还是基础地形string name = bgNames[this.selectMapIndex].ToLower();switch (selectTypeIndex){case 2:name = "obstacle";break;case 3:name = "gold"; break;}Texture[] ts = Resources.LoadAll<Texture>("baseImg/" + name);if (ts.Length<=0) return;// 无图_items = ts;int sizeY = 100 * Mathf.CeilToInt(_items.Length / 5f);_select = GUI.SelectionGrid(new Rect(new Vector2(0, 385), new Vector2(100 * 5, sizeY)), _select, _items, 5); //可以给出grid选择框,需要传入贴图数组_itemsif (_select != _curImgIndex || lastSelectTypeIndex != selectTypeIndex){// 切换图片了,清楚上次使用的同时刷的最后一个物体的x y  记录的刷出来的固定数量lastSelectTypeIndex = selectTypeIndex;_curImgIndex = _select;_lastBrushY = -10000;_lastBrushX = -10000;_curFixCount = 0;}}// 加载背景图private void LoadBg(){if (lastSelectMapIndex == selectMapIndex) return;if (!bgParent) return;lastSelectMapIndex = selectMapIndex;RemoveParentChild(bgParent);// 删除之前的背景RemoveParentChild(parentMap);// 删除之前铺设的int dis = 19;//间距 根据实际背景图算的UnityEngine.Object a = Resources.Load<GameObject>("Prefabs/" + bgNames[selectMapIndex]);for (int i = 0; i < 100; i++){GameObject o1 = Instantiate(a) as GameObject;o1.transform.parent = bgParent.transform;o1.transform.localPosition = new Vector3(-488 + dis * i, o1.transform.position.y, o1.transform.position.z);// -488是根据实际的quad的长度一半得到的}}// 获取要刷的图片private GameObject GetBrushName(){string tag = "Ground";// 设置物体的tagstring name = bgNames[this.selectMapIndex].ToLower();switch (selectTypeIndex){case 2: name = "obstacle"; tag = "Obstacle"; break;case 3: name = "gold"; tag = "Gold"; break;}name = "Prefabs_block/" + name + "/" + _items[_select].name;UnityEngine.Object a = Resources.Load<GameObject>(name);GameObject obj = Instantiate(a) as GameObject;obj.tag = tag;obj.name = name;obj.transform.parent = parentMap.transform;return obj;}// 删除父节点的所有子private void RemoveParentChild(GameObject parent){if (parent){while (parent.transform.childCount > 0){UnityEngine.Object.DestroyImmediate(parent.transform.GetChild(0).gameObject);}}}#endregionprivate void Update(){if (this.funcTypeIndex != 2)// 点击{// 不单独选择,那就把选择取消,取消编辑器的选中物体EditorGUIUtility.PingObject(null);Selection.activeGameObject = null;}// 修改鼠标样式//if(_items!=null) Cursor.SetCursor(_items[_select] as Texture2D, Vector2.zero, CursorMode.Auto);}
}

项目github地址:https://github.com/SuiFengErQu/unity----map-Editor

参考:https://www.cnblogs.com/wayneWy/p/13087940.html

unity实现简单的地图编辑器,实现跑酷地图编辑器 2d地图编辑器,导出地图json数据,导入地图json数据相关推荐

  1. 出租车数据的地图展示

    出租车数据的地图展示 实现方法 python数据预处理后将数据导入地图代码. 效果 数据预处理: f1['dropoff_longitude'].fillna(value=f1['dropoff_lo ...

  2. 卡马克算法(地图重复利用,跑酷类游戏)

    ----------------------------下面是理论知识--------------------------   卡马克算法:由约翰·卡马克(John Carmack)开发的一种游戏地图 ...

  3. unity实现简单巡逻兵

    unity实现简单巡逻兵 游戏视频 游戏要求 创建一个地图和若干巡逻兵(使用动画): 每个巡逻兵走一个3~5个边的凸多边型,位置数据是相对地址.即每次确定下一个目标位置,用自己当前位置为原点计算: 巡 ...

  4. Unity优化——简单AOI实现原理

    声明:本文为个人笔记,用于学习研究使用非商用,内容为个人研究及综合整理所得,若有违规,请联系,违规必改. Unity网络--简单AOI实现原理 文章目录 Unity网络--简单AOI实现原理 一.开发 ...

  5. QT实现简单的2d游戏地图编辑器

    QT实现简单的2d游戏地图编辑器 我写的这个地图编辑器主要实现了用键盘配合鼠标点击屏幕,间接生成一个二维数组,再将这个二维数组写入到文件中的操作,以直观.方便地对二维数组进行更改,以用作2d游戏的地图 ...

  6. Unity 制作简单的任务动画

    Unity 制作简单的任务动画 1.添加人物模型到unity 我使用的是unity store中的免费模型: https://assetstore.unity.com/packages/3d/char ...

  7. unity实现简单fps游戏功能

    unity实现简单fps游戏鼠标功能 1.unity实现瞄准镜功能 实现原理 按下鼠标右键镜头拉近,再次按下镜头拉远(设置Camrea的FOV属性) 逐渐拉近(例如:60->20逐渐拉近) 设置 ...

  8. unity实现简单坦克对战

    unity实现简单坦克对战 游戏要求 使用"感知-思考-行为"模型,建模 AI 坦克 场景中要放置一些障碍阻挡对手视线 坦克需要放置一个矩阵包围盒触发器,以保证 AI 坦克能使用射 ...

  9. unity ui框架_用unity制作简单的太空游戏(2)-简单炮台

    多铆蒸刚,炮塔至大! 亿万星辰,亿万炮塔! 多铆蒸刚,炮塔至上! 亿万炮塔,亿万荣光! (PS:我没有咕咕咕,就是比较惨,一口气出了半个月的差,人瘦了,也黑了,心塞塞--赶紧写个文章压压惊--) 这一 ...

  10. Unity 实现简单力场效果

    Unity 实现简单力场效果 前言 效果 源码 前言 项目中要用到一个力场的效果,偶然在bilibili中找到了.记录一下. 原视频: https://www.bilibili.com/video/B ...

最新文章

  1. Spring Boot第四篇:SpringBoot 整合JPA
  2. keil 查看 stm32 io波形_这样学习STM32单片机,从菜鸟到牛人很简单!
  3. 编程方法学12:枚举
  4. 通过hibernate去调用存储过程
  5. ansible-plabybook 常用的有用的命令
  6. Hibernate,JPA注解@Embeddable
  7. 清华AI画虾师,想当现代齐白石
  8. 后台系统上传文件回显上传进度条
  9. 学术英语视听说2听力原文_做英语听力题有哪些非常实用的小技巧?
  10. python+selenium+chrome driver 64位环境配置
  11. nodejs注册为windows服务实现开机自启动
  12. python____Django实战(1)
  13. 【软件工程作业3】DFD数据流图和SC结构图
  14. oracle是java代码块,Oracle中施行java代码
  15. mfc中StretchBlt缩放图像失真问题【zozo】
  16. 【压测】压力测试ab的用法【原创】.md
  17. 【0429】散列函数和消息鉴别
  18. 运算符优先级(总结)关于与的区别 ||与|的区别
  19. 坯子库曲面推拉教程_坯子助手下载_坯子助手最新版下载-下载之家
  20. 【大数据】数据驱动的大数据金融应用-2017CCTC大会-专题视频课程

热门文章

  1. 蒜厂年会|计蒜客2019蓝桥杯省赛 B 组模拟赛(一)
  2. PPT计算机原理结构初步,测量实践初步(赖丽娟).ppt
  3. vs2008 html5 的安装,vs2008安装教程,详细教您vs2008安装教程
  4. CVPR 2021 目标检测论文大盘点(65篇论文)
  5. 【羊了个羊】什么!第二关难如上青天,能不能简单版??
  6. 上传图片预览图片方向错误
  7. Mask R-CNN网络详解
  8. linux戒游戏下载,苍月之戒手游下载-苍月之戒公测版v1.0-Linux公社
  9. 数值分析常用的几个小程序C++实现
  10. 零信任兴起:从理念到实践