Search Unity

Setting a general code to access inherited variables for Buffs/Debuffs system

Discussion in 'Scripting' started by RenatoCrovella, Oct 23, 2021.

  1. RenatoCrovella

    RenatoCrovella

    Joined:
    May 7, 2019
    Posts:
    1
    Hello everyone!

    I'm struggling to create a TCG (Trading Card Game) battle system with a Buffs/Debuffs system.
    My main problem now is: I have different kinds of Buffs (class buffs, elemental buffs, turn-based buffs, formation buffs, etc.) and I want to create some generic methods that can be used with all of them (i.e.: add stacks, add/remove buff values, etc...).
    There are two important examples I can quote here that I think if I can solve them, I'll probably be able to solve any other related to this topic. They are:

    1. Turn based Add/Remove buffs
    I found a LOT of examples of buffs systems in the internet, but all of them are based in time activation/deactivation and I need to make it work with turns, not time.deltaTime. I tried that with these codes below, but it is not working well (sometimes I keep adding buffs ignoring my limits, or remove my buffs sooner because of extra turns that shouldn't be counted, my attribute values don't get back to the original values after buff removal, etc...).

    Code (CSharp):
    1. //Infos Battle management variables
    2.     public BattleState currentState;
    3.     public int battleTurn;
    4.     public int battleRound;
    5.     public bool isPlayerTurn = false;
    6.     public bool enemyPlayed = false;
    7.     public DoDamage doDamage;
    8.  
    9.     //Infos de batalha/dano
    10.     public int damage;
    11.     public int currentHP;
    12.  
    13. void Start()
    14.     {
    15.         SetupBattle();
    16.     }
    17.  
    18.     void SetupBattle()
    19.     {
    20.         currentState = BattleState.SETUP;
    21.         battleRound = 1;
    22.         battleTurn = 0;
    23.         playerBehave = playerUnit.GetComponent<CardBehavior>();
    24.         enemyBehave = enemyUnit.GetComponent<CardBehavior>();
    25.         playerBuffs = playerUnit.GetComponentInChildren<CardBuffsController>();
    26.         enemyBuffs = enemyUnit.GetComponentInChildren<CardBuffsController>();
    27.         currentState = BattleState.START;
    28.      
    29.         dialogueText.text = "A new battle starts with ";
    30.      
    31. //Decides which player will be the first to play
    32.         StartJokempo();
    33.     }
    34.  
    35. public void EndTurn()
    36.     {
    37.         battleTurn++;
    38.         Debug.Log("Turn: " + battleTurn);
    39.         Debug.Log("Round " + battleRound);
    40.      
    41.         if (playerBehave.turnsToPlay == 0 && enemyBehave.turnsToPlay <= 0)
    42.         {
    43.          
    44.             NextRound();
    45.             CheckTurnSort();
    46.             Debug.Log(currentState);
    47.         }
    48.         else if (playerBehave.turnsToPlay <= 0 && enemyBehave.turnsToPlay != 0)
    49.         {
    50.             NextTurn(BattleState.ENEMYTURN);
    51.             Debug.Log(currentState);
    52.         }
    53.         else if (playerBehave.turnsToPlay != 0 && enemyBehave.turnsToPlay == 0)
    54.         {
    55.             NextTurn(BattleState.PLAYERTURN);
    56.             Debug.Log(currentState);
    57.         }
    58.  
    59. public void NextTurn(BattleState _battleState)
    60.     {
    61.         if (playerBehave.turnsToPlay <= 0 && enemyBehave.turnsToPlay > 0)
    62.         {
    63.             EnemyTurn();
    64.         }
    65.         else if(playerBehave.turnsToPlay > 0 && enemyBehave.turnsToPlay <= 0)
    66.         {
    67.             PlayerTurn();
    68.         }
    69.     }
    70.  
    71. public void NextRound()
    72.     {
    73.         battleRound++;
    74.         playerBehave.turnsToPlay = 1;
    75.         playerBuffs.gotExtraTurn = false;
    76.         enemyBehave.turnsToPlay = 1;
    77.         enemyBuffs.gotExtraTurn = false;
    78.         }
    79.  
    80.  
    2. Access to the General Buffs Variables
    I know that all bufs will have some basic information, like "buff name", "buff description", "buff stacks", and I've made the specific buffs (like Class Buffs) inherit this variables. The problem is: when I try to access (and change) this variables in other scripts, I can't reach them without using the specifications (example: add stacks could be a generic method, but instead, I'm having to create a different method per kind of buff, like "Add Class Bonus Stacks", "Add Attributes Buffs Stacks", etc...). It doesn't make any sense because I'm mostly copying and pasting the same method for each kind of buff and just changing the same variables in the inherited script (such as: rather than just asking my script to get GeneralBuff maxBuffStacks variable, I have to create two methods, one to use maxBuffStacks of Class Bonus and one another to use maxBuffStacks of a Attribute Bonus (but both actually do the same thing: check if there is "room" for new stacks or not. I wanted to make it happen independent of the kind of Buff/Bonus).


    Code (CSharp):
    1. public abstract class BuffsGeneral : MonoBehaviour
    2. {
    3.     //Duration = time (in turns) that buff will be activated
    4.     public int duration;
    5.  
    6.     public string buffName;
    7.  
    8.     //Buff Desc = Buff's description
    9.     public string buffDesc;
    10.  
    11.     //Buff Alive = active buff turn count
    12.     public int buffAlive;
    13.  
    14.     //Buff Stacks = cumulative buff effect
    15.     public int buffStacks;
    16.  
    17.     //Max Buff Stacks = cumulative buff effect limit
    18.     public int bonusMaxStacks;
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using System.Linq;
    5. using UnityEngine.UI;
    6.  
    7. public class CardBuffsController : MonoBehaviour
    8. {
    9.     //Buffs Spawner object
    10.     public Transform controllerTransform;
    11.  
    12.     //Battle Script to control turns/rounds
    13.     public BattleSystem battleSystemScript;
    14.  
    15.     //Controladores de Buffs
    16.     public List<GameObject> listBuffs = new List<GameObject>();
    17.     public bool gotExtraTurn = false;
    18.     public bool gotClassBonus = false;
    19.  
    20.     public void AddClassBonus(GameObject _classB, GameObject _tgt)
    21.     {
    22.         //Instantiating the Buff Game Object
    23.         GameObject _bonusController = _tgt.GetComponentInChildren<CardBuffsController>().gameObject as GameObject;
    24.         Vector3 tgtPos = _bonusController.transform.position;
    25.         GameObject _bonus = Instantiate<GameObject>(_classB, tgtPos, Quaternion.identity, _tgt.transform) as GameObject;
    26.  
    27.         //Add this Buff GameObject to the Buffs list of the character
    28.        _bonus.transform.SetParent(_bonusController.transform);
    29.         _bonusController.GetComponent<CardBuffsController>().listBuffs.Add(_bonus);
    30.      
    31.         //Adding 1 stack to the bonus;
    32.         _bonus.GetComponent<ClassBonus>().buffStacks += 1;
    33.         _bonus.GetComponentInChildren<Text>().text = _bonus.GetComponent<BuffsGeneral>().buffStacks.ToString();
    34.     }
    35.  
    36.     public void RemoveBonus(GameObject _bonus)
    37.     {
    38.         Destroy(_bonus);
    39.     }   //Remove the _bonus
    40.  
    41.     public void AddStacks(GameObject _stacksBuff, int _qttStacks)
    42.     {
    43.         //Defining the variables which will be used to check if there are "room" for new stacks
    44.         bool canReceiveStacks;
    45.      
    46.         int cardBuffStacks = _stacksBuff.GetComponent<ClassBonus>().buffStacks;
    47.         int buffMaxStacks = _stacksBuff.GetComponent<ClassBonus>().bonusMaxStacks;
    48.  
    49.         //UI variables
    50.         Text stacksTxt = _stacksBuff.GetComponentInChildren<Text>();
    51.         stacksTxt.text = cardBuffStacks.ToString();
    52.  
    53.         //Checking if the list contains the buff
    54.         if (listBuffs.Contains(_stacksBuff))
    55.         {
    56.             if (cardBuffStacks < buffMaxStacks)
    57.             {
    58.                 canReceiveStacks = true;
    59.             }
    60.             else
    61.             {
    62.                 canReceiveStacks = false;
    63.             }
    64.  
    65.             //Add stacks and adjust it to the limit (if necessary)
    66.             if(canReceiveStacks == true)
    67.             {
    68.                 cardBuffStacks += _qttStacks;
    69.                 if(cardBuffStacks >= buffMaxStacks)
    70.                 {
    71.                     cardBuffStacks = buffMaxStacks;
    72.                 }
    73.             }
    74.          
    75.         }
    76.         else { Debug.Log("Nothing find"); }
    77.  
    78.  
    79.     }
    NOTE: I'm calling those methods in a "Do Damage" script. If necessary, I can send it too.
    EDIT: I kinda solved some issues with the "timing" of a buff add/removal using bool variables, but I still want to try to find a way to do these checks "automatically", since It'll probably be complicated to control after adding the other types of buffs and battle features.

    Please, can you help me with these 2 struggles? :(
     
    Last edited: Oct 23, 2021
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,742
    I would guess a combination of interfaces coupled with ScriptableObjects would get you a large amount of what you want above. You would have various types of buffing interfaces (or perhaps just one to start with) and the implement as many different ScriptableObjects instances as you like, and slot them into cards.

    Here's my blurb on interfaces:

    Using Interfaces in Unity3D:

    https://forum.unity.com/threads/how...rereceiver-error-message.920801/#post-6028457

    https://forum.unity.com/threads/manager-classes.965609/#post-6286820

    Check Youtube for other tutorials about interfaces and working in Unity3D. It's a pretty powerful combination.