Problems with shared variables and classes

Hello.

I’ve been dealing with this issue for, who knows how long, and i’m getting really tired of it.
Anyway, i’m building the AI for an enemy and I want to it react in certain ways when their HP is higher or lower than x. The thing is that the HP of my enemy is a variable of a class that is being shared with the script that i’m using right now and another one. The script that has the reaction based on the enemy’s HP(the one below) must call the class to get their information, but doing this causes the issue! Having the information also means being able to manipulate the HP values from this script since the two scripts are sharing the class, which is something I don’t want! Let me show you the script:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class Dog : Base_Class {

public Base_Enemy enemy;

public void UsedMove()
{

if ((enemy.curHP / enemy.baseHP) * 100 >= 20.0f)
{
Debug.Log(“HP is above 20%.”);
}
else if ((enemy.curHP / enemy.baseHP) * 100 <= 20.0f)
{
Debug.Log(“HP is under 20%.”);
}
else if(enemy.curHP < 1) // Test
{
Debug.Log(“Works, even though I don’t want it to. :(”);
}
}

}

enemy.curHP is supposed to be the variable in the class. How do I make it possible for enemy.curHP to ignore the curHP in THIS script and only check for those in the other script?
Btw, the last if statement is the one that works because, as I said, the values are reset and all set to 0 in this script.
I know this sounds a bit confusing, English isn’t my first Language, but that was pretty clear, haha.
If there’s more information you, please let me know! Thank you.

I’m not entirely sure I fully understand what you’re asking. Basically you want to be able to get the HP value without being able to modify it?

If so, then you probably want to use a property like so:

public int CurrentHP {get; private set;}

This means you can get the value of CurrentHP, but you can’t set it from another script, because it’s private to the script it’s in. Only the script it’s in can change it.

If you want to expose this in the inspector, then do something like this instead:

[SerializeField] 
private int _currentHP; 

public int CurrentHP { get {return _currentHP; }}

The [SerializeField] attribute exposes the HP value in the inspector, but it’s still kept private.

2 Likes

Mmm… No, that’s not exactly what i’m trying to do. Also, I think it’s giving me some errors. :frowning: (Probably my fault, my scripts are messy as hell)

Maybe if I say it like it’ll make more sense…

I’d like for my class to have variables that have sharables values. For example, if my enemy script has currently 30 HP left after receiving 10 damage, I want my enemy AI script to know that, so my enemy can react in some way.

But what is happening right now is that the 2 scripts both have the variables, but not with shared values. So, if my enemy is left with 30 HP after receivng 10 damges, my enemy AI script doesn’t care because it has its own values( which is 0 right now, I didn’t touch them)

My explanations are terrible and this issue is even worse, i’m sorry. xD

No worries! I think I’m beginning to understand what you’re asking. It sounds like you want an event.

Basically if the HP changes, you want the AI to know about it (as well as the UI so it can update with the new value, and so on…)

Here’s a very simple example (and I’m typing this off the top of my head since I’m on mobile and don’t have a compiler nearby, so…)

public class Enemy
{
    public event Action<int> OnHealthChanged = delegate{};

    private int _health;
    public int Health 
    { 
        get { return _health; } 
        set { _health = value; OnHealthChanged(_health); }
    }
}

public class EnemyAI : MonoBehaviour
{
    public Enemy EnemyData;

    private void Start()
    {
        EnemyData = ... // whatever code is required to get the enemy instance goes here
        EnemyData.OnHealthChanged += OnEnemyHealthChanged;
    }

    private void OnEnemyHealthChanged(int newHealth)
    {
        // do something, change state, whatever...
    }
}

public class EnemyUI : MonoBehaviour
{
    public Text HealthLabel; 
    public Enemy EnemyData; 

    private void Start()
    {
        EnemyData = ... // whatever code is required to get the enemy instance goes here
        EnemyData.OnHealthChanged += OnEnemyHealthChanged;
    }

    private void OnEnemyHealthChanged(int newHealth)
    {
        HealthLabel.text = "HP: " + newHealth;
    }
}

So basically you have the AI and UI add a listener to the Enemy so that it gets called when the Health value changes. You can have anything else also add their own listeners, etc. This keeps your enemy data structure clean and contain no logic it shouldn’t know about.

1 Like

I didn’t know about the existence of delegates! I’ll have to check them out. Thank very much for the help.

1 Like