New Tile Maps Implementation

Discussions for core devs and contributors. Read only for normal forum members to keep the noise low

New Tile Maps Implementation

Postby BurningHand » Tue Jan 15, 2013 2:16 pm

As promised to Mario long ago, I have finally been working on a new tile map implementation. I am at a point where I wanted to show it to you guys and get some feedback / suggestions / hate mail about it.

Background
As we all know, the current tile map implementation was created by a contributor who is no longer with us. For a long time it sat untouched, despite people reporting problems and having all sorts of issues in using it. The reality is, I don’t think anyone really “understood” it enough to really support it.

I never really used the current implementation because I’ve never been much a fan of how it was constructed. The preprocessing and the pre-caching of the tiles made it cumbersome to use, and not very dynamic (at all).

When I set out to rebuild it, I wanted it to be the opposite of that. I wanted simple, easy to use, and easy to extend. Accordingly, I tried to make some base classes which could be used by a variety of map types. My goal was to be able to treat a map as more of a layered scene than something that was strictly a rigid grid of tiles. The result is something of a mix between the Tiled and GLEED2D notions of a map/level. I hope I’ve achieved this goal.

Links

Code:
https://github.com/MobiDevelop/libgdx/t ... s/gdx-maps

Test:
https://github.com/MobiDevelop/libgdx/b ... Tests.java

Overview
The new implementation has been made as an extension, as opposed to being in the core. I feel that by separating it, people will feel more comfortable extending it to meet their needs (and possibly contributing back to it). There are two projects that comprise the maps extension: the core extension and a gwt add-on that modifies some classes to allow for GWT consumption (I didn’t want to do this, but had to for compatibility).

Classes

  • Map - A holder for layers.
  • MapLayer - A layer of the map.
  • MapLayers - A list collection of MapLayer.
  • MapObject - A generic object to be part of the map.
  • MapObjects - A list collection of MapObject.
  • MapProperties - A key/value collection of properties, allows casting values.

Interfaces

  • MapLoader - Defines a load method (Not sure this interface is needed).
  • MapRenderer - Defines render methods that all renderers must implement.

Loaders Subpackage
This is where MapLoader implementations will live. There is currently a TmxMapLoader which, as you might imagine, loads Tiled TMX files into out Map structure. I am currently working on implementing the Gleed2D loader, as well as a loader for tIDE format.

Objects Subpackage
In this package you will find some general MapObject subclasses. These are self explanatory so I won’t really discuss them here. They pretty well follow the model of LevelObject subclasses in the Gleed2D extension.

Tiled Subpackage
This is where things specific to tile maps live. There is no strict correlation between this these classes and the Tiled format (although it closely resembles it - after all, how many ways to define tile maps can there be). In here we subclass some of the generic Maps classes to provide tile functionality.

Classes
  • TiledMap - a subclass of Map that adds tilesets.
  • TiledMapRenderer - a renderer implementation for TiledMap.
  • TiledMapTileLayer - A subclass of MapLayer that holds a grid of Tiles.
  • TiledMapTileSet - A set of Tiles.
  • TiledMapTileSets - A collection of TileSet that allows easy access of Tiles by their id when multiple TileSets exist.

Interfaces

  • TiledMapTile - Defines a Tile as a TextureRegion provider.

Tiles Subpackage
Houses implementations of the Tile interface. Currently, there is a StaticTiledMapTile that holds one TextureRegion and represents a single non-animated Tile. I have an AnimatedTiledMapTile as well, but did not include it in the initial code dump because it still needs some love.

Usage
Maps can easily be created either from a loader, or in code. Once a map is created, a MapRenderer will need to be provided to renderer it. There is currently only a TiledMapRenderer implemented, but it is trivial to implement a MapRenderer for other needs, see the TiledMapRenderer for an example.

