Enemy with character controller has inconsistent hit detection

I’ve created an enemy and attached a character controller to it. In the past, it had a simple capsule collider set as a trigger, to be used to detect player bullets. All was fine until I started using character controllers instead so that enemies don’t pass through obstacles. Now that I’ve changed it, the bullets will register seemingly only half of the time, and even then the bullets are not being destroyed as they should. The other half of the time they will just pass through without causing any damage.

This is the code on the enemy detailing the collision detection for player bullets:

function OnTriggerEnter (other : Collider)
    {
    	if (other.gameObject.tag == "Bullet")
    	{
    		var bullet1 : BulletScript = other.GetComponent(BulletScript);
    		health -= bullet1.damage;
    	}
    }

And this is the bullet’s code detailing enemy collision:

var damage : int;

function OnTriggerEnter (other : Collider)
{
	if (other.gameObject.tag == "Environment")
	{
		impact.PlayClipAtPoint(clank, transform.position);
		Destroy(gameObject);
	}
	else if (other.gameObject.tag == "Monster")
	{
		impact.PlayClipAtPoint(hit, transform.position);
		Destroy(gameObject);
	}
}

The bullets have a box collider set as a trigger and a rigid body.

I probably should not be using OnTriggerEnter on the enemy, but nothing else has worked. Not OnCollisionEnter, not OnControllerColliderHit (the game thinks the bullets are Untagged when I do this, even though they’re not). Changing the bullet’s function to OnControllerColliderHit has the same effect as OnTriggerEnter. I’ve tried adding an extra capsule collider on the enemy, but that only causes hits to register twice. So unless I’ve been using these functions incorrectly, I don’t know how to fix this.

Usually bullets are rigidbodies and use OnCollisionEnter to detect when something is hit (bullet script):

var damage : int;
 
function OnCollisionEnter (col : Collision)
{
    if (col.gameObject.tag == "Environment")
    {
       impact.PlayClipAtPoint(clank, transform.position);
       Destroy(gameObject);
    }
    else if (col.gameObject.tag == "Monster")
    {
       impact.PlayClipAtPoint(hit, transform.position);
       Destroy(gameObject);
       // try to get the enemy script EnemyHealth:
       var eScript: EnemyHealth = col.gameObject.GetComponent(EnemyHealth);
       // if found, decrement the enemy health
       if (eScript) eScript.health -= damage;
    }
}

The enemy script don’t even need to know that it was hit - the bullet script itself can do the job like above.

Maybe your problem is being caused by the discrete nature of collision detection: when a projectile moves reasonably fast, it may be before the target in one frame and after it in the next, and no collisions are detected. A simple solution is to elongate the bullet collider a lot, so that it extends way ahead the bullet:

11159-extendedcollider.png

Since the physics default rate is 50 cycles per second, a collider with about 0.5 meter long can travel at up 0.5 * 50 = 25 meters per second without miss any hit - smaller colliders at this speed will depend on the target width in order to not miss the collision.