Store in progress … please stand by

Over the past two weeks I’ve mainly been implementing the TilemapKit store and associated functionality.

Store Progress

Testing payment gateways (Stripe, Paypal) and invoice creation (Fastbill) mainly. It’s an arduous process. But it also has its satisfactory moments.

For instance I’ve been tweaking PHP scripts to create invoices according to law, mainly things concerning VAT, and then sending them out as PDF automatically. It’s quite neat when a service provides all that functionality via public APIs and I can interface with that so that it’s completely automated.

And the product and checkout pages are starting to look good. Now if only there weren’t this many browsers. It’s incredible how wrong things can go just by switching browsers.

Feel free to test-drive the Store and post your feedback here.

TilemapKit Progress

I’ve been trying for weeks to make new framework builds for TilemapKit. Unfortunately, I’m not only on OS X 10.11 beta, I’m also forced to using Xcode 7 beta. And every new beta, one or the other, fixes a few issues and introduces a couple more. Nasty ones, like Xcode currently not being able to open any storyboard file – meaning: no iOS builds with SpriteKit.

Yes, of course you can run Xcode 6.x on OS X 10.11 just by opening its executable directly. That doesn’t mean it’s running without problems though.

I’ve been trying to move the build process over to an older Mac mini, but it’s mocking me with yet more strange errors that only occur when I do command line builds. Suddenly there’s duplicate classes, and builds are super-slow, so it seems wasteful to try and debug that.

This has been quite frustrating, not being able to publish updated TilemapKit builds. Which also delays my plans of launching the Store.

At least I got the TMX writer done (TKMapWriter). And yesterday I’ve started writing the documentation guides after figuring out how to embed it with the class reference.

Maybe I’ll work on tile animations in the meantime, between store, website and documentation. Just to relax. :)

Well …

The whole beta thing will work out eventually. I just wanted to let you know that things are still moving forward on several fronts, even though I haven’t been posting updates frequently.

Although it looks like I’ll have to postpone my plans of launching TilemapKit next week. ETA? No idea …

I’m also curiously watching the votes on the ideas page. What will I be in for after the TilemapKit launch? Port it to Cocos2D-X / C++? Write a GameplayKit Editor? Design and implement a game Starterkit?

They all look equally daunting and fun to do at the same time! :)

SpriteKit vs Cocos2D + TilemapKit Performance Optimization

Over the last couple days I optimized the performance of TilemapKit, specifically the “core render loop” where all tiles are enumerated and (if needed) their sprites updated.

Here’s a before (left) and after (right) chart that shows how much time I was able to save on each iteration:

Screen Shot 2015-07-16 at 22.59.38

The left chart was already measured with a semi-optimized version, so the comparison doesn’t show the full impact of the optimizations I’ve performed (pun subconsciously intended, it appears).

Also it doesn’t show the fact that the render loop is now spread across all available CPU cores thanks to Grand Central Dispatch. All in all I estimate that TilemapKit performance went up roughly by 5-10 times.

SpriteKit vs Cocos2D + TilemapKit Performance

So, which one is faster: SpriteKit or Cocos2D(-SpriteBuilder/-ObjC)?

Well, there’s been a lot of debate and when SpriteKit came out many simply assumed that SpriteKit is faster than Cocos2D. Or maybe it was at the time. But how about now, with iOS 9 on an iPad Air 2?

Cocos2D wins, hands-down! At least when you compare it with the SpriteKit in the iOS 9 beta 3 – so it’s not really a fair comparison because SpriteKit most likely also runs debug code and/or is built without optimizations. Specifically on iPod touch 5G the results for Cocos2D were strangely the same as on iPad while SpriteKit’s performance was another 50% lower.

SpriteKit vs Cocos2D Performance (iOS 9 beta 3)

I’ll re-test when iOS 9 is final, and I’m sure it’ll be competitive in release versions of iOS.

The iPad Air 2 is the thus-far latest iPad model the only one with a triple-core CPU and a GPU that’s on par with Nvidia’s Shield tablet. The impact of multi-threaded vs single thread is less pronounced on dual-core devices but still gives you an appreciable speed-boost even on an iPod Touch 5G (the de-facto “lowest-end” device capable of running iOS 8/9).

It’s also worth pointing out that all iOS 8 devices have at least a dual-core CPU, and it’s only a matter of time until there’ll be a quad-core iOS device. Perhaps the rumored iPad Pro?

Multithreaded tilemap updates are a huge benefit on OS X where my extrem test tilemap jumped from 20 fps up to 60+ fps instantly on a quad-core Intel i7 with hyperthreading (8 virtual cores). It also had an audible impact on fan performance. 😀

The Art of Accurately Measuring Loop Performance

I wanted to share my experience in trying to optimize TilemapKit. Most people would jump out and say “Use Instruments!” but yeah, no, not really.

The nice thing with Instruments is that it quickly allows you to drill down to that one method where most of the time is spent. But other than that, it just produces an unmanagable load of data that’s very difficult to sift through and understand, while not presenting me the data I really want to see.

That is: execution times of individual lines or statements in nanoseconds.

Admittedly, I’m not an Instruments crack. And honestly, every time I see that tool, I feel like I don’t want to be using it. It always leaves me with a sense of confusion rather than certainty.

Still, Instruments did tell me that the tile layer update method is the largest chunk. Nothing I didn’t already know but when you want to optimize performance you better be sure to assert your assumptions.

So I checked what code solutions are out there to measure performance? Turns out these are the most viable options:

  1. NSDate (used by MGBenchmark)
  2. mach_time
  3. dispatch_benchmark

