Game Optimizing Techniques. How to get to 60 FPS consistently!

Opening this topic to discuss and post tips and tricks on how to optimize your game to 60 fps which is ideal.

Let me start with the first.

  1. Try not to move large graphics. Split your small elements and leave the large graphics static if you can.

i.e. platformer with blue sky and stuff moving in the background. Make the sky graphic static and use other layers for the small things moving in the front.

  1. Use the Corona drawing functions( i.e. display.newRect, over loading an image if you can)
    Please keep adding your knowledge.

By the way what are the memory specs for graphics for the various devices?
[import]uid: 8192 topic_id: 2726 reply_id: 302726[/import]

I love this topic! I have been trying to optimize some code for 60 fps on an iPhone 3g, and it is a real hassle.

First and foremost, the large graphic moving thing is #1 on the list to avoid. I realized this myself just a few days ago and have had to scale some things back… that I really did not want to.

If you break up one large object in to several smaller, yet equal number of pixels, does that increase performance in Corona? And if so… why?

For the most part, it looks like Corona on an iPhone 3g has a real problem when there are lots of display objects on the screen.

Here are my tips:

  1. Try and use transition.to to help with some animation. I use my own enterFrame loop and move objects manually, but if you can get objects out of your main enterFrame loop and in to transition.to, Corona seems to be able to handle the extra animation without too much of a performance hit.

  2. Your main enterFrame loop has to be try and keep under a 16ms logic time to keep the game running smooth. That right there is extremely difficult.

  3. Background music does have a performance hit, which is rather sad in my opinion. I have not found a way around the game slowing down by perhaps 3-5 fps while media.playSound() is doing its thing.

One thing I have not had much luck on is touch response time at 60fps. The touch event usually fires 1 - 2 frames later than when I press the screen. I think that is a bug within Corona, thinking it only needs to check every 33ms or so (basically 30fps).

Does the iPhone understand any other images besides .png’s to load images? Or is that a limitation of corona?

Has anyone done any performance testing to see how many small display objects Corona can handle at 60fps on a 3G? I would love to know, but have not tried a test myself. [import]uid: 8541 topic_id: 2726 reply_id: 8119[/import]

Good topic, more details please :slight_smile: [import]uid: 8741 topic_id: 2726 reply_id: 8123[/import]

What is the largest image size supported by iphone and Android? 1024 x 1024 or 2048 x 2048 [import]uid: 8192 topic_id: 2726 reply_id: 8129[/import]

About the large image. I had a ground texture that was 1000 px wide that repeated 4 times. I tried to replace it with many 32 x 32 px instead to see if it was better. Way worse at least using display.newImage. I think it might be different with the sprite sheet. So lesson learned. Moving one big image is better than moving 33 small images. I don’t know where the point of diminishing return is. I think it all depends on texture memory.

I know there is a way to monitor that. I saw it in the API. I will try to pull that out to see if I can post more info.

By the way. With the new spritesheet functions you could put all of your graphics in a giant spritesheet. I think this will have significant advantages on texture memory vs. all separate files.

@sanchan91. Can you explain more your point about the 16 ms? Also interesting thing about the touch event. You should open a bug report for that. I currently have a game that has lots of touching and it might be suffering from that, how did you find out about it?

As far as I know PNG is the only format possible. I think it works quite well. Are you thinking of using other formats? If you are looking to save memory use the spritesheet.

Transition.to is great but without a pause feature it’s impossible to pause. Ansca should be putting a pause feature soon. [import]uid: 8192 topic_id: 2726 reply_id: 8128[/import]

Objects that are not on the screen should made invisible (for the engine). You can do this by setting the alpha value to zero or set isVisible=true.
[import]uid: 5712 topic_id: 2726 reply_id: 8135[/import]

>>2) Your main enterFrame loop has to be try and keep under a 16ms logic time to keep the game running smooth.

The event is called at 16ms or 33 ms (each frame). There is no way you can to have that event called faster. [import]uid: 5712 topic_id: 2726 reply_id: 8136[/import]

@mikeHart Aren’t objects outside of the viewing field automatically discarded by the engine? [import]uid: 8192 topic_id: 2726 reply_id: 8142[/import]

The enterFrame loop should be left as empty as possible. Don’t put anything there unless you have tested every other possible way to implement the same functionality on demand (on event).

Some times you can register a lazy timer to check for some conditions and if true initialize a quicker timer to check things and act accordingly. For example, instead checking for Energy==0% inside the enterFrame (huge loss of cpu cycles), check every two seconds for Energy<=20% and if yes initialize a second check: Energy==0 that runs every 500 mls.

