How to give buff to the specific player in the beginning of the game?

Hi,

I want to know how to increase or decrease some stats of the specific players. For example; In the beginning of the game, each player will able to select some buffs.(increase damage %20, increase max. health %30, decrease cooldown times %20… etc.). So, how can I apply these selections to each player?

Thank you.

This question is so generic and uninformational I really dont know where to start.
Show some code, what you got. What did you try? Where are you stuck?

Anyways I will give you a simple explanation.
Lets say the Player class contains a field for every stat thats editable.

public float BasicAttackDamage { get; private set; }
public float BonusAttackDamage { get; set; }
public float TotalAttackDamage
{
   get { return BasicAttackDamage + BonusAttackDamage; }
}

It is needed that the basic attack damage (which is equal to the initial attack damage of the player that will not change while playing) and the attack damage editable by buffs needs to be splitted from eachother. That is to protect the basic value from modifications (which will boil down to undefined behaviour after some divisions and multiplications).

You design the buff feature with a simple class that is derivable to fill it with some edits.

abstract class Buff
{
   public Player AffectedPlayer { get; private set; }

   public virtual void Apply(Player affectedPlayer)
   {
      AffectedPlayer = affectedPlayer;
   }

   public virtual void Unapply()
   {
   ]
}

class SharpenBuff : Buff
{
   public float sharpeningAttackDamagePercentage  = 10; // +10% attack damage
   private float addedAttackDamagePercentageAbsolute;

   public override void Apply(Player affectedPlayer)
   {
      addedAttackDamagePercentageAbsolute = affectedPlayer.BasicAttackDamage * (sharpeningAttackDamagePercentage / 100); // Store the absolute added value to substract the exact same number when unapplying
      affectedPlayer.BonusAttackDamage += addedAttackDamagePercentageAbsolute;

      base.Apply(affectedPlayer);
   }

   public override void Unapply()
   {
      AffectedPlayer.BonusAttackDamage -= addedAttackDamagePercentageAbsolute;
      base.Unapply();
   }
}

Now you have to implement this feature into the Player class:

public void ApplyBuff(Buff buff)
{
   buff.Apply(this);
}

public void UnapplyBuff(Buff buff)
{
   buff.Unapply();
}

To enhance performance you probably have to play around with the properties and virtual methods. You can extend the properties of the buff in terms of behaviour (is the buff automatically removed after some time, is it a debuff, and so on) and let the Buff class derive from ScriptableObject. That makes it easy for you to create blueprints for all kinds of choosable buffs.

Thank you for replying…

First of all, in my game players don’t have damage values, they shoot a magic ball prefabs(this prefab have baseDamage value). Players have maxHealth value and skill buttons(2) have baseCooldown values.
These buffs initialize in the beggining of the game and continue to the end of the game. And there is no such debuff feature.
In your scripts there is AffectedPlayer value, but how can I assign this value? I don’t understand that part.

Edit : I quite understand how to affectedplayer value work. And I did some research about abstract classes and override methods. So, can we extend the Buff class affectedMagicBall and affectedSkillButtons?

Edit2: You said let the Buff class derive to the Scriptable Object. However, if I do this, the buffs stored in the Assets, so making this kind of thing does some sort of security issues? Like players can able to hack the stored data and change the buffs or price of the buffs?
I ask that because I didn’t use the Scriptable Objects for storing data, in my previous game I store the data in Json files and this Json files is in stored in the database.

I see you have basically no knowledge of scriptable objects and basic object oriented programming. Learn those basics and read through the Unity docs link I gave you for further information.

To answer the unrelated questions:

That makes no difference. When instantiating and setting those “baseDamage” values you have to apply exactly those with the Player.TotalAttackDamage property. Call it how you want, attack or magic ball damage I dont care.

What do you mean with security issues? Using scriptable objects makes no difference if you meant memory editing.

Thats even less secure than scriptable objects if you havent encrypted the data (which database stores Json files anyways?). All unity assets are bundled and compressed into the asset files in your game executable data path which are hard to unlock.

Please offer more information and your attempts to solve the problem the next time you post a question here.

Hi SirNiklas,

Thank you for replying…

I saw your latest post and then I worked on a scriptable objects and OOP. And I’m still in learning phase. But I think the best way to learn OOP is do practising. So, I implement your codes to my project and tamper with it. And I have some new questions, but this time with my attempts.

1- On your base Buff class, you used “abstract” but in this class you didn’t write a non-body method, so why you used it? I ask this question because if I use abstract class, Unity cannot create a Scriptable Object on this class.
2- I expand this Buff class like this;

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
using UnityEditor;
using System;

