1
\$\begingroup\$

I'm currently working on my first game in Unity, and I'm having some trouble with attacking. Currently, I have a game object with a 2D capsule collider child. When the attack button is pressed, the trigger hitbox becomes active and checks if it overlaps with a game object that has health. If so, that game object takes damage. The trigger hitbox only seems to work if the player or enemy are moving. If both are stationary, it won't register the collision.

Here is the current C# script that should check for collisions:

private void OnTriggerEnter2D(Collider2D collider)
{
    if (collider.GetComponent<Health>() != null);
    {
        Health health = collider.GetComponent<Health>();
        health.Damage(damage);
    }
}
\$\endgroup\$
1
  • \$\begingroup\$ Tip: you can simplify your code to if (collider.TryGetComponent(out Health health)) health.Damage(damage); to save calling GetComponent twice. 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\$ Commented Jun 3 at 13:51

1 Answer 1

0
\$\begingroup\$

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;
    }
}
\$\endgroup\$

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.