Jump to content

Mobile performance - tips && tricks


valueerror
 Share

Recommended Posts

Because a new thread on this topic pops up every 2 to 3 days in this forum I would like to fill this thread (this first post to be precise) with tips and tricks to maximize mobile performance or things you should probably avoid if targeting mobile devices.

 

I totally rely on your support because my own knowledge on this topic is quite limited.

 

giving explanations(why a tip actually works), pointing out errors in this post, and new tips to fill this post would be very appreciated. (i don't want to spread false "knowledge" )

 

thx in advance !

 

:)

 

P2:

  • polygon shapes will be more expensive than simple circles - especially huge polygons (keep them simple)
  • enabling p2 impactEvents is expensive - use onBeginContact instead
  • having a bunchload of revolute constraints seems to be expensive
  •  

 

 

Arcade:

  • don't call  game.physics.arcade.collide   20 times in the update loop.. try to do the same thing with 5 calls ;-)
  •  

 

 

Both (general programming) :

  • reuse sprites whenever possible - create multiple / kill and revive them (e.g. bullets)
  • be careful with the resolution of your game 640x480 will run faster than 1024x768
  • keep physics simple 
  • instead of "game.time.now" use "game.time.time" or one of the physicsElapsed values, as "now" can often contain high precision timer values (depending on the browser)
  • arcade is faster than p2
  • rendering normal text is expensive, using bitmap-fonts seems to be better but is still somehow heavy on mobile 
  • using tilemaps with more than 2 layers is going to be slow (depending on your device) - try the new tilemap plugin
  • huge tilemaps will be slow
  • when using webGL use a sprite atlas that contains all your sprites instead of many different image files.
  • make use of the particles system - but not to much ^^ (it may be better to use the particlesystem than to create all particles "by hand" but spawning particles will cause a frame drop on slow devices)
  • try to keep the update loop simple - do not call a function 60 times a second if not definitely needed
  • make sure the garbage collector can free some memory - use var  ^^
  • make sure the garbage collector doesn't have too much to do - don't create new objects all the time (functions are treated in the same way)  and finding the balance between to much and to little is the trick
  • don't use the native webview (especially on older android versions) - use a wrapper (like cocoonjs) or use intel crosswalk (which builds on chromium)
  • intel  crosswalk seems to run much better with webgl enabled
  • cocoonjs seems to run much better in canvas mode
  • do not use splice. If you have only one element to cut off an array, use this function, which is multiple times faster that the build in one, and aside it low GC (the built in is the opposite!): 1-item-splice
  • using a lot of tweens in parallel can cause lags
  • using Prototype simply slows down things. It's faster to use precached functions.
  • do not use classes, no new, no prototype, no this, track length by yourself, use custom splice or avoid it completely by using double linked lists
  • tweens that start on creation of a state will be choppy.. use game.time.events.add(1, fadeIn); to delay the tween (it seems that game.time.events will not start before everything is loaded)
  •  
Link to comment
Share on other sites

Well, there are a lot of things you should take care for when programming. To get the highest FPS you should especially know how to handle animations and sprites. The second big point is writing your code in a way the browsers can convert it to native code easyly. Third, garbage collection, is hardest to handle since this mostly interferes with performance and you have to find a good way to combine both. 

 

But it all leads to one thing: profile, research, optimize, start again. A good example is splice. If you have only one element to cut, use this function, which is multiple times faster that the build in one, and aside it low GC (the built in is the opposite!): 1-item-splice

Link to comment
Share on other sites

Well, there are a lot of things you should take care for when programming. To get the highest FPS you should especially know how to handle animations and sprites. The second big point is writing your code in a way the browsers can convert it to native code easyly. Third, garbage collection, is hardest to handle since this mostly interferes with performance and you have to find a good way to combine both. 

 

But it all leads to one thing: profile, research, optimize, start again. A good example is splice. If you have only one element to cut, use this function, which is multiple times faster that the build in one, and aside it low GC (the built in is the opposite!): 1-item-splice

 

