Tips for mobile games that make heavy use out of triggers/colliders

I am developing a strategy game that has many units that must be able to attack each other. Each unit has a rigidbody (kinematic) and sphere collider (trigger) attached. This sphere collider allows them to “see” enemies, which will make them chase said enemy. The units work in such a fashion due to the mechanics of the game.

At any one time the amount of units will grow to a few hundred (let’s say 400-500 max). This slows down mobile devices a lot, so I decided to use layers so that units don’t “see” (or do collisions) against their friends. Also, I disable the trigger colliders when units are occupied with a certain task. I realize that several hundred units may seem strange to some. Keep in mind that each unit is essentially expendable and quite simple. Still, I have to give of them some sort of behavior.

Anyway, it is still difficult to optimize my game for iOS despite my efforts. The game becomes even slower when units actually move with the triggers enabled. I was wondering if anyone had ideas to share in regards to optimizing physics to physics-heavy games, which would go beyond ignoring collisions using layers? i.e. are the sizes of the game objects important as well? This would relate to whatever acceleration structure that Unity uses for physics. Thanks…

Hmmmm, mobile game…a few hundred units…i wonder why your device slows down.

Don’t post anything if you’re going to be sarcastic. I’m looking for ideas here.

As I said in my post, I know that this type of idea would be strange. But that’s type of game we are going for; there are a swarm of many units that you could control as an army. Each unit is quite simple, and essentially expendable. Like an army of ants. While mobile devices are becoming more powerful, putting a sphere collider around each unit so that it could “see” enemies is no the best idea. Slowdowns typically occur for non-static objects, probably because some acceleration structure is involved.

1 Like

Not really sure exactly how your game works, but it sounds like once a bunch of units get near each other, every unit’s sphere would be colliding with every other one all the time. Crazy strain on the system.

Is your game 2D or 3D?

Either way, I’d say to get rid of the sphere colliders completely. In your unit update, just check by distance to other objects, and only check periodically, like once per second. Then change their state to attacking or lost target, etc.

Basically, do it all in scripting, forget the collision system and triggers. Manage your own object states, and then optimise it. For instance, if ont unit sees another and attacks, the other unit must also be able to see the first and want to attack.

So loop through one unit finding another unit close enough, then change both states of both units to attacking each other.

Since you are using triggers and the collision spheres I bet you don’t keep track of units in an array. Don’t use GameObject.Find to do this, actually don’t use it ever.

All setup and management of units and unit states should be pure scripting, you might want one master object with a script that can own and iterate through all the units on the screen.

Basically, to recap. Forget about sphere colliders, do it yourself, keep references to every object, do your own distance checks and communicate directly between units. In the end, write it like games have always been written before the ‘simplicity’ of the Unity 3D editor came around, your game is more of that style.

P.S. I’m sure you know it, but also never use transform, gameobject, rigidbody, variables directly. Always cache them in the object if you are going to need to reference it more than once, those are actually not variables, but slow functions. At Start() do something like _transform = transform and then use _transform from then on. Basically there are these helpers in Unity, but they are always slower than doing it the correct way yourself.

1 Like

The game has 3D objects but it’s effectively 2D (objects move on a plane only).

Thank you for the suggestions. I thought about the square magnitude test before, however I went with the physics solution because I thought that it would be optimized more (and I thought physx would scale better). Right now the units do the change state thing as you suggested, but it uses physics.

But I think back now, and it appears that checking distsqr between each object would be best. If I had all the units in one huge array, and did a check distance square thing once a frame (or periodically as you indicated), then that would be fastest I think. It’s kind of like the Unity boids project they made for the performance optimization presentation a few years back.

In regards to Find functions, I fortunately only use those in Awake/Start as they are quite expensive. I did know about the transform, gameobject, rigidbody, etc thing but it helps to check that I didn’t do anything stupid.

Glad to help. I hope that these improvements help. It sucks to get so far into a design and then hit a dead end.

Yeah, even though I constantly try to cache the component variables too, things always slip through. Once in a while I will just step through all my code looking for stuff like that. It seems I can be lazy when trying something new, and then I don’t remember to fix it. :slight_smile:

Before completely converting everything over the just a plain distance check, you might want to write some form of test to make sure it will really be faster. Like you said, you thought the physics engine would be optimized better, and it is probably very optimized. It would suck to find out your new solution ends up slower.

But I think the best improvement with your own check would be the fact you don’t have to check each frame. If you find every frame is too slow, every 3rd frame would triple the speed. You might want to stagger the objects though, a third on one frame, a third on the next, etc. Or however you split it up, in thirds or tenths, etc.

but physics probably calculates a bunch of other stuff you dont need.

if your units act together and are organized in groups of fleets you can also use a distance test for all of them in one group so some kind of tree structure where you first check group against group and only when they are close together you check the single units. and you can have several test distances like see (move towards), in shooting range (shoot) in melee range (fight) etc. so several conditions can all be checked in one loop iteration. thats quite faster than having 3 colliders per object in physics system.

you should also consider checking if a unit is visible. make a sphere in the center of the fov and check this against each unit. one that is inside the sphere is updated more frequently than one outside.

a problem which might occur is the visibility test as you cant use raycasts without collider/rigidbody. so with distance test your units will see through obstacles but this can explained with recon/satellites etc in game design. you cant have everything ;).

