返回目录

第三章 绘制地图

一        导入素材

http://blog.csdn.net/darkrabbit/article/details/79168225

二        绘制一张简单地图

http://blog.csdn.net/darkrabbit/article/details/79177935

三        创建自己的SrpgTile

这一节中,我们选择继承Rule Tile的方式来创建自己的SrpgTile。

1     创建SrpgTile.cs

经过我们之前的分析,我们知道地形需要一个类型,还有数据。我这里只添加两个,一个地形类型,一个是回避率,同样你可以按你的需求添加所需数据。

地形类型枚举事例TerrainType.cs:

using System;namespace DR.Book.SRPG_Dev.Maps
{/// <summary>/// 地形类型/// </summary>[Serializable]public enum TerrainType : byte{/// <summary>/// 平地/// </summary>Plain,/// <summary>/// 湿地(沼泽)/// </summary>[Obsolete("Game Not Used", true)]Swamp,/// <summary>/// 道路/// </summary>Road,}
}

FE4中共26种,使用18种;这里创建的共3种,使用2种。其中可以看到湿地(Swamp)项目有个Obsolete Attribute,这是一个小技巧,意思是这个地形虽然定义了,但不使用它,在编辑器的Inspector面板中也不会显示。如果以后的版本你需要使用,只要去除Obsolete就可以了。

创建好地形后,就该创建Tile文件了。

完成后的文件SrpgTile.cs:

