-
-
Save savage69kr/2a21d5fa30ea2ce316dae4de5eb862d1 to your computer and use it in GitHub Desktop.
Effects Over Time Example
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Collections.Generic; | |
| using ImprovedTimers; // https://github.com/adammyhre/Unity-Improved-Timers | |
| using UnityEngine; | |
| [Serializable] | |
| public class Ability { | |
| public AudioClip castSfx; | |
| public GameObject castVfx; | |
| public GameObject runningVfx; | |
| [SerializeReference] public List<IEffect<IDamageable>> effects = new(); | |
| public void Execute(IDamageable target) { | |
| foreach (var effect in effects) { | |
| if (target is Enemy enemy) { | |
| enemy.ApplyEffect(effect); | |
| } else { | |
| effect.Apply(target); | |
| } | |
| } | |
| } | |
| } | |
| public interface IDamageable { | |
| void TakeDamage(int amount); | |
| } | |
| public interface IEffect<TTarget> { | |
| void Apply(TTarget target); | |
| void Cancel(); | |
| event Action<IEffect<TTarget>> OnCompleted; | |
| } | |
| [Serializable] | |
| public class DamageEffect : IEffect<IDamageable> { | |
| public int damageAmount = 10; | |
| public event Action<IEffect<IDamageable>> OnCompleted; | |
| public void Apply(IDamageable target) { | |
| target.TakeDamage(damageAmount); | |
| OnCompleted?.Invoke(this); | |
| } | |
| public void Cancel() { | |
| OnCompleted?.Invoke(this); | |
| } | |
| } | |
| [Serializable] | |
| public class DamageOverTimeEffect : IEffect<IDamageable> { | |
| public float duration = 5f; | |
| public float tickInterval = 1f; | |
| public int damagePerTick; | |
| public event Action<IEffect<IDamageable>> OnCompleted; | |
| IntervalTimer timer; | |
| IDamageable currentTarget; | |
| public void Apply(IDamageable target) { | |
| currentTarget = target; | |
| timer = new IntervalTimer(duration, tickInterval); | |
| timer.OnInterval = OnInterval; | |
| timer.OnTimerStop = OnStop; | |
| timer.Start(); | |
| } | |
| void OnInterval() => currentTarget?.TakeDamage(damagePerTick); | |
| void OnStop() => Cleanup(); | |
| public void Cancel() { | |
| timer?.Stop(); | |
| Cleanup(); | |
| } | |
| void Cleanup() { | |
| timer = null; | |
| currentTarget = null; | |
| OnCompleted?.Invoke(this); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System.Collections.Generic; | |
| using UnityEngine; | |
| public class Enemy : MonoBehaviour, IDamageable { | |
| public int health = 50; | |
| readonly List<IEffect<IDamageable>> activeEffects = new(); | |
| public void TakeDamage(int amount) { | |
| health -= amount; | |
| Debug.Log($"Enemy took {amount} damage. Health now {health}"); | |
| if (health <= 0) { | |
| Die(); | |
| } | |
| } | |
| public void ApplyEffect(IEffect<IDamageable> effect) { | |
| if (health <= 0) return; // Dead enemies should't receive effects | |
| effect.OnCompleted += RemoveEffect; | |
| activeEffects.Add(effect); | |
| effect.Apply(this); | |
| } | |
| void RemoveEffect(IEffect<IDamageable> effect) { | |
| effect.OnCompleted -= RemoveEffect; | |
| activeEffects.Remove(effect); | |
| } | |
| void Die() { | |
| Debug.Log("Enemy died."); | |
| for (int i = activeEffects.Count - 1; i >= 0; i--) { | |
| var effect = activeEffects[i]; | |
| effect.OnCompleted -= RemoveEffect; | |
| effect.Cancel(); | |
| } | |
| activeEffects.Clear(); | |
| Destroy(gameObject); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System.Collections; | |
| using UnityEngine; | |
| using UnityUtils; // https://github.com/adammyhre/Unity-Utils | |
| public class PlayerAbilityCaster : MonoBehaviour { | |
| public Ability[] hotbar; | |
| void Update() { | |
| for (int i = 0; i < hotbar.Length; i++) { | |
| if (Input.GetKeyDown(KeyCode.Alpha1 + i)) { | |
| Cast(hotbar[i], FindFirstObjectByType<Enemy>()); | |
| } | |
| } | |
| } | |
| void Cast(Ability ability, IDamageable target) { | |
| ability.Execute(target); | |
| var targetMb = target as MonoBehaviour; | |
| if (ability.castVfx && targetMb) { | |
| Instantiate(ability.castVfx, targetMb.transform.position.Add(y:2), Quaternion.identity); | |
| } | |
| if (ability.runningVfx && targetMb) { | |
| var runningVfxInstance = Instantiate(ability.runningVfx, targetMb.transform); | |
| Destroy(runningVfxInstance, 3f); | |
| } | |
| if (ability.castSfx) { | |
| AudioSource.PlayClipAtPoint(ability.castSfx, transform.position); | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment