Friday, March 1, 2013

Mega Dragon Run

  It's out in the AppStore! Here's the link.


We've worked on Mega Dragon Run for a while. The thing is finally out and doing good. The highest rank we reached was #5 Top Overall Free App in the US AppStore. That's a huge achievement. Here are some of the things that I personally feel good about having contributed to the game as a technical and creative person. None of them are supposed to be too impressive, smart or complex, but I feel they're cool.

By the way, the game is free. Go get it. Now. And buy some coins.

Facebook Friend Score Boards

The reason I enjoyed doing that was the server side work. The game consumes many different web services but writing both ends of a client-server system and seeing it in action, at least for me, is very satisfying, especially considering all the new stuff I got to work with. I'm going to go into the server architecture we used for the feature and the problems we had to overcome.

We originally used a WAMP (Windows, Apache, MySQL, PHP) stack for the server side here. Almost every development tool that composes the setup was new to us - before this, we never wrote a line of code in PHP, used Apache outside of school, or done any meaningful work with MySQL. After a couple of weeks we had the web services up and running on AWS EC2. The stack worked just fine for the following months until release day came and that's when (obviously) everything started crashing. Apache was able to serve requests for less than a minute before crashing and having to be restarted, with the error log reporting hitting the maximum thread count. Upping the thread count limit gave it just a little more uptime. The game was already live in the AppStore, but this didn't seem to be a load-related issue because usage was still very low.

It seems I'm as good at the game as I am at server architecture





After research and long attempts to stabilize the server with Dan B. from AWS support I realized the best shot would be to set up a new stack, this time using Linux instead of Windows, and separating the database and application to 2 different servers. A Facebook message to server guru and friend +Shai Mishali (who also advised the use of Nginx instead of Apache), and 3 hours later we had a stable working stack consisting of Ubuntu, Nginx, MySQL, PHP. So thanks to Shai everything seems to be fine right now. Shai is also a web developer and a native iOS app developer and is available for freelance work - highly recommended.

Shadows

 At some point in the development of MDR (Mega Dragon Run) we switched all 3 background layers of the game with another (the current) backgrounds that are more consistent with the rest of the art style. The downside was that the change made it harder to visually distinguish the enemies from the backgrounds, making gameplay suffer. The main thing we did to solve the issue was assing a thicker stroke for the enemies. The second thing was the shadows, which made the game look prettier and gave the player a visual logical indication of the existence and position of actors, making the player and enemies more distinctable to the eye.

Here's a comparison of a typical scene in the game with and without shadows (the point is made better in motion, though):
Enemies use same colors as background and platforms, hurting gameplay

Shadows give a realistic look and indicate actor position


The shadows were implemented using OpenGL blending functions to use the platforms as a mask for the shadows. We could not use shaders for the job as they are not supported on OpenGL ES 1 (cocos2d 1.0) which MDR is using. In case you're wondering why we didn't just stick shadow sprites that follow their actors, the reason is that partial rendering of shadows is required over edges of platforms.

Camera Movement

The game is based on the code of Mishu the Dragon, which went through a lot of changes. I didn't like the way the camera moved in he original game, so I decided to try a different system. The best way to feel both is to simply play both of them which are available for free in the App Store. The camera position and the way it moves is based on the these priorities:
  1. Keep the player on the screen.
  2. Keep the lowest visible platform on the screen (ignoring those already behind the player).
  3. Accelerate and move smoothly, minimize fast movements.
I think that the end result is good. Try it in the game right now and let me know what you think.

Friday, February 15, 2013

Adding Jenkins Latest Changes to Release Notes When Sending to Testflight

