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

I was talking by experience from other platforms. I don’t know how to check the fps, it is actually a question of mine too.

You can not “cap” (attempt to stabilize) the fps to 50, only 30 and 60 (due to hardware sync reasons). Generally speaking, the game experience is better with an achieved stable 30 fps than with varying 45-60 fps.

So, go for 60 fps only if you can keep the performance stable there. With an asset-rich physics game, I don’t believe you can have acceptable experience of 60 fps in iPhone3G with Corona today. Nor with Unity, only with cocos2d. The whole story changes for not so heavy types of games…

[import]uid: 7356 topic_id: 2726 reply_id: 8441[/import]

You can use Instruments (part of Xcode) to attach to a process on the iPhone and read the fps.

Use the graphics openGL template apple provides. [import]uid: 8741 topic_id: 2726 reply_id: 8444[/import]

Or collect the delta time from each frame and count your own FPS.

Magenda, there is no general rule to it. You said it yourself, you talked from experience… but from other platforms. My experience is that you don’t see a difference. And my advice is to try and see if it fits your needs. That’s all. [import]uid: 5712 topic_id: 2726 reply_id: 8459[/import]

@MikeHart, I think we agree!

@ORBZ, Didn’t know that you can still use Apple Profiling Tools with an app not written in Xcode. I’ll try this… [import]uid: 7356 topic_id: 2726 reply_id: 8472[/import]

I am interested in performing some profiling of my game. You mentioned being able to use “Apple Profiling Tools”. I am not familiar with these. Anyone care to share a run down of how to use such a tool to profile a Corona game? And a link to where to get these profiling tools.

Any alternative method will be of interest too.

Thanks

Paul [import]uid: 7863 topic_id: 2726 reply_id: 8473[/import]

Profiling tools are embedded in Xcode
See an example for memory leaks http://mobileorchard.com/find-iphone-memory-leaks-a-leaks-tool-tutorial/

I don’t know whether you can use them with Corona though. I’ll try it when get back home. [import]uid: 7356 topic_id: 2726 reply_id: 8475[/import]

Thanks Magenda - look forward to hearing if you could use them with Corona. [import]uid: 7863 topic_id: 2726 reply_id: 8477[/import]

Good news: read post #4 [import]uid: 7356 topic_id: 2726 reply_id: 8489[/import]

Stumbled upon this post as I’m in the process of optimizing my app. This is in response to “how to get the fps count”. While the ways outlined in this post are exactly the ways to do it, here’s an implementation of a graphical output to the screen of the fps count and memory usage:

PerformanceOutput = {};  
PerformanceOutput.mt = {};  
PerformanceOutput.mt.\_\_index = PerformanceOutput;  
local prevTime = 0;  
local maxSavedFps = 30;  
  
local function createLayout(self)  
 local group = display.newGroup();  
  
 self.memory = display.newText("0/10",20,0, Helvetica, 15);  
 self.framerate = display.newText("0", 30, self.memory.height, "Helvetica", 20);  
 local background = display.newRect(-50,0, 175, 50);  
  
 self.memory:setTextColor(255,255,255);  
 self.framerate:setTextColor(255,255,255);  
 background:setFillColor(0,0,0);  
  
 group:insert(background);  
 group:insert(self.memory);  
 group:insert(self.framerate);  
  
  
 return group;  
end  
  
local function minElement(table)  
 local min = 10000;  
 for i = 1, #table do  
 if(table[i] \< min) then min = table[i]; end  
 end  
 return min;  
end  
local function getLabelUpdater(self)  
 local lastFps = {};  
 local lastFpsCounter = 1;  
 return function(event)  
 local curTime = system.getTimer();  
 local dt = curTime - prevTime;  
 prevTime = curTime;  
  
 local fps = math.floor(1000/dt);  
  
 lastFps[lastFpsCounter] = fps;  
 lastFpsCounter = lastFpsCounter + 1;  
 if(lastFpsCounter \> maxSavedFps) then lastFpsCounter = 1; end  
 local minLastFps = minElement(lastFps);   
  
 self.framerate.text = "FPS: "..fps.."(min: "..minLastFps..")";  
  
 self.memory.text = "Mem: "..(system.getInfo("textureMemoryUsed")/1000000).." mb";  
 end  
end  
local instance = nil;  
-- Singleton  
function PerformanceOutput.new()  
 if(instance ~= nil) then return instance; end  
 local self = {};  
 setmetatable(self, PerformanceOutput.mt);  
  
 self.group = createLayout(self);  
  
 Runtime:addEventListener("enterFrame", getLabelUpdater(self));  
  
 instance = self;  
 return self;  
end  

Usage (for example, in main.lua):

local performance = PerformanceOutput.new();  
performance.group.x, performance.group.y = display.contentWidth/2, 0;  

