Mobile performance tips

Hello,

I am trying to make RTS/TD game for mobile platforms and I would be glad, if you could share some performance optimization tips with me.

I made simple scene with A* navigation plugin. I used blender plane (4000 tris) as terrain. Than I spawn simple rigged and animated humanoid characters (800 tris), that move towards their goal and every bit of time check for near enemies. Shaders are all mobile difuse. no shadows, no point/spot lights.

When there is 50 or more of such moving characters on the screen, the FPS drops on my Galaxy S3 (25-30 FPS), which is fairly fast device. I can not find the bottle neck. When I use animated characters without AI script, the game runs well. When I use cubes instead of characters with AI, the game also runs well. But together it is quite slow.

Is there something, I could do to improve the performance even, when there is 50 or more characters in the scene? Is it possible to batch them some way? I am afraid, that when I add more details to the scene, slower mobile devices won’t handle it.

Pseudo AI script is here:

private void makeDecision() {
		//nothing to do, find tower or base to attack
		if(currentState == STATE.IDLE) {
			move();
			findTarget();
		}
		if(currentState == STATE.MOVING_TO_TOWER) {
			move();
		}
			move();
			StartCoroutine(findTower());
		}
		if(currentState == STATE.ATTACKING_TOWER) {
			if(!base.target) {
				currentState = STATE.IDLE;
				return;
			}

			RotateTowards (base.target.parent.position - transform.position);
			StartCoroutine(attack());
		}
		if(currentState == STATE.MOVING_TO_FRIEND) {
			if(!base.target) {
				currentState = STATE.IDLE;
				return;
			}

			if(base.target && Vector3.Distance(transform.position, base.target.position) <= transform.GetComponent<CapsuleCollider>().radius/2 + base.target.GetComponent<CapsuleCollider>().radius/2) {
				currentState = STATE.ATTACKING_FRIEND;
			} else {
				move();
				if(Time.time - lastRepathTime > 0.3F) {
					doRepath();
					lastRepathTime = Time.time;
				}
			}
		}
		if(currentState == STATE.ATTACKING_FRIEND) {
			if(!base.target) {
				currentState = STATE.IDLE;
				return;
			}
			RotateTowards (base.target.position - transform.position);
			if(base.target && Vector3.Distance(transform.position, base.target.position) <= transform.GetComponent<CapsuleCollider>().radius/2 + base.target.GetComponent<CapsuleCollider>().radius/2) {
				currentState = STATE.ATTACKING_FRIEND;
			}
			StartCoroutine("attack");
			if(base.target && Vector3.Distance(transform.position, base.target.position) > transform.GetComponent<CapsuleCollider>().radius/2 + base.target.GetComponent<CapsuleCollider>().radius/2) {
				currentState = STATE.IDLE;
			} 
		}
	}

Screenshot of the scene is also included (it’s from editor, so do not mind the FPS value).

Take a look at this: Blogs | Game Developer

I learnt some new things, I hope you do aswell.

We made the experience, that not the tris are what limits you, but the draw calls. We optimised our character meshes so that they consist of only one mesh (1 drawcall per mesh and material) and so we got the draw calls down from 100 per character to 4 and where suddenly able to display 180+ of them.

Use the “Stats” button in the “Game” window and take a look at the draw calls and try to figure out the draw call limit for your device.

I estimated them by spawning one enemy after another until i noticed a significant fps drop. when you spawn the same amount of enemies in the editor you get an approximate draw call limit.

You have 44’000 poly with 50xAI, it’s normal to have some bad performance.
1/Limit the number of enemies, 50 it’s too much
2/Reduce again the Poly if possible.
3/Detect the distance between you and the enemies, and show/hide the enemies

4/Reduce the AI speed loop by 10 for example
5/Limit the number of AI at the same time, if your enemies are a object in a table, you can add a property int AIEnabled=0; and check if your enemy has a AIEnabled or not.

//Add a property to your enemy object
int AIEnabled=0;

//Declare counter as public variable
int counter = 0;
int slowBy=10;

//In your AI loop
counter++;
if(counter==slowBy){
	For each enemies>0{
		if(enemy.AIEnabled==0 && enemy.live>0){
			//Calculate AI
		}else{
			enemy.AIEnabled--;
		}
	}
	counter=0;
}