Myself, I wouldn't use a collider toggled on and off for something you want to detect collisions only on certain frames. I'd use a physics overlap query.
Here's a way you could make a script that acts a bit like a capsule collider, but instead of checking for collisions when things move, it checks when you call CheckHits(), returning you a count of matching hits, and invoking a custom event handler for each one:
using UnityEngine;
using UnityEngine.Events;
public class HitCapsule2D : MonoBehaviour {
[Tooltip(@"x = width (twice the radius),
y = height (end-to-end distance).
Not affected by scale - always measured in worldspace units.")]
public Vector2 size = new Vector2(0.5f, 1);
[Tooltip("Use this to limit the search to only the layers you want to hit.")]
public LayerMask layersToCheck = (LayerMask)(-1);
// (Defaults to hitting everything)
[Tooltip("Handle this event to act on a hit collider.")]
public UnityEvent<Collider2D> onHit;
static Collider2D[] _hits = new Collider2D[10];
// Call this when you want to hit things touching this capsule.
public int CheckHits()
{
// Get the in-plane rotation of the capsule, in degrees.
var bearing = transform.right;
float angle = Mathf.Atan2(bearing.y, bearing.x) * Mathf.Rad2Deg;
// Find all overlapping colliders in the selected layers,
// using the non-allocating form for efficiency.
int hitCount = Physics2D.OverlapCapsuleNonAlloc(
transform.position,
size,
CapsuleDirection2D.Vertical,
angle,
_hits,
layersToCheck
);
// For each hit found, fire an event to process it.
for (int i = 0; i < hitCount; i++) {
onHit.Invoke(_hits[i]);
}
// Report back how many hits we got.
return hitCount;
}
// Draw a preview of the hit capsule shape.
void OnDrawGizmos() {
// Cache the incoming values (this might not be necessary).
var mat = Gizmos.matrix;
var col = Gizmos.color;
Gizmos.color = Color.green;
// Draw in the capsule's local coordinates - ignoring scale.
Gizmos.matrix = Matrix4x4.TRS(
transform.position,
Quaternion.LookRotation(Vector3.forward, transform.up),
Vector3.one
);
float radius = size.x * 0.5f;
Vector3 span = new Vector3(0, (size.y - size.x) * 0.5f, 0);
// Draw the circles at either end of the capsule.
Gizmos.DrawWireSphere(span, radius);
Gizmos.DrawWireSphere(-span, radius);
// Draw the two straight sides of the capsule.
Vector3 spoke = new Vector3(radius, 0, 0);
Gizmos.DrawLine(spoke + span, spoke - span);
Gizmos.DrawLine(-spoke + span, -spoke - span);
// Put everything back the way we found it.
Gizmos.matrix = mat;
Gizmos.color = col;
}
}
if (collider.TryGetComponent(out Health health)) health.Damage(damage);to save callingGetComponenttwice. This does the job of testing for the presence of the component and fetching it in one pass, without calling Unity's overridden comparison function for the null check (and without an extra allocation in the editor), so it's a little more efficient for the CPU as well as being shorter to write. \$\endgroup\$