ActionScript
TypeScript
JavaScript

laya.map.TiledMap应用学习

发布时间:2017-01-09

 LayaAir内置了 Tiled Map Editor 导出的指定格式的地图的解析。使用laya.map.TiledMap对其进行解析,以及使用提供的API操控它们。Tiled Map Editor 的官方网址是 http://www.mapeditor.org/

 Tiled Map Editor 支持多种地图方向:

• 正常

• 45度

• 等角(交错)

• 六角(交错)

 LayaAir并没有提供解析45度地图。下面介绍在LayaAir中使用 Tiled Map Editor 创建的地图。地图使用 Tiled Map Editor 自带的 examples,该文件夹就位于 Tiled Map Editor 安装目录之下。

生成项目所需的文件

打开地图之后,着手生成程序需要用到的文件,以下是文件的生成步骤。

1、选择地图->地图和属性在左侧打开属性面板,在图块层格式行中把Base64 (zlib压缩)改成XML

blob.png


2、在右下方中选择图块面板,然后在下方工具栏按钮中选择图标导入地图块


blob.png

3、然后选择文件->导出保存到项目资源目录下,选择保存类型为JSON 地图文件 (*.json),使用默认名称desert.json


4、导出的desert.json中保存了使用的区块图集的路径,这个时候使用的路径是位于 Tiled Map Editor 安装目录下的,我们需要把它改成项目资源路径下的图片路径。把该地图使用的区块图集 tmw_desert_spacing.png 复制到项目资源目录,并且修改desert.jsontilesets.image字段为项目路径下的图片相对路径。

  "tilesets":[
{
 "columns":8,
 "firstgid":1,
 "image":".\/tmw_desert_spacing.png",
  
  ......


加载和显示地图

 首先使用一个正常方向的地图,位于 examples 文件夹名为 desert.tmx 的地图文件,它看起来是这样的:

blob.png

 按照上一节步骤生成程序所用的文件后,就可以在项目中加载并显示地图了,在程序入口中加入以下代码。

Laya.init(Browser.width, Browser.height);
 
tiledMap = new TiledMap();
tiledMap.createMap("desert.json", new Rectangle(0, 0, Laya.stage.width, Laya.stage.height), null);

 此时调试程序已经可以看到一个充满窗口的正常方向地图。

 地图的类型和布局都是在 Tiled Map Editor 中完成的,这和引擎没什么关系,所以等角地图和六角地图仅需要在 Tiled Map Editor 中创作,之后使用一样的代码即可加载和显示。我们打开 examples 下面的 isometric_grass_and_water.tmx 文件,然后按照上述步骤导出 isometric_grass_and_water.json 文件,之后只需要将代码中加载的地图文件名改为 isometric_grass_and_water.json 即可。

tiledMap.createMap("isometric_grass_and_water.json", new Rectangle(0, 0, Laya.stage.width, Laya.stage.height), null);

 运行后可以看到下图所示地图:

blob.png


 

地图操作

 TiledMap提供一系列API操作地图,包含缩放,移动地图,以及更改视窗等。地图的操作都需要在地图加载完成之后进行,因此,需要给TiledMap.createMap传入加载完成后的回调处理器。

tiledMap.createMap("map.json", new Rectangle(0, 0, Laya.stage.width, Laya.stage.height), new Handler(this, onMapLoaded));

function onMapLoaded()
{
 // Code here.
}


缩放地图

 通过设置TiledMap.scale来设置缩放值。

function onMapLoaded()
{
 tiledMap.scale = 0.5;
}


 缩放的中心点是在地图的中心位置。在游戏中,通过使用双指中心点(移动设备)来作为缩放中心,或者鼠标位置(PC设备)来作为缩放心中。我们可以通过调用TiledMap.tiledMap.setViewPortPivotByScale()来设置缩放的中心点,中心点的作用域是,视窗左上角为[0, 0],视窗右下角为[1, 1],默认值为0.5,即视窗中心。

function onMapLoaded()
{
tiledMap.setViewPortPivotByScale(0, 0);
tiledMap.scale = 0.5;
}

 使用滚轮缩放我们的地图:

{
// 在构造函数加入下面这行代码
Laya.stage.on(Event.MOUSE_WHEEL, this, scaleMap);
}

function onMapLoaded()
{
// 地图加载完成后设置缩放中心
tiledMap.setViewPortPivotByScale(0.5, 0.5);
......
}

function scaleMap(e)
{
// 根据滚动距离缩放的地图
tiledMap.scale += e.delta / 300;
}

滚动视窗

 moveViewPort()用于滚动视图,其函数签名如下:

function moveViewPort(moveX:Number, moveY:Number):void

 我们用它来滚动地图:

{
// 在构造函数加入下列代码
Laya.stage.on(Event.MOUSE_DOWN, this, onMouseDown);
Laya.stage.on(Event.MOUSE_UP, this, onMouseUp);
}

var mx = 0,
my = 0;
var previousX;
var previousY;

function onMouseDown()
{
previousX = Laya.stage.mouseX;
previousY = Laya.stage.mouseY;

Laya.stage.on(Event.MOUSE_MOVE, this, onMouseMove);
}

function onMouseMove()
{
var dx = Laya.stage.mouseX - previousX;
var dy = Laya.stage.mouseY - previousY;
tiledMap.moveViewPort(mx - dx, my - dy);
}

function onMouseUp()
{
var dx = Laya.stage.mouseX - previousX;
var dy = Laya.stage.mouseY - previousY;
mx -= dx;
my -= dy;

Laya.stage.off(Event.MOUSE_MOVE, this, onMouseMove);
}

移动地图位置

 TiledMap.mapSprite返回了地图容器,可以通过修改它的xy坐标来移动地图位置。

获取选中区块的坐标

 在正常视角的地图中,选中区块的坐标很容易就能算出,但是在等角地图和六角地图中,选中区块的坐标就没那么容易得到了。TiledMap提供了方面的接口用于获取选中区块的索引(世界坐标),以及索引对应的屏幕坐标。

// 通过屏幕坐标获取世界坐标的函数签名
// screenX和screenY为屏幕坐标
// 计算结果会被存入result中
// 如果转换不成功,返回false
function getTilePositionByScreenPos(screenX:Number, screenY:Number, result:Point = null):Boolean

// 通过世界坐标获取屏幕坐标的函数签名
// tileX和tileY为世界坐标
// 计算结果保存在screenPos中
// 我们在地图上创建一个指示区域,指示当前所选的区块:
function getScreenPositionByTilePos(tileX:Number, tileY:Number, screenPos:Point = null):void
{
 // 在构造函数中加入click事件处理
 Laya.stage.on(Event.CLICK, this, onStageClick);
}

// 加载完地图后,绘制一个指示器Sprite
function onMapLoaded()
{
 ......
 var radiusX = 32;
 var radiusY = Math.tan(180 / Math.PI * 30) * radiusX;
 var color = "#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);
}

function onStageClick(e)
{
 // 显示鼠标坐标转换成世界坐标,再把世界坐标转换成屏幕坐标。
 layer.getTilePositionByScreenPos(Laya.stage.mouseX, Laya.stage.mouseY, point);
 layer.getScreenPositionByTilePos(Math.floor(point.x), Math.floor(point.y), point);
 sprite.pos(point.x, point.y);
}

// 此外,在缩放地图的时候,也缩放指示器
function scaleMap(e)
{
 tiledMap.scale += e.delta / 300;
 sprite.scale(tiledMap.scale, tiledMap.scale);
}