Optimization - Distance vs Collisions

I’m wondering if anyone can give me a tip on optimizations.

Right now, my enemy objects each contain an empty gameObject with a “wake-up” collider attached to them. If the player enters the wake-up collider than the enemy (enemy is a child of its wake-up gameObject) becomes active.

In the interest of optimization, I’m wondering if it would be less resource intensive to calculate the distance between the player and the enemy, say every 1 second, as apposed to using the OnTriggerEnter function of the collider. My thinking is that Unity will need to process/calculate all interactions that the enemy’s collider may have with other colliders that are not relevant (terrain, other enemies etc) - and every frame. Whereas if I just calculate the distance every 1 second or so then…
1.) Only the calculations for the distance from the enemy to the player will be performed
2.) Only performs the calculation every X amount of time as apposed to every frame

Does anyone know if this can lead to better optimization, or are Unity’s collision detections so efficient that they’d be faster?

Thanks!

The thoughts I have for your type of requirement would be,

a) Have an Update function on every enemy/NPC and calculate the sqrmagnitude on the difference between this position and Player position. If the is less than some value, then activate.

b) Try to create a event or delegate system with a for loop on a empty gameobject on the scene (not on the player). Do the sqrmagnitude, difference on the player and all the NPC (foreach). Trigger the event when the sqrmagnitude is less. Now the reason for using an empty gameobject is because of the usage of a foreach loop. As Player might have a lot of functions running on Update().

c) You could do (b) by invoking a function which would have a foreach statement every ‘n’ seconds. This would reduce a much of load.


But, I think using OnCollisionEnter is better. I do not get the reason where you say it is resource intensive as opposed to calculating every 1 second.

Sorry to post this as an answer but it was too long for a comment.

Karsnen, I’ve had a few minutes to check these out in Profiler now.

chelnok’s suggestion of using the colliders on a distinct layer that only the Player interacts with was difficult to track down in the Profiler. So I’m honestly not sure of the results.

As for the approach of checking the sqrmagnitude distance between the player and the enemies, I’ve managed to get the processing time down fairly low. Right now the most I’ve seen it take is 0.30ms, which I think it acceptable. That’s the total time for calculating the distances to about 100 or so enemies and other items in the environment that I needed control over. In combination with a Yield in the coroutine which only checks one enemy per LateUpdate, I feel like this is fairly streamlined, but could stand corrected. :slight_smile:

Here’s my current sourcecode.

 /* This script is designed for SuperSpaceTrooper.com.  It will enable and disable 
 child objects based upon their distance to the player.  It may be useful 
 where you're trying to save resources if there is a large number of child
 objects.  This script should be placed on the parent object */
 
 private var player : GameObject; 				// Get the player so we can check for distance every X seconds (distanceCheckTime)
 private var distanceCheckTime : int = 1.0; 	// Time between checking distance of player to the bush
 var visibleDistance : int = 100; 				// Distance between player and bush before being visible
 private var tempTime : float = 0;				// Holds the next time to check time
 private var theObject : Array = new Array();	// Cache objects so we don't need to access them directly (Profiler)
 private var theLocation : Array = new Array();	// Cache locations so we don't need to access them directly (Profiler)
 private var theStatus : Array = new Array();	// Cache status so we don't need to access them directly (Profiler)
 private var arrLength : float = 0;				// Holds the array length of theObject
 private var cachedPlayerPosition : Vector3;
 
 function Start () {
      visibleDistance = visibleDistance*visibleDistance;
      player = GameObject.Find("Player/Ship/Ship");
      for (var child : Transform in transform) {
      // Lets us specify which child to enable/disable based on distance.
      child.transform.gameObject.SetActiveRecursively(false);
      theObject.Push(child.gameObject);
      theLocation.Push(child.position);
      theStatus.Push(false);
      }
      arrLength = theObject.length;
 }
 
 function LateUpdate () {
      if(tempTime <= Time.time) {
      // Cache the player's position so we don't have to access it every loop in CheckShowOrDontShow().  Saves CPU (Profiler)
      cachedPlayerPosition = player.transform.position;
      CheckShowOrDontShow();
      
      tempTime = distanceCheckTime + Time.time;
      }
 }
 
 function CheckShowOrDontShow() {
      // Get the distance to all the objects which enable or disable based on distance
      for (i=0;i<arrLength;i++) {
           if (player && theObject) {
                if(theStatus *== false) {*

if((cachedPlayerPosition - theLocation*).sqrMagnitude <= visibleDistance) {*
/* Then we tell it to enable.
Alternatively, we could just enable and disable materials, but I
feel like completely disabling the objects may save resources. */
theObject*.SetActiveRecursively(true);*
theStatus = true;
}
} else {
// We should also disable currently enabled objects if they’re farther than visibleDistance
if((cachedPlayerPosition - theLocation*).sqrMagnitude > visibleDistance) {*
theObject*.SetActiveRecursively(false);*
theStatus = false;
}
}
}
yield; // Delays each enemy distance check by one LateUpdate.
}
}