I went through the steps in this awesome tutorial by Charlie Fulton to use unit tests and Jenkins CI as part of our workflow. In short, you end up with a little robot that checks every five minutes for changes in your source control server (we're using Mercurial with Bitbucket), pulls all the changes if there are any new ones, performs a clean build, all your unit tests, archives the application, and sends it to TestFlight. It will let you know by email (zero configuration required) if something goes wrong.

I decided to make a small addition to the process and make Jenkins include the changes (commit message) of the build it is sending to TestFlight in the TestFlight Build Information part.

Instructions 

Go to Configure in your Jenkins Job. Find this line
# 5
/usr/bin/zip -r "${IPA_DIR}/${PROJECT}.dSYM.zip" "${DSYM}"
 

And modify everything after that as follows:
# extract changes message JENKINS_PORT=$"8080" JENKINS_URL=$"localhost" COMMENTS=$(curl "$JENKINS_URL:$JENKINS_PORT/job/${JOB_NAME}/${BUILD_NUMBER}/
api/xml?xpath=//msg&wrapper=w") COMMENTS=${COMMENTS##<w>} COMMENTS=${COMMENTS%</w>} COMMENTS=${COMMENTS%<w/>} COMMENTS=${COMMENTS//<msg>/} CLOSINGTAG=$"</msg>" NEWLINE=$" " COMMENTS=${COMMENTS//$CLOSINGTAG/$NEWLINE} # # Send to TestFlight # /usr/bin/curl "http://testflightapp.com/api/builds.json" \ -F file=@"${IPA_DIR}/${PROJECT}.ipa" \ -F dsym=@"${IPA_DIR}/${PROJECT}.dSYM.zip" \ -F api_token="${API_TOKEN}" \ -F team_token="${TEAM_TOKEN}" \ -F notes="Build ${BUILD_NUMBER} uploaded automatically from Xcode. Changes: ${COMMENTS} Revision ${MERCURIAL_REVISION}" \ -F notify=True \ -F distribution_lists='all' echo "Successfully sent to TestFlight"

Change the values of JENKINS_PORT and JENKINS_URL to your own.

If anyone has a safer way of extracting the text from the xml than replacing the tags manually as I did let me know and I'll edit it in. I tried using xpath's string-join and text() but Jenkins doesn't seem to support xpath 2.0.

Monday, February 11, 2013

Easily Make Your iOS Game Friendlier to Game Designers


Tanks is the inside name for a top down, 2d shooting game we worked on in HumanGNA. 
We worked on the project for about a month before it was cancelled. This is a dev log kind of post.

You are in a Tank traveling through a map shoot-em-up style, without any control over your position, so it's rail-shmup kind of game. We had some good discussions and ideas about game mechanics that could make it more interesting than "just shoot those guys as fast as you can to stay alive" but never got to the point of implementing any of them.

We built the game with the guy who designs the levels in mind. We believe that the more fluid and frictionless the designer's work, the better the levels and the game will be. There isn't anything fancy  technology-wise here, but I think there is still some good stuff to share when it comes to implementing a data-driven, good enough code design for your cocos2d game.

While trying to make life good for the designer, we also tried to push this game out asap, so we refrained from creating any home made tools for anything.

I will go over some ideas which I think are post-worthy. If you read this and are interested in hearing more about any of them, let me know, and if there's interest I'll make a more specific and detailed post.


Data-Driven Design

This is a buzzword you hear often, but for a good reason. Your game engine should be data driven.
If you find words such as "machinegun", "truck", "sunglasses", "soldier", "lava" in your code then you are probably doing something wrong. "Weapon", "Vehicle", "Item", "Character", "Combatant", "Level" are probably fine.

Think of a class that represents a Weapon in a game. Some of the data that the Weapon class contains is truly Weapon-specific, such as the bullet count in the magazine. But some of the data is Weapon-Type-specific - data that identifies an M16 from an AK47, but not my M16 from your M16. Many instances of Weapon can be of type AK47, and they will all have the same rate of fire which will never change. The Weapon class contains Weapon-specific properties and a pointer to a WeaponType object that contains its Weapon-type-specfic properties.

The WeaponType class would contain the properties of a weapon that don't change between instances of the same kind of weapon. Damage per bullet, rate of fire, and the weapon's image are some examples.

Your game engine would have a class that provides access to a collection of WeaponType objects which is populated from human-readable text files. Every time you create a Weapon you pass it the pointer to the WeaponType that identifies it.

The next chapter shows some relevant code.

Property List Files

Cocoa gives you some methods to make .plist (Property List) files a powerful tool in implementing a data driven design. Using some NSDictionary magic you can populate an instance your own "Type" class, a simple NSObject subclass, in very few lines of code. For example, here's WeaponType.h:

@interface WeaponType : NSObject
@property (nonatomic, retain) NSNumber *bulletDamage;
@property (nonatomic, retain) NSNumber *rateOfFire;
@end
Here's the UziWeaponType.plist file:



Now you just need a constructor that takes a plist filname and returns a populated instance:
-(id)initWithFile:(NSString *)plistFile{
    if (self = [super init]){
        NSString *fullPath = [[NSBundle mainBundle] pathForResource:plistFile
                                                             ofType:nil];
        NSDictionary *dictionary =
        [NSDictionary dictionaryWithContentsOfFile:fullPath];
        [self setValuesForKeysWithDictionary:dictionary];
    }
    return self;
}
From here you might want the plist to contain data on the appearance of a weapon. All you need to add to the plist and WeaponType class is a string property for a png file. Enhance this further by creating a folder that contains WeaponType plist files, have the game engine iterate over its contents and load the files into an NSDictionary where the keys are filenames and the values are your WeaponType objects.

Now all your game designer needs to do to add a pistol class is duplicate the Uzi file, rename it, and change its properties. We used a system just like that for projectiles and combatants in Tanks.

Another noteworthy thing about plist files is that they are automatically converted to a binary format in the build process, so your application has to parse a binary format instead of XML making it much easier on the CPU.

Actors & Game World


We did not use a component based pattern in Tanks, though we probably will for our next project. If you want to become familiar with the pattern this is the article that helped me understand it best.
We did use an Actor system, but it wasn't component based.

Every object that appears in Tanks is a subclass of Actor. Explosions, bullets, fighters (enemies, the player, the player's allies) are all Actors.

The Actor class encapsulates the physical body (from box2d) and the parallel cocos2d node (that is part of the scene graph) that most of the game objects will use. It is contained by the GameWorld class which manages the root node in the cocos2d graph and the parallel box2d world. It is true that many objects in your game will not require a physical body, and those unnecessary objects could have been spared from your obejcts, but the solution (a component system) would add complexity, so this was good enough for us.

GameWorld took care of stuff like iterating over the box2d bodies, adding and removing Actors, invoking a method to inform subclasses of a collision between two actors, and other general-purpose responsibilities.

The TanksGameWorld class inherited from GameWorld and handled behavior that is specific to Tanks. It had all of the lower level details handled by its base class and ended up only working in terms of Actors, never with nodes or bodies. It was very pretty, and a classic candidate for conversion to a scripting language.

Controls



The team couldn't make a decision on the best control scheme. One involved a joystick that moves your crosshair around the screen, and a fire button. The other was much simpler and involved tapping the screen to give the tank the command to fire wherever you tapped. The latter scheme had some variations because firing wasn't instant due to cannon rotation and reloading time - slow cannon rotation vs faster, a queuing system with many crosshairs on the screen vs switching to the latest command given. For me making decisions on gameplay mechanics is the best part of working on games.

Because we were frequently switching between two types of controls, we decided to make it simple to switch between the two. We used a property list file to populate a global configuration class. It looked like this:

Switching between the two was as simple as changing the value of joystickEnabled between YES and NO.

Levels with LevelHelper

We did not want to have to write any tools on our own. It would be a lot of work and our GUI would probably be inferior to a ready made solution. A 3rd party editor obviously wouldn't integrate as nicely as our own single purpose editor but the solution we ended up using was excellent for our needs.

Calling LevelHelper a level editor doesn't do it any justice, you can check out all their features in their website. At first we thought we'd use the freely available, cocos2d out of the box integrated TileD but we wanted to visuall position level decorations and objects without being restricted to a tile system. We used LevelHelper to position everything within a level. Tiles, decorations, event objects, enemy spawns, paths and assign them to actors. It did an excellent job at all of that. We did not use the built in path following and game engine features, we instead loaded their data and parsed it for our needs, and into our own data structures and game engine. The integration was easy and painless. The only point we did anything hackish was reading the waypoints of paths, which are represented by LHBezier Objects. The solution to retrieving the coordinate array from a LHBezier lhBezier was:
[lhBezier valueForKey:@"pathPoints"];
 
The game had a FighterActor class that represented a combatant of either the player's side or an enemy (and even a player). To spawn a Fighter, the game designer would position a sprite that represented the fighter, as simple as drag and drop, and then and mark the sprite as an LHFighter in the LevelHelper editor. When the game loaded the level and reached the Fighter spawn it would look for a FighterType of the corresponding sprite frame name and load it. 

This means that the level designer doesn't even have to manually associate the fighter with a fighter type at any point - the type is implicitly recognized by the game engine based on which image the designer drags into the world in the LevelHelper UI. I think that's awesome.

Scripting With UIWebView 

We wanted to easily define custom behavior for different types of enemies (especially bosses!). This is a textbook example of where scripting should be considered. The idea is that you integrate some sort of an engine that will allow you to call functions in a scripting language (we tried JavaScript), parse the script file and allow it to make calls back into your native language (Objective-C).

Here's what the script for a Soldier Fighter looked like:


The most well discussed advantage of scripting is having a way to make changes in behavior without having to recompile or touch any native source code, but I've found that the best thing it did in our case was the effect on the cleanliness and quality of the code. Having to support high level function calls such as moveTo() or fire() in arbitrary points in the lifetime of actors forced us to come up with a really nice and structured system.

Our implementation relied on the UIWebView class, or more specifically its underlying JavaScript engine, and we used this as a starting point. Unfortunately the UIWebView solution proved to be way too slow. It would cause a very noticeable freeze of about a whole second running 3 line scripts in the moment of Spawning 4 enemies. At this point the project was cancelled for entirely unrelated reasons, so we didn't get to invest too much time in finding a solution with this or another engine.

 It isn't clear whether Safari's Nitro JS engine is enabled for UIWebView (it seems not), if not, it could have helped, possibly. Having access to the underlying JS specific classes (which are available on Cocoa but not Cocoa-touch) would have been nice too. Getting UIWebView to even work properly had us doing different hacks such as removing and re-adding the view onto the view hierarchy before making script calls, so you shouldn't rule out on this blog post alone.

Tuesday, November 20, 2012

Objective-C Swizzling - Quick & Dirty Way of Adding Sounds to CCMenuItem

If you need to add sounds to your GUI or gameplay buttons and you're using CCMenuItem to do all the touch handling for you, than creating a class that contains or inherits from CCMenuItem that adds your own functionality is what you probably have in mind. In this post I present an alternative way of doing that, using a technique called Swizzling, which I explain.

Sometimes the quick and dirty approach, for you, is the right one. Maybe you're prototyping. Maybe you inherited a large project with CCMenuItems everywhere, including some instances serialized in CCB files which would make them even messier to replace, and you have a couple of hours to make small UX improvements such as adding a click sound to to get a more responsive UI.
Maybe in your eyes the quick and dirty approach isn't even that bad.

Each class has a "dispatch table" which associates selectors with their implementation code. Swizzling methods in Objective-C is a nick name given to the dark art of swapping between the implementations of two functions, or in Obj-C terms, exchanging between the implementations associated with two message selectors - during runtime.

Normally you have selectorA which invokes implementationA, and selectorB which invokes implementationB. Swizzling allows you to make selectorA invoke implementationB, and selectorB invoke implementationA.

The technique is often used to do things that Apple doesn't let us, intentionally or not. I've seen it used to give the built in map UI components a different look, and personally used it for stuff such as getting notified when a certain thing happens that you don't have a delegate or an NSNotification for. Swizzling should normally be your choice when there is no other way to do what you want.

When using Swizzling you should make sure that you test your solution with each update of the API whose methods are being Swizzled - for example cocos2d or the iOS SDK (You should also give it a very good test to begin with).

The reason for this, and why you'd normally want to avoid swizzling, is because it relies on private methods or classes - implementation details of the APIs you are using. You should be working with interfaces and not implementation details. API programmers rarely modify their interfaces. Changing the interface means forcing users to adapt the code that consumes the API. The concept of deprecating code (as opposed to just deleting code) exists to allow API programmers modify interfaces without breaking existing code that works with them. The same obligations just don't exist for implementation details, which can change as radically as the writers see fit.
Swizzling methods in cocos2d is safer than in UIKit because of two reasons.
First, no one is ever forcing you to update cocos2d (or most 3rd party libraries) - if an update is causing problems with your Swizzling solution, you can keep using the non problematic version until you adjust the new one. With UIKit your application is running against whatever version is installed on the user's device, so your application is better be ready by the time each iOS update is out.
The second reason is that cocos2d is open-source. When relying on implementation details, being able to see the source code can very helpful.

Adding Click Sounds to CCMenuItems

CCMenuItem has a private method named 'activate' which we are going to intercept. We'll then play our click sound every time it's being called.

  • You can apply this to an existing project, or if you just want to see this in action create a new project from the cocos2d template, and put a couple of CCMenuItems in a CCMenu on HelloWorldLayer.
  • Download HGSwizzler. It's a super simple Swizzling implementation taken from here wrapped in an Objective-C class method. Add the two code files and the included 'click.wav' into your project. The click sound is taken from here.
  • Create a new category on CCMenuItem, and add the following function to it:

  • Go to your UIApplicationDelegate class (typically AppDelegate.m) and import both HGSwizzler.h and the new CCMenuItem category you created
  • Add the following line to applicationDidFinishLaunching:
 
 
You've added a new method to CCMenuItem and exchanged the implementations of the 'activate' and 'activateSwizzle' methods. That means that when you do [myMenuItem activate], 'activate' will not be called and 'activateSwizzle' will be called instead. Calling 'activateSwizzle' will call the original implementation of 'activate', this is why the call to [self activateSwizzle] at the end of the function doesn't create an infinite loop resulting in a stack overflow. It is the equivalent of calling [super activate] if we'd subclass instead of swizzling.

That's it.  If you've found a problem in the code, typos the post, inaccuracies in the information, or just want a clarification feel absolutely free to leave a comment or mail me.

Sunday, November 4, 2012

What's This About

I kept this entry as a draft until I had something with "real" content to post. So here's the introduction post.

  

 Summary / preemptive TLDR

 

The content in this blog will be mostly about software development related stuff - information is share-worthy about working with the environments I use at the time, which at the foreseeable future means Objective-C, cocos2d, UIKit, Cocoa-Touch.

 I'll try to also post useful information that I feel I can share on other environments, languages, and programming in general.
Here and there I may stray off-topic and make a post about something that I feel like expressing my opinion about. My piece of the internet after all.


  About Me

My name is Zaky. I was born in Narva, Estonia, currently living in Ashkelon, Israel. Been living in Israel for almost my whole life - ever since my family got here when I was less than a year old.
I'm a programmer, and this blog will be mainly about programming (maybe even game programming) related stuff.


 


Like many others in the field, my interest in programming is something that I had since a young age. In my case it started when my father, who's only relation to programming was when he studied programming using punch cards in his university days, brought me a Quick Basic book. I went through that book within about a week, writing small command line applications, before getting the next one in the series, which taught more advanced stuff like graphics. My first triumph as a programmer was when I managed to write the classic Guess The Number game on my own. I remember that feeling well.

For the last 3 years I've been professionally developing and participating in the design process of many different mobile applications, most of them being for iOS, and with a small venture into Android land. I've been also doing server-side work working with the .NET framework and the C# language, writing CRUD web services, crawlers, management interfaces, etc. These days I work at a company called HumanGNA, which makes iPhones games, and aiming to branch out to other platform as well.

You can see some of the stuff I've worked on in my homepage.


  What I'm Trying to Achieve With This

 

Blogging about problems I encounter at work and the ways that I solve them is something that I've been wanting to do for a while. Other programmers who took the time to describe in detail the way they solved problems have helped me at work in a level that I can't possibly describe (but I imagine that most developers understand from their own experience), so it would be appropriate that I at least try and give something back to the community.
While I certainly have the will of helping others and returning the favor, the reasons I'm making this blog are mostly selfish. From my experience, communicating about your knowledge with others by doing things such as helping out colleagues and participating on Stack Overflow helps you understand it better. Blogging should also be a healthy practice of communicating about work related problems and challenges, a skill which is critical for this field of work. If some of the most respected bloggers that I follow urge everyone, with even a minimal amount of experience, to start a blog than there's probably something in what they are saying.
This is my first attempt of anything like this. I'll try my best to submit worthy content with a level of persistence, and if there will be anyone reading, even better.

Saturday, November 3, 2012

An overview of Spritesheets and a streamlined approach for Marmalade with TexturePacker



This post is made of two parts, I originally just wanted to share a small class that should Marmalade developers with an annoying task that game developers face frequently, but to add some meat to the post I decided to first explain spritesheets in a way that will hopefully help non game developers or programmers who are new to game development understand why they should go through the (manageable) mess of maintaining spritesheets - as opposed to using individual images as it's done in other applications.

The class itself is super small and simple. It parses TextureFile metadata files that were created with JSON-ARRAY data format and allows to extract the sprite rectangles in a hash table like manner using the frame names. To get the parser just scroll to the bottom. I wrote it while doing some heavy maintenance on an iOS game that was built with Marmalade. It had numbers representing Sprite frames all over the code. Suspecting there may be others using the same painful approach made the class share-worthy in my eyes.



Spritesheets

 

A Spritesheet (also knows as a Texture Atlas) is a big image file that includes all of your game's graphical assets in it, including all the frames of your animations. Depending on the size of your game, you may find yourself using more than one of them.
Rather than having all your characters, buttons and such sitting in different files, you stick them all into one big spritesheet, and use that in your game.

In order to draw individual images, you will have objects that represents portions (locations and sizes, or rectangles) of the Spritesheet and their location on the screen, knows as Sprites, and draw them on the screen.


 

 














There are two main reasons why you would want to use spritesheets. One is the advantages (or the requirement) of using power-of-two sized textures, and the other is minimizing the overall amount of textures to minimize the amount of state changes in the game's rendering code.

 

Power of Two 

 

When working with graphics APIs - DirectX, OpenGL - or game engines that abstract them, there's a  chance that you'll into the requirement that each dimension of the textures (images) that you load into memory are a POT (power-of-two, such as 32x32, 256x256, 1024x512, etc). If the engine you're working with has this rule and you break it, you'll probably either get an exception thrown or the problematic dimension will be scaled up to the nearest POT, wasting memory.

Even now that modern hardware no longer has this restriction, I've seen reports of XNA applications that crashed 5 year old PCs, which seems to be about the average age of a PC today. POT sized textures are required for mip-mapping techniques, and allow the rendering pipeline are able to take advantage of various optimizations.

Many texture compression formats such as PVRTC require that the texture is a square with POT dimensions.

On iOS, non POT textures are supported on iPhone 3GS, 3rd gen iPod touch and newer devices.

On Android, you should query OpenGL ES to test whether it supports the NPOT textures extension.

Draw Calls

 

The more elements you draw on the screen per frame, the harder it is going to be for the GPU to keep working at an acceptable frame-rate. The renderer is going to go over every element that needs to be drawn on screen, "adjust" itself accordingly in preparation to drawing, and then render it. OpenGL was built as a state machine (thought it's more object-oriented in modern versions), and each one of those "adjustments" is called a "state change".
One of the costliest kind of state changes that the renderer does when it draws your game is when it changes the textures that it uses. For this reason, it would be beneficial to reduce the number of times the renderer has to change the active texture by using less textures, which is achieved by using spritesheets. Instead of having 50 small textures - one for each image, you put them all in one big texture.


The Pains of Creating and Managing Spritesheets


 
Creating a spritesheet (without tools that ease the process) means taking multiple images and putting them all manually in a big new image.
Your art guys will often give you new assets to add into the game, or to put in place of existing ones. You will have to manage versions of the Spritesheets for different resolutions, for retina on iOS or different Android devices. You may want to have a couple of pixels of padding between sprites and from the borders to avoid having visual artifacts, which means that due to having pixels occupied by a non scalable element (1 pixel of padding) you may end up having the same spritesheet with different resolutions and different layouts. In that case having the origin of a sprite in the standard-definition spritesheet doesn't mean that you can multiply it by two in order to get the sprite's origin in a high-definition spritesheet.

If you use POT textures, having just one pixel too many to fit into the current size of your spritesheet means having to either resize the atlas to the nearest power of two (doubling the memory space it occupies) or to create another spritesheet, which will be more messy and result in slower rendering due to additional state changes. Even if you didn't have the extra burden of manually moving images around using an image editor, having to minimize the wasted transparent pixels between the sprites in your spritesheet puts you in front of a Knapsack problem every time you make any asset changes.

When you get to the part of your program where you draw a Sprite to the screen, you'll need to have the exact origin and size of the rectangle that represents it's area location in the texture. Changing art assets in the spritesheet will make those coordinates change frequently, and remember that you are most probably managing different resolutions of them (at least in the world of mobile).


TexturePacker & Marmalade



In order to do all this and stay sane, you need a streamlined process of modifying your spritesheets. TexturePacker by Code'n'Web seems to be the most popular tool for the task these days. I won't go into detail about it's many features, but the basic idea is that you throw in all your image assets, it packs them all together into a spritesheet, and at a click of a button you get a texture file containing your spritesheet and a metadata file containing information about the locations of sprites in the atlas.

Loading the texture file is a responsibility of the rendering engine being used, but not all of them know how to read TexturePacker data files - Marmalade is an example of an engine that doesn't provide such a parser. To easily load frame data into Marmalade:

  • Create a TexturePacker spritesheet and export it with JSON-ARRAY as the Data Format
  • Create an instance of SpritesheetReader passing the path to the data file (you have to pass the path to the file of the specific resolution, for example Retina or standard definition for iOS)
  • Pass the names of original files to GetTextureRect when passing UV rects to the renderer.