Hi,everyone
I would like to create buff system by use coroutine by I have a caster[for buff skills] when cast skill start a coroutine (“PlusAttackSpeed”) when I use 2 or more if I use stop(“PlusAttackSpeed”) the script stop all of them
Can I only Stop only 1 of them and specific index for stop?
Get a reference to the coroutine when you start it. eg:
int index = 1;
Coroutine recent;
IEnumerator Test () {
int i = index++;
Debug.Log( "started test " + i );
yield return new WaitForSeconds( 5 );
Debug.Log( "finished test " + i );
}
void OnGUI () {
if ( GUILayout.Button( "begin test" ) ) {
recent = StartCoroutine( Test() );
}
if ( GUILayout.Button( "stop most recent test" ) ) {
StopCoroutine( recent );
}
}
if you click begin 2 times, it prints “started test 1” “started test 2” … “finished test 1” “finished test 2”
if you click begin 2 times then stop, the most recent referenced coroutine stops, and you only the first get “finished”
now you should be able to store many coroutines in an array or list to stop as many as needed
PS. in your example, simply ‘stopping’ the coroutine will not remove the buff
Thankyou as you said this can’t remove the buff or can force WaitForSeconds to zero while return ?
Or who can suggest me how to create buff debuff system.
You could set up a system where you have 2 functions, one sets up the buff, then after x seconds call the other, the other removes the buff (but you can also call this second function early)
Wow it look very simple but if I use coroutiens with objects how I choose stop only 1 and debuff correct value(each object get percent value)
I think about use bool[ ] for stop and let each coroutien check everyframe but I don’t know are this expansive?
don’t change the original attack speed, instead accumulate the values in a modifier. then your scripts can grab either the base stat or the modified stat.
private List<BuffHandler> m_activeBuffs = new List<BuffHandler>();
public float baseStat = 15;
//provide hard caps
public float minStat = 1;
public float maxStat = 255;
public float ModifiedStat
{
get
{
float modified = baseStat;
for(int i=0;i<m_activeBuffs.Count;i++)
{
modified *= m_activeBuffs[i].multiplicativeModifier;
}
for(int i=0;i<m_activeBuffs.Count;i++)
{
modified += m_activeBuffs[i].additiveModifier;
}
return Mathf.Clamp(modified, minStat,maxStat);
}
}
public void AddBuff(BuffHandler buff)
{
//if already buffed, remove and refresh its duration
if(m_activeBuffs.Contains(buff))
{
StopCoroutine(buff.handle);
m_activeBuffs.Remove(buff);
}
buff.handle = StartCoroutine(ApplyBuff(buff));
}
public void RemoveBuff(BuffHandler buff)
{
if(m_activeBuffs.Contains(buff))
{
StopCoroutine(buff.handle);
m_activeBuffs.Remove(buff);
}
}
private IEnumerator ApplyBuff(BuffHandler buff)
{
if(!m_activeBuffs.Contains(buff))
m_activeBuffs.Add(buff);
yield return new WaitForSeconds(buff.duration);
m_activeBuffs.Remove(buff);
}
public class BuffHandler
{
public Coroutine handle{get;set;}
public float duration;
public float additiveModifier;
public float multiplicativeModifier;
}
if needed you can pre-cache the modified stat every time you add/remove the buff. in this example I use a list of BuffHandlers and each handler holds its coroutine reference, but you might want to turn m_activeBuffs into a dictionary of <Buffhandler,Coroutine> and remove the Coroutine property from the BuffHandler class if you plan on multiple monobehaviours needing to run a buff through a coroutine in parallel. it just depends on your plans.
There is no real need to use SendMessage in the current version of Unity. It used to be useful, but nowdays GetComponent and ExecuteEvents tend to be superior.