6
\$\begingroup\$

I'm currently designing a game using a game engine I created and I'm currently implementing a method that loads maps into my game. The maps are made using Tiled Map Editor, saved as an XML file and are loaded using TiledSharp.

At the moment, I'm trying to load a map, that contains 1437 'Game Objects' (These are just tiles, as far as tiled is concerned) and currently it takes around 360ms to load. I was just wondering what I can do to load my maps faster.

Here is the code that loads my maps:

public void LoadMap(string path)
{
 Console.WriteLine("Loading map...");
 var watch = new Stopwatch();
 watch.Start();
 // Import XML data using TiledSharp
 var tmxMap = new TmxMap(path);
 // Lets all the classes variables
 width = tmxMap.Width;
 height = tmxMap.Height;
 tileWidth = tmxMap.TileWidth;
 tileHeight = tmxMap.TileHeight;
 wholeWidth = width * tileWidth;
 wholeHeight = height * tileHeight;
 // Now lets load all the sprite sheets that are used in this map
 var spriteSheets = LoadSpriteSheets(tmxMap);
 // A value that indicates what layer we're drawing to
 int currentLayer = -1;
 foreach (var layer in tmxMap.Layers)
 {
 // Increment a layer foreach layer we're in
 currentLayer++;
 foreach (var tile in layer.Tiles)
 {
 // Get the tiles x, y and global id
 int x = tile.X;
 int y = tile.Y;
 int gid = tile.Gid;
 // Now lets loop through the tilesets in the map
 for (int i = 0; i < tmxMap.Tilesets.Count; i++)
 {
 var tileset = tmxMap.Tilesets[i];
 // This just figures out how many images are in the tileset
 int firstGid = tileset.FirstGid;
 int lastGid = firstGid + (int)tileset.TileCount;
 // Check if the tile we're on is in this tileset, if it isn't continue
 if (!gid.IsWithin(firstGid, lastGid)) continue;
 // Get the regular id, used to get the correct sprite from the sprite sheet
 int id = gid - firstGid;
 // Create a new object, set its position and scale
 var obj = new GameObject();
 obj.Transform.Position = new Vector2f(x * tileWidth, y * tileHeight);
 obj.Transform.Scale = new Vector2f(tileWidth, tileHeight);
 // Now lets add a sprite renderer component, and pass it the correct sprite
 var sprite = new Sprite(spriteSheets[i][id], currentLayer, 1.0f);
 var renderer = new SpriteRenderer(sprite);
 obj.AddComponent(renderer);
 // Now lets get the tiles from the tile set, and check if it contains any properties we need to know about
 // Things like if its solid, or has a different depth
 var tiles = tileset.Tiles;
 if (tiles.ContainsKey(id))
 HandleProperties(obj, tiles[id].Properties);
 // Finally, lets add our game objec to the map
 AddGameObject(obj);
 }
 }
 }
 // Dispose of our sprite sheets
 foreach (var sheet in spriteSheets)
 sheet.Bitmap.Dispose();
 watch.Stop();
 Console.WriteLine("Load time: {0}ms", watch.ElapsedMilliseconds);
 if (GameObjects.Contains(Game1.Player)) return;
 AddGameObject(Game1.Player);
}
private void HandleProperties(GameObject obj, PropertyDict properties)
{
 var value = "";
 if (properties.ContainsKey("Solid"))
 {
 value = properties["Solid"];
 if (value == "true")
 {
 // We know we need to add physics and a collider
 var physics = new PhysicsComponent();
 physics.DetectCollisions = true;
 obj.AddComponent(physics);
 var collider = new BoxCollider();
 collider.Size = new Vector2f(tileWidth, tileHeight);
 obj.AddComponent(collider);
 }
 }
 if(properties.ContainsKey("Depth"))
 {
 // Lets set the new depth of the sprite
 value = properties["Depth"];
 int depth = int.Parse(value);
 obj.GetComponentOfType<SpriteRenderer>().Sprite.Depth = depth;
 }
}
private List<SpriteSheet> LoadSpriteSheets(TmxMap tmxMap)
{
 List<SpriteSheet> sheets = new List<SpriteSheet>();
 for (int i = 0; i < tmxMap.Tilesets.Count; i++)
 sheets.Add(new SpriteSheet(tmxMap.Tilesets[i].Image.Source, tmxMap.TileWidth, tmxMap.TileHeight, Color.White));
 return sheets;
}
t3chb0t
44.6k9 gold badges84 silver badges190 bronze badges
asked Apr 9, 2017 at 13:52
\$\endgroup\$
1
  • \$\begingroup\$ I don't see any obvious optimizations in your code - it looks good. You'll have to run it with a profiler. \$\endgroup\$ Commented Apr 10, 2017 at 14:53

2 Answers 2

2
\$\begingroup\$

You should start with a profiler. Having said that, there is one easy optimization you can make without a lot of code changes.

Change the following line in LoadSpriteSheets from
List<SpriteSheet> sheets = new List<SpriteSheet>();
to
List<SpriteSheet> sheets = new List<SpriteSheet>(tmxMap.Tilesets.Count);

The amount of elements in the list is known in advance so you can avoid the cost of repeatedly resizing the container.

answered Jun 16, 2017 at 23:48
\$\endgroup\$
0
\$\begingroup\$

Your code looks well written and is easy to read and understand. As t3chb0t stated, you'll have to run a profiler and see where you might make optimizations.

One micro-optimization I found was following: the Transform properties of the GameObject can be set outside the most inner loop, since the parameters to set them don't change in the inner loop.

foreach(var layer ...)
{
 foreach(var tile ...)
 {
 int x = tile.X;
 int y = tile.Y;
 int gid = tile.Gid;
 var obj = new GameObject();
 obj.Transform.Position = new Vector2f(x * tileWidth, y * tileHeight);
 obj.Transform.Scale = new Vector2f(tileWidth, tileHeight);
 // Now lets loop through the tilesets in the map
 for (int i = 0; i < tmxMap.Tilesets.Count; i++)
 {
 //...
 }
 }
}
answered Jun 16, 2017 at 14:50
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.