原文鏈接:https://github.com/libgdx/libgdx/wiki/Tile-maps
譯者:重慶好爸爸 game4kids@163.com
謝絕轉載
術語對照
- 瓦片地圖 - Tile Maps
- 基類 - Base Classes
文章中提到的類
- MapProperties
- TiledMap
- TiledMapTileLayer
- TiledMapTile
- TiledMapTileSet
瓦片地圖
地圖
LibGDX具有通用的地圖API。所有與地圖相關的類可以在com.badlogic.gdx.maps包中找到。com.badlogic.gdx.maps包含了基類,其下的子包包含了tile地圖的其他類型地圖的實現(xiàn)。
基類
基類,意味著是一個通用的集合,除了Tiled地圖外,也支持其他2D地圖格式。
地圖由一系統(tǒng)圖層組成。每個圖層包含了一系統(tǒng)對象。地圖,圖層,對象都有屬性,屬性取決于加載方式。對于某些格式,還有專門的地圖,圖層和對象實現(xiàn),稍后會有更多的內容。 基類的類層次結構如下所示:

屬性
地圖,圖層,對象的屬性在代碼中由MapProperties類表現(xiàn)。MapProperties類本質上是一個Hash map。
地圖,圖層或者對象的屬性的可用的Key-value取決于加載的格式??梢允褂萌缦碌姆绞饺シ謩e訪問地圖,圖層或者uixiagn的屬性:
map.getProperties().get("custom-property", String.class);
layer.getProperties().get("another-property", Float.class);
object.getProperties().get("foo", Boolean.class);
許多受支持的編輯器允許你在地圖,圖層和對象上指定這些屬性。這些屬性的類型取決于具體格式。 如有疑問,請在libgdx應用程序中使用一個地圖加載程序去實際加載地圖,并研究一下你感興趣的屬性。
地圖圖層
地圖中的每個圖層有時有排序和索引的,索引從編號0開始??梢杂萌缦路椒ㄔL問地圖中的圖層:
MapLayer layer = map.getLayers().get(0);
也可以通過名字查找圖層:
MapLayer layer = map.getLayers().get("my-layer");
這些getter方法會返回一個Maplayer對象。有的圖層可能被特殊化后提供了更多的功能,這種情況下,你可以進行強制轉換:
TiledMapTileLayer tiledLayer = (TiledMapTileLayer)map.getLayers().get(0);
圖層有幾個屬性,我們嘗試為所有支持的地圖格式歸一化:(譯者注:名字,透明度,可見性)
String name = layer.getName();
float opacity = layer.getOpacity();
boolean isVisible = layer.isVisible();
你也可以修改這些屬性去影響圖層的渲染。
除了這幾個歸一化的屬性外,還可以用上面的方法訪問更多的通用屬性。
可用通過下面的方法,從圖層中獲取對象:
MapObjects objects = layer.getObjects();
MapObjects實例允許你通過名字,索引或者類型去獲取對象,也可用通過它們去插入/刪除對象。
Map 對象
API以已經提供了很多特定的MAP對象了,比如CircleMapObject, PolygonMapObject等等。
地圖加載器會解析對象,并將它們放入相應的MapLayer中。
針對所有支持的格式,我們嘗試針對所有對象,提取出下面歸一化的屬性:(譯者注:名字,透明度,可見性,顏色)
String name = object.getName();
float opacity = object.getOpacity();
boolean isVisible = object.isVisible();
Color color = object.getColor();
特定的Map對象,比如PolygonMapObject,可能有額外的屬性等等。
Polygon poly = polyObject.getPolygon();
改變任何一個屬性都會影響到對象的渲染。
對象,和地圖和和圖層一樣,你可以訪問對象更多的通用屬性。
注意: “Tiled”地圖工具的tiles,不會保存為map對象。 有特別的圖層可用來更有效的保存它們。 上面描述的對象一般用于定義:trigger areas, spawn points, collision shapes 等等。
地圖渲染器 MapRenderer
MapRenderer接口,定義了渲染圖層和對象的方法。
在你開始渲染前,你必須定義地圖的View。把View想象成窗口。實現(xiàn)這一點的最簡單的方法是告訴地圖渲染器它可以使用的OrthographicCamera:
mapRenderer.setView(camera);
或者,你也可以手動指定投影矩陣和視圖邊界:
mapRenderer.setView(projectionMatrix, startX, startY, endx, endY);
View的邊界由x/y定義,y軸朝上。所使用的單位是特定于地圖和從其加載的格式。
通過調用如下方法如渲染所有圖層:
mapRenderer.render();
如果你想要更多的控制渲染,你可以指定需要渲染圖層的索引。比如:假設你有3個圖層,2個背景和1個前景圖層,你想渲染處于前景和背景之間的Sprite,可以這么做:
int[] backgroundLayers = { 0, 1 }; // don't allocate every frame!
int[] foregroundLayers = { 2 }; // don't allocate every frame!
mapRenderer.render(backgroundLayers);
renderMyCustomSprites();
mapRenderer.render(foregroundLayers);
通過單獨渲染每個圖層并修改每個圖層的視圖,您還可以實現(xiàn)視差效果。
Tiled Map
包含Tiles圖層的地圖,其處理的相關的類,在包com.badlogic.gdx.maps.tiled中。這個包里面也包括用于不同格式地圖的加載器。
瓦片地圖被加載到TiledMap類的實例中。TiledMap是通用地圖類的子類,TiledMap中增加了額外的方法和屬性。
Tiled Map的圖層
包含tiles 的圖層,是加載到 TiledMapTileLayer 實例。為了訪問這些tiles,可以做如下轉換
TiledMap tiledMap = loadMap(); // see below for this
TiledMapTileLayer layer = (TiledMapTileLayer)tiledMap.getLayers().get(0); // assuming the layer at index on contains tiles
其他通用的MapLayer有的全部屬性,TiledMapTileLayer都有。除此之外,TiledMapTileLayer還有一個包含TiledMapTileLayer.cell實例的二維矩陣。
通過如下方法訪問Cell:
Cell cell = tileLayer.getCell(column, row);
column和row指明了cell的位置,都是整數(shù)。tiles是在一個y軸向上的坐標系中。左下角的tile是(0,0),右上角的tile坐標為(tileLayer.getWidth()-1,tileLayer.getHeight()-1)
如果指定的位置沒有tile,或者如果列/行參數(shù)超出范圍,則返回null。
可以通過以下方式查詢圖層中的水平和垂直圖塊數(shù):
int columns = tileLayer.getWidth();
int rows = tileLayer.getHeight();
Cells
Cell是 TiledMapTile 的容器。cell存儲對Tile的引用,還有指定在渲染它時是否應該旋轉或翻轉瓦片的屬性。
Tiles經常在多個cells之間共享。
Tilesets & Tiles
TiledMap包含一個或者多個 TiledMapTileSet 實例。Tileset 包含許多 TiledMapTile 實例。有多種方法實現(xiàn)tiles,比如:靜態(tài)tiles,動畫tiles等。您還可以為特殊目的創(chuàng)建自己的實現(xiàn)。
Tile圖層中cells引用這些tiles。 Tile圖層中的cells可以可以引用多個tileset中的tiles.為了減少紋理切換,建議每個圖層只用一個tileset。
渲染Tiled Maps
為了渲染TiledMap和它的圖層,你需要一個特定的MapRenderer實現(xiàn)。對于正交的或者自上而下視角的地圖,可以使用OrthogonalTiledMapRenderer. 對于isometric地圖,則使用IsometricTiledMapRenderer。其他的渲染器暫時是實驗性的,不推薦。
通過下面方法創(chuàng)建渲染器:
float unitScale = 1 / 16f;
OrthogonalTiledMapRenderer renderer = new OrthogonalTiledMapRenderer(map, unitScale);
這個渲染器只能對傳入構造函數(shù)的地圖進行渲染。 這個限制允許渲染器對該特定地圖執(zhí)行優(yōu)化,并緩存它們。
unitScale告訴渲染器一個游戲世界的unit是多少個像素。在上面的例子中,16個像素等同于1個游戲世界的unit. 如果需要1個像素和游戲世界的1個Unit對應,那么unitScale需要設置為1,以此類推。
unitScale是將渲染坐標系與游戲世界坐標系相結合的一種方式。
一個小例子:
假定你有一個tile地圖,每個tile為32×32像素。在你的世界地圖中,你想這些tile映射為世界地圖的 1×1 unit的方塊。你需要設置unitScale = 1/32f. 你現(xiàn)在可以將相機設置為在該單位刻度上。 假設你想在屏幕上查看地圖的30x20 tile,那么你可以像這樣創(chuàng)建你的相機:
OrthographicCamera camera = new OrthographicCamera();
camera.setToOrtho(30, 20);
如果使用的是IsometricTiledMapRenderer,則:
renderer = new IsometricTiledMapRenderer(isoMap, 1 / 32f);
再次,你必須指定地圖(它應該是一個isometric tile地圖)和一個unitScale。
注意:isometric渲染器是實驗性的,使用風險自負,請報告您發(fā)現(xiàn)的任何問題。 從性能角度來看,移動設備上的渲染等距映射是非常昂貴的,因為每個瓦片必須混合。
加載TMX/Tiled地圖
Loading TMX/Tiled maps