It outputs the current fps and the lowest fps among the last maxSavedFps (the variable defined at the top of the class) frames in brackets.
Edit : also, the way the code is written now, only a single instance of this class can be created without inducing bogus results (due to me using a local variable for things like the time of the previous frame, instead of a variable stored in the object). However, I doubt there’s really a use case in using two of these, so I don’t see a practical reason to change this :slight_smile: (I use this style with singletons a lot, because it kind of resembles private variables of a singleton class; table members are all public-like, so I avoid them where possible)
Another edit: changed it to be impossible to create 2 instances by using a local instance variable :slight_smile: [import]uid: 8145 topic_id: 2726 reply_id: 8586[/import]

@Wizem

Brilliant, thanks a lot!

What I did was to save the code in a “fps.lua” adding in the first line:
[lua]module(…, package.seeall)[/lua]

Then in first line of main.lua require it:
[lua]fps = require(“fps”)[/lua]

and in the last lines (bellow any other display calls) of main.lua call the fps counter:

[lua]local performance = fps.PerformanceOutput.new();
performance.group.x, performance.group.y = display.contentWidth/2, 0;[/lua]
Just one comment: Without this counter the actual fps might be some frames higher, since updating the text object adds a draw call.
Wizem, why don’t you add this to the code section, so others can find too! It is something that everyone needs at sometime.

Thanks again! [import]uid: 7356 topic_id: 2726 reply_id: 8602[/import]

Done, added Magenda’s modifications since I know a lot of people prefer modules over improvised namespaces via tables :slight_smile:

http://developer.anscamobile.com/code/output-fps-and-texture-memory-usage-your-app [import]uid: 8145 topic_id: 2726 reply_id: 8605[/import]

@Wizem. This is amazing. Thanks so much! [import]uid: 8192 topic_id: 2726 reply_id: 8612[/import]

Question. Is there any value to put all the graphics in a sprite sheet? Even the background ones? Or is it a waste of time? [import]uid: 8192 topic_id: 2726 reply_id: 9121[/import]

@amigoni, yes. There’s a number of advantages to using a sprite sheet. First, you use overall less texture memory, a highly limited resource on a phone. Second, OpenGL undergoes fewer state changes when submitting frames from one texture, so it’s a performance win overall (although this is more difficult to quantify). Third, the sprite engine is written in C++, where some other approaches are in Lua, so that’s a performance win as well. [import]uid: 54 topic_id: 2726 reply_id: 9176[/import]

How do you unload sprites from memory? It seems that they stay in there even after you remove the sprite object.
Also what is a decent memory usage for iphone 3g ? is 16 MB too much?
[import]uid: 8192 topic_id: 2726 reply_id: 12720[/import]

I have also noticed that there is a significant performance difference the first time I run a scene and game vs. the subsequent times. The subsequent times are much smoother and faster. Does anyone know why this is? [import]uid: 8192 topic_id: 2726 reply_id: 12723[/import]

Are you using OpenFeint? I get similar behavior and OpenFeint is the culprit. Especially if you enter an elevator. The game will slow down for a sec when you lose your connection and then again when you regain it. Annoying, but c’est la vie. [import]uid: 10835 topic_id: 2726 reply_id: 12726[/import]

@Magenda. Great info. Thank you.

@IgnacioIturra. That is another type of slowdown. Every game has that. I noticed as well.

Does anyone know about the unloading of sprite sheets from memory? [import]uid: 8192 topic_id: 2726 reply_id: 12730[/import]

@amigoni

Take a look at SpriteGrabber in code section. I have implemented a remove function for the spritesheets you load. Look at line 40-41 of the example provided (before the module code).

If you want to use only the SDK, take a look at the dispose() function. [import]uid: 7356 topic_id: 2726 reply_id: 12738[/import]

In Unity3d and less in Cocos2d there is a “warming up” slowdown effect for the first 15-20 seconds of a fresh run. I suppose that some textures/sounds are not immediately deleted from iphone memory when closing the app and the game runs better if you open it again after a while (as some resources are already “cached”).

Personally, I don’t see this slowdown effect in Corona. Only when I have the usb cable connected for transferring a new build from the mac. That first run is always not very smooth.

Also, there is some other cause of slowdowns on iphone: when the carrier signal is not very strong you can see periodical slowdowns every 15-20 seconds. This is because the device spends more cpu-cycles while trying to find the best available antenna. The latter effect was a huge nightmare for me while working with Unity, as the engine is very sensitive to cpu changes and the outcome is a visually perceivable stutter (something like pausing the game for 3-4 frames).

In Corona, cpu availability drops are translated to a smoothly slower fps for the next 100+ frames, an effect which is not so perceivable visually :slight_smile:

Actually, this was one of the main reasons I adopted Corona. When I first tried some stress-test code which always was giving stutters in other platforms, I got a stabilized, maybe not screaming but smooth, performance with Corona.

“Yeahhh… no more stutters :open_mouth:
Eurekaaa !!!” [import]uid: 7356 topic_id: 2726 reply_id: 12729[/import]