SRPG游戏开发(六)第三章 绘制地图 - 三 创建自己的SrpgTile
2018-01-27 17:58
591 查看
返回目录
地形类型枚举事例TerrainType.cs:
FE4中共26种,使用18种;这里创建的共3种,使用2种。其中可以看到湿地(Swamp)项目有个Obsolete
Attribute,这是一个小技巧,意思是这个地形虽然定义了,但不使用它,在编辑器的Inspector面板中也不会显示。如果以后的版本你需要使用,只要去除Obsolete就可以了。
创建好地形后,就该创建Tile文件了。
完成后的文件SrpgTile.cs:
不要忘记添加“CreateAssetMenu”,否则我们在Create菜单中看不到它。
这样我们就我们完成了SrpgTile.cs的编写,如果你要创建它,可以选择菜单Assets/Create/SRPG/Tile。
请注意原始的Rule Tile Editor类使用了internal class,我们需要将它改成public class。在Tile/Script下创建一个新的文件夹,重命名为Editor。在这个文件夹下创建SrpgTileEditor.cs。
完成后的文件SrpgTileEditor.cs:
这样,Inspector面板就显示了我们要的数据了。
![](https://oscdn.geek-share.com/Uploads/Images/Content/201909/13/991af12169e2cb0a3984487a448dd8f0)
图 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之间并没有很好的衔接,如图。
![](https://oscdn.geek-share.com/Uploads/Images/Content/201909/13/79f7f23533199d2e31a46679c0741e05)
图 3 - 14没有衔接的Tile
这可不是我们想要的,我们希望不同地形之间也能很好的衔接。而产生的原因是因为Rule Tile判断邻居的方法限定了只有相同Tile才是邻居。这需要我们在Rule
Tile中找到相应的位置,并加以修改,让它认为只要有Tile就是邻居。
有了方法后,我们要找到使用它的地方,在RuleTile中有两处。
修改前代码:
修改后的代码:
修改后的代码:
Any Tile打勾。
![](https://oscdn.geek-share.com/Uploads/Images/Content/201909/13/dc305d455c2aa53d78cd9fa841677a5e)
图 3 - 15 Check Any Tile
再次在Scene面板中绘制地图,是不是好多了。
![](https://oscdn.geek-share.com/Uploads/Images/Content/201909/13/e2c71687cd7cec53ea08016feeae7520)
图 3 - 16不再衔接不正常
第三章 绘制地图
一 导入素材
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的CheckAny Tile打勾。
图 3 - 15 Check Any Tile
再次在Scene面板中绘制地图,是不是好多了。
图 3 - 16不再衔接不正常
6 Tile之间的细线
你可能会发现,有的Tile之间会有一条细线,这是Unity渲染模式造成的,并不是Tile的问题。无论什么贴图,在同一张贴图中的两个Sprite如果是紧贴着的,有一定几率会出现这个问题,有两种解决办法,一种就是在每个Sprite边缘加一个像素,还一种是加入图集(加入图集时,Unity会自动在边缘补像素,查看图集可以看到),说道图集时再来详细说。相关文章推荐
- SRPG游戏开发(七)第三章 绘制地图 - 四 初步完善地图编辑器(Map Graph)
- SRPG游戏开发(四)第三章 绘制地图 - 一 导入素材
- 【Iphone 游戏开发之一】创建视图并绘制简单图形 推荐
- (转)Android游戏开发之地图编辑器的使用以及绘制地图 (四)
- J2ME游戏开发中的地图设计与绘制
- JavaFX战旗类游戏开发 第二课 游戏地图绘制
- SRPG游戏开发(十二)第五章 颜色映射与职业动画 - 四 测试与创建Class Animator
- SRPG游戏开发(三)第二章 创建项目
- Android游戏开发之地图编辑器的使用以及绘制地图 (一)
- Cocos2d-X游戏开发之CCTMXTileMap(瓦片地图)
- Android游戏开发之地图编辑器的使用以及绘制地图 (四)
- Android游戏开发之地图编辑器的使用以及绘制地图
- 【Iphone 游戏开发之一】创建视图并绘制简单图形
- flash游戏开发-地图相关-Tile layout非常好的入门教程。
- 【Iphone 游戏开发之一】创建视图并绘制简单图形
- Cocos2d-x 瓦块地图小游戏 (二) 用Tiled创建自己的游戏地图
- vc.net 游戏开发 第三章 创建Direct3D对象和设备例子
- Android游戏开发之地图编辑器的使用以及绘制地图 (四)
- Android游戏开发之地图编辑器的使用以及绘制地图 (四)
- lua脚本调用cocos2d-x 之实现精灵、Tmx地图创建【iOS游戏开发征文】