using System;
using UnityEngine;namespace DR.Book.SRPG_Dev.Maps
{[Serializable][CreateAssetMenu(fileName = "New SRPG Tile.asset", menuName = "SRPG/Tile")]public class SrpgTile : RuleTile{private TerrainType m_TerrainType = TerrainType.Plain;private int m_AvoidRate = 0;/// <summary>/// 地形类型/// </summary>public TerrainType terrainType{get { return m_TerrainType; }set { m_TerrainType = value; }}/// <summary>/// 回避率/// </summary>public int avoidRate{get { return m_AvoidRate; }set { m_AvoidRate = value; }}}
}

不要忘记添加“CreateAssetMenu”,否则我们在Create菜单中看不到它。


这样我们就我们完成了SrpgTile.cs的编写,如果你要创建它,可以选择菜单Assets/Create/SRPG/Tile。


2     创建SrpgTileEditor.cs

创建完SrpgTile后,发现Rule Tile的Inspector面板被我们破坏了。这就需要我们也继承它的Editor文件,而且还要在Inspector面板中添加我们的数据。

请注意原始的Rule Tile Editor类使用了internal class,我们需要将它改成public class。在Tile/Script下创建一个新的文件夹,重命名为Editor。在这个文件夹下创建SrpgTileEditor.cs。


完成后的文件SrpgTileEditor.cs:

using UnityEditor;namespace DR.Book.SRPG_Dev.Maps
{[CustomEditor(typeof(SrpgTile))][CanEditMultipleObjects]public class SrpgTileEditor : RuleTileEditor{public SrpgTile srpgTile { get { return target as SrpgTile; } }public override void OnInspectorGUI(){// 渲染新增的数据EditorGUI.BeginChangeCheck();srpgTile.terrainType = (TerrainType)EditorGUILayout.EnumPopup("Terrain Type", srpgTile.terrainType);srpgTile.avoidRate = EditorGUILayout.IntSlider("Avoid Rate", srpgTile.avoidRate, -100, 100);if (EditorGUI.EndChangeCheck()){EditorUtility.SetDirty(target);}// 渲染RuleTile的内容EditorGUILayout.Space();base.OnInspectorGUI();}}
}

这样,Inspector面板就显示了我们要的数据了。

3     测试SrpgTile

首先,在Tile/Asset中创建2个SrpgTile,并设置他们。

图 3 - 13设置SrpgTile

  • Default Sprite:Tiling Rules中没有合适的贴图时使用;
  • Default Collider:Collider类型,项目不需要;
  • Tiling Rules:Tile规则。
    • Rule:设置贴图旋转或镜像;
    • Collider:Collider类型,项目不需要;
    • Output:Tile类型,有普通(Single),随机(Random),动画(Animation)三个选项。

Tiling Rules中右侧有绿色箭头和红色叉子的地方是设置规则的地方,根据是否有邻居瓦片(Neighbor Tile),选择其中的贴图,绿色代表有邻居,红色代表没邻居,空白代表不关心。


设置好之后,我们将其拖入Tile Palette中。选择它开始绘制地图。但你会发现两种Tile之间并没有很好的衔接,如图。

图 3 - 14没有衔接的Tile

这可不是我们想要的,我们希望不同地形之间也能很好的衔接。而产生的原因是因为Rule Tile判断邻居的方法限定了只有相同Tile才是邻居。这需要我们在Rule Tile中找到相应的位置,并加以修改,让它认为只要有Tile就是邻居。


4     修改RuleTile.cs与SrpgTileEditor.cs

我们已经知道原因了,我们添加一个bool变量来控制邻居的类型是否为其本身,这样可以有选择的使用我们的Tile。

4.1      修改RuleTile.cs

打开RuleTile.cs,添加变量与检测方法:

        /// <summary>/// true: 只要旁边有Tile就使用Rule;/// false: 旁边只有是自己时才使用Rule。/// </summary>public bool m_CheckAnyTile = false;/// <summary>/// 我们添加的方法,判断是不是采用规则(Rule)/// true: 使用/// false: 不使用/// </summary>/// <param name="neighbor"></param>/// <param name="neighborTile"></param>/// <returns></returns>private bool NeighborMatches(TilingRule.Neighbor neighbor, TileBase neighborTile){switch (neighbor){/// 不关心,直接采用规则case TilingRule.Neighbor.DontCare:return true;/// 绿色箭头,/// 如果检测所有Tile,返回neighbor是不是不为null,/// 否则返回neighbor是不是自己case TilingRule.Neighbor.This:return m_CheckAnyTile ? neighborTile != null : neighborTile == this;/// 红色叉子,/// 如果检测所有Tile,返回neighbor是不是为null,/// 否则返回neighbor是不是不为自己case TilingRule.Neighbor.NotThis:return m_CheckAnyTile ? neighborTile == null : neighborTile != this;default:return false;}}

有了方法后,我们要找到使用它的地方,在RuleTile中有两处。

修改前代码:

       public bool RuleMatches(TilingRule rule, Vector3Int position, ITilemap tilemap, int angle){for (int y = -1; y <= 1; y++){for (int x = -1; x <= 1; x++){if (x != 0 || y != 0){Vector3Int offset = new Vector3Int(x, y, 0);Vector3Int rotated = GetRotatedPos(offset, angle);int index = GetIndexOfOffset(rotated);TileBase tile = tilemap.GetTile(position + offset);if (rule.m_Neighbors[index] == TilingRule.Neighbor.This && tile != this || rule.m_Neighbors[index] == TilingRule.Neighbor.NotThis && tile == this){return false;}   }}}return true;}
        public bool RuleMatches(TilingRule rule, Vector3Int position, ITilemap tilemap, bool mirrorX, bool mirrorY){for (int y = -1; y <= 1; y++){for (int x = -1; x <= 1; x++){if (x != 0 || y != 0){Vector3Int offset = new Vector3Int(x, y, 0);Vector3Int mirrored = GetMirroredPos(offset, mirrorX, mirrorY);int index = GetIndexOfOffset(mirrored);TileBase tile = tilemap.GetTile(position + offset);if (rule.m_Neighbors[index] == TilingRule.Neighbor.This && tile != this || rule.m_Neighbors[index] == TilingRule.Neighbor.NotThis && tile == this){return false;}}}}return true;}

修改后的代码:

       public bool RuleMatches(TilingRule rule, Vector3Int position, ITilemap tilemap, int angle){for (int y = -1; y <= 1; y++){for (int x = -1; x <= 1; x++){if (x != 0 || y != 0){Vector3Int offset = new Vector3Int(x, y, 0);Vector3Int rotated = GetRotatedPos(offset, angle);int index = GetIndexOfOffset(rotated);TileBase tile = tilemap.GetTile(position + offset);// 修改的地方if (!NeighborMatches(rule.m_Neighbors[index], tile)){return false;}}}}return true;}
        public bool RuleMatches(TilingRule rule, Vector3Int position, ITilemap tilemap, bool mirrorX, bool mirrorY){for (int y = -1; y <= 1; y++){for (int x = -1; x <= 1; x++){if (x != 0 || y != 0){Vector3Int offset = new Vector3Int(x, y, 0);Vector3Int mirrored = GetMirroredPos(offset, mirrorX, mirrorY);int index = GetIndexOfOffset(mirrored);TileBase tile = tilemap.GetTile(position + offset);// 修改的地方if (!NeighborMatches(rule.m_Neighbors[index], tile)){return false;}}}}return true;}

4.2      修改SrpgTileEditor.cs

Editor的修改相对简单,只要加一条bool变量的就可以了。

修改后的代码:

        public override void OnInspectorGUI(){// 渲染新增的数据EditorGUI.BeginChangeCheck();srpgTile.terrainType = (TerrainType)EditorGUILayout.EnumPopup("Terrain Type", srpgTile.terrainType);srpgTile.avoidRate = EditorGUILayout.IntSlider("Avoid Rate", srpgTile.avoidRate, -100, 100);// 添加的bool变量srpgTile.m_CheckAnyTile = EditorGUILayout.Toggle("Check Any Tile", srpgTile.m_CheckAnyTile);if (EditorGUI.EndChangeCheck()){EditorUtility.SetDirty(target);}// 渲染RuleTile的内容EditorGUILayout.Space();base.OnInspectorGUI();}

5     再次测试SrpgTile

首先在Inspector面板中把2个Plain的SrpgTile的Check Any Tile打勾。

图 3 - 15 Check Any Tile

再次在Scene面板中绘制地图,是不是好多了。

图 3 - 16不再衔接不正常

6    Tile之间的细线

你可能会发现,有的Tile之间会有一条细线,这是Unity渲染模式造成的,并不是Tile的问题。无论什么贴图,在同一张贴图中的两个Sprite如果是紧贴着的,有一定几率会出现这个问题,有两种解决办法,一种就是在每个Sprite边缘加一个像素,还一种是加入图集(加入图集时,Unity会自动在边缘补像素,查看图集可以看到),说道图集时再来详细说。

SRPG游戏开发(六)第三章 绘制地图 - 三 创建自己的SrpgTile相关推荐

  1. SRPG游戏开发(七)第三章 绘制地图 - 四 初步完善地图编辑器(Map Graph)

    返回目录 第三章 绘制地图 四       初步完善地图编辑器(Map Graph) 到目前为止我们可以开心的绘制我们的地图了,但有不少小问题.一直开心忘我的绘制地图,却不知道地图已经绘制了多大,还要 ...

  2. SRPG游戏开发(五)第三章 绘制地图 - 二 绘制一张简单地图

    返回目录 第三章 绘制地图 一 导入素材 点击进入 二 绘制一张简单地图 这一节我们来看如何绘制一张地图. 1     新建Grid与Tilemap 在Hierarchy面板中,点击Create/2D ...

  3. SRPG游戏开发(四)第三章 绘制地图 - 一 导入素材

    返回目录 第三章 绘制地图 这一章我们来创建自己的Tile,绘制我们的地图,然后显示我们的角色.如果你已经对Tilemap非常的熟悉,可以跳过本章.

  4. SRPG游戏开发(六十四)间章 第十一点五章 总结(Summary)

    返回<SRPG游戏开发>导航 间章 第十一点五章 总结(Summary) 这一章,是对第十章与第十一章的一个补充性质的文章. 文章目录 间章 第十一点五章 总结(Summary) 一 说明 ...

  5. 《SRPG游戏开发》导航(2019.03.04更新)

    <SRPG游戏开发>导航 第一章到第五章并没有使用Markdown,且经过CSDN几次改版和取消目录,这几章排版有些怪怪的. 2019.03.04 第十一章(十 - 十二) ,间章 第十一 ...

  6. SRPG游戏开发(六十三)第十一章 地图动作与地图事件 - 十二 完善地图信息与测试(Perfect MapEventInfo and Testing)

    返回<SRPG游戏开发>导航 第十一章 地图动作与地图事件(Map Action and Map Event) 我们已经有了剧本,而且可以运行剧本,但我们还缺少对地图的操作控制. 我们这一 ...

  7. SRPG游戏开发(六十)第十一章 地图动作与地图事件 - 九 触发事件与切换回合(Trigger Events and Change Turn)

    返回<SRPG游戏开发>导航 第十一章 地图动作与地图事件(Map Action and Map Event) 我们已经有了剧本,而且可以运行剧本,但我们还缺少对地图的操作控制. 我们这一 ...

  8. SRPG游戏开发(六十一)第十一章 地图动作与地图事件 - 十 NPC操作(NPC Control)

    返回<SRPG游戏开发>导航 第十一章 地图动作与地图事件(Map Action and Map Event) 我们已经有了剧本,而且可以运行剧本,但我们还缺少对地图的操作控制. 我们这一 ...

  9. OCulus Rift 游戏开发六原则

    本文章由cartzhang编写,转载请注明出处. 所有权利保留. 文章链接:http://blog.csdn.net/cartzhang/article/details/46685477 作者:car ...

最新文章

  1. KPCR:CPU控制区(Processor Control Region)
  2. 下巴痤疮的治疗方法有哪些?
  3. 此情应是长相守 你若无心我便休
  4. 计算机基础- -操作系统环境
  5. java接收二进制数据_java-从套接字读取二进制数据
  6. php调用restful接口_分享一个PHP调用RestFul接口的函数
  7. CentOs6.6安装Python3
  8. 最优化 | 二次规划的基础知识理论 | 例题讲解
  9. 网上车市通过聆讯:营收单一,上半年减员15%,徐翀持股80%
  10. 电视剧《乡村爱情2》之演员表(ZT)
  11. 随机池化(Stochastic Pooling)
  12. ARGIS利用计算器对属性表数据进行编号
  13. http/2与http/1的区别
  14. Mantis -- linux
  15. Java学习打卡第八天——[Collection终结之HashMap,Collections的简介和使用]
  16. 详解i++和++i,通俗易懂
  17. 故障申报系统php源码,seay源代码全自动在线审计系统,PHP源代码缺陷自动审计平台-在线工具...
  18. android开发和手游开发工具,developer盘点Android开发者必备十大开发工具
  19. 虚拟化之Proxmox VE安装教程
  20. Power BI常见问题篇1:无法打开文档

热门文章

  1. 线性代数 --- 投影Projection 六(向量在子空间上的投影)
  2. Coursera| Mathematics for maching learning | Linear Algebra
  3. python面对对象建立自己的电子宠物的编码_一种基于Kinect技术的电子宠物的制作方法...
  4. 个人开发android如何赚钱
  5. CSS水平垂直居中常见方法总结
  6. 弘辽科技:淘宝劳动节活动什么时候开始呢?商家要准备什么呢?
  7. 一款超级简单的后台管理系统模板
  8. java的反射和反编译机制介绍
  9. 95后女数据分析师的千字经验,都在这了
  10. Geant4教程学习(一)