So what is each unit represented by? Is it a 3D object? If so, how detailed is the model - in terms of poly count? If you have 400-500 units on screen, each represented by even a 500 poly object, then that might be your problem in itself. Nothing to do with the physics side of things.

?

I thought that physics would be fast enough, but it isn’t unfortunately. So I’m going to try this distance test as an alternative. I know it seems strange, but the physics calculations seem to slow things down for me. Especially when objects move.

I guess one could make an acceleration structure to support the distance tests as you indicated. Keep in mind though, all the units need to do is “see” enemies and chase them. There is no shooting. On another note, my comment about the comparison with the Unity boids demo was inaccurate.

Each unit right now is represented by a box, which is eight vertices but since Unity splits things up into triangles, each boxi s a 24 verts. I’m only using a box as a placeholder; they will likely be triangular in the future as each unit is really simple. So I don’t think it has anything to do with rendering as I encourage unity to batch stuff and I keep vertex counts low in general (I know this based on the profiler in Unity and in xcode).

For one scene, the number of vertices goes up to 10k near the end of the game, which is the end of world for my 2nd gen ipod touch but is no problem for 3gs/4g/4gs. Once I have a simpler model for each unit the vertex count will be even lower.

I did notice an improvement in performance if all triggers are turned off.

I unfortunately don’t have any additional suggestions but I did want to say thanks to TheClarkster for this

I did not know this!

1 Like

Do you use OnTriggerStay ? If so, I would advice to use OnTriggerEnter and OnTriggerExit instead. First make an empty list of the type “GameObject”. If OnTriggerEnter detects something, add that object to the list. If OnTriggerExit detects something, remove that object from the list. Loop through the list every frame, if an object’s HP drops below zero, remove that object from the list. Also you should start with fewer units, then gradually increases the number until device slows down noticeably.

The game does start with few units and the number grows gradually.

I do use OnTriggerEnter/Exit. In my case I use a dictionary to keep track of objects entering/exiting the trigger (which means I add/remove objects from said dictionary, respectively). The first object that had entered the trigger (or added to the dictionary) will be the candidate for the chase. If that object exits the trigger, the unit will then see if there are any other candidates in the dictionary.

I guess I could use a List<>, but I think it’s quite fast to remove objects from a dictionary as I use the object’s name for the key. I appreciate the comment though. When I have time I will let you guys know what happens when I implement the distance thing…just almost finished with this one bug.

Have you done any profiling to see where the performance is taking a hit?

That would be my first suggestion… otherwise without seeing any code its hard to say exactly whats causing it.

The profiling I’ve done is the “printing to the console” option in xcode where it prints vert count, frame time, et cetera. I don’t have access to the professional version of unity. Which profiler are you referring to?

By the way, the slowdowns typically occur BEFORE I hit somewhere around 400 units (I’ll have check when…). The only objects I have right now are a handful of bases (which are represented by unity’s cubes as placeholders) and units which are each represented as a cube. Since unity renders each cube using 24 verts, then 400 units be around 9600 vertices/second. That’s within the graphical capabilities of most iOS devices. I’m not using fancy lighting or anything as the one light in my scene is not important. I should probably check my lightmapping settings too…

yeah im referring to unity profiling.

Have you used your pro trial?

I would consider doing this just to be sure the slow down is occurring where expected, otherwise you may have to do some clever coding to minimise the problem. I cant suggest anything, because without seeing your code its hard to know.

I didn’t even know that there was a Pro Trial available. We just paid for the iOS license. I’ll look into it.

We’re trying to keep this an internal project for now. If I were to share code, it would be bits and pieces…I’ll look into doing that.

First use distance not physics for sight as suggested. There are a lot of heuristics you can use to save computational time. For example if one unit sees something it can tell other units that they see it too. You don’t have to run the “sight” algortihm on every unit.

i.e. (PSUEDO CODE)

class Unit() {

list friendlyUnits;

enum State {SEARCHING, TARGET_FOUND, FIGHTING};

Search() {
   if (state == State.SEARCHING ) {
      LookForTarget();
      yield return new WaitForSeconds(TIME_BETWEEN_SCANS);
  }
}

LookForTarget() {
  target = FindTarget()
  if (target != null) {
    foreach (unit in friendlyList) {
     friendly.ReportTarget()
   }
  }
}

ReportTarget(target) {
  if (state == State.SEARCHING  targetWithinSightRange(target)) {
    state = State.TARGET_FOUND;
    myTarget = target;
  }
}

}

You can extend:
Periodically update the friendlyList (no need to report to people far away).
Ensure not too many in friendlyList (you don’t want all units to target same enemy).
Use the friednly list of enemies to quickly find groups of targets, etc.

I guess the key is create the behaviour you want, don’t try to simulate the “reality” of the situation.

How about the idea of unit group. One group contains many units, which share a single sensor. Just treat the whole group as a single unit.

I didn’t read the whole thread, but this is what I was going to suggest. Instead of having hundreds of units making independent decisions, choose a few “generals” and have the others do whatever the generals are doing. Sort of like flocking behavior.

But as others mentioned, before you start trying to optimize, you need to make sure you know exactly what is slowing you down. If you start messing with the behavior and your bottleneck is poly count or draw calls, then you are wasting your time.

So you store a copy of whatever your transform is at startup. How is that useful past the first update? What am I missing here?

EDIT: Nevermind. Found the answer here: http://unity3d.com/support/documentation/ScriptReference/index.Performance_Optimization.html