Unity2D 自定义Scriptable Tiles的理解与使用(一)——了解TileBase类

本文章使用的Unity版本为 Unity2018.4.36f1,脚本语言为C#

引言:

在Untiy2D中,我们可以使用Unity自带Tilemap与其相关功能来方便地进行游戏关卡的制作,但是Unity自带的Brush和Tile分别只有一种,想实现一些特殊功能的话就有点不够用了,这时我们可以导入2d-extras拓展包来添加一些新的Brush,如Line Brush、Coordinate Brush等;以及一些新的Tiles,例如Pipeline Tile、Rule Tile等。

      不过显而易见的是,这些新添加的Brush和Tiles的功能也是有限的(每种Brush和Tile都实现一种特殊功能),如果还是没有实现我们想要的功能,就只能自己来编写Bursh和Tile了,这篇文章重点介绍TileBase类以及它所含有的方法。

      该文章大部分的内容其实是对Unity官方文档内容的转述与补充,因为Unity文档对一些地方写的不是太清楚,需要大量的自行理解,所以为了让大家理解得更加深入且高效(不用再去反复揣摩某些地方的意义),我就写了这么一篇文章,文章中有大量的地方是查阅了其他文章获得的资料和通过自行测试得出的结论,奈何作者水平有限,有些地方或许讲得并不准确甚至是错误的,大家有什么问题可以在评论区写出来。

正文:

Scriptable Tiles介绍:

首先说明的一点,Unity中是没有ScriptbaleTiles这个类的,这个称呼只是对这个概念的称呼,Scirptable Tiles是一种可编程的Tiles,也就是说,我们可以在Scriptable Tiles中编写我们自己想要的Tile功能。

下面将介绍一下要编写自己的Scriptable Tiles必须要认识的一些类。

TileBase类: 

Unity中文文档介绍:

所有要添加到瓦片地图的瓦片必须继承自 TileBaseTileBase 为瓦片地图提供了一组固定 API 来传达其渲染属性。对于 API 的大多数情况,瓦片的位置和瓦片所在瓦片地图的实例作为 API 的参数传入。由此可确定用于设置瓦片信息的所有必需属性。

Unity英文文档介绍:

All tiles to be added to the Tilemap must inherit from TileBaseTileBase provides a fixed set of APIs to the Tilemap to communicate its rendering properties. For most cases of the APIs, the location of the Tile and the instance of the Tilemap the Tile is placed on is passed in as arguments of the API. You may use this to determine any required attributes for setting the tile information.

TileBase类是所有Tiles的基类,所有自己创建的Tile必须继承自此类或是继承自此类的子类。这个类本身继承自ScriptableObject,所以我们创建的自定义tile类就自然而然是ScriptableObject类的子孙类,所以可以用创建一个ScriptableObject实例的方法创建一个tile的实例。这一点我们后面的章节会讲到。

TileBase类有以下几个方法(简述):

1.RefreshTile方法:

public void RefreshTile(Vector3Int location, ITilemap tilemap)

调用时机:

This method is called when the tile is refreshed.(官方介绍)

就是说当格子瓦片被刷新的时候被调用,这是unity官方文档给出的结论,那么我实验的结果是怎么样呢,请看下面的介绍

当选中一个tilemap层,再选中Palette的Paint工具或BoxFill工具中的一个,再在Palette选中我们自己创建的Tile时,鼠标进入离开一个tilemap的格子的一瞬间(没有任何按任何鼠标按键),或是绘制瓦片时(按下鼠标左键),或是将瓦片旋转时,这个方法就会被自动调用。(图1右边Palette栏里的红色方格就是我创建的自定义ScriptableTile)

只不过不同的具体情况调用的次数会不同,有些情况会调用多次(应该和tilemap系统的实现原理有关),这个就不多讲了,因为调用多少次其实不重要,重要的是调用了。

                                                                     图1

此方法的目的:

RefreshTile 确定将此瓦片添加到瓦片地图时所更新的附近瓦片。默认情况下,TileBase的 RefreshTile 方法会调用 参数tilemap的RefreshTile(location) 方法来刷新当前位置的瓦片。对此进行重写可以确定由于放置新瓦片而需要刷新的瓦片。(官方解释)

所以说这个方法存在的意义就是更新指定位置的瓦片,这个方法有两个参数,一个是location,类型为Vector3Int,表示更新的瓦片的坐标;一个是tilemap,类型为ITilemap,表示目前选中的tilemap。默认调用tilemap的RefreshTile(Vector3Int location)方法,将location传入这个方法,就可以在tilemap上正常地显示tile了。

2.GetTileData方法:

public override void GetTileData(Vector3Int position, ITilemap tilemap, ref TileData tileData)

调用时机:

无官方介绍。

