Forum begins after the advertisement:


[Part 16] Adding a buff system to the game

Home Forums Video Game Tutorial Series Creating a Rogue-like Shoot-em Up in Unity [Part 16] Adding a buff system to the game

Viewing 6 posts - 1 through 6 (of 6 total)
  • Author
    Posts
  • #13637
    Cam
    Silver Supporter (Patron)

    i managed to get some time today had a play with buff system with a freind, stll not working yet but you love for you to have a look (also when can we watch the live Stream from last night would love to look back at it

    Buff.cs

    using System;
    
    public class Buff
    {
        public string StatAffected { get; private set; }
        public float Modifier { get; private set; }
        public float Duration { get; private set; }
        private float remainingDuration;
    
        public Buff(string statAffected, float modifier, float duration)
        {
            StatAffected = statAffected;
            Modifier = modifier;
            Duration = duration;
            remainingDuration = duration;
        }
    
        // Method to update the remaining duration of the buff
        public void UpdateDuration(float deltaTime)
        {
            remainingDuration -= deltaTime;
            if (remainingDuration <= 0)
            {
                // Buff expired
                // Optionally: Trigger an event to notify listeners that the buff expired
            }
        }
    }
    

    BuffData.cs

    using System.Collections.Generic;
    using UnityEngine;
    
    public class BuffData : MonoBehaviour
    {
        private List<Buff> activeBuffs = new List<Buff>();
    
        // Method to apply a buff to an entity
        public void ApplyBuff(Buff buff)
        {
            activeBuffs.Add(buff);
            // Optionally: Trigger an event to notify listeners that a new buff was applied
        }
    
        // Method to remove a specific type of buff
        public void RemoveBuff(string statAffected)
        {
            for (int i = activeBuffs.Count - 1; i >= 0; i--)
            {
                if (activeBuffs[i].StatAffected == statAffected)
                {
                    activeBuffs.RemoveAt(i);
                    // Optionally: Trigger an event to notify listeners that a buff was removed
                    break; // Stop after removing the first matching buff
                }
            }
        }
    
        // Method to update active buffs
        public void UpdateBuffs(float deltaTime)
        {
            for (int i = activeBuffs.Count - 1; i >= 0; i--)
            {
                activeBuffs[i].UpdateDuration(deltaTime);
                if (activeBuffs[i].Duration <= 0)
                {
                    // Buff duration expired, remove it
                    activeBuffs.RemoveAt(i);
                    // Optionally: Trigger an event to notify listeners that a buff expired
                }
            }
        }
    
        // Method to recalculate entity stats based on active buffs
        public void RecalculateStats()
        {
            // Logic to recalculate entity stats based on active buffs
        }
    }
    

    WeaponDamageBuff.cs

    
    public class WeaponDamageBuff : Buff
    {
        public WeaponDamageBuff(float modifier, float duration) : base("WeaponDamage", modifier, duration)
        {
            // The "WeaponDamage" string indicates that this buff affects weapon damage
        }
    }
    

    and lastly when im putting it on my “rage System”

        private void ToggleDrunkState()
        {
            IsDrunk = !IsDrunk;
            if (IsDrunk)
            {
                drunkParticle.Play();
            ApplyBuffs();
            }
            else
            {
                drunkParticle.Stop();
            }
    
            if (!IsDrunk)
            {
            drunkParticle.Stop();
            RemoveBuffs();
            }
        }
    
        private void Drunk()
        {
            currentDrunk -= player.Stats.soberRate * Time.deltaTime;
            if (currentDrunk < 0)
            {
                currentDrunk = 0;
            }
        }
        private void ApplyBuffs()
        {
            // Apply weapon damage buff
            Buff weaponDamageBuff = new Buff("WeaponDamage", WeaponDamageBuffAmount, float.MaxValue);
            buffData.ApplyBuff(weaponDamageBuff);
    
            // Recalculate stats after applying buffs
            buffData.RecalculateStats();
    
        }
    
        private void RemoveBuffs()
        {
            // Remove weapon damage buff
            buffData.RemoveBuff("WeaponDamage");
            
            // Recalculate stats after removing buffs
            buffData.RecalculateStats();
        }
    
    #13639
    Terence
    Keymaster

    Hey Cam, the stream is here. I’ve timestamped it to make it easier for you to find the part.

    I’ll have a look at your code tomorrow.

    #13641
    Cam
    Silver Supporter (Patron)

    the video you link here says “Video unavailable”
    and its not showing up on your youtube channel under live

    #13642
    Terence
    Keymaster

    Hey Cam, here’s how I would organise the Buff class. It should store all of its data in BuffData and just have a reference to it.

    using System;
    
    public class Buff
    {
        public string StatAffected { get; private set; }
        public float Modifier { get; private set; }
        public float Duration { get; private set; }
        private float remainingDuration;
        public BuffData data;
        float remainingDuration;
    
        ...
    }

    The BuffData script should be a scriptable object, so you can use it to create different buffs in the project window. In it, you should store all attributes of the buff, e.g. name, duration, stat modifiers, etc.

    using System.Collections.Generic;
    using UnityEngine;
    
    [CreateAssetMenu(fileName = "Data", menuName = "Your Game Name/Buff Data", order = 1)]
    public class BuffData : MonoBehaviour
    {
        public string name;
        public CharacterData.Stats modifier;
        public float duration;
    
        // These shouldn't be here. They should be somewhere else, preferrably in the player script
        private List<Buff> activeBuffs = new List<Buff>();
    
        // Method to apply a buff to an entity
        public void ApplyBuff(Buff buff)
        {
            activeBuffs.Add(buff);
            // Optionally: Trigger an event to notify listeners that a new buff was applied
        }
    
        // Method to remove a specific type of buff
        public void RemoveBuff(string statAffected)
        {
            for (int i = activeBuffs.Count - 1; i >= 0; i--)
            {
                if (activeBuffs[i].StatAffected == statAffected)
                {
                    activeBuffs.RemoveAt(i);
                    // Optionally: Trigger an event to notify listeners that a buff was removed
                    break; // Stop after removing the first matching buff
                }
            }
        }
    
        // Method to update active buffs
        public void UpdateBuffs(float deltaTime)
        {
            for (int i = activeBuffs.Count - 1; i >= 0; i--)
            {
                activeBuffs[i].UpdateDuration(deltaTime);
                if (activeBuffs[i].Duration <= 0)
                {
                    // Buff duration expired, remove it
                    activeBuffs.RemoveAt(i);
                    // Optionally: Trigger an event to notify listeners that a buff expired
                }
            }
        }
    
        // Method to recalculate entity stats based on active buffs
        public void RecalculateStats()
        {
            // Logic to recalculate entity stats based on active buffs
        }
    }

    Your PlayerStats script is where you put the functions to add / remove buffs:

    public class PlayerStats : MonoBehaviour
    {
        ...
        public List<Buff> buffs = new List<Buff>(); // aka the buff list.
        ...
        // The update function will reduce the duration of the buffs and remove expired buffs.
        void Update()
        {
            ...
            // Counts down duration of buffs.
            List<Buff> expiredBuffs = new List<Buff>();
            foreach(Buff b in buffs)
            {
                b.duration -= Time.deltaTime;
                if(b.duration <= 0) expiredBuffs.Add(b);
            }
    
            // Create a new list excluding expired buffs.
            if(expiredBuffs.Count > 0)
                buffs = buffs.Except(expiredBuffs).ToList();
    
            ...
        }
    
        public Buff AddBuff(BuffData buffData)
        {
            // You can also create a constructor for buff and use that.
            Buff b = new Buff {
                data = buffData,
                remainingDuration = buffData.duration
            };
            buffs.Add(b);
            
            RecalculateStats(); // Calls the function from PlayerStats added in Part 15. This is very important.
    
            return b;
        }
        
        // Removes all copies of a certain type of buff.
        public Buff RemoveBuff(BuffData data)
        {
            List<Buff> toRemove = new List<Buff>();
            foreach(Buff b in buffs)
            {
                if(b.data.name == data.name) toRemove.Add(b);
            }
    
            buffList = buffList.Except(toRemove).ToList();
    
            RecalculateStats(); // Whenever we modify the buff list, we need to recalculate stats.
        }
    
        // Remember that you also need to get RecalculateStats() to add buffs to your stats.
        // This is equally important as calling RecalculateStats() above.
        public void RecalculateStats()
        {
            actualStats = baseStats;
            foreach(PlayerInventory.Slot s in inventory.passiveSlots)
            {
                Passive p = s.item as Passive;
                if(p)
                {
                    actualStats += p.GetBoosts();
                }
            }
    
            foreach(Buff b in buffList)
            {
                actualStats += b.data.modifier;
            }
        }
    }

    I hope this makes sense! It is quite a lot to digest, but feel free to ask if you have any further questions.

    #13644
    Terence
    Keymaster

    It looks like the coding stream #20 video has been blocked by YouTube because the BGM I used was not copyright free. I’ve clipped the part where I talked about the buff system here: https://www.patreon.com/posts/101282948

    #13648
    Cam
    Silver Supporter (Patron)

    Bloody awesome got my buff system working now!!!

Viewing 6 posts - 1 through 6 (of 6 total)
  • You must be logged in to reply to this topic.

Go to Login Page →


Advertisement below: