Damage related to distance

If you would like to apply damage related to distance from explosion and get tool to modify damage multiplier, you should use AnimationCurve.

public class GrenadeProjectile : MonoBehaviour
[SerializeField, Min(0.1f)] private float _moveSpeed;
[SerializeField, Min(0f)] private float _damage;
[SerializeField, Min(0.1f)] private float _damageRadiusInCells;
[SerializeField] private AnimationCurve _damageMultiplierCurve;

private Vector3 _targetPosition;
private Vector3 _moveDir;
private float _distance;
private Action _onGrenadeExplodes;

private void Update()
    float translation = _moveSpeed * Time.deltaTime;
    transform.position += _moveDir * translation;
    _distance -= translation;

    if (_distance <= 0)
        float damageDistance = _damageRadiusInCells * LevelGrid.Instance.CellSize;
        Collider[] colliders = Physics.OverlapSphere(_targetPosition, damageDistance);
        foreach (Collider collider in colliders)
            if (collider.TryGetComponent(out Unit targetUnit))
                var distanceToUnit = Vector3.Distance(targetUnit.GetWorldPosition(), _targetPosition);
                if (distanceToUnit < damageDistance)
                    float curveTime = distanceToUnit / damageDistance;
                    targetUnit.Hit(_damage * _damageMultiplierCurve.Evaluate(curveTime));

public void Setup(GridPosition gridPosition, Action onGrenadeExplodes)
    _targetPosition = LevelGrid.Instance.GetWorldPosition(gridPosition);
    _moveDir = (_targetPosition - transform.position).normalized;
    _distance = Vector3.Distance(_targetPosition, transform.position);
    _onGrenadeExplodes = onGrenadeExplodes;


And add to LevelGrid these properties:
[field: SerializeField, Min(1)] public int Width { get; private set; }
[field: SerializeField, Min(1)] public int Height { get; private set; }
[field: SerializeField, Min(0.1f)] public float CellSize { get; private set; }


That’s a great addition, using the animation curve makes it really easy for game balancing, good job!


Wow, this is awesome!
Thanks for sharing.

I had the same idea and saw this implementation so it saved me a bit of time, thank you.

Just a heads up though I don’t think your _onGrenadeExplodes event is going to be called as the game object gets destroyed first.

The gameObject is only going to be destroyed at the end of the frame so I think this will still be good. I would swop the two lines though.

I say frame. It’s really the current Update(). The object stays for the duration of the current Update()

1 Like

Ahh yep, this has caught me a few times, thinking something was destroyed but the update hadn’t ended yet. Yeah, probably still best practice to switch the two lines around though.

Privacy & Terms