Tips & Tricks learned while developing ShaqDown

Hi Corona devs! I was the lead developer of ShaqDown (Currently featured on the Corona Labs homepage). You can check it out at http://shaqdown.com

ShaqDown is our second release and the third Corona game we’ve worked on, so we’ve had a lot of opportunity to learn how to build great Corona games.

Overall Corona has been an incredible platform for us. I never imagined we could build games this good with a small team and a short timeframe. The cross platform support has been particularly excellent. Our code is essentially identical on both platforms and performance is superb.

Here’s a list of some of the things we’ve learned that will hopefully be useful for you guys:

Essential tools

  1. SpriteHelper - By far the most valuable tool we’ve used has been SpriteHelper. Much of ShaqDown just would not have been possible to build in any reasonable amount of time without it.

SpriteHelper lets you put all your sprites into sprite sheets, crop any whitespace, as well as instantaneously generate and modify animations. Then it saves out up to 3 versions for different resolution devices. We probably have over 500 sprite frames, and around 100 animations, so there’s no way we could have managed without it.

  1. GlitchGames open source libraries - Unfortunately we found out about these towards the end of our development, so we only ended up using GGRating. But next time around we might end up using every single one. The code quality is excellent and they have a library for just about everything you might want to do.

  2. loq_profiler - This is a little hidden gem that I was able to dig up. It’s a beautiful plugin that displays a graph of frame rate and memory usage over time in a transparent box at the top of your game. It’s part of the sprite loq api (http://www.loqheart.com/spriteloq/apidocs/files/index-lua.html), but you don’t need to have spriteloq or use any other parts of it. Just download that file and copy out loq_profiler and loq_util, require them in your app, and you’re done. Very useful for tracking down memory leaks and frame rate performance issues.

  3. tnt transitions library. A library that lets you pause, resume, and change the speed of transitions and timers. Seriously amazing. It’s available here: http://developer.coronalabs.com/code/pausable-timers-and-transitions-speed-adjustment

Make sure to follow the directions and call cleanTimersAndTransitions on a timer, or it will leak tons of memory.

  1. PushWoosh.com. Hosted push notification service. We had to implement some special code to get this working right (Around generating unique device ids and saving them). But its been working great. Corona cloud has push notification support too, so that’s probably even better

Little known but important tips

  1. Texture memory is not the only story. Audio is loaded into memory uncompressed too!. A 2 minute track will be around 20 megabytes. Roughly 170kilobytes memory usage per second of audio loaded. I don’t know for sure how streaming audio works, but I suspect that at some point the entire streamed audio file is loaded into memory.

  2. Memory limits seem to be as follows for each device type. Remember this includes uncompressed audio and textures, and is a very rough estimate:

iPad1: 90MB (But resolution same as iPad2!!)
iPad2: 160MB
iPad3: 280MB
3GS: 70MB
iPod Touch 3rd gen: 90MB (But resolution same as iPhone4!!)
iPhone4: 160MB
iPhone4S: 160MB
iPhone5: ?
iPod Touch 4th Gen: ?
Old Android Device (Droid Incredible): 70MB.
Newer Android Device: (Samsung Galaxy S3): 160MB+

  1. If you use textures that have a width or height larger than 1024px, you must use the largeHeap setting or your app will randomly crash on some android devices (The Kindle Fire HD seems to be a common one).

  2. The only cross-platform compatible audio formats are Wav and mp3. Wav is uncompressed so it will make your app download huge, and mp3 has licensing restrictions that could put you at legal risk unless you pay for a license to use it.

Fortunately, there’s an easy fix. Compress audio to ogg for android and to m4a for iOS, then load the right file depending on which device you’re on. There’s an amazing free tool that will quickly convert to these for you called Max: http://sbooth.org/Max/

  1. Transitions appear to be faster performance-wise than repeatedly modifying X and Y attributes on each frame. We use them like crazy! The tnt library (mentioned above) has been a huge help.

  2. Pop up dialogs with 3 buttons will fail to show a caption on landscape apps in iOS. The Glitch Games GGRating library is affected by this. Be careful!

  3. The Android emulator is a great tool to test apps. I posted a forum thread a few weeks ago with directions on how to get it to work with Corona.

  4. If you use GameCenter on a landscape app, make sure to use the CoronaUseIOS6LandscapeOnlyWorkaround workaround, or your app will crash on iOS6.

  5. Texture memory used by images is determined by rounding up the width and height to the next power of two, then taking the larger of the two values, squaring it, then multiplying it by 4, and then you have number of bytes used. So an image that is 1000x600 will get rounded up to 1024, square that and you get 1048576, multiply by 4 to get 4194304 bytes (Exactly 4 megabytes).

Or to simplify matters,
width or height rounds up to 512px: 1mb memory used
width or height rounds up to 1024px: 4mb memory used
width or height rounds up to 2048px: 16mb memory used
width or height rounds up to 4096px: 48mb memory used

You can see why using sprite sheets is helpful. If you have an image that is 600x600, it gets rounded up to 1024x1024. If you made it 1024 in the first place and used the extra space to store other sprites, then it’s basically a chance to put in more images with zero more memory usage. Use SpriteHelper to help you do this and you’ll save tons of texture memory!

  1. If you want to push the boundaries with Corona, be extremely careful about managing memory leaks. It’s extremely easy to leak memory in Lua. Also, there’s either a Corona bug or SpriteHelper bug that causes entire spritesheets to not be garbage collected if animated sprites are loaded in a require()'d file and that file is not unrequire()'d.

  2. Some Android devices fail to download apps on the Google Play market if that app is greater than 30MB in size. The Samsung Captivate seems to be one affected device. A lot of apps seem to ignore this fact, but if you can get under 30MB, then you should. (ShaqDown is 29MB on Android – barely made it!)

  3. Unicode strings are not supported by Lua string functions. But there is a good library with functions that supports them https://github.com/alexander-yakushev/awesompd/blob/master/utf8.lua (Important if you’re trying to localize)

  4. Dispose of unused audio tracks and sounds, but don’t dispose of them twice or your app will completely crash. I wish Corona protected against this automatically, but until it does, be careful how you handle audio.

  5. Straying from the default content size of 320x480 can cause a lot of headaches. There was a good Corona blog post about how to have device-specific resolution, and that method is probably ideal. But unless you know what you’re doing, I wouldn’t change this value. For our first app we used 640x960 and it caused a lot of headaches when trying to use tools like SpriteHelper.

  6. Use 60FPS instead of 30. Especially if you’re building an action game. If you’re careful then you should be able to get good performance at 60FPS for most games and it makes the game look much smoother.

  7. The FPS that you set your game to affects the physics engine. So changing it later can cause headaches.

  8. Objects nested in groups, where the parent group is moved no longer correctly collide with each other and the hybrid overlay becomes inaccurate.

This is a huge problem if you want to have grouped sprites with separate collision areas. For example – A ship that flies around where each wing is a different sprite with its own collision behavior.

The best solution for this problem appears to be to generate an invisible sprite that detects collisions placed in the same group as your other physics objects and then align it visually on top of the nested sprite by using localToContent() within a timer.

If you get to the last level of ShaqDown, you’ll see this taken to the extreme. I build a join system for the boss, and then each body part of the boss has an invisible copy that handles collision that is placed on top of the visible body part and then correctly rotated and positioned on a frequently run timer. Hopefully you won’t need to do anything quite so crazy :slight_smile:

  1. Dither your PNGs if your app build is getting too big. Dithering PNGs results in relatively minor quality loss, but huge space savings (around 70%).

Corona bugs to watch out for

In general Corona is amazingly stable and the quality of the Daily Builds in particular is top notch. Still, there are bugs in all software, and some of the following can really sting.

I know I should report all these using the bug tracker, but I just haven’t had the time to put together good test cases. Some of these issues may also be already known by the Corona, but perhaps not by some developers.

  1. Storyboard is really, really buggy. Or at least it was buggy and the latest patch may have fixed it (But I’m pretty sure it’s still buggy).

Here’s some of the weird things I’ve seen.

Paramaters dont get passed in some cases.
reloadScene() sometimes just doesn’t work.
exitScene is sometimes not called.
enterScene is sometimes not called the second time a scene is loaded if the scene is unloaded a certain way
Scenes are sometimes not removed from memory completely.

Admittedly, some or all of these might be from incorrect implementation on my side, but the documentation is quite poor too.

I ended up putting in some insane workarounds that may have just made the problem worse, but they seem to be holding up for now. Things like calling exitScene before calling loadScene, or setting self.view to nil at the end of my exitScene handler.

At some point I want to go through and figure out exactly what’s broken in each case (or what I’m doing wrong), but I just haven’t had the time. Maybe another ambitious Corona dev can submit some good bug reports (Or put together a good tutorial on advanced usage of Storyboard)

  1. As I mentioned above, if you load spritesheets bigger than 1024x1024 you must use largeHeap on android or you will get random crashes (especially on the Kindle Fire). I also noticed this issue in the Android emulator and on the Sony Tablet S.

  2. Sound sometimes lags on Android. A fix that was mentioned was to use media.playEventSound on Android, but that may also have its own problems. In either case, test carefully to make sure audio works as expected and the volume control works the way you want it to. There doesn’t appear to be an ideal solution for audio issues on Android yet, but it’s worth spending a few minutes to figure out the best solution for your app.

In our cases we ended up using the normal audio API. Reviews on Android have been great, so I guess it worked out OK for us.

  1. GameCenter can be really screwy. The app is not notified if the user cancels the game center log in popup, but then if the app tries to launch the game center popup again then nothing happens (And the app is not notified). Suspending the app and resuming it seems to cause the GameCenter pop up to be visible again? Weird!

Fortunately this is more of a problem during testing than anything else, but it can be quite frustrating.

  1. Siri and Phone Calls can cause audio to stop playing on iOS. This seems to affect a lot of iOS apps, so it’s not necessarily a Corona issue. But this topic comes up from time to time on the forum, so I think it’s worth noting.

I hope at least some of this is helpful. Thanks for reading, and I hope you all enjoy ShaqDown!

I’ll be watching the comments and I’m happy to answer any questions if you have them :slight_smile:
[import]uid: 135827 topic_id: 34739 reply_id: 334739[/import]

Regarding #7, I wish that I could find a computer than can run the Android Emulator reliably. I’ve tried using it in my “real job,” but it would just crash. I asked our web QA team there if they had it working and they could only get it working reliably on one machine. I believe we just stopped testing because it wasn’t worth it to us.

When I was forced to install Corona on my Windows machine at home to start doing Android builds, surprise… it crashed there as well.

I’d like to think that it is a good tool. But good tools really don’t crash that often. I mean seriously, is it Windows? :slight_smile:

A friend of mine at Google keeps telling me that I should come have lunch and he’ll introduce me to people on the Android team. But I think he just wants me to start trashing them. :slight_smile: [import]uid: 17827 topic_id: 34739 reply_id: 138035[/import]

@thegdog

The problem is that the emulator just crashes for you? That’s a weird one.

I do have a problem on my Mac where if I set the emulator to use Hardware GPU Emulation (required to run Corona apps) then the screen doesn’t redraw if I use a version of Android >= 2.3.3. I can force it to redraw by dragging the emulator window outside the bounds of my screen and then dragging it back. Very annoying, but at least it kind of works. Emulating Android >= 4.0 seems to work ok at least.

The other important thing I had to figure out was that in order to update the Android developer tools, I had to run them as sudo. [import]uid: 135827 topic_id: 34739 reply_id: 138037[/import]

It was Windows that I was running it on, both at the “real job” and trying to use the Android SDK at home. Maybe it is a Windows thing, but I have chatted with other friends who have developed (not using Corona) and the Android emulator regularly gets slammed.

I was able to get it to working at the “real job” with one version or device or whatever they call it. But all others I tried to load would just crash. I did a Google search and came up with a number of responses but no quick fixes.

Considering how little independent developers seem to make from Android, it didn’t seem worth my time to really focus a lot of effort going further. I test on real hardware and will hope for the best. :slight_smile: [import]uid: 17827 topic_id: 34739 reply_id: 138039[/import]

Fantastic post george18!

Congrats on the game coming out too. Man Shaq Fu, wicked stuff. That brings back some serious 90’s nostalgia for me :wink:

Will grab it for sure

Cheers

J [import]uid: 26289 topic_id: 34739 reply_id: 138052[/import]

Thanks for the tips, george18!

Would you be able to provide some advice / code snippets for how you implemented PushWoosh? I’ve followed the tutorial on their website, but can’t seem to get it working. [import]uid: 12217 topic_id: 34739 reply_id: 138063[/import]

@george18, thanks for taking the time to put all of this together. This is priceless not just for the developers, but also for Corona Labs as well.

I am certain we will study your feedback and address the points you’ve highlighted.
This is a true testament to the great community that Corona has.

Good luck on the game and keep up the great work.

-Mohamed [import]uid: 201995 topic_id: 34739 reply_id: 138070[/import]

@george18 - A fantastic set of tips, thanks for putting it all together! Also thanks for mentioning our libs and I’m glad you liked them, I’m hoping to get an update to GGRating up soon for the landscape issue. Hope you managed to get some use out of the rest of them for your next games :slight_smile: [import]uid: 119420 topic_id: 34739 reply_id: 138072[/import]

TNT sounds interesting; I wonder what it offers beyond the Improved Transition Calls lib (especially concerned about how TNT recommends running cleanup every 2 seconds?!)

Never seen the failed parameter passing problem. Wonder what causes that…what build do you guys use to compile with? [import]uid: 41884 topic_id: 34739 reply_id: 138092[/import]

Great list! Thank you for sharing, and good luck with ShaqDown!

Naomi [import]uid: 67217 topic_id: 34739 reply_id: 138105[/import]

@Cell Game Labs
Thanks!

@SimonBurford

Our code for push notifications has some dependencies that are a bit tricky to replace. For example, we use a custom library to save/retrieve settings from the sqlite database that you’d need to replace with your own code (Or use GGData).

I can send it to you with a description of what you’ll need to change to get it to work if you’d like.

@Glitch Games

Thanks!

@richard9

The main difference is that TNT uses the built in Corona Transition functions and the Improved-Transitions-Lib modifies the object attributes directly on each frame. This seems to result in slower performance from the benchmarks I’ve done. We actually ended up replacing most of our manually coded transitions (modifying ‘x’ and ‘y’ attributes on enterframe) in GoNinja with TNT in an update and it significantly boosted performance on slower android devices.

I can’t say for 100% certainty that it will work for you though. And in most cases any added performance benefit won’t matter because most apps are either slow for other reasons or run perfectly fine already.

Also TNT manages timers as well and Improved-Transitions library does not. Improved-Transitions does have a lot more easing options which is really nice.

@Naomi

Thaks!
[import]uid: 135827 topic_id: 34739 reply_id: 138153[/import]

Thanks for the feedback George, I’ll definitely take a closer look at that library. The cleaner scares me but maybe the performance is worth it! [import]uid: 41884 topic_id: 34739 reply_id: 138156[/import]

@richard9

Oh yeah, I forgot to address that. I’m actually not quite sure why the library is coded in such a way as to require that. It uses an array that holds a list of references to transitions that have ended and the clean up timer just clears out the array. Clearing the array is a really fast operation so it’s no big deal to run it on a frequent timer.

I was worried for a while about just how many transitions we could do at the same time and still get good performance on slow devices. Turns out the limit is very high. We probably do 30+ simultaneous transitions at some points. [import]uid: 135827 topic_id: 34739 reply_id: 138159[/import]

Wait, a lot *more* easing options? Does TNT have any? The docs don’t even mention it apart from a line to say it wasn’t implemented?

EDIT: That is to say, Corona gives no error if you set a non-existant transition; I’m trying a few and don’t see a difference between them. And the docs also say easings restart after pause…starting to sound worse and worse unless you’re using it for just character animation [import]uid: 41884 topic_id: 34739 reply_id: 138335[/import]

Awesome post!

Storyboard is definitely a concern of mine as well. It really needs to be cleaned up, optimized, and bugs worked out. It is too critical to be “flaky”.

I use MP3 myself, it is too standard and easy for me not to use it. I am not really all that concerned about legal issues as everyone uses it and the legal issues are just theoretical. If it was a real concern, the entire Internet would been sued many times over by now since pretty much everyone uses it.

Have to agree, the GG libraries are an amazing resource that was more than generous of Graham. [import]uid: 160288 topic_id: 34739 reply_id: 138355[/import]

@richard9

Yeah, easing does work. It supports the same easings as transition.to. We use very easing very sparingly so fortunately the restart-after-pause thing hasn’t been a problem in our case. [import]uid: 135827 topic_id: 34739 reply_id: 138370[/import]

Alright, maybe it just needs an extreme use case to notice. (I’m assuming you mean it’s just a { transition=easing.toQuad } command) Perhaps the best route is to use tnt for character/world animations and the improved transition library for UI. [import]uid: 41884 topic_id: 34739 reply_id: 138381[/import]

Regarding #7, I wish that I could find a computer than can run the Android Emulator reliably. I’ve tried using it in my “real job,” but it would just crash. I asked our web QA team there if they had it working and they could only get it working reliably on one machine. I believe we just stopped testing because it wasn’t worth it to us.

When I was forced to install Corona on my Windows machine at home to start doing Android builds, surprise… it crashed there as well.

I’d like to think that it is a good tool. But good tools really don’t crash that often. I mean seriously, is it Windows? :slight_smile:

A friend of mine at Google keeps telling me that I should come have lunch and he’ll introduce me to people on the Android team. But I think he just wants me to start trashing them. :slight_smile: [import]uid: 17827 topic_id: 34739 reply_id: 138035[/import]

@thegdog

The problem is that the emulator just crashes for you? That’s a weird one.

I do have a problem on my Mac where if I set the emulator to use Hardware GPU Emulation (required to run Corona apps) then the screen doesn’t redraw if I use a version of Android >= 2.3.3. I can force it to redraw by dragging the emulator window outside the bounds of my screen and then dragging it back. Very annoying, but at least it kind of works. Emulating Android >= 4.0 seems to work ok at least.

The other important thing I had to figure out was that in order to update the Android developer tools, I had to run them as sudo. [import]uid: 135827 topic_id: 34739 reply_id: 138037[/import]

It was Windows that I was running it on, both at the “real job” and trying to use the Android SDK at home. Maybe it is a Windows thing, but I have chatted with other friends who have developed (not using Corona) and the Android emulator regularly gets slammed.

I was able to get it to working at the “real job” with one version or device or whatever they call it. But all others I tried to load would just crash. I did a Google search and came up with a number of responses but no quick fixes.

Considering how little independent developers seem to make from Android, it didn’t seem worth my time to really focus a lot of effort going further. I test on real hardware and will hope for the best. :slight_smile: [import]uid: 17827 topic_id: 34739 reply_id: 138039[/import]