I would like to add some important information related to this :

Getting distance X times per a specific amount of time should be priories when :

• If you plan on having multiple Triggers zones overlapping each others.
There are many issues with the Tiggers colliders in Unity (even Unity 5). One being that having too many calls from collisions can end up with some triggers being ignored.

• If some Trigger collider might be in contact with multiple none-trigger colliders. This is another issue with Unity. Having a trigger collider from which some none-trigger colliders intersect too much of its “zone” can add a kind of glitchy collision to the trigger itself. Whenever I put a trigger collider and it has around 2/3 or more of its “zone” covered with none-trigger colliders, anything with a Character Controller seems to bounce off from it through not completely (the trigger still works, but well… you can’t move within the zone anymore).

• If you require a trigger that is really big. While “zoning” can be done with triggers, a problem with triggers is that they are still getting their checkup on every OnTriggerEnter(), OnTriggerStay(), OnTriggerExit() even if those aren’t used. It also create an interne list of whatever is within it. Triggers can’t be turned into stand-by unless turned off. You can’t have control over the “refreshing rate” of the checks either. Whenever any collider or Character Controller enter or stay or exit a trigger collider, its functions are called at every frame even if empty. So, a big zone will mostly be called every frame since the chance of it having absolutely no colliders within might never be real.

• If your zoning/collision trigger is either a sphere or especially rectangle prisme or square prisme. As you can controls such “zone” with ease (Make use of a radius or 3 sizes) and do a check on specific target at specific point of time. Even better, you can actually build a list of asset (and update it) from which the “zone” can look at and get whatever it needs to check. In other words, recycling a maybe-already-existing list you might have created for another purpose.

• If your zone is moving. Trigger zone that moves requires a Rigidbody… and rigidbodies, while optimized, still take a lot memory more than a raycast. Triggers that aren’t with a Rididbody but still move is really taking a toll on the memory because every time it move, it’s trigger is getting reconstructed at the new position while, with a rigidbody, the “center” zone of the trigger is based on the rigidbody’s physic system.

Trigger colliders could be useful for :

• You require a really specific and complex form for the trigger zone. Well, if you require a zone that is quite complex and precise, it’s quite a better option than doing a kind of insane amount of raycast from many points with different distance and all. (For example, a laser grid-like trigger zone with a bunch of specific complex sized holes for the player to move in)

• For area with little chances existing collision. For example, the transition zone at the edge of a map could be launched from a Trigger collision. As you can make the trigger zone into the air and leave the open transition zone empty from anything. (Not necessary fully empty, but leaving a “slice” of space empty which will include the trigger zone.

• If you requires to get data from the trigger. It’s surely more simple to get the data from the trigger’s collision than doing it from a series of raycast since triggers (as well as collider) register any points of entry or exit from other collider (the good side of the 3 previously mentioned functions that are automatically called).

Those are the general points about whenever you should check distance or use a Trigger Collider.