[CreateAssetMenu(fileName = "BuffData", menuName ="SingleBuff",order =1)]
public class Buff : ScriptableObject{

    public int BuffID;
    public string BuffName;
    public string BuffInformation;
    public Sprite BuffImage;
    public int BuffPercentage { get; set; }
    public int AddedBuff { get; set; }
    public int BuffPrice;

    BuffableList listofBuffableObjects = (BuffableList)AssetDatabase.LoadAssetAtPath("/Assets/BuffableObjectList.asset", typeof(BuffableList));
    public Player affectedPlayer { get; private set; }
    public MagicBall affectedMagicBall { get; private set; }
    public MagicMeteor affectedMagicMeteor { get; private set; }
    public PlayerHUDController affectedHUDController { get; private set; }
   
    public virtual void ApplyBufftoPlayer(Player affectedP)
    {
        affectedPlayer = affectedP;
    }
    public virtual void ApplyBufftoMagicBall(MagicBall affectedMB)
    {
        affectedMagicBall = affectedMB;
    }
    public virtual void ApplyBufftoMagicMeteor(MagicMeteor affectedMM)
    {
        affectedMagicMeteor = affectedMM;
    }
    public virtual void ApplyBufftoHUDController(PlayerHUDController hudController)
    {
        affectedHUDController = hudController;
    }
    /*public virtual void ApplyBuff<T>(T affectedObject)
    {
        string nameofType = affectedObject.GetType().ToString();
        for (int i=0; i<listofBuffableObjects.buffableGameObjectList.Count; i++)
        {
            if (listofBuffableObjects.buffableGameObjectList[i].GetComponent(nameofType))
            {
               

            }
        }
    }*/
}
class PlayerHealthBuff : Buff
{
    public override void ApplyBufftoPlayer(Player affectedP)
    {
        AddedBuff = affectedPlayer.playerBaseHeath * (BuffPercentage / 100);
        affectedPlayer.playerBonusHealth += AddedBuff;

        base.ApplyBufftoPlayer(affectedP);
    }
}
class MagicBallAttackDamageBuff : Buff
{
    //public int magicBallAttackDamageIncreasePercentage = 50;
    //private int magicBallAddedAttackDamage;

    public override void ApplyBufftoMagicBall(MagicBall affectedMB)
    {
        AddedBuff = affectedMagicBall.magicBallBaseAttackDamage * (BuffPercentage / 100);
        affectedMagicBall.magicBallExtraAttackDamage += AddedBuff;

        base.ApplyBufftoMagicBall(affectedMB);
    }
}
class MagicMeteorAttackDamageBuff : Buff
{
    public override void ApplyBufftoMagicMeteor(MagicMeteor affectedMM)
    {
        AddedBuff = affectedMagicMeteor.magicMeteorBaseAttackDamage * (BuffPercentage / 100);
        affectedMagicMeteor.magicMeteorExtraAttackDamage += AddedBuff;

        base.ApplyBufftoMagicMeteor(affectedMM);
    }
}
class SkillCooldownReduceBudd : Buff
{
    public override void ApplyBufftoHUDController(PlayerHUDController hudController)
    {
        AddedBuff = (int)affectedHUDController.magicMeteorCastBaseCooldownTime * (BuffPercentage / 100);
        affectedHUDController.magicMeteorCastDecreaseCooldownTime += AddedBuff;
        affectedHUDController.flashCastDecreaseCooldownTime += AddedBuff;

        base.ApplyBufftoHUDController(hudController);
    }
}
/*class ApplyBufftoObject : Buff
{
    public override void ApplyBuff<T>(T affectedObject)
    {
        AddedBuff = (int)

        base.ApplyBuff<T>(affectedObject);
    }
}*/

I also tried to implement ApplyBuff method, but I couldn’t do it. I created a list of GameObject derived from Scriptable Object. Then, I put the GameObjects that are buffable. In the Buff class I created a method ApplyBuff , this method gets the class and find the gameobject in bufflableGameObject list that has same Type of class name. Then apply the buff this gameobject. But I couldn’t figured out how to declare a class of type the method gets.
So, can we do this kind of thing ?

3- I create a basic menu that players can choose this buffs. And I created a BuffManager(as Singleton), this class gets the selected buffs and store this buffs in a list of Buff class. I did a change of all buffable game objects’ classes, so in the Start method, they get the selected buffs list on BuffManager, search this list and find if there is a Buff that related to themselves and use this buff.

