Class.Set; does not fire functions

I already asked that one some time back, but because I mingled with code, and it changed couple times, and the answer is for the old answers and everything essentially went off the hook. I really feel the need to start that one over, I’m sorry for inconvenience. The original talk can be found here , although I’ve forsaken it. Do not use it as reference of context. Context and nuance of question have been altered.

What I attempt at creating in this tiny demo is a system, in which user can select an in-game character (one of many), and then have things like HP bar automatically adjusted in a GUI screen (when character is damaged). For this I choose to create a List<> with users, based off a class, and a single variable based off the same class. Every time user clicks on a player, it will assign that particular human to that single variable. Every time this human loses health (due to nature of classes), it will update it both in variable containing all users, as well as this single variable. I want to watch out every time the single variable is modified, so I can trigger certain functions that will allow UI adjustment, if health of a selected human changes, UI will receive signal and resize the bar and change color accordingly. Now here’s the code (simple tech demo):

PlayerMaster, which will assign and invoke GUI functions

public class PLAYERMASTER : SerializedMonoBehaviour {

    // I 1000000% set this in Inspector
    public PLAYERINDICATOR indicator;

    public class PlayerClass {
        public string name;
        public float health;
    }

    private PlayerClass _taggedPlayer;
    public PlayerClass taggedPlayer {
        get { return _taggedPlayer; }
        set {
            print("taggedPlayer+set triggered. HP: " + value.health);
            _taggedPlayer = value;
            indicator.UpdateHealth(value.health);
        }
    }

    public List<PlayerClass> listOfAllPlayer;

    private void Awake() {
        listOfAllPlayer.Add(new PlayerClass { name = "Robbie", health = 325.0f });
        listOfAllPlayer.Add(new PlayerClass { name = "Dirk", health = 500.0f });

        taggedPlayer = listOfAllPlayer[1];
    }

    [Button("Remove Health", ButtonSizes.Medium)]
    void _x_() {
        taggedPlayer.health -= 11.0f;
    }

}

PlayerIndicator:

public class PLAYERINDICATOR : MonoBehaviour {

    public float health;

    public void UpdateHealth(float hp) {
        print("UpdateHealth() triggered: " + hp);
        this.health = hp;
    }

}

In aforementioned (old) thread, following has been mentioned:

So with that all out of the way. How would I make it work? How do I trigger it when the object it references gets altered, or otherwise, how would I get it to work in more or less same schematics.

Note: Due to game/application context in which it will be used, I cannot have PlayerMaster’s functions (not accessors) directly invoke PlayerIndicator’s functions (not accessors). I really need that particular selected player put in that public PlayerClass taggedPlayer, no way around that. (Unless there’s a logical solution that I don’t know of, which does work and does what I need).

I hope that I’ve written big enough of an essay that one wouldn’t be able to confuse of what my intent is.

PS: No errors. The only debug logs I get (once each) is:

taggedPlayer+set triggered. HP: 500
UnityEngine.DebugLogHandler:LogFormat(LogType, Object, String, Object[])

and:

UpdateHealth() triggered: 500
UnityEngine.DebugLogHandler:LogFormat(LogType, Object, String, Object[])

If I understand your use case, what you want is the basic delegate subscription pattern.

You want a data object to which various systems can subscribe in order to be notified when things change.

If you look in my Datasacks project, it uses this pattern EVERYWHERE. Datasacks are my lightweight data objects to which anybody can subscribe, including elements that drive the Unity UI, accept input from the Unity UI, or even any piece of code anywhere.

Datasacks is presently hosted at these locations:

https://bitbucket.org/kurtdekker/datasacks

Basically every monobehavior subscribes/unsubscribes in its OnEnable() and OnDisable() functions. Here’s sort of a broad system overview, but the part that’s interesting to you is going to be the various OnChanged delegates and their listeners.

Sorry, I am just guessing at what you want here:

If all you want is for UpdateHealth to be called whenever health changes, the first thing I would recommend you do is make the field health private. As a rule of thumb, classes should be solely responsible for manipulating their data. Instead of accessing the field health directly, you would change it’s value via a function, which allows you to do things when you modify the value.

That way, the only way you can change health is from UpdateHealth.

For example, something along the lines of:

public class PLAYERINDICATOR : MonoBehaviour {
    private float health;
    public void UpdateHealth(float hp) {
        print("UpdateHealth() triggered: " + hp);
        this.health = hp;
    }

   public float GetHealth()
   {
      return health;
   }
}
    [Button("Remove Health", ButtonSizes.Medium)]
    void _x_() {
        taggedPlayer.UpdateHealth(taggedPlayer.GetHealth() - 11f);
    }

I don’t understand what you mean. taggedPlayer is a variable, not MonoBehavior class.
This doesn’t update HP in PlayerIndicator, your code, simply edits the value in PlayerMaster.

Upon update of variable in PlayerMaster.taggedPlayer, I want it to trigger PlayerIndicator.UpdateHealth(value); which is referenced as indicator.UpdateHealth(value);.

Could you not just add a call to indicator.UpdateHealth(value); in function x()?

    void _x_() {
        taggedPlayer.health -= 11.0f;
        indicator.UpdateHealth(taggedPlayer.health);
    }

I would have to work around it a little bit, but I could check whether player is “the one” and then update the health. Nonetheless I’m still confused on why my code didn’t work, why it didn’t trigger. _x_(); is only a simulation of being hit with a bullet.