OnCollisionEnter vs OnTriggerEnter for performance

I am looking at a bullet script and trying to find the most efficient way of detecting bullet damage. I see two options:

1. Have an OnTriggerEnter script
attached to all damageable items
(enemies, crates, barrels, etc.)
checking if the entered object is
tagged as a bullet, apply damage and
destroy bullet.
2. Have a single
OnCollisionEnter check in the bullet
script itself.

I know OnTriggerEnter is more efficient than OnCollisionEnter, but is anyone willing to take a guess on which of the above approaches is the more optimized route?

That’s weird: are the damageable items triggers? Or is the bullet a trigger? OnCollision and OnTrigger events usually are mutually exclusive: if the bullet is a trigger, OnCollision events will never occur; if it’s a rigidbody with a regular collider, OnCollision events may occur when it hits a collider, not a trigger.

Anyway, fast bullets don’t generate collisions/trigger events reliably because they may be before a collider in one physics cycle and after it in the next. A good and efficient solution is to calculate the bullet trajectory as a sequence of line segments: calculate the bullet position each frame and do a Physics.Linecast between it and the previous position in order to know whether anything was hit. This also makes it easy to apply gravity to the bullet, since you’re calculating the trajectory. You don’t need a real bullet, just a coroutine that does the simulation like this:

``````var bulletSpeed: float = 100;
var force: float = 20;
var damage: float = 10;
var gravity: float = 9.8;
var range: float = 1000;

function Shoot(pos: Vector3, dir: Vector3): IEnumerator {
var vel: Vector3 = bulletSpeed * dir.normalized; // calculate velocity vector
var dist: float = 0; // initialize distance travelled
while (dist < range){
yield; // let Unity free till next frame
vel.y -= gravity * Time.deltaTime; // apply gravity
var newPos: Vector3 = pos + vel * Time.deltaTime; // calculate current position
var hit: RaycastHit;
if (Physics.Linecast(pos, newPos, hit)){ // if something hit...
if (hit.rigidbody){ // apply impact force if it's a rigidbody
}
// call ApplyDamage(damage) in the hit object:
return; // shot ended because bullet hit something
}
dist += Vector3.Distance(pos, newPos); // update distance
pos = newPos; // update position
}
// shot ended because it's out of range
}
``````

Supposing that you shoot from the weapon position and in the weapon forward direction, this function may be called like this (weapon script):

``````StartCoroutine(Shoot(transform.position, transform.forward));
``````

or simply:

``````Shoot(transform.position, transform.forward);
``````

If you really want a bullet model, simply update the model position in the last line of Shoot, and remember to destroy or deactivate the model when the bullet hit something or when it goes out of range.