Laya TileMap 系列二 如何在Laya中使用

参考用LayaAir引擎解析Tiled Map地图
1.必须是CSV格式,不支持Tiled Map地图为Base64的图块层格式。
2.导出为json格式

image.png

3.修改图集路径
打开刚刚保存的orthogonal.json,搜索关键字"image"我们会发现默认的image路径位于Tiled安装目录中。如图4所示。
图4

路径在Tiled安装目录中肯定是不行的,所以,我们需要先将这个图片(buch-outdoor.png)复制到项目目录,与之前保存的orthogonal.json同级,如图5所示。
图5

然后将orthogonal.json中的image路径修改为相对路径"image":"buch-outdoor.png"
但是我在做这一步时,发现我的json文件中tileset指向的没有image,而是一个source:

 "tilesets":[
        {
         "firstgid":1,
         "source":"Tile01.tsx"
        }, 
        {
         "firstgid":561,
         "source":"Tile02.tsx"
        }

估计是新建图块时设置有问题,重新建图块,如图,勾选嵌入地图即可


image.png
{
 "columns":19,
 "firstgid":1209,
 "image":"..\/..\/tiled-windows-64bit-snapshot\/examples\/Tile03.PNG",
 "imageheight":480,
 "imagewidth":640,
 "margin":1,
 "name":"Tile03",
 "spacing":1,
 "tilecount":266,
 "tileheight":32,
 "tilewidth":32
}

4.创建TiledMap地图


laya.map.TiledMap类中的createMap方法
//初始化舞台
Laya.init(Laya.Browser.width, Laya.Browser.height, Laya.WebGL);
//创建TiledMap实例
var tMap = new Laya.TiledMap();
//创建Rectangle实例,视口区域
var viewRect: Laya.Rectangle = new Laya.Rectangle
(0, 0, Laya.Browser.width, Laya.Browser.height);
//创建TiledMap地图
tMap.createMap("res/TiledMap/orthogonal.json", viewRect, null);

5.缩放

通过动图9-3,从原图比例的0.1到2倍的缩放变化效果,来进一步理解scale属性的中心点
在laya.map.TiledMap类中的setViewPortPivotByScale()方法可以设置视口的中心点
private tMap: Laya.TiledMap;
constructor() {
    //初始化舞台
    Laya.init(Laya.Browser.width, Laya.Browser.height, Laya.WebGL);
    //创建TiledMap实例
    this.tMap = new Laya.TiledMap();
    //创建Rectangle实例,视口区域
    var viewRect: Laya.Rectangle = new Laya.Rectangle
        (0, 0, Laya.Browser.width, Laya.Browser.height);
    //创建TiledMap地图
    this.tMap.createMap("res/TiledMap/orthogonal.json"
        , viewRect, Laya.Handler.create(this, this.onMapLoaded));
}
private onMapLoaded(): void {
    //设置缩放中心点为视口的左上角
    this.tMap.setViewPortPivotByScale(0, 0);
    //将原地图放大2倍
    this.tMap.scale = 2;
}

6.拖动地图,需要用到moveViewPort()(移动视口)方法和changeViewPort()(改变视口大小)方法

private tMap: Laya.TiledMap;
private MapX: number = 0;
private MapY: number = 0;
private mLastMouseX: number;
private mLastMouseY: number;

constructor() {
    //初始化舞台
    Laya.init(Laya.Browser.width, Laya.Browser.height, Laya.WebGL);
    //创建TiledMap实例
    this.tMap = new Laya.TiledMap();
    //创建Rectangle实例,视口区域
    var viewRect: Laya.Rectangle = new Laya.Rectangle
        (0, 0, Laya.Browser.width, Laya.Browser.height);
    //创建TiledMap地图
    this.tMap.createMap("res/TiledMap/orthogonal.json"
        , viewRect, Laya.Handler.create(this, this.onMapLoaded));
}
private onMapLoaded(): void {
    //设置缩放中心点为视口的左上角
    this.tMap.setViewPortPivotByScale(0, 0);
    //将原地图放大2倍
    this.tMap.scale = 2;

    Laya.stage.on(Laya.Event.RESIZE, this, this.resize);
    Laya.stage.on(Laya.Event.MOUSE_DOWN, this, this.mouseDown);
    Laya.stage.on(Laya.Event.MOUSE_UP, this, this.mouseUp);
    this.resize();
}
/**
 * 移动地图视口
 */
private mouseMove(): void {
    var moveX: number = this.MapX - (Laya.stage.mouseX - this.mLastMouseX);
    var moveY: number = this.MapY - (Laya.stage.mouseY - this.mLastMouseY)
    //移动地图视口
    this.tMap.moveViewPort(moveX, moveY);
}
private mouseUp(): void {
    this.MapX = this.MapX - (Laya.stage.mouseX - this.mLastMouseX);
    this.MapY = this.MapY - (Laya.stage.mouseY - this.mLastMouseY);
    Laya.stage.off(Laya.Event.MOUSE_MOVE, this, this.mouseMove);
}
private mouseDown(): void {
    this.mLastMouseX = Laya.stage.mouseX;
    this.mLastMouseY = Laya.stage.mouseY;
    Laya.stage.on(Laya.Event.MOUSE_MOVE, this, this.mouseMove);
}
/**
 *  改变视口大小
 *  重设地图视口区域
 */
private resize(): void {
    //改变视口大小
    this.tMap.changeViewPort(this.MapX, this.MapY
        , Laya.Browser.width, Laya.Browser.height);
}

7.销毁地图
当Tiled Mapa不再使用的时候,需要使用destroy()方法进行销毁,回收被占用的内存。tMap.destroy();

8.开启和关闭自动缓存
LayaAir引擎使用TiledMap时,默认会将没有动画的地块自动缓存起来,并且缓存类型默认为normal。

//自动缓存没有动画的地块
tMap.autoCache = true;
//自动缓存的类型,地图较大时建议使用normal
tMap.autoCacheType = "normal";
//消除缩放导致的缝隙,也就是去黑边,1.7.7版本新增的优化属性
tMap.antiCrack = true;

以上的代码属性是引擎的默认值,在多数情况下,保持默认值即可,无需额外设置。那么为什么要再介绍一遍呢?因为有的时候,缓存后的Tiled地图会出现黑边(缝隙)。尽管在1.7.7版本新增了antiCrack属性,可以消除绝大多数因normal缓存导致的黑边。但如果偶现的黑边问题仍未得到解决时。可以通过关闭自动缓存来解决黑边(缝隙)问题。

9.设置缓存区块大小
TiledMap地图都是由一个个单元区块拼接组成。如果缓存时保持原大小,当小图区块很多时会对性能产生影响。因此建议开启缓存区块设置,并将缓存区块的大小设置为512像素左右,必须保持原小图区块的整数倍。
例如,本文示例中的单图区块大小为1616,那么缓存区块可以设置 16的32倍,即为512512。如果单图是1515,缓存可区块可以设置为510510(34倍),以此类推,尽量在原区块整数倍的前提下,设置在512左右。推荐为512*512。

缓存区块的设置需要在createMap(创建地图)的时候设置。设置第四个参数gridSize,示例如下:

//为第二个参数创建Rectangle实例,视口区域
var viewRect:Rectangle = new Rectangle(0, 0, Browser.width, Browser.height);
//为第四个参数gridSize创建一个512*512大小的Point对象实例
var gridSize:Point = new Point(512, 512);
//创建TiledMap地图
tMap.createMap("res/TiledMap/orthogonal.json"
,viewRect, Handler.create(this,onMapLoaded), null, gridSize)

10.开启合并图层
当TiledMap里有多个图层时,开启合并图层的属性enableMergeLayer,可以将图层合并,会对性能有所提高。开启的方式为:tMap.enableMergeLayer = true;需要注意的是,如果需要对合并前的图层进行操作,那就不能直接合并。因为合并后会导致无法对合并前的图层进行操作。

如果没有在TiledMap里将图层分组,那么图层合并时,会将所有图层合并到一起。因此,需要分为多个图层并分别操作时。可以在TiledMap里将图层分组。打开TiledMap地图编辑器,选中要分组的图层,在图层的自定义属性栏,添加一个名为layer的string类型属性。操作如图14-1所示。

图14-1

开启合并图层时,图层属性内可添加layer属性,运行时将会将相邻的layer属性相同的图层进行合并以提高性能。例如,我们将块层2与块层3的分组名称设置为layaAir,那么名为layaAir的图层,开启enableMergeLayer后,会合并到同一个图层。操作如图14-2所示。
图14-2

11.移除被覆盖的格子
如果下层的格子被遮挡,并且遮挡地块并不是透明的,那么被遮挡的部分直接移除而不被渲染,可以提高性能。移除被覆盖的开启方式为:tMap.removeCoveredTile = true;//移除被非透明地块覆盖的部分
Tips:如果开启后,需要对移除的部分进行操作,是不可能的。所以开启该功能前要确认,不再对移除部分进行操作。

如果在Tiled Map中没有对图块设置type属性,那么即便开启了removeCoveredTile ,也是无效的。所以,开启之前,需要先在TiledMap编辑器中,为图块新增自定义属性type,并将设置为1。


在图块面板中,点击图块编辑,打开图块地形编辑面板

在图块地形编辑面板内,选中地形,在自定义属性栏,点击+号图标,添加int类型的type属性

完成添加后,设置type属性值为1

只要是自定义属性type设置为1的地形,当removeCoveredTile开启后。被遮挡不可见时都可以被移除,以提高性能。

12.设置tiledMap宽高
参考分享:TiledMap设置viewport后黑屏问题!
tiledMap默认是没有宽高的,所以我们在设置viewport的时候,要为tiledMap设置一个宽高,否则tiledMap将可能会被裁剪掉

//切记:设置tiledMap的宽高,需要在地图创建完成之后
private function onLoaded():void
{
    var sp:Sprite=tiledMap.mapSprite() as Sprite;
    //为tiledMap整个地图的显示容器设置宽高
    sp.size(800,800);
}

13.屏幕坐标和地图坐标转换
参考官方示例 等角地图

private function onStageClick(e:*=null):void
{
    var p:Point = new Point(0, 0);
    layer.getTilePositionByScreenPos(Laya.stage.mouseX, Laya.stage.mouseY, p);
    layer.getScreenPositionByTilePos(Math.floor(p.x), Math.floor(p.y), p);
    sprite.pos(p.x, p.y);
}

private function mapLoaded(e:*=null):void
{
    layer = tiledMap.getLayerByIndex(0);
    
    var radiusX:Number = 32;
    var radiusY:Number = Math.tan(180 / Math.PI * 30) * radiusX;
    var color:String = "#FF7F50";
    
    sprite = new Sprite();
    sprite.graphics.drawLine(0, 0, -radiusX, radiusY, color);
    sprite.graphics.drawLine(0, 0, radiusX, radiusY, color);
    sprite.graphics.drawLine(-radiusX, radiusY, 0, radiusY * 2, color);
    sprite.graphics.drawLine(radiusX, radiusY, 0, radiusY * 2, color);
    Laya.stage.addChild(sprite);
}
效果就是有个红框,鼠标点哪,红框就在相应的图块里出现

参考一下这两个方法源码的API说明:

/**
 * 通过屏幕坐标来获取选中格子的索引
 * @param   screenX 屏幕坐标x
 * @param   screenY 屏幕坐标y
 * @param   result 把计算好的格子坐标,放到此对象中
 * @return
 */
public function getTilePositionByScreenPos
(screenX:Number, screenY:Number, result:Point = null):Boolean {}

/**
 * 通过地图坐标得到屏幕坐标
 * @param   tileX 格子坐标X
 * @param   tileY 格子坐标Y
 * @param   screenPos 把计算好的屏幕坐标数据,放到此对象中
 */
public function getScreenPositionByTilePos
(tileX:Number, tileY:Number, screenPos:Point = null):void {}

14.动画

laya官方回复是,不支持Laya的ani动画放置到tiledMap中,参考可以用laya的ani动画系统动态插入到tiledmap的tiled中吗

参考官方示例 带动画的地图
Tiled地图编辑器 Tiled Map Editor 的使用(二)动画效果
在最新版本的tiled map editor中,需要进入图块文件,然后在主菜单->Tile集->图块动画编辑器

image.png

双击图块即可添加到左侧,但是没看懂怎么把添加上去的帧删掉……
看一下tmx中对应的标签:

   <animation>
    <frame tileid="30" duration="1000"/>
    <frame tileid="31" duration="2000"/>
    <frame tileid="38" duration="3000"/>
   </animation>

没有看到Frame Duration:500ms在哪里,另外动画的三帧,也不是按1秒为间隔来播放的。第1帧的仙人掌,到第2帧的石头特别快。
最终,导出的json是这样的:

 "tiles":[
        {
         "id":29,
         "properties":[
                {
                 "name":"isCanPass",
                 "type":"bool",
                 "value":true
                }]
        }, 
        {
         "animation":[
                {
                 "duration":1000,
                 "tileid":30
                }, 
                {
                 "duration":2000,
                 "tileid":31
                }, 
                {
                 "duration":3000,
                 "tileid":38
                }],
         "id":31,
         "properties":[
                {
                 "name":"isCanPass",
                 "type":"bool",
                 "value":false
                }]
        }],

在TiledMap.as的源码中,可以看到onJsonComplete中关于动画的解析:

//动画数据
var tTiles:* = tileset.tiles;
if (tTiles) {
    for (var p:*in tTiles) {
        var tAnimation:Array = tTiles[p].animation;
        if (tAnimation) {
            var tAniData:TileMapAniData = new TileMapAniData();
            _animationDic[p] = tAniData;
            tAniData.image = tileset.image;
            for (var j:int = 0; j < tAnimation.length; j++) {
                var tAnimationItem:Object = tAnimation[j];
                tAniData.mAniIdArray.push(tAnimationItem.tileid);
                tAniData.mDurationTimeArray.push(tAnimationItem.duration);
            }
        }
    }
}

class TileMapAniData {
    public var mAniIdArray:Array = [];
    public var mDurationTimeArray:Array = [];
    public var mTileTexSetArr:Array = [];
    public var image:*;
}

会把duration、tileid存到TileMapAniData这个类型的相应数组里去,tAniData.image = tileset.image;取到的是"image":"tmw_desert_spacing.png"这个属性。

/**
 * 初始化地图
 */
private function initMap():void {
var i:int, n:int;
for (var p:*in _animationDic) {
var tAniData:TileMapAniData = _animationDic[p];
var gStart:int;
gStart = _texutreStartDic[tAniData.image];
var tTileTexSet:TileTexSet = getTexture(parseInt(p) + gStart);
if (tAniData.mAniIdArray.length > 0) {
    tTileTexSet.textureArray = [];
    tTileTexSet.durationTimeArray = tAniData.mDurationTimeArray;
    tTileTexSet.isAnimation = true;
    tTileTexSet.animationTotalTime = 0;
    for (i = 0, n = tTileTexSet.durationTimeArray.length; i < n; i++) {
        tTileTexSet.animationTotalTime += tTileTexSet.durationTimeArray[i];
    }
    for (i = 0, n = tAniData.mAniIdArray.length; i < n; i++) {
        var tTexture:TileTexSet = getTexture(tAniData.mAniIdArray[i] + gStart);
        tTileTexSet.textureArray.push(tTexture);
    }
}
}

在initMap中,把属性都放到TileTexSet中。

/**
 * 加入一个动画显示对象到此动画中
 * @param   aniName //显示对象的名字
 * @param   sprite  //显示对象
 */
public function addAniSprite(aniName:String, sprite:TileAniSprite):void {
    if (animationTotalTime == 0) {
        return;
    }
    if (_aniDic == null) {
        _aniDic = {};
    }
    if (_spriteNum == 0) {
        //每3帧刷新一下吧,每帧刷新可能太耗了
        Laya.timer.frameLoop(3, this, animate);
        _preFrameTime = Browser.now();
        _frameIndex = 0;
        _time = 0;
        _interval = 0;
    }
    _spriteNum++;
    _aniDic[aniName] = sprite;
    if (textureArray && _frameIndex < textureArray.length) {
        var tTileTextureSet:TileTexSet = textureArray[_frameIndex];
        drawTexture(sprite, tTileTextureSet);
    }
}
/**
 * 把动画画到所有注册的SPRITE上
 */
private function animate():void {
    if (textureArray && textureArray.length > 0 && 
        durationTimeArray && durationTimeArray.length > 0) {
        var tNow:Number = Browser.now();
        _interval = tNow - _preFrameTime;
        _preFrameTime = tNow;
        if (_interval > animationTotalTime) {
            _interval = _interval % animationTotalTime;
        }
        _time += _interval;
        var tTime:int = durationTimeArray[_frameIndex];
        while (_time > tTime) {
            _time -= tTime;
            _frameIndex++;
            if (_frameIndex >= durationTimeArray.length ||
                       _frameIndex >= textureArray.length) {
                _frameIndex = 0;
            }
            var tTileTextureSet:TileTexSet = textureArray[_frameIndex];
            var tSprite:TileAniSprite;
            for (var p:* in _aniDic) {
                tSprite = _aniDic[p];
                drawTexture(tSprite, tTileTextureSet);
            }
            tTime = durationTimeArray[_frameIndex];
        }
    }
}

可以看出,每3帧会刷新一下animate方法。相当于不停地去检查_interval,然后累加到_time变量上。然后把_time一直和durationTimeArray数组中的时间戳去比较,如果达到了,就进入while循环更新一下帧图片。
在while循环中,会把_time减掉这个时间戳,并且会把时间戳更新到下一个节点。这样就明确了,durationTimeArray这个数组中的值,确实是时间的间隔,而不是时间轴。上面导出的资源,间隔是1000,2000,3000。这就意味着动画间隔越来越长。如果需要每秒切换1帧,都改成1000即可。

但是,当前版本下,laya仍然播放不出动画。经过代码检查,应该是版本不匹配导致的。在TiledMap中的onJsonComplete方法中,_animationDic[p] = tAniData;是有问题的,因为现在的导出数据是这样的:

         "tiles":[
                {
                 "animation":[
                        {
                         "duration":1000,
                         "tileid":30
                        }, 
                        {
                         "duration":1000,
                         "tileid":31
                        }, 
                        {
                         "duration":1000,
                         "tileid":38
                        }],
                 "id":31
                }],

可以看到,现在的p实际上是0,真正的值是存在了与animation同级的id属性上,所以改成这样,_animationDic[tTiles[p].id] = tAniData;,就能运行了:

//动画数据
var tTiles:* = tileset.tiles;
if (tTiles) {
    for (var p:*in tTiles) {
        var tAnimation:Array = tTiles[p].animation;
        if (tAnimation) {
            var tAniData:TileMapAniData = new TileMapAniData();
            //_animationDic[p] = tAniData;
            _animationDic[tTiles[p].id] = tAniData;
            tAniData.image = tileset.image;
            for (var j:int = 0; j < tAnimation.length; j++) {
                var tAnimationItem:Object = tAnimation[j];
                tAniData.mAniIdArray.push(tAnimationItem.tileid);
                tAniData.mDurationTimeArray.push(tAnimationItem.duration);
            }
        }
    }
}

15.图块的自定义属性访问,截止到2018.5.16号,当前1.78.beta版本仍然是错的,关于动画的操纵也需要关注
参考TiledMap格子上的自定义数据问题

都2018年了,TS依然没有这个接口。
我用ts直接objdata.properties["R"]来读取。直接F5调试勉强可以用。
发布重新编译ts会报错。希望能尽快提供直接访问的方法。
需要:
1 枚举图层的全部成员。我现在直接用Layer._objDic来强行读取的。
2 getObjectDataByName("").type 也需要访问。
3 getObjectDataByName().properties需要公开访问。
4 tiledMap的动画貌似跟Laya的动画实现方法不一样。不知如何Stop.如何替换。比如,我想实现一个人物奔跑到停止,转身,巡逻。求演示。目前我是用Laya.Animation做的动画,找到目标GridSprite然后addChild实现的。把原有的GridSprite的成员移除,它会再回来。只好用透明图占位。我总觉得这种方法不科学。求更科学的套路。

首先,来看看访问自定义属性的调用API

/**
 * 得到tile自定义属性
 * @param   index       地图块索引
 * @param   id          具体的TileSetID
 * @param   name        属性名称
 * @return
 */
public function getTileProperties(index:int, id:int, name:String):* {
    if (_tileProperties[index] && _tileProperties[index][id]) {
        return _tileProperties[index][id][name];
    }
    return null;
}

第一个参数,地图块索引,注释写得并不清楚,根据导出的json和相关代码来观察,指的是在json导出的tilesets数组中,占的索引,当然是从0开始的。


这个顺序在原始的tmx中也能看出来

也就是说,要获取一个格子tile的自定义属性,首先要知道它是属于哪个地块的。

第二个参数,就是具体的TileSetID,当然如前文所述,这个ID并不是从1开始的,而是从0开始。而layers保存的data却是从1开始的,所以如果是点击地块,去获取相应的自定义属性,注意需要减1。

第三个参数是自定义属性的名称,根据这个key返回value值。

那么我们看一下json中保存自定义属性的部分:

 "tilesets":[
        {
        ...
        "tiles":[
                {
                 "id":29,
                 "properties":[
                        {
                         "name":"isCanPass",
                         "type":"bool",
                         "value":true
                        }, 
                        {
                         "name":"tileType",
                         "type":"int",
                         "value":1
                        }]
                }, 
                {
                 "animation":[
                        {
                         "duration":1000,
                         "tileid":30
                        }, 
                        {
                         "duration":1000,
                         "tileid":31
                        }, 
                        {
                         "duration":1000,
                         "tileid":38
                        }],
                 "id":31
                }, 
                {
                 "id":39,
                 "properties":[
                        {
                         "name":"isCanPass",
                         "type":"bool",
                         "value":false
                        }]
                }],
        ...

这里以构建第一个图块的自定义数据为例,根据return _tileProperties[index][id][name];,构建数据结构如下:

_tileProperties = {};
_tileProperties[0] = {};
_tileProperties[0] = {};

_tileProperties[0][29] = {};
_tileProperties[0][29]["isCanPass"] = true;
_tileProperties[0][29]["tileType"] = 1;

_tileProperties[0][39] = {};
_tileProperties[0][39]["isCanPass"] = false;

在onJsonComplete方法中,我们发现因为版本问题,代码并不是这样去构建数据结构的。

var tArray:Array = tJsonData.tilesets;
var tileset:*;
var tTileSet:TileSet;
var i:int = 0;
for (i = 0; i < tArray.length; i++) {
    tileset = tArray[i];
    tTileSet = new TileSet();
    tTileSet.init(tileset);
    
    if (tTileSet.properties && tTileSet.properties.ignore) continue;
        _tileProperties[i] = tTileSet.tileproperties;

上面的i确实是从0开始循环的,代表着获取方法中getTileProperties第一个参数。但是它指向的内容是错误的,在TileSet的init方法中,只是简单粗暴地一句话处理:

//自定义属性
tileproperties = data.tileproperties;

可是现在的版本里,json里没有tileproperties。我们可以模仿解析动画animation的代码来写:

var tTiles:* = tileset.tiles;
if (tTiles) {
    for (var p:*in tTiles) {
        var tAnimation:Array = tTiles[p].animation;
        if (tAnimation) {
            var tAniData:TileMapAniData = new TileMapAniData();
            //_animationDic[p] = tAniData;这一句也改了,见上面动画部分
            _animationDic[tTiles[p].id] = tAniData;
            tAniData.image = tileset.image;
            for (var j:int = 0; j < tAnimation.length; j++) {
                var tAnimationItem:Object = tAnimation[j];
                tAniData.mAniIdArray.push(tAnimationItem.tileid);
                tAniData.mDurationTimeArray.push(tAnimationItem.duration);
            }
        }
        //下面这部分是我自己添加的:
        //检查tiles中,有properties属性的object
        var properties:Array = tTiles[p].properties;
        if(properties){
            //构造_tileProperties[0][29] = {};
            _tileProperties[i][tTiles[p].id] = {};
            //把properties中的属性都放进去
            for (var k:int = 0; k < properties.length; j++) {
                _tileProperties[i][tTiles[p].id][properties[k].name] 
                                = properties[k].value;
            }
        }
    }
}

js版本的代码如下:

//检查tiles中,有properties属性的object
var properties = tTiles[p].properties;
if(properties){
    //构造_tileProperties[0][29] = {};
    this._tileProperties[i][tTiles[p].id] = {};
    //把properties中的属性都放进去
    for (var k = 0; k < properties.length; k++) {
        this._tileProperties[i][tTiles[p].id][properties[k].name] 
                = properties[k].value;
    }
}

当然在这段 代码前,要先把_tileProperties[i]给初始化:

// this._tileProperties[i]=tTileSet.tileproperties;
this._tileProperties[i]={};

使用以下代码测试一下,发现成功了:

console.log("test:",this.tMap.getTileProperties(0,29,"isCanPass"));//test:true
console.log("test:",this.tMap.getTileProperties(0,39,"isCanPass"));//test:false

16.如何隐藏tiledMap中指定的GridSprite

17._showGridList
参考tiledmap 可以在图块层的指定格子上添加Sprite吗
LayaAir能做RPG吗?不要问我能不能,因为我已经在做 - 杀意来袭

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,108评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,699评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,812评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,236评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,583评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,739评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,957评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,704评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,447评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,643评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,133评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,486评论 3 256
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,151评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,108评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,889评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,782评论 2 277
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,681评论 2 272

推荐阅读更多精彩内容