Creating a Map in code
Code: Select all
TiledMap map = new TiledMap();
MapLayers layers = map.getLayers();
TiledMapLayer layer = new TiledMapTileLayer(15, 10, 64, 64);
for (int x = 0; x < 15; x++) {
   for (int y = 0; y < 10; y++) {
      layer.setCell(x, y, new StaticTiledMapTile(getTextureRegion())); // Create a Tile which lives outside of a TileSet
}
}
layers.addLayer(layer);

TiledMapRenderer renderer = new TiledMapRenderer(map);


Loading a Map
Code: Select all
assetManager = new AssetManager();
assetManager.setLoader(TiledMap.class, new TmxMapLoader(new InternalFileHandleResolver()));
assetManager.load("data/maps/tiles.tmx", TiledMap.class);
assetManager.finishLoading();
map = assetManager.get("data/maps/tiles.tmx");
renderer = new TiledMapRenderer(map);


To Do
Here’s some things I have on my list to do. Some of them sooner than others.

  • JavaDocs
  • Additional loaders (Gleed2D, tIDE, others?)
  • Isometric Tile Map Renderer
  • Hexagonal Tile Maps Renderer

There you have it... Now, let me have it (your feedback, suggestions, and hate mail that is).
IRC: nexsoftware / mobidevelop; GitHub: MobiDevelop;
BurningHand
 
Posts: 2812
Joined: Mon Oct 25, 2010 4:35 am

Re: New Tile Maps Implementation

Postby bach » Wed Jan 16, 2013 4:34 am

Said it before, I'll say it again: I really like what you've done :) Can't wait for this to be in the nightlies.

Re: SpriteCache. Maybe we could add the option to make use of sprite caches if applicable? I think it could definitely improve performance in some circumstances.

Personally I wouldn't have any problem making this part of core - it's not a whole lot of code and doesn't bring any additional dependencies. It's also something that'd be used by quite a few people. Just my opinion though.

Cheers,
Bach
bach
 
Posts: 713
Joined: Mon Mar 07, 2011 1:50 am

Re: New Tile Maps Implementation

Postby mzechner » Wed Jan 16, 2013 12:19 pm

I haven't looked at the code yet, i'll do so when i have more free time.

On the matter of inclusion in core: we already have a TMX loader and renderer in core, and this is meant to be its replacement. I think similar to box2d, it's an essential part of the API, hence it should go into core. 90% of our target audience is working on 2D stuff (maybe that changes with the new fancy 3D API :D).

Btw, siondream already wrote a gleed2d loader, and we've made it an extension (didn't include it in the build yet). Maybe you two could collaborate on that?
mzechner
Site Admin
 
Posts: 4875
Joined: Sat Jul 10, 2010 3:50 pm

Re: New Tile Maps Implementation

Postby BurningHand » Wed Jan 16, 2013 12:51 pm

Location doesn't matter much to me. If it's better in core, that's cool with me.

As far as Gleed goes, most of the "Objects" package was lifted from that extension so I bet it will be easy to convert. I'll get in touch with siondream to get his thoughts.

I added some additional MapRenderer implementations in the Tests project: ShapeMapRenderer (renders shape objects as... you guessed it, shapes), SplatMapRenderer (renders TextureMapObjects using a SpriteBatch) and SuperMapRenderer (combines ShapeMapRenderer and SplatMapRenderer).
IRC: nexsoftware / mobidevelop; GitHub: MobiDevelop;
BurningHand
 
Posts: 2812
Joined: Mon Oct 25, 2010 4:35 am

Re: New Tile Maps Implementation

Postby mzechner » Wed Jan 16, 2013 10:41 pm

I'm sorry if the following is a bit incoherent, i tried to distill this post as much as possible. Here we go.

Code Structure[b]
  • There's a bin folder in the gwt project :)
  • The GWT project seems to be only necessary due to missing crossplatform reflection API. I shall open a new thread for that so we can start working on that (hopefully with a lot of Mr. Reflection, aka Nate)
  • I think we should move this into core, remove the current tilemap stuff and related classes. We should create a branch for this migration, once everything is in place, we merge with master.
  • The tiled package name is a bit missleading, but i can live with it. TiledMapTileSet et al. sound a little strange as well, but i think it's OK.