根据我的实验,这个方法调用的时机为:当选中一个tilemap层,再选中Palette的Paint工具或BoxFill工具中的一个,再在Palette选中我们自己创建的Tile时,鼠标进入一个tilemap的格子的一瞬间(没有任何按任何鼠标按键),或是绘制瓦片时,这个方法就会被自动调用。这个时机和RefreshTile方法很像,唯一的不同是鼠标离开格子时不会被调用。

此方法的目的:

Unity手册描述:确定瓦片在瓦片地图上的外观。

Unity Scripting API手册 描述:Retrieves any tile rendering data from the scripted tile.Implement this and fill in the TileData to have the Tilemap to render the tile.翻译:获取自定义瓦片渲染信息,使用这个方法可以把这些信息存入tileData参数中使得Tilemap可以渲染瓦片。

API手册描述的比较详细,也非常容易理解。这个方法的目的就是将瓦片渲染的信息暴露给tileData对象(参数中的对象),注意看tileData参数有ref关键字,所以这个tileData其实是要作为一个返回值传递出去的,tileData得到了想要的信息,Tilemap就可以正常地渲染了。至于要怎样传递信息,传递怎样的信息,那就可以让我们自由发挥了。

3.GetTileAnimationData

public bool GetTileAnimationData(Vector3Int location, ITilemap tilemap, ref TileAnimationData tileAnimationData)

调用时机:

无官方介绍。

根据我的实验,这个方法调用的时机为:1.若某格没有瓦片,当瓦片被确定绘制到Tilemap上的一瞬间(点击鼠标左键绘制)调用该方法。2.若该格子已经有绘制瓦片,这时候,若我们编写的自定义瓦片能影响到周围的瓦片(如规则瓦片),然后该格子上的瓦片被我们的自定义瓦片影响了,那也会调用这个方法。

                                                                         图2 

例如这张图我将画笔放在了一个本来就有瓦片的格子的下方,因为我现在使用的自定义瓦片有类似RuleTile的效果,所以会影响到上方的瓦片,所以也调用了GetTileAnimationData方法。

此方法的目的:

Unity Scripting API手册 描述:Retrieves any tile animation data from the scripted tile.

Implement this and fill in the TileAnimationData to have the Tilemap run an animation for the tile.

翻译:获取自定义瓦片的动画信息,使用这个方法可以把这些信息存入tileAnimatorData参数中使得Tilemap可以在瓦片上运行一个动画。

由此可见,这个方法和上述的GetTileData方法还是比较相似的,目的都是讲某些信息传给指定参数,我们可以通过编写逻辑来决定要具体传入哪些动画以及调整动画的相关参数。(后面的章节会详细讲解)

4.StartUp方法:

调用时机:StartUp is called on the first frame of the running Scene.(官方介绍)

就是说当场景开始运行的第一帧,该方法会被调用。

我实验的结果为:就算场景没有处于运行状态(仍处于编辑状态),该方法也会被调用,而且这时调用的时机和GetTileAnimationData方法应该是一模一样的的。当点击开始(Play)按钮时,就像上述的一样会在第一帧被调用。

                                                                            图3

例如这张图我点击了开始按钮,我在方法中写了一个Debug代码,会输入一个字符串。

此方法的目的:

Unity Scripting API手册 描述:Use this to set values for the instantiated GameObject or run any logic at the beginning of the Scene.翻译:使用这个方法来给实例化的游戏对象赋值或在场景开始时运行任何逻辑。

这段话稍稍难以理解,其实可以看看API手册的例子:

 public override void GetTileData(Vector3Int location, ITilemap tilemap, ref TileData tileData)
    {
        tileData.sprite = m_Sprite;
        tileData.gameObject = m_Prefab;
    }

    public override bool StartUp(Vector3Int location, ITilemap tilemap, GameObject go)
    {
        if (go != null)
        {
            go.transform.rotation = Random.rotation;
        }
        return true;
    }

所以他所谓的instantiated GameObject其实是GetTileData里面赋值好的一个游戏对象,这个游戏对象会传递给go参数,由go来表示这个对象,至于这个对象具体有什么作用,后面的章节再讨论。

所以这个方法主要用来设置这个游戏对象或者让瓦片在游戏开始时做出一些逻辑上的调整。

以上是TileBase类的所有要了解的方法。

那么TileBase类就简单介绍到这里,这篇文章只是简单介绍了一下TileBase类以及它的方法,并没有很深入去讲各个方法具体的用法,那么我会在后面的文章深入探讨到底该怎么用这些方法。

下篇文章链接:(29条消息) Unity2D 自定义Scriptable Tiles的理解与使用(二)——通过了解Tile类来对TileBase类的方法(主要是GetTileData方法)进行详细理解_see的再生的博客-CSDN博客

猜你喜欢

转载自blog.csdn.net/scombropidae/article/details/125124843