enterFrame is your enemy!
*****
This is the exact reason that I finally hated Unity3D. In Unity, the default way of programming is to place all of your code (except the initial setup on level beginning) inside an “Update” function (an enterFrame) ! You can imagine what happens to unoptimized code! [import]uid: 7356 topic_id: 2726 reply_id: 8143[/import]

Sorry Magenda,

but I dissagree with your theory about enterFrame is an enemy. It all depends what you are doing there. The nice thing about programming is that there are so many ways of doing things. For an example, I think I have not one timer in my code.

Of course, I would not base the whole logic around this event, but things that run at every frame go there in my game. Also I am using transition.to a lot as I think it is one of the engines best feature. But also I have a main event running at every frame.

Cheers
Michael [import]uid: 5712 topic_id: 2726 reply_id: 8146[/import]

@Amigoni: Not from my experience. I didn’t check that with the latest release, but a while it was said my AM that you need to make them invisible to have no effect of rendering. I could confirm this via tests and by the two methods I mentioned before. [import]uid: 5712 topic_id: 2726 reply_id: 8147[/import]

@MikeHart

Let me rephrase it… enterFrame is not an enemy, it’s a friend that when called once for coffee, he will revisit you, uninvited, every day at afternoon! [import]uid: 7356 topic_id: 2726 reply_id: 8158[/import]

and takes all your cookies too!! [import]uid: 8192 topic_id: 2726 reply_id: 8160[/import]

@amigoni What is the largest image size supported by iphone and Android? 1024 x 1024 or 2048 x 2048

It depends on the phone. Older iphones are 1024x1024. iPhone 4 goes up to 2048. On Android it depends on the chipset.

Right now Corona supports up to 1024x1024. We have a case to up this limit, but for compatibility you should stick with 1024. [import]uid: 54 topic_id: 2726 reply_id: 8161[/import]

My comment about 16ms (60fps) and 33ms (30fps) is referring to the code in your enterFrame loop, or really, any code anywhere that is run. If you have some code that eats cpu cycles, are you subtracting from the 16ms you have left to do stuff before the next frame is rendered.

Basically, if you want to maintain 60fps, your code can not execute longer than it takes the next frame to get here. If it does, it causes the frame rate to drop because one of your frames took, say… 70ms instead of 16ms.

Time and print your enter frame loop. Here is an example of what might happen:
16ms --good, still at 60fps
16ms --same
16ms
70ms --Arg, enterFrame took up 4 frames instead! (70/16) so now you have lost 4 frames and the game has choppy animation
16ms – back to 60fps
50ms – enterFrame took up 3 frames!
24ms – took an extra 1 frame!
16ms – back on track

This is, of course, if you use frame based animation. Time based animation still has the same problem though, the animation looks jerky or images jump from location A to B and do not animate smoothly.
I am always open to new ideas. In my case, I need to check for collisions every frame AND move objects manually. I use transition.to to offload images from my enterFrame loop if I can.

How would you implement something that would run at 60fps, have custom animations where you move stuff per frame, check for collisions each frame, and NOT have any or very little code run in enterFrame?

Are custom timers more efficient? Say, timer.performWithDelay(16,doStuff) ?

Why would that be more efficient, the code run in doStuff still has to be faster than 16ms or you lose a frame. [import]uid: 8541 topic_id: 2726 reply_id: 8258[/import]

The question imho is do you really need 60 or is 50 not enough. Even 30 I found sufficient.

One nice things about LUA are coroutines. Nice feature of this language.

Or do simple tricks like in even frames you do task A + B, in off frames you do task C+D. Or other tricks.

For an examples I used pregenerated tables with random numbers as I think it is faster to look up a table than several math.random calls. Or if you need a lot of sin/cos calls each frame, precalcualte them and store the result in tables. These mobile devices have their limits and sometimes you have to cut back the features so it runs smoothly on older devices.

The great thing about Corona is its event system and some automatism features like transition.to. In my game I don’t move anything by setting x/y manually. All done with transition.to with onComplete handlers that are called automatically when the transition is done. [import]uid: 5712 topic_id: 2726 reply_id: 8291[/import]

You can see quite a bit of a difference between 30 and 60. 60 is smooth as butter. [import]uid: 8192 topic_id: 2726 reply_id: 8416[/import]

Sure you see a difference between 30 and 60. But not between 50 and 60. [import]uid: 5712 topic_id: 2726 reply_id: 8423[/import]

Persistent 50 would not be a problem at all, but ranging from 60 to 50 gives awful results! [import]uid: 7356 topic_id: 2726 reply_id: 8434[/import]

@Magenda. How do you keep checking the FPS and is there anything to maybe cap it at 50? [import]uid: 8192 topic_id: 2726 reply_id: 8439[/import]