for(int i=0; i< BuffManager.buffManager.selectedBuffsList.Count; i++)
        {
            if(BuffManager.buffManager.selectedBuffsList[i].BuffID == 0)
            {
                ApplyBuff(BuffManager.buffManager.selectedBuffsList[i]);
                print(playerBonusHealth);
                print(playerTotalHealth);
                break;
            }
        }

Later I will improve this search thing a little bit. But this code for trial.
But, when I try this playerBonusHealth always returns 0. Override method does not override playerHealth. Why is that?

Thank you for helping again…

1: Abstract means that this class is used to derive classes from it and nothing else. Its an abstract sketch of what sub classes should basically look like and extend exactly this with individual features. You shall not create scriptable objects from the Buff class but only from sub buff-classes like your PlayerHealthBuff.

2: Your changes to the buff class are okay, but contain one or two very important thinking errors. You have a property called “AddedBuff” which should not exist in the base class for the buffs. The only reason the Buff type exists is to create a basis for everything your buffs have in common, not specify how they work.

If you want to have different targets to apply on, you need to create respective sub classes for those and let the targets have something in common.
For example an interface that indicates every class thats affectable by buffs.

interface IBuffTargetable<T> where T : Buff
{
   List<T> AppliedBuffs { get; }
   void ApplyBuff(T buff);
   void UnapplyBuff(T buff);
}

Now implement this interface in the MagicMeteor, MagicBall and Player class. The generic parameter needs to be filled out with the MagicBallBuff for MagicBall, MagicMeteorBuff for MagicMeteor and PlayerBuff for Player.

The Buff type needs a new overhaul as well. You need to get rid of the current Apply and Unapply methods.
The two new and simple Apply/Unapply methods should look like this:

public abstract void Apply(IBuffTargetable<Buff> target);
public abstract void Unapply();
class MagicBallBuff : Buff
{
   public MagicBall AffectedMagicBall { get; private set; }
   public override void Apply(IBuffTargetable<Buff> target)
   {
      AffectedMagicBall = (MagicBall)target;
   }
   public override void Unapply()
   {
      AffectedMagicBall = null;
   }
}

class MagicMeteorBuff
{
   public MagicMeteor AffectedMagicMeteor { get; private set; }
   public override void Apply(IBuffTargetable<Buff> target)
   {
      AffectedMagicMeteor = (MagicMeteor)target;
   }
   public override void Unapply()
   {
      AffectedMagicMeteor = null;
   }
}

class PlayerBuff
{
   public Player AffectedPlayer { get; private set; }
   // ...
}

Now that you have pretty much individualized every sub buff-class you can start creating different buffs for those. Your PlayerHealthBuff would derive from PlayerBuff and so on.

Here is the whole code piece: aB3GOM - Online C# Compiler & Debugging Tool - Ideone.com

Your last problem cannot get answered by me because I do not have the Player class code available. Please post it here so that I can review it.

Edit: By the way why is this posted in Multiplayer Networking? Your questions have nothing to do with that topic.

Thank you again, sorry for bothering you.

I posted this topic in Multiplayer Networking, because I’m trying to do a multiplayer game, and before your answers I think that this type of buff system requires SyncVar’s or some of Network methods. Sorry for that.

I created a class for holding Buff Properties and this class derived from Scriptable Object.
Here is the class : http://ideone.com/yHssEF

Then I created a list of this Buff Properties class.
Here is the class : http://ideone.com/Mouoia

And implement your codes to my Buff class.
Here is the class : http://ideone.com/e.js/W2Y19n

I created an interface IBuffable ( I couldn’t understand why you created T array in that interface so I didn’t implement it)

Now, when the player select a buff, the buff’s properties saved in BuffManager.
Here is the class : http://ideone.com/crfh2n

Then finally game starts, but I get an error when applying the buff to the player.
Error : InvalidCastException: Cannot cast from source type to destination type.

This error happened in here :

public void ApplyBuff(PlayerHealthIncreaseBuff buff)
{
buff.Apply((IBuffable)this);
}

I tried to change it PlayerBuff(of course both interface and this method), but always keep getting this error. Why is that?

Edit : After bunch of tryings I inherit the Player class from IBuffable and it worked(I can cast now). But now Unity throws nullReferenceException error in Buff class. I thinkPlayerHealthIncreaseBuff class can’t get affectedPlayer in PlayerBuff class. But I don’t understand how ? The PlayerHealthIncreaseBuff class inherited from PlayerBuff right?

