Repeat Composite Effect

I do believe I nailed this on my first try. Thanks to Sam with lectures and @Brian_Trotter for being my mental backstop here. This was INCREDIBLY satisfying to do to make a heal over time spell(which I also made an inflict self pain spell so I could see the heal working).

public class RepeatCompositeEffect : EffectStrategy
{
    [Tooltip("Duration of Effect")]
    [Min(0)][SerializeField] int duration = 10;
    [Tooltip("Tick cycle time")]
    [Min(0)][SerializeField] int tickTime = 1;
    [Tooltip("List of effects to repeat.")]
    [SerializeField] EffectStrategy[] delayedEffects;

    public override void StartEffect(AbilityData data, Action finished)
    {
        data.StartCoroutine(RepeatEffect(data, finished));
    }

    private IEnumerator RepeatEffect(AbilityData data, Action finished)
    {
        for (int i = 0; i < duration; i += tickTime)
        {
            foreach (var effect in delayedEffects)
            {
                effect.StartEffect(data, finished);
            }
            yield return new WaitForSeconds(tickTime);
        }
    }
}

}

(it doesn’t like namespace and CreateAssetMenu up there)
[CreateAssetMenu(fileName = “Repeat Composite Effect”, menuName = “Abilities/Effects/Repeat Composite”, order = 0)]

1 Like

@Brian_Trotter any ideas how to track this down and stop it from elsewhere?

Specifically, this really messes with the new player death stuff we are doing in the course. It resurrects you if it fires off a heal effect.

Ideally, I wish we had learned how to have active effects. To display buffs/effects over time on the HUD and to be able to cancel/remove them at will or with debuffs (or in this case, death).

Edit: Well… doing an IsDead Check before StartEffect and yield breaking is a good fix for if the user dies to stop. But that gets dependent on game specific code… Which is fine to me honestly. But it doesn’t allow for dynamically stopping effects like I mentioned above. I have a bad feeling some sort of Manager or state storing will need to be happening to do it with more bells and whistles.

Do you suffer from URE? Unplanned Ressurection Effects are a real thing, and could be infecting your game in ways that some could percieve as being a bug. URE is known to cause zombie outbreaks, and we here at the Institute for Filter Strategies believe we have the cure.

Institute For Filter Strategies special formula for preventing URE
using System.Collections.Generic;
using RPG.Attributes;
using UnityEngine;

namespace RPG.Abilities.Filters
{
    [CreateAssetMenu(fileName = "IsAliveFilter", menuName = "Filters/IsAliveFilter", order = 0)]
    public class IsAliveFilter : FilterStrategy
    {
        public override IEnumerable<GameObject> Filter(IEnumerable<GameObject> objectsToFilter)
        {
            foreach (GameObject gameObject in objectsToFilter)
            {
                if (gameObject.TryGetComponent(out Health health) && !health.IsDead())
                {
                    yield return gameObject;
                }
            }
        }
    }
}

Warning: Side effects include an inability to target dead beings. If your dead being stays dead longer than four hours, go to the nearest emergency room where Miracle Max will go through his pockets for change.

1 Like

Ah yeah nice. Should have been obvious to make a filter. And this works after the fact? After I fire off my delayed composite each tick of the effect will be weighed against the filter? I’d think so but my brain isn’t working.

Still doesn’t help for some specific cases where I might want to force effects to end. Dispels and to prevent stacking are big ones. Beyond that having UI to show active effects is always a nice feature. I thought maybe add the icon when you fire off and remove in finish but the effect would yoyo back and forth on ticks. Maybe remove it after the loop but that ignores any of my other wishes for early cancels

No… the answer is no. Filters do not work with my Repeat Composite. The target is already chosen (you) when the effect is being run I believe. Granted, I want this to keep other effects from targeting dead people, but yep… gotta keep that same if statement inside my Repeat Composite or it’ll keep on after death. Well, I also have a toggle for the designer to say if they want the repeat to stop on death. There would be edge cases that you’d be fine with it staying on.

public class RepeatCompositeEffect : EffectStrategy
{
    [Tooltip("Duration of Effect(in seconds).")]
    [Min(0)][SerializeField] int duration = 10;
    [Tooltip("Tick cycle time(in seconds.")]
    [Min(0)][SerializeField] int tickTime = 1;
    [Tooltip("Should the effect stop on user's death?")]
    [Min(0)][SerializeField] bool stopOnDeath = true;
    [Tooltip("List of effects to repeat.")]
    [SerializeField] EffectStrategy[] delayedEffects;

    public override void StartEffect(AbilityData data, Action finished)
    {
        data.StartCoroutine(RepeatEffect(data, finished));
    }

    private IEnumerator RepeatEffect(AbilityData data, Action finished)
    {
        Health health = data.GetUser().GetComponent<Health>();
        if (health == null) yield break;

        for (int i = 0; i < duration; i += tickTime)
        {
            foreach (var effect in delayedEffects)
            {
                if (stopOnDeath && health.IsDead()) yield break; //Stop executing over time if user dies. **RPG TUTORIAL SPECIFC**
                effect.StartEffect(data, finished);
            }
            yield return new WaitForSeconds(tickTime);
        }
    }
}

I surprise myself sometimes.

public class BuffsUI : MonoBehaviour
{
    [SerializeField] Transform rootList;
    [SerializeField] GameObject buffPrefab;

    public void AddBuff(Sprite sprite, float duration)
    {
        GameObject buffInstance = Instantiate(buffPrefab, rootList);
        buffInstance.GetComponent<Image>().sprite = sprite;
        Destroy(buffInstance, duration);
    }

    public void ClearBuffs()
    {
        if (rootList.childCount <= 0) return;
        foreach(Transform kiddo in rootList)
        {
            Destroy(kiddo.gameObject);
        }
    }
}

This… actually works… I set up a horizontal layout group for tiny 18x18 icons right below our shoddy player “HUD.” Made a prefab for a blank image that gets it Sprite set with code.

I call ClearBuffs in Respawner to remove them all on death(contradicts my decision to let the designer allow buffs to last past death)… I add the buff from my Repeat Composite and it passes the duration so this script removes it on its own… I’m still kind of in shock that this was this easy. Sam has really reached my brain with UI which I thought impossible.

I suppose I could do one of those neat radial/linear image covers like we did for Cooldown for this too. Hell. I could even superimpose some text that has alpha lowered a bit over top of the images and have it as a live countdown if I wanted. This is neat.

Mission accomplished. I got that working too.

Gotcha… my filter prevents the effect from working in the first place, but it’s not a constant thing…

You could filter the dataset between repeats… within the RepeatCompositeEffect itself…

Privacy & Terms