Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

[Tutorial] Character Stats (aka Attributes) System

Discussion in 'Community Learning & Teaching' started by Kryzarel, Nov 11, 2017.

  1. PimpPanda

    PimpPanda

    Joined:
    Jun 4, 2021
    Posts:
    2
    Hello.
    I know this is a very old post but, I would like to know if there is a way to modify the base value of a stat by calling a method like level up?
     
  2. akduy

    akduy

    Joined:
    Dec 31, 2016
    Posts:
    3
    I must log in to like this post. Thank you very much for your effort!
     
  3. Duffer123

    Duffer123

    Joined:
    May 24, 2015
    Posts:
    1,215
    @Kryzarel ,

    Hi there. Been using a version of your CharacterStats and StatModifier code for years now and to great effect and so thank you very much. I was wondering about say CharacterStats in a c# List collection effecting others depending on their value. Specifically I was wondering about the very useful remove all stat modifiers functionality - but where the modifiers are coming from an element in a List as opposed to coming from a specific class? Will/can the 'object' be the element in the c# List as opposed to the class housing this List and the element within it? How best to implement that?

    If you are about on these forums still, could do with a sentence or two from you with your thoughts on that?
     
  4. Dorscherl

    Dorscherl

    Joined:
    May 29, 2017
    Posts:
    26
    Referring back to this post and I'm curious if you ever flushed this out. Would be interested in seeing your proposed system.
     
  5. Nixellion

    Nixellion

    Joined:
    Jun 17, 2015
    Posts:
    7
    What I am curious about is how to make the system more dynamic. Currently stats have no way to clearly identify them by name or id or something, making it so that for a lot of use cases things like "case" have to be used. Meaning that adding new stats becomes more and more complicated as the project grows, as every script that has anything to do with stats, like say showing a different pop-up message whenever any class is modified, gets quite tedious. Stats dont even have a name property attached to them.

    I'm currently thinking about how I could modify the system to allow adding classes easily, either by editing 1 single 'list' of names, or through additional scriptable objects... Ideally I would like to keep the "CharacterStats.health" kind of accessor, even though turning all that into a single dict would be easier.

    Wonder if anyone tackled this?
     
  6. vNtzY

    vNtzY

    Joined:
    Oct 12, 2020
    Posts:
    1
    Hello,
    I just wanted to thank you for this Stat System of yours. It has most of the things I needed and it can be easily expanded upon.
    Hope you're doing good these days,
    Cheers
     
  7. Adeladen

    Adeladen

    Joined:
    Dec 13, 2019
    Posts:
    1
    Last edited: May 24, 2022
  8. AFlamel

    AFlamel

    Joined:
    May 20, 2021
    Posts:
    15
    I found the post much more informative than the video, or rather that the information registered a lot better when I read it than when I watched the video. I'm gonna read this again to try to get my brain to grasp he techniques used, but I am very impressed.
    -----------
    Alright goofed around with this and tried to make an SO that worked with it. The first Challenge was getting this to work with enum, I realized it was above my pay grade and thus a waste of time so I simply made each attribute.

    In the case of Heatlh, I made two attributes, Health and HealthMax.

    Then I made a function and dropped it in the AddModifier function so whenever it adds a modifier it will check if the Health.Value is greater than the HealthMax.Value and if so it will add a modifier doing a subtraction of the difference to get Health back to MaxHealth.Value.

    Then if the Health is less than or equal to MaxHealth it will remove the Modifier.

    Overall for less dynamic attributes this system is easy enough to understand and apply, but for stuff that changes a lot and has a max value it's a bit tricky.
     
    Last edited: Jul 3, 2022
  9. Eddie21uk

    Eddie21uk

    Joined:
    May 24, 2017
    Posts:
    3
    Hi all for all those who a wanting to convert the health/vitality values to a slider and updates as items are take on and off:
    This is what i did:

    public class Character: MonoBehaviour

    public int currentHealth = 30; // set out your starting health
    public CharacterStat Health;

    [SerializeField]
    public int maxHealth; // set a value i did 100

    public void Update()
    {
    maxHealth = (int)Health.Value;

    uIbarScripts.SetHealth(currentHealth); // this is for current health the player has.
    uIbarScripts.SetMaxHealth(maxHealth); // this is for the max health the player has.

    }

    In your UI bar Script:

    public Slider Healthslider;

    public void SetHealth(int currentHealth)
    {
    HealthSlider.value = currentHealth;
    }
    public void SetMaxHealth(int maxHealth)
    {
    HealthSlider.maxValue = MaxHealth;
    }
     
  10. Eddie21uk

    Eddie21uk

    Joined:
    May 24, 2017
    Posts:
    3
    Hi,

    I have noticed a but in crafting:
    If you equip one item( example the dagger) and you need 2 of the same (daggers) to craft a sword.
    When you press the craft the button the system doesnt like it and crashed out.
    Any ideas?

    I resolved the issue after comparing my version with the downloadable:
    Item scriptableObject and EquipableItem scriptableObject cant mix.
    I noticed that with the coin you used Item so may need to change it to EquipableItem.
     
    Last edited: Jul 21, 2022
  11. shanecelis

    shanecelis

    Joined:
    Mar 26, 2014
    Posts:
    22
    Thank you, Kryzarel, for CharacterStats. Your articles, videos, and code have been very informative. I would not have thought as hard about this space without them. I've been pining away on an attribute design that deals with a few difficulties in this space. It's generically typed, notifies on changes, and allows one to reuse attributes as modifiers. Here is an example that addresses AFlamel's issue:

    Code (CSharp):
    1. var maxHealth = new ModifiableValue<float> { baseValue = 100f };
    2. var health = ModifiableValue.FromValue(maxHealth);
    3. var damage = Modifier.Subtract(0f);
    4.  
    5. health.modifiers.Add(damage);
    6. health.PropertyChanged += (_, _) => Console.WriteLine($"Health is {health.value}/{maxHealth.value}.");
    7. health.modifiers.Add(priority: 100, Modifier.FromFunc((float x) => Math.Clamp(x, 0, maxHealth.value));
    8. // Prints: Health is 100/100.
    9. damage.value = 10f;
    10. // Prints: Health is 90/100.
    11. maxHealth.modifier.Add(Modifier.Plus(20f, "+20 max health"));
    12. // Prints: Health is 110/120.
    It's called SeawispHunter.RolePlay.Attributes and it's available under an MIT license.
     
  12. ckamarga

    ckamarga

    Joined:
    Aug 31, 2013
    Posts:
    15
    Hi,

    I just found this and it looks like a great system for dealing with stats and one or more modifiers but I don't understand how you use it.

    You mentioned that this script will not be attached to a game object so how does it work exactly?
     
  13. shanecelis

    shanecelis

    Joined:
    Mar 26, 2014
    Posts:
    22
    Sure. You can use the
    ModifiableValue
    in your
    MonoBehaviour
    . Its base value will be editable in the inspector just like a regular value.

    Code (CSharp):
    1. public class Character : MonoBehaviour {
    2.   public ModifiableValue<int> strength = new ModifiableValue<float>(10);
    3.   public ModifiableValue<int> constitution = new ModifiableValue<int>(5);
    4.   // ...
    5. }
    6.  
    I have samples available on this branch that show how you might use it in a more complete example.
     
  14. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    4,013
    Thanks for sharing this! Not sure if that was mentioned elsewhere, but I feel this StatModType enum idea is going in the wrong direction and needlessly complicates the code with the order value.

    Rather than attributing values as absolute, percent and additive, my preferred solution would be to split those three into separate "pipelines" and sum them up independently, then use them in the final calculation.

    What I imagine and have experienced as the better approach (I worked on RPGs 15-20 years ago) is this:

    Calculate flat value as:
    Code (CSharp):
    1. var flatValue = BaseValue;
    2. foreach (var offset in BaseValueOffsets)
    3.     flatValue += offset; // can be positive or negative, order irrelevant
    Sum up percent modifiers:
    Code (CSharp):
    1. var modifiers = BaseModifier;
    2. foreach (var mod in AdditiveModifiers)
    3.     modifiers += mod; // can be positive or negative, order irrelevant
    Then sum up the multipliers (for things like "critical damage" or considering an opponent's weaknesses / resistances / armor):
    Code (CSharp):
    1. var multipliers = BaseMultiplier;
    2. foreach (var mul in MultiplierModifiers)
    3.     multipliers += mul; // can be positive or negative, order irrelevant
    Finally, you can calculate the final value as simply as this:
    Code (CSharp):
    1. var finalValue = flatValue * modifiers * multipliers;
    You don't need any kind of ordering. That bothers me with the current design, as it makes the code needlessly complicated for no discernable benefit. Almost all RPG stats are calculated as the sum of their constituents in the above order:

    (sum of values) times (sum of percentages) times (sum of bonus/malus)

    This can be extended with any other kind of bonus/malus, for example a separate multiplier for armors vs weapon type, spell type vs resistances, passive effects (buffs, debuffs). In the end, it's just more multipliers summed up individually with 1f as the default multiplier.
     
    Last edited: Aug 26, 2023
    hopeful likes this.
  15. SuperFranTV

    SuperFranTV

    Joined:
    Oct 18, 2015
    Posts:
    140
    I use this stat system to describe the stats of an item, now I want to integrate an event system, add interactions like eating an apple or using a buildable item. Do you have any tips on what would be the best practice to do this?