well that's the point. if you don't know how to optimize and what you just can't do it..  

 

could you give some examples on "how to handle sprites/animations" or "what is browserfriendly code" (or provide some useful links to explanations) ?

Link to comment
Share on other sites

Well, it's mostly in my head due to lot's of experience and it's also mainly focused on mobile. It's mainly build on such things as how you write your code, like this hint: don't use prototype

It's also important to know that a lot of tutorials out there are simply outdated or wrong. For example in one tutorial on HTML5Rocks it is recommended to use an object pool to lower GC (which is correct). However, in the next step implementations or shown, which are dead wrong! Never ever use an array with pop() and push() to pool your objects, GC will punish you for this for sure ;-)

 

But it is also important to know that a lot of things are only important to know if you build a game / engine completely by your own and target 60fps on mobile / want to get the performance advantage. For most games this massive optimizing is not needed (like Mahjong, smaller games etc.). But beginning with Samsung S3 (Chrome) & iPad 2 you are able to boost your games, even arcade ones, to 60fps without a wrapper and by using plain 2D canvas in HTML5.

 

Maybe I should write a tutorial...

Link to comment
Share on other sites

I will do so for sure, but don't know when. Some hints can be found in the link below.

GC means garbage collection. It means the browser tries to find out which memory isn't used anymore and cleans it up. This can be a heavy job to do.

Depending prototyping, try to avoid using it. It simply slows things.

Precached function mean you do not declare your function in an object or a class, but rather outside and just link them in the object or class. This is also a nice performance boost if used correctly.

However, you should always try to find the parts that take most of your time in your engine. And optimize only that. Optimizing function being only called once or don't eat up much CPU time are not worth the effort.

Link to comment
Share on other sites

I'm developing mostly in CocoonJS for iOS.
There it themes that the particle system slows everything down - extremely.

 

Particle System: Slow
iPad Air / iPad Mini, same result: If you use an particle system effect you get lost a lot of FPS.

As more complicated the graphics or amount of particle are the slower the game runs.

 

Bitmaps: Very Slow

Bitmaps. We are now avoiding the use of any kind of bitmaps. Because indifferent for which kind you use it, it slows everything down.
Backgrounds, Bitmap font, gradients... only one bitmap causes a few fps..

 

WebGL: System crashes
we also running cocoonJS in Canvas-Mode. With WebGL we had a lot of crashes and rarely total system crashes of iOS 7 & 8.

with Black Screen and no reaction of the device for about 5 - 10 Minutes.

 

Tweenings: lagging

One problem that we were not able to solve is that if you use a few tweenings parallel: 

All devices which are not at the hardware level of the iPad Air are lagging for a few fps.

Hope that helps.

 

 

 

 

Well, it's mostly in my head due to lot's of experience and it's also mainly focused on mobile. It's mainly build on such things as how you write your code, like this hint: don't use prototype

 

That's interesting and one thing we haven't approached yet. It would be very nice if you give some more informations about that.

Link to comment
Share on other sites

I don't know how CocoonJS handles bitmaps, but nowadays bitmaps do not slow down browsers so much, if used properly. I for example use 3 fullscreen-parallax planes about 130 vector polygons and roughly 120 additional bitmap objects. All move in 60fps on iPad 2.

 

Prototype simply slows down things. It's 4x faster to use precached functions. Avoiding classes alltogether increase speed even more. I for example do not use classes, no new, no prototype, no this, track length by myself, custom splice or avoid it completely by using double linked lists etc.

 

So setting up on an engine means always you should know where the strengths and weaks are.

Link to comment
Share on other sites

ad. particle emitters:   if i trigger a bunch of particles to explode on contact with a specific object it slows down the game dramatically on mobile BUT only the first time..    my 55-60 fps drop to 30...  the second time everything is smooth..  (maybe 2-5 fps lost)

 

