2D Splash Damage for rocket launcher

Ive been trying to create a rocket launcher for my 2d game for a while now, but i cant get the splash damage to work at all. My target takes damage on direct hits but otherwise, nothing. Any help would be great, possibly even some criticism on how stupidly long it might be. Heres the code:
public float gjallerhornProjectileSpeed;
public float raycastDistance;
public float damage;
public float splashRange = 3.0f;
public LayerMask whatIsSolid;

// Update is called once per frame
private void Update()
{
    RaycastHit2D hitInfo = Physics2D.Raycast(transform.position, transform.up, raycastDistance, whatIsSolid);
    if (hitInfo.collider != null)
    {
        if (hitInfo.collider.CompareTag("Enemy"))
        {
            hitInfo.collider.GetComponent<EnemyHealth>().TakeDamage(damage);
        }
        Destroy(gameObject);
    }

    transform.Translate(Vector2.right * gjallerhornProjectileSpeed * Time.deltaTime);
}

private void OnCollisionEnter2D(Collision2D collision)
{
    if (splashRange > 0)
    {
        var hitColliders = Physics2D.OverlapCircleAll(transform.position, splashRange);
        foreach (var hitCollider in hitColliders)
        {
            var enemy = hitCollider.GetComponent<EnemyHealth>();
            if (enemy)
            {
                var closestPoint = hitCollider.ClosestPoint(transform.position);
                var distance = Vector3.Distance(closestPoint, transform.position);

                var damagePercent = Mathf.InverseLerp(splashRange, 0, distance);
                enemy.TakeDamage(damagePercent * damage);
            }
           
        }
    }

    else
    {
        var enemy = collision.collider.GetComponent<EnemyHealth>();
        if (enemy)
        {
            enemy.TakeDamage(damage);
        }
    }
    Destroy(gameObject);
}

Delete your entire Update function - that’s what’s giving you problems. You’re manually checking for collisions in Update, but your AOE code is under OnCollisionEnter - if you didnt know, raycasting wont automatically call OnCollisionEnter, that’s only called when unity detects the collision. What’s happening is that you are raycasting ahead of the projectile, and destroying it before the projectile itself actually reaches anything, so Unity never gets to register that collision.


Replace Update with this:

OnStart()
{
    rb = GetComponent<Rigidbody2D>();
    rb.velocity = transform.right * gjallerhornProjectileSpeed * Time.deltaTime;
}

What I’ve done here is let Unity handle moving the projectile, AND stopped your raycasting so that unity can also start handling the collisions too. If you didnt already have a Rigidbody2D on your projectile prefab, add one now, mark it as a trigger, and also tick the box to constrain its rotation. Now lets rework your OnCollisionEnter:

void OnTriggerEnter2D(Collider2D other)
{
    if (splashRange > 0)
    {
        Collider2D[] hitColliders = Physics2D.OverlapCircleAll(transform.position, splashRange);
        foreach (Collider2D hitCollider in hitColliders)
            hitCollider.GetComponent<EnemyHealth>()?.TakeDamage(damage);
    }
    else
        other.GetComponent<EnemyHealth>()?.TakeDamage(damage);

    Destroy(gameObject);
}

Now that we’re using triggers instead of solids, OnCollisionEnter will never be called, but OnTriggerEnter will be used in its place. The logic on the inside worked just fine, but again the problem was that you were never called this function in the first place.

You’ll also notice a few things you might not have seen before such as the “?”. That’s the symbol for null propagation, basically short for “if (this=null) stop the line, else continue”, which makes the code look neat in some places. I’ve also removed the damage reduction logic - you can keep it in if you want, however most players don’t like that. At the very least, I’d highly recommend putting in a minimum damage, nothing sucks more than hitting an enemy for 0.000001 hp.


Some general tips since you asked for it - don’t use var, use the expected type instead. Makes debugging easier, and prevents type ambiguity user errors. Don’t use tags either, tags are for tiny projects and beginners. You already do the GetComponent<> check which is correct, just swap that for the tag part. Tags are very limiting since they are one dimensional, such that if you wanted to tag enemy/player but also ground/air, tags couldn’t do that.