Usually, if you ask a question from the course lecture page, it gets tagged automagically. Not sure what happened here. You can add a tag to a topic when you create it.
There are two ways you can go about DoT… You could make a function on the Health component, or you could have a manager. For now, we’re going to create a dedicated manager to deal with Health. I’ll probably create a topic soon with a more generic approach that can let you do almost -=anything=- over time.
using System.Collections.Generic;
using UnityEngine;
namespace RPG.Attributes
{
public class HealthDoTManager : MonoBehaviour
{
public class DamageOverTimeInstance
{
public string name = "Generic effect"; //useful for debugging
public float amount = 1.0f; //How much damage we want to do each interval
public int repeats = 10;
public float interval = 1.0f; //time between each repeat.
public GameObject instigator = null;
public float timer = 0.0f;
public Health health;
public bool Update()
{
timer += Time.deltaTime;
if (timer > interval)
{
repeats--;
Debug.Log($"{health.gameObject.name} taking Damage Over Time from {name} effect inflicted by {instigator}. {repeats} cycles remaining.");
health.TakeDamage(instigator, amount);
if (repeats < 0) return true;
timer=0.0f; //Edit: Thanks to dramolxe for spotting this, I forgot to reset the timer!
}
return false;
}
}
private Health health;
private List<DamageOverTimeInstance> instances = new List<DamageOverTimeInstance>();
private List<DamageOverTimeInstance> instancesToRemove = new List<DamageOverTimeInstance>();
private void Awake()
{
health = GetComponent<Health>();
}
private void Update()
{
if(instances.Count) return;
foreach (DamageOverTimeInstance instance in instances)
{
if(instance.Update(health)) instancesToRemove.Add(instance);
}
foreach (DamageOverTimeInstance expiredInstance in instancesToRemove)
{
instances.Remove(expiredInstance);
}
instancesToRemove.Clear();
}
public DamageOverTimeInstance CreateDamageOverTimeInstance(GameObject instigator, float amount, int repeats,
float interval)
{
DamageOverTimeInstance result = new DamageOverTimeInstance();
result.instigator = instigator;
result.amount = amount;
result.repeats = repeats;
result.interval = interval;
result.health = health;
instances.Add(result);
return result;
}
public void RemoveInstance(DamageOverTimeInstance instance)
{
instances.Remove(instance);
}
}
}
Lots of stuff going on here…
The real work is being done by the DamageOverTimeInstance. This inner class keeps track of a specific Damage Over Time effect (imagine six different characters poisoned you, yep, lots of DoTs overlapping, and this class handles it just fine).
Each instance is responsible for managing itself, through it’s Update method. This is a fairly straightforward approach… increase timers, do something when the timer exceeds the interval. We decrement the number of repeat, when it runs out, the result returns true to our regular update.
In the regular update, we call each of the interval’s Update methods, and if they return true, we add them to a list of instances to remove. We can’t just remove them right away because of the way collecitons work. Once we’ve cycled through the collection of instances, we can remove them in the next loop.
This component should be placed on each character. Whenever you want to perform a damage over time effect, GetComponent the HealthDoTManager on the target and call CreatedDamageOverTimeInstance with the required information.
I made the method return the instance for more advanced functions, perhaps some way that the effect decides to end the DoT prematurely. It’s really not needed for what we’re doing, so you can discard the result (just call CreateDamageOverTimeInstance without caching the result).