2014-02-20

The following blog post, unless otherwise noted, was written by a member of Gamasutra’s community.

The thoughts and opinions expressed are those of the writer and not Gamasutra or its parent company.



We are TeaPOT Games, and we just released our award winning game – The Domingos on Google Play. It is a puzzle gam…

“Wait a minute, I’ve never heard of your stupid game before. Which award did u win? Best Game from the Great Nation of Grand Fenwick? “

Well, no, the web version of the game won the Excellence award in a Game Design Competition, held in India by Square Enix. Granted, it’s no Oscar, but the phrase “award winning game” sounds cool as long as you don’t say which award it is. So we are exploiting it

Anyway, in this post I will be covering few optimization tips for Unity 3D we implemented in the Android port of Domingos.

This article is aimed at (and hopefully will help) the Intermediate/beginner users of Unity 3D. If you are an Advanced/Expert user, you might as well close the tab, or better yet, read the post keeping an eye out for anything we missed.

It’s recommended that you play the game (The Domingos, link: http://goo.gl/aJUf85) to understand how certain aspects of the game work. If you don’t have an android device, have a look at the trailer on the google play page to at least understand what the gameplay constitutes.

1. Using InvokeRepeating instead of Update.

Unity’s mono functions like Update, LateUpdate, FixedUpdate, are not Functions per se. They are SendMessage calls from the unity engine to the respective game objects. They are by no means performance hampering, but you can earn some performance points by using InovkeRepeating instead.

How it is implemented: As you can see, the game has lots of dominos (some levels have 200+) toppling left, right and centre. Each domino has a script attached to it, which checks if the domino has fallen to the ground or not. If yes, it will make a light sound, and change a public Boolean flag to true- indicating that the domino has toppled. Depending on the type of domino, this flag will help determine the outcome of the level- level complete, or level failed.


Must… Topple… Dominos

Clearly, this has to be checked in each frame(or at least at regular intervals). So, if this code is placed in the Update function, it would mean that the unity engine has to do SendMessage on 200 game objects- this can’t be good.

Instead, we did this

function Start ()

{

//calling the invoke repeating on dominostatecheck function instead of putting all that code in

//the Update

InvokeRepeating(“DominoStateCheck”,0.02, 0.02);        

}

function DominoStateCheck ()

{

//checking if the domino has toppled if it hasn’t already

//if the y coordinate is less than 0.25, the domino is ruled as toppled. It’s a crude way, but it works.

if(dominoToppled==falsetransform.position.y0.25)

{

//playing the domino topple sound

SoundManager.soundManager.PlayDominoFallSound();

//changing the toppled flag

dominoToppled =true;

}

}

To summarize, if you have an update function that doesn’t use Time.deltaTime in it, you can consider replacing the function with a InvokeRepeating  call, especially if you are bound to have high number of instances of that game object, just like in Domingos.

[Edit: according to this redditor, there is a even better way(albeit, a bit more complex) of doing this. check it out here: http://www.reddit.com/r/Unity3D/comments/1xz4wa/i_wrote_a_blog_post_on_some_of_the_techniques_we/cfg14m1]

2. Toggling isKinematic field on/off on rigid bodies.

Like I said, some levels of the game have more than 200+ dominos(play level 61). This means 200 small domino sized boxes that the game engine has to take care of, as they topple and slide on each other.

This will make an average android device hot enough to cook an omelette on its back. You might not like this – especially if you hate omelettes

Here’s the fix: After say, 0.5 seconds, the dominos will come to a rest, either flat on the ground, or slumped against another domino. But the game engine doesn’t know that the dominos have come to a ‘practical’ stop. It relentlessly applies gravitational force on a slumping domino, and calculating its collision parameters against the dominos it is in contact with – all for no visible result. I experienced a frame rate of 4fps on Samsung p3100 when I let the dominos topple through, prior to optimization.

So, after that said 0.5s, you check if the dominos have come to a stop. If they have, turn the isKinematic flag to true. This will cut the dominos off force and collision calculations

Code with comments:

function Start ()

{

InvokeRepeating(“DominoStateCheck”,0.02, 0.02);

//saving the position of the domino

prevPosition =   gameObjectTransform.position;

}

function DominoStateCheck ()

{

if(dominoToppled==false transform.position.y {

SoundManager.soundManager.PlayDominoFallSound();

dominoToppled =true;

//save the time when the domino was toppled

dominoToppleStartTime = Time.time;

}

//if the domino is not moving, and if some time had passed since the domino was toppled, we

//disable it

if(dominoToppled

Vector3.SqrMagnitude(transform.position- prevPosition)0.01

Time.time dominoToppleStartTime +0.5)

{

//this will make the rigidbody immobile for forces and collisions

rigidbody.isKinematic=true;

}

//saving the position for the next cycle

prevPosition =   gameObjectTransform.position;

}

Doing this will freeze the dominos, but we can activate them( toggling the isKinematic back to false) when we need them to act up again.

For example, in Domingos, there is certain kind of domino which explodes when toppled (play level 13). We call it – the Dyanimo, because we love squeezing two words into one. BTW, Domingo is Domino + amigo. Award winning games don’t name themselves, you know

So, when a Dyanimo topples, and explodes, it naturally has to push everything near it away, including the toppled dominos.

Code with comments:

//cast a physics.overlapsphere at the position of the dynamite domino in the

//Layer(http://goo.gl/bFei6H) of dominos to get the colliders of dominos nearby

disabledDominos = Physics.OverlapSphere (dyanimoPosition, radius, dominoLayer);

//cycle through the dominos and set isKinematic to false on them

for (i=0; i disabledDominos.Length;i++)

{

disabledDominos[i].gameObject.rigidbody.isKinematic=false;

}

I believe one can use this technique in games with physics-centric mechanics and high object count.

I am going to write another post explaining in detail how the domino sequence drawing mechanic was implemented in the game.  It involves considerable amount of vector math. One look at that code will turn newbies into Math Doctors, or at least Math Nurses -perhaps neither.

Try our “award winning game” over here: 
https://play.google.com/store/apps/details?id=com.teapotgames.thedomingos

You can try the bread winner of our studio, our debut game- Total Parking, over here:
https://play.google.com/store/apps/details?id=com.teapotgames.totalparking

Follow TeaPOT Games

Facebook: http://goo.gl/EpIULi

Twitter: http://goo.gl/VV5T4p

Google+: http://goo.gl/HXs7am

Article source: http://www.gamasutra.com/blogs/SatishChandra/20140215/210811/Unity_Android_Performance_Optimization_in_Domingos__part_1.php

Show more