[b]MapProperities

  • Looks like Preferences :D
  • I'm kinda worried about all the boxed primitives, but i don't see a better solution

MapLoader & MapRenderer
  • I guess an interface doesn't hurt. I don't have a use case just yet, but being able to handle different map loaders through the same interface kinda makes sense to me.
  • Not sure about MapRenderer taking an OrthographicCamera. I can see that it allows for a ton of optimizations. I guess we can keep it for now. Folks doing something crazy like actually using matrices or PerspectiveCameras will have a hard time. Maybe add a method that takes a matrix and bounds in map coordinates to reduce the amount of tiles being rendered? Open to suggestions, we can also just keep it as is and fix that later.

TMX Loader & TiledMapRenderer
  • TMX loader is super goody, can't see anything wrong with it. Could actually make it an asynchronous loader so the XML parsing and base64 decoding is done on a separate thread as well. Not a big prio, should be fast enough as is.
  • The TiledMapRenderer is indeed flexible in that it can react to changes in the map immediately. However, i'd imagine that rendering each tile separately just kills performance on Android. The culling helps of course. Did you benchmark this on Android? We should compare it in speed to the old TMX implementation, not entirely fair, but we should get a good feel for it.
  • I think we could optimize it by using SpriteCache or a Mesh directly. We'd need to make sure the renderer gets notified on changes in the TileMap it owns, so it can rebuild the caches. I've done this for a few prototypes and it's not too big of a deal. We'll need to look into sideeffects though, especially concerning objects.
  • I also think we could merge tile set images into a TextureAtlas on the fly via PixmapPacker
  • If we stick to the per tile drawing, we could check if composing the vertices into a float[] and passing that to SpriteBatch is actually faster. We'd have to duplicate some SpriteBatch code in TileMap, not sure that's worth it though.
  • Much of the weirdness of the old implementation can be attributed to the fact that rendering tilemaps just by blitting each individual tile and changing states for blended and non-blended tiles kills everything under the sun. I'd say we should make sure that a moderately complex tile map renders at 60fps on Nexus One class hardware.
  • TL;DR: All of these things would be premature optimizations, we should benchmark first.

I agree with bach that i like where this is going. One additional thing we should consider is collision detection and intersection testing. I guess the current object model facilitates that, maybe some explicit methods could help users out even more.

Great stuff, thanks for all the effort!
mzechner
Site Admin
 
Posts: 4875
Joined: Sat Jul 10, 2010 3:50 pm

Re: New Tile Maps Implementation

Postby BurningHand » Thu Jan 17, 2013 4:03 pm

Code Structure
  • Oh noez!!! There is a bin folder in there isn't there? I'll go stand in the corner now.
  • Yeah, the GWT project is there mostly for the reflection, but also to accomodate TmxLoader (allowing CSV and Base64 maps to be loaded on GWT).
  • I'll move it into core, and wipe out the existing tilemap stuff.
  • Would you prefer to move the tiled stuff into the main maps package? Probably would want to keep the tiles package in that case. I like the separation, but I can see how it could be misleading (making people think it is specific to the Tiled program or format).

MapProperties
  • Yeah, it is pretty similar to Preferences, huh?
  • Indeed, the boxing could be a problem - but I'd imagine that the properties would not be read frequently enough for it to be. Not sure of a better way either... Perhaps some linked list sort of deal with typed arrays for the primitive types and a lookup table (though this would increase complexity and memory usage considerably I am sure).

MapLoader & MapRenderer
  • Yeah, I am not sure about the MapLoader interface, as I am sure you noticed, I didn't implement it in the TmxMapLoader (I guess proving that it is extraneous).
  • I'm not opposed to investigating the best way to support passing in just a Camera, or a matrix and bounds. I'll welcome any input on that front as I typically stick with orthographic. I'd we'd be fine in the near-term but with a to-do item to add new render methods to support these options.