it seems that i would need to preload them somehow to get rid of this problem..   any ideas?    

Link to comment
Share on other sites

I don't know who Sam is, but Littera still generates bitmap fonts. Using anything else (except hardcoded bitmaptext) in a game based environment on mobile is a decision which should be reversed. Because when ever you change a value of a textfield you start a DOM reflow, which forces the browser to repaint / rerender. This leads to such strange things, that the first FPS-tracker module I added (build one by myself after) ate about 10fps on a Samsung S3 Mini, which is crazy for an FPS tracker... ;)

Link to comment
Share on other sites

That may not by bound by your engine, but simply by browser optimization. The browser determines your hot functions and optimizes those. At best all your code is optimized to native code. You could force this also by starting a small particle effect in a non visible are. That may also help and let the browser determine what you want to do.

Link to comment
Share on other sites

Only for those who use CocoonJS.

You can simply use an .ttf font into the ./font folder and preload it via <style> @fontface ....</style> in your index.html.

Since then you can use this font in game.

I embed my fonts always like this and there are no FPS changes.

So for those who use cocoonJS, this would be a good alternative to other implementations.

 

the Particle System depends on the amount,
let's say I use 3 particle effects which are all creating 20 1px * 1px sprites a second. that drops my fps dramatically.
Even the phaser examples of particle effect do - and after a few seconds the fps got slower and slower.
()

Link to comment
Share on other sites

@valueerror

LOL, sorry, missed the name, sorry ;-)

 

@sam

If you include TTF fonts in CocoonJS then they are handled as TTF fonts. So you slow your game down with them, especially on Android. Have you tried disabling them (if you used them)? I could only recommend to not use TTF fonts, only bitmap font, if you target fast games.

Link to comment
Share on other sites

Thanks for the explanation :)

 

However, I am still having hard time understanding the "prototyping vs precached functions". Here is an example of my code:

BallObject = function(game, x, y) {  Phaser.Sprite.call(this, game, x, y, 'basketball');  this.game.physics.p2.enable(this);  game.add.existing(this);       this.body.setCircle(31);  this.body.mass = 10;  this.body.damping = 0.0;  this.body.data.gravityScale = 1;  this.inputEnabled = true;  this.events.onInputDown.add(function(){      game.ball = this;      game.touchdown = true;   }, this);  this.events.onInputUp.add(function(){      game.touchdown = false;      this.launch(this.getLaunchForceX(),this.getLaunchForceY());      game.firstBall = false;  }, this);};BallObject.prototype = Object.create(Phaser.Sprite.prototype);BallObject.prototype.constructor = BallObject;BallObject.prototype.launch = function(Xvelocity,Yvelocity){      this.body.velocity.x = Xvelocity;      this.body.velocity.y = Yvelocity;};BallObject.prototype.getLaunchForceX = function(){      return -(game.input.x - this.x) * 5;};BallObject.prototype.getLaunchForceY = function(){      return -(game.input.y - this.y) * 5;};

The code is just for throwing basketballs. How should I to change the code to gain better performance (precached functions)?

Link to comment
Share on other sites

@valueerror

LOL, sorry, missed the name, sorry ;-)

 

@sam

If you include TTF fonts in CocoonJS then they are handled as TTF fonts. So you slow your game down with them, especially on Android. Have you tried disabling them (if you used them)? I could only recommend to not use TTF fonts, only bitmap font, if you target fast games.

Thanks for the reply ;)

If have used Bitmap fonts (only developing for iOS), but it was damn slow. Then changed to TTF and it went fast. 

Maybe I have made something wrong?

But I get much more performance with the ttf solution.  (only relating to iOS)

Link to comment
Share on other sites

  • 2 weeks later...

Thanks for the explanation :)

 

However, I am still having hard time understanding the "prototyping vs precached functions". Here is an example of my code:

BallObject = function(game, x, y) {  Phaser.Sprite.call(this, game, x, y, 'basketball');  this.game.physics.p2.enable(this);  game.add.existing(this);       this.body.setCircle(31);  this.body.mass = 10;  this.body.damping = 0.0;  this.body.data.gravityScale = 1;  this.inputEnabled = true;  this.events.onInputDown.add(function(){      game.ball = this;      game.touchdown = true;   }, this);  this.events.onInputUp.add(function(){      game.touchdown = false;      this.launch(this.getLaunchForceX(),this.getLaunchForceY());      game.firstBall = false;  }, this);};BallObject.prototype = Object.create(Phaser.Sprite.prototype);BallObject.prototype.constructor = BallObject;BallObject.prototype.launch = function(Xvelocity,Yvelocity){      this.body.velocity.x = Xvelocity;      this.body.velocity.y = Yvelocity;};BallObject.prototype.getLaunchForceX = function(){      return -(game.input.x - this.x) * 5;};BallObject.prototype.getLaunchForceY = function(){      return -(game.input.y - this.y) * 5;};

The code is just for throwing basketballs. How should I to change the code to gain better performance (precached functions)?

 

@defic. My code also looks like that and I am interested how to go with the pre-cached functions.

 

@SolarJS: Perhaps you can show an example, based on the code above?

 

Thanks :)

Link to comment
Share on other sites

Sure, here's how it's done above:

classABC = function () {}classABC.prototype.myMethod1 = function ()     {    console.log('myMethod');    }  classABC.prototype.myMethod2 = function ()     {    console.log('myMethod2');    }

Now change this to:
 

var myMethod1F = function ()     {    console.log('myMethod1');    };var myMethod2F = function ()     {    console.log('myMethod2');    };classABC = function ()     {    return         {        myMethod1: myMethod1F,        myMethod2: myMethod2F        }  }

You might also consider to leave classes at all, if you don't have many balls to handle or do other fancy stuff with it. Know your tools ;)

Link to comment
Share on other sites

one simple (general) javascript programming question that came to my mind because of the post above:

 

is there a difference between :

 var myMethod1F = function ()  { }

and

function myMethod1F() { }

or is it just different notation for the exact same thing ? does this affect memory management in some way?

Link to comment
Share on other sites

Sure, here's how it's done above:

classABC = function () {}classABC.prototype.myMethod1 = function ()     {    console.log('myMethod');    }  classABC.prototype.myMethod2 = function ()     {    console.log('myMethod2');    }

Now change this to:

 

var myMethod1F = function ()     {    console.log('myMethod1');    };var myMethod2F = function ()     {    console.log('myMethod2');    };classABC = function ()     {    return         {        myMethod1: myMethod1F,        myMethod2: myMethod2F        }  }

You might also consider to leave classes at all, if you don't have many balls to handle or do other fancy stuff with it. Know your tools ;)

 

Thank you very much SolarJS. Your sample was really helpful, but what about inheritance? In the first case we can inherit Phaser.Sprite like this:

BallObject = function(game, x, y) {     Phaser.Sprite.call(this, game, x, y, 'basketball');};BallObject.prototype = Object.create(Phaser.Sprite.prototype);BallObject.prototype.constructor = BallObject;

What would be the analog in the second method?

 

Thank you once again.

Link to comment
Share on other sites

Thank you very much SolarJS. Your sample was really helpful, but what about inheritance? In the first case we can inherit Phaser.Sprite like this:

BallObject = function(game, x, y) {     Phaser.Sprite.call(this, game, x, y, 'basketball');};BallObject.prototype = Object.create(Phaser.Sprite.prototype);BallObject.prototype.constructor = BallObject;

What would be the analog in the second method?

 

Thank you once again.

 

I am curious about this too. I am also using this method to extend Phaser.Sprite.

What alternatives can we use here?

 

Thanks for the tips so far.

Link to comment
Share on other sites

 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...