Stats 04: Scalable

In this section, we’ll be creating a new stat class named RPGAttribute along with another interface named IStatScalable. The attribute stat will inherit from the RPGStatModifiable class and implement the new IStatScalable interface. This new interface will contain the method used to scale the value of the stat by another value such as a character’s level.

This post is an old implementation and should be only used as a reference. This post maybe updated or replaced in the future.

Scalable Interface

The IStatScalable interface will only contain one method, which will take in an int. The parameter in this instance will be the character’s level.

public interface IStatScalable {
    void ScaleStat(int level);
}

Attribute Stat

Below we will implement the IStatScalable into the new RPGAttribute class. The attribute class later on will have additional features, but for now we’ll only implement the scalable interface.

using System.Collections.Generic;
public class RPGAttribute : RPGStatModifiable, IStatScalable {
    private int _statLevelValue;
    
    public int StatLevelValue {
        get { return _statLevelValue; }
    }

    public override int StatBaseValue {
        get { return base.StatBaseValue + StatLevelValue; }
    }

    public virtual void ScaleStat(int level) {
        _statLevelValue = level;
    }
}

In the Attribute class we make the ScalStat method virtual to allow classes inheriting from the class to be able to define how the new stats will scale with the given level.

In addition we make a new property called StatLevelValue which will be the value gained from scaling the stat. This new level value will need to be added into the base value of the stat to create the new value of the StatBaseValue property.

Additional Stats

public enum RPGStatType {
    None = 0,
    Health = 1,
    Mana = 2,

    Stamina = 10,
    Wisdom = 11,
}

We add two additional stats, Stamina and Wisdom. In an example game these two stats will be scaled based of the character’s level, while the Health and Mana values do not. (Health and Mana in the future will change based off the value of other stats. We’ll add this feature later on)

Updating the Default Stats

Next we update the Default Stats collection to create the Stamina and Wisdom stat, both of which will use the new RPGAttribute class.

public class RPGDefaultStats : RPGStatCollection {
    protected override void ConfigureStats() {
        var health = CreateOrGetStat<RPGStatModifier>(RPGStatType.Health);
        health.StatName = "Health";
        health.StatBaseValue = 100;

        var mana = CreateOrGetStat<RPGStat>(RPGStatType.Mana);
        mana.StatName = "Mana";
        mana.StatBaseValue = 2000;

        var stamina = CreateOrGetStat<RPGAttribute>(RPGStatType.Stamina);
        stamina.StatName = "Stamina";
        stamina.StatBaseValue = 10;

        var wisdom = CreateOrGetStat<RPGAttribute>(RPGStatType.Wisdom);
        wisdom.StatName = "Wisdom";
        wisdom.StatBaseValue = 5;
    }
}

Testing Scalable Stats

Finally we test the scalable attributes below.

public class RPGStatTest : MonoBehaviour {
    private RPGStatCollection stats;

    void Start () {
        stats = new RPGDefaultStats();

        DisplayStatValues();

        var stamina = stats.GetStat<RPGAttribute>(RPGStatType.Stamina);
        stamina.ScaleStat(16);

        DisplayStatValues();
    }

    void ForEachEnum<T>(Action<T> action) {
        if (action != null) {
            var statTypes = Enum.GetValues(typeof(T));
            foreach (var statType in statTypes) {
                action((T)statType);
            }
        }
    }

    void DisplayStatValues() {
        ForEachEnum<RPGStatType>((statType) => {
            RPGStat stat = stats.GetStat((RPGStatType)statType);
            if (stat != null) {
                Debug.Log(string.Format("Stat {0}’s value is {1}",
                stat.StatName, stat.StatValue));
            }
        });
    }
}

Interface Checking

When working with a collection of classes, which is made up of classes that may or may not implement a given interface there is a simple method that you can use to check if the interface is implemented. Below is an example of taking the Stamina stat from the collection casted to the base class RPGStat and then we check if the stat implements the IStatScalable interface.

var stamina = stats.GetStat<RPGStat>(RPGStatType.Stamina);

IStatScalable statScalable = stamina as IStatScalable;

if(statScalable != null) {
    statScalable.ScaleStat(16);
}

Leave a Reply

Your email address will not be published. Required fields are marked *