TMX Loader & TiledMapRenderer
  • I wasn't sure whether there'd be much benefit to async, so I just did sync. If we need to go async it should be trivial to change it to that.
  • I have a variant that uses a dynamic SpriteCache but did not include it. The way it works is that it recaches when necessary (based on new tiles becoming visible or tiles going out of view, etc...) but the way it was setup it depended on equal tile size across layers, but the TiledMap implementation does not enforce that to be true so I'd need to rework the renderer. So far, performance hasn't been a problem using SpriteBatch. I've been testing with maps up to 10 layers of 32 x 32 tiles (with blending on) using my G2x and my Nexus 4 and haven't dropped below 55fps. Not sure how well that relates to other hardware, I'll have to find my other devices to test on I guess.
  • I'm open to using a PixmapPacker but will need some guidance on how that would be set up. I am not super familiar with it.
  • I'll find my old phones to benchmark on. I have a MyTouch 3G, an original Droid, and an Evo 4G somewhere in my house.

Thanks for all the input.
IRC: nexsoftware / mobidevelop; GitHub: MobiDevelop;
BurningHand
 
Posts: 2812
Joined: Mon Oct 25, 2010 4:35 am

Re: New Tile Maps Implementation

Postby siondream » Thu Jan 17, 2013 5:54 pm

Hey guys!

I love the idea of providing interfaces to 2D map management in libgdx, kudos for BurningHand :-). Not only it'd possible to work with tile and non tile based maps but also we'd achieve file format independence. It'll be clearer for everyone and much more intuitive. Sweet.

I'm more than willing to adapt my GLEED2D system as NonTiledMap/TextureMap (what name would we use?). I'd also add my GLEED format level loader. How would we proceed? I could wait for BurningHand to get his stuff committed, I'll adapt it using the same API and then make a pull request.

I don't mind whether you guys want to make it an extension or part of the core. To be honest, GLEED2D strikes me as a non standard tool in 2D gamedev so maybe that module should still be an extension.

Cheers.
siondream
 
Posts: 364
Joined: Tue Apr 03, 2012 11:59 pm

Re: New Tile Maps Implementation

Postby mzechner » Thu Jan 17, 2013 6:22 pm

i suggest you great a new branch besides master, similar to the new3dapi branch, and do all modifications there (move to core, remove old stuff, integrate gleed). once things are tested we can merge with master for everyone to enjoy it.
mzechner
Site Admin
 
Posts: 4875
Joined: Sat Jul 10, 2010 3:50 pm

Re: New Tile Maps Implementation

Postby BurningHand » Thu Jan 17, 2013 6:34 pm

I'm assuming you mean doing that on the main repo, as opposed to my fork?
IRC: nexsoftware / mobidevelop; GitHub: MobiDevelop;
BurningHand
 
Posts: 2812
Joined: Mon Oct 25, 2010 4:35 am

Re: New Tile Maps Implementation

Postby davedes » Fri Jan 18, 2013 8:03 am

Generally we should be weary of things like SpriteBatch.setProjectionMatrix and begin/end, as these things flush the batch and send uniform data to the shader. Where possible, it's better to give more control over flushing to the user. This way they can tailor the "batch count per frame" to suit their exact performance needs. See here for info:
http://bit.ly/WlAZLR

The use of begin/end is also problematic if at some point in the future we decide TiledMap should play nicely with scene2D (i.e. say you wanted a tiled map inside a scroll pane).

These are very small nitpicks and may be somewhat of a "premature optimization," but nevertheless something to keep in mind when working with batching. :)
davedes
 
Posts: 434
Joined: Thu Oct 11, 2012 7:51 pm

Next

Return to Libgdx Development

Who is online

Users browsing this forum: No registered users and 1 guest