RPGSystems: Stat System 06: RPGVital

In this tutorial, we’ll be creating the new RPGVital stat class that will be inheriting from the RPGAttribute class. The key addition to the vital stat that makes it important is that it contains an additional variable that will keep track of the current value of the stat. This comes in to play for stats such as Health, Mana, or Energy that have a current value that usually range from 0 to the max value of the stat. (In our case the max value of the stat will be RPGStat.StatValue)

RPGVital

using System;
using UnityEngine;
public class RPGVital : RPGAttribute {
	private int _statCurrentValue;
	
	public int StatCurrentValue {
		get {
			if(_statCurrentValue > StatValue) {
				_statCurrentValue = StatValue;
			} else if(_statCurrentValue < 0) {
				_statCurrentValue = 0;
			}
			return _valueCurrent = _statCurrentValue;
		}
		set {
			_statCurrentValue = value;
		}
	}
	
	public RPGVital() {
		_valueCurrent = 0;
	}
	
	public void SetValueCurrentToMax() {
        StatValueCurrent = StatValue;
    }
}

The RPGVital is a simple class that will mostly contain just the private variable to store the current value of the stat. The key element of the class is the property that lets us set and get the current value along with automatically restricting its value between 0 and the StatValue. The SetCurrentValueToMax method is to allow for a quick means to max out the current value.

Note* Changing when the current value is restricted will change how the vital’s current value behaves and can result in an undesirable affect. For example: if the restricting of the current value was in the Setter and we then set the current value to an example value of 80, then the StatValue was reduced below 80. The next time we would access the current value, it’s value would be above the StatValue and would not be correctly restricted until we used the Setter.

Adding Events

The next addition to our RPGVital class will be to create an event that other scripts can subscribe to. This will allow other scripts to be notified when the event is trigger, and our stat’s value is changed.

The following will be added to the RPGVital class.

	public event EventHandler OnCurrentValueChange;

The EventHandler is a premade delegate supplied to use within the System namespace (Must add ‘using System;’ to the top of the script). This event delegate allows any function that follows its defined function signature to listen to the event(Example Signature: void Foo(object sender, EventArgs e)).

	private void TriggerCurrentValueChange() {
        if (OnCurrentValueChange != null) {
            OnCurrentValueChange(this, null);
        }
    }

The TriggerCurrentValueChange method will do important tasks. It will both trigger the OnCurrentValueChange event with the correct parameters, and it will Check if the event is currently being subscribed to by other objects.

Note* To check if an event has a subscriber, simple check if the event is not null.

We want to trigger this event only when the current value changes. Change the Setter of the StatCurrentValue property to the following

	set {
		if (_valueCurrent != value) {
			_valueCurrent = value;
			TriggerCurrentValueChange();
		}
	}

This code add a small check to see if the value has changed. If the value changed we will update the current value, then trigger the event to notify that the current value of the stat has changed.

Testing

using UnityEngine;
using System.Collections;
using System;

public class RPGVitalTest : MonoBehaviour {
    public RPGStatCollection stats;

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

        var health = stats.GetStat<RPGVital>(RPGStatType.Health);
        health.OnCurrentValueChange += OnStatValueChange;

        DisplayStatValues();

        stats.GetStat<RPGAttribute>(RPGStatType.Stamina).ScaleStat(5);

        DisplayStatValues();
	}

    void OnStatValueChange(object sender, EventArgs e) {
        RPGVital vital = (RPGVital)sender;
        if (vital != null) {
            Debug.Log(string.Format("Vital {0}'s OnStatValueChange event triggered", vital.StatName));
            vital.StatCurrentValue = vital.StatValue;
        }
    }

    void DisplayStatValues() {
        ForEachEnum<RPGStatType>((statType) => {
            RPGVital stat = stats.GetStat<RPGVital>((RPGStatType)statType);
            if (stat != null) {
                Debug.Log(string.Format("Stat {0}'s value is {1}/{2}",
                    stat.StatName, stat.StatCurrentValue, stat.StatValue));
            }
        });
    }
	
	void ForEachEnum<T>(Action<T> action) {
        if (action != null) {
            var statTypes = Enum.GetValues(typeof(T));
            foreach (var statType in statTypes) {
                action((T)statType);
            }
        }
    }
}

Our testing code does has two important parts. The first is how we are subscribing to the OnCurrentValueChange event.

		var health = stats.GetStat<RPGVital>(RPGStatType.Health);
        health.OnCurrentValueChange += OnStatValueChange;

We use the += operator to add a method to event. In order to unsubscribe from the event we simply need to use the same line of code, but substitute the -= operator.

The Next feature of the Test class is the following method:

	void OnStatValueChange(object sender, EventArgs e) {
        RPGVital vital = (RPGVital)sender;
        if (vital != null) {
            Debug.Log(string.Format("Vital {0}'s OnStatValueChange event triggered", vital.StatName));
            vital.StatCurrentValue = vital.StatValue;
        }
    }

This method will be called from the vital class everytime the current value of the class changes. The object sender parameter of the method is the RPGVital that had its current value changed, and will need to be typecast from an object back to a RPGVital. For now the EventArgs parameter is not used and will be null. Later on we can create our own EventArgs and pass additional data to give the subscriber additional details.

Helpful Reads


Microsoft Documentation: EventHandler Delegate
Microsoft Documentation: Events Tutorial
Event Implementation Fundamentals

Github Repository

https://github.com/jkpenner/RPGSystemTutorial

Leave a comment