So how did these choices compare against each other?

  1. NSDate: Plain and utterly useless. Perhaps if you want to measure code that runs for several tens of a second it may be helpful. But other than that, NSDate/MGBenchmark is just awfully inaccurate since it only measures milliseconds (ms). That’s one million times less accurate than performance counters that work on a nanosecond scale! The results, even the averages, were also all over the place. And with MGBenchmark it was not possible to have the setup and shutdown code before and after the loop, while measuring only specific lines within the loop repeatedly.
  2. mach_time: Accurate, but difficult to use. Requires manually converting the result from mach time units (MTU) to nanoseconds. And there’s no average – if you want average, you got to write your own loop and divide the result by the number of iterations. Plus you need to #import several headers. Therefore you end up with several lines of code before and after anything you measure unless you wrap this stuff in a helper class, which I didn’t want to do to avoid as much overhead as possible.
  3. dispatch_benchmark: A true (and hidden) gem! (Thanks @NSHipster!) I bet it uses mach_time internally.

So I went with dispatch_benchmark – but why?

First of all, it executes the code you want to measure in a block, and you specify the number of iterations and as the return value you get the average runtime of a single iteration in nanoseconds:

That also makes it easy to print, and the overhead I measured by running an empty block clocks in at a negligible 2 ns.

Also notice how the measuring code is just 3 lines, and you can easily paste code into and out of the block. The only downside is that you’ll have to flag any assigned variable with the __block keyword. But, oh well, so be it.

The cool thing was that not only could I run each and every line in the render loop 1000 times per iteration, I also added all numbers up for the entire loop and got the average for all tiles after the loop. I did this in case some tiles spend more time in any given line than others.

The only other thing that you have to do to setup dispatch_benchmark is to declare this private method with external linkage, somewhere at the top of the source file:

You don’t even need to #import anything! That makes measuring performance and watching the impact of your changes almost a fun leisurely thing to do. :)

Tilemap Pathfinding now with Travel Costs

TilemapKit is now able to generate grid graphs from tile costs. Rather than using walkable/blocked flags on tiles you would use a “cost” property whose floating point value is in the range 0.0 to infinity.

Though you should try to restrict your value range from 0.0 to 1.0 or 0 to 100, that’ll make it easier to get a feel for the relation of individual cost values.

In this example, the road has a cost of 0.5 while grass is 3.0, ice is 4.0 and mud is 6.0. Any tile without a cost is considered blocked, but you can also specify a negative value to block off a tile.

Tile cost for pathfinding, Tiled propertiesTile cost property for road

The code to generate this graph is even simpler than what you would use for non-cost based graphs:

Each node in the cost graph uses the TKGridGraphNode subclass of GKGridGraphNode, which adds a cost property and implements the costToNode: function to simply return the cost.

You can further subclass this class and override the costToNode: function if you need to base the cost on certain conditions. Or you could fix certain undesirable behavior such as where the roads don’t actually connect even though their tiles are neighbors the cost should probably be higher. You can see this issue in the video if you watch closely:

Path … never been so much fun. 😀

Tilemap Pathfinding Example on Hexagonal Map

A picture says more than a thousand words, they say.

Screen Shot 2015-07-11 at 20.06.18

But then, what does a video say? :)

GameplayKit pathfinding support is built into TilemapKit. See how easy it is to create a grid graph from a tilemap:

You’ll also be able to create obstacle graphs from Tiled objects (polygons, rectangles and circles).

TilemapKit Development Report 2015

I want to let you know what’s in store for TilemapKit in the near future. If I don’t drown too much in actual work, I’m hoping I’ll be able to do this on a more regular basis. :)

Screen Shot 2015-07-07 at 17.33.37

Shapes of all kinds, even rotated. The barrels are tile objects, some flipped and resized.

Completed Tasks

These features will be in v0.8 (available soon). Several of these tasks are summarized by the screenshots to the right.

  • Performance: maps with non-zero renderSize will only draw visible tiles.
  • Tilesets: “Collection of Images” tilesets are supported.
  • Image layers supported.
  • Object layers supported.
    • Draws shapes and tile objects.
    • Object rotation, flipping and (for tile objects) size are applied correctly.
    • Shape objects return a CGPathRef for use in followPath: actions and similar.
  • Screen Shot 2015-07-08 at 19.34.09

    GKGridGraph generated from tiles across several layers. Graph drawing is part of TilemapKit.

    Layer alpha is now applied correctly.

  • GameplayKit support:
    • Create GKGridGraph from tile layers using “positive” and “negative” GIDs.
    • Get array of Tiles with a given property and value, for use in above function.
    • Draw graph on map, for debugging the above.
  • Major refactoring, mainly to improve Swift interoperability.

Next Tasks (July/August)

I will work on these features in July and possibly into August.

  • GKGridGraph with proper offsets for staggered isometric maps.
  • GKGridGraph with proper offsets for hexagonal maps, and two of the 8 grid directions disconnected.
  • Create GKObstacleGraph, with blocked tiles treated as “tile-shaped obstacles” and additional obstacles on object layers.
  • Analyzing and optimizing performance of render loop.
  • Reduce framework/code installation steps to a minimum.
  • Documentation with examples.
  • Start selling TilemapKit by end of July / early August. :)  This means setting up plugins, pages, eCommerce stuff. :(

Help out!

If you like what we do, please share it. Thanks! 😉

Just by sharing our pages and posts on social networks or linking them in your blog would help us a great deal. It’ll result in better google rankings and ultimately more traffic.

And don’t forget to suggest features and vote on upcoming tasks!