Edit2 : I solved the problem finally. But I don’t know this solution is the right solution.
Solution:
In the PlayerBuff class, I change the “affectedPlayer{get; private set;}” to "affectedPlayer{get; set;} and then in PlayerHealthIncreaseBuff class, I set the affectedPlayer = (Player)target. But unfortunately I had to break “private” access modifier :frowning:

But I learned so many things trying to solve this problems with your helps. Thank you so much, I won’t forget you and your helps.

Okay take it easy there, I think right now you are continuing a feature you do not understand and try to fix it with trial and error solutions. Thats not the right way. You need to understand what your source does, there is much logically wrong with your source code and that is merely my fault.

I should not have continued to show you the solution but explain how you could have found it on your own.
Basically, the biggest object orientation topics you struggle with are inheritance and casting.
Also you need to learn how to design classes from theoretical plans and ideas, sketch members of each type to let them work how you want it but especially how to utilize them right.

Its nice to hear that you have learned much from this, but you should not further try to fix those issues because it will teach you wrong ways of solving and completing features with the object oriented paradigm. Start over and lookup every step, every word and way of implementing this feature you dont understand.
Try to see the journey to the solution as the reward, not the solution itself.

I looked over your current code bits and have to say I cannot decypher any use out of them anymore.
The BuffList is confusing, what is it for? Why save it as a Unity asset? Why is there a class called BuffProperties? By the way the “Buff”-prefix in front of every field in this type is redundant. Its called BuffProperties, sure thing only buff related members are in there.
And you have an inconsistent coding style, fields, properties and methods are written in different ways for every new type you have declared. Sometimes you use upper camel case (Use for methods and properties: SomePropertyHere), sometimes lower camel case (Use for fields and local variables: someFieldHere). I recommend the Microsoft Coding Conventions for C#.

The sense of the ApplyBuff method is to accept all buffs that inherit from PlayerBuff but leave it completely to the caller which PlayerBuff sub-class is put as an argument here. Using PlayerHealthIncreaseBuff as the declaring parameter-type eradicates this option as only exactly this class and ones that are derived from it (hopefully none) can then be used there.

Also you want to put a *SerializeField-*attribute above the private fields in your Buff sub-classes so that you can edit them in the Unity inspector. Simply click on the created scriptable object blueprint in the project view in which all your assets are located and see all the fields Unity could fetch to show them on there.

Everything I learned about C# and Unity, I learned by myself. I don’t want(or ask) anyone to give me code. I know that I don’t fully understand every aspect of OOP, but when I post this question I’m not aware of “What is OOP?”, what is “abstract” classes, what is “overriding” etc. and now at least I know what these kind of things is. And I want to keep improving myself of this subjects.

Ok, show me the path and I will definitely follow this path. I’m fully open to learning. I don’t hesitate studying.

BuffList holds the all buffs I have and save it. So, I show this buffs to the player in the beggining of the game.
I’m aware that saving that as a Unity Asset is not the right thing and I will change it.
Because I want to create Buffs easily in the editor.
Basically I want to keep all my buffs into one file. And in the game, when the Buff Selection Scene is open, I want to list all buffs to the player.
Ok, I understand what you mean and I will look this guide.

I understand the sense of the ApplyBuff method and I wanted to use it that way. But when I use this I get a cast error. Why I’m getting cast error.
IBuffable where T: Buff → Is this means that you can only use Buff class or classes that derives from Buff class? So,in our case the generic type T can be either Buff, PlayerBuff(or the others) or PlayerHealthIncreaseBuff(or the others), right? Otherwise, we can write this interface like IBuffable.

Oh, I understand, when I do this I don’t have to do what I did in Edit2.

Thank you again man, you are the best…

As you already wrote above, thats your job and I can only guide you which I think I did enough in the last days.

You should not care about how Unity manages the asset files. All you do is creating buffs from scriptable objects and retrieving them again. Define a new MonoBehaviour that contains an array with all buffs available to pick and splitted into players, magic balls and magic meteors. In the inspector you can drag all buffs in their respective arrays and access those collections from the UI. Then instantiate the referenced blueprints you just dragged into the inspector and you can use/apply them after the player selected the ones he wanted to choose.

Correct, but Buff and PlayerBuff are abstract classes (at least should be) so you cannot practically use them there.

I hope that was enough help and I am stopping here to let you find the solution by yourself, sometimes trying out one way after another is best but only if you understand how and why it doesnt work. Good luck.