“Tiled”是一個通用的瓦片地圖編輯器,可運行在windows/Linux/MAC OS X上,可以用來創(chuàng)建Tile圖層和Object圖層,包含用來觸發(fā)區(qū)域的任意形狀和其他目的。LibGGX提供一個加載器,可以用來讀取“Tiled”生成的文件。
有兩個方法可以加載瓦片地圖:直接加載或者通過AssetManager。直接加載如下:
TiledMap map = new TmxMapLoader().load("level1.tmx");
這將會從assets文件夾加載這個叫做level1.tmx的文件。如果你想加載另外的文件類型,你必須在TmxMapLoader的構造其中提供一個FileHandleResolver。
TiledMap map = new TmxMapLoader(new ExternalFileHandleResolver()).load("level1.tmx");
我們選擇這種機制,因為TmpMapLoader也可以用和AssetManager類一起使用,F(xiàn)ileHandleResolvers統(tǒng)計了地址。通過AssetManager加載TMP地圖的方法如下:
// only needed once
assetManager.setLoader(TiledMap.class, new TmxMapLoader(new InternalFileHandleResolver()));
assetManager.load("level1.tmx", TiledMap.class);
// once the asset manager is done loading
TiledMap map = assetManager.get("level1.tmx");
加載后,你可以把這個地圖當成一個新的TiledMap.
注意:如果你通過“直接加載”的方式加載了TMX地圖,你需要調用TiledMap#dispose()去釋放。這個函數(shù)也會釋放地圖中所有加載的的textures.
注意:如果你想把TMX地圖和GWT backend結合使用,你需要保證地圖使用pure base64編碼。由于GWT的限制,GWT不能使用壓縮的TMX格式。
加載 Tide地圖

“Tide” 是另外一個通過用的瓦片地圖編輯器,只能適用于windows平臺。(譯者注:考慮程序員用MAC的較多,因此不推薦使用"Tide"). LibGDX也提供了支持Tide工具輸出的加載器。
和TMX文件一樣,你可以直接加載“Tide”文件或者通過AssetManager加載:
// direct loading
map = new TideMapLoader().load("level1.tide");
// asset manager loading
assetManager.setLoader(TiledMap.class, new TideMapLoader(new InternalFileHandleResolver()));
assetManager.load("level1.tide", TiledMap.class);
注意:如果你直接加載Tide地圖,你需要調用TiledMap#dispose()去釋放。這個函數(shù)也會釋放地圖中所有加載的的textures.
性能考慮 Performance considerations
我們希望渲染的速度越快越好,有一些東西你可以考慮下,一邊加快渲染速度:
- 僅使用圖層中單個圖塊集中的圖塊。這將減少紋理綁定。
- 將不需要混合的圖塊標記為不透明。 目前您只能以編程方式執(zhí)行此操作,我們將提供在編輯器中自動執(zhí)行的方法。
- 不要超過層數(shù)。(Do not go overboard with the number of layers.???)