- Home /
Accessing a Script's Sub-Class's Variables from another Script
Total newbie here, so please excuse my incompetence; I'm currently making a game that has 3 playable characters, each with stats such as HP, Attack and Defense. To try and keep things organized I thought I'd make one Script (called "charStatManager") and create sub-classes within it for each character to store their stat variables, that way I'd only have to reference "charStatManager" in other scripts when I need to access each characters' stats:
public class charStatManager : MonoBehaviour {
public class Tom {
private int hitPoints = 50;
public int HitPoints {
get { return hitPoints; }
set { hitPoints = value; }
}
public int attackVal = 10;
public int defenseVal = 10;
}
public class Dick {
private int hitPoints = 50;
public int HitPoints {
get { return hitPoints; }
set { hitPoints = value; }
}
public int attackVal = 10;
public int defenseVal = 10;
}
public class Harry {
private int hitPoints = 50;
public int HitPoints {
get { return hitPoints; }
set { hitPoints = value; }
}
public int attackVal = 10;
public int defenseVal = 10;
}
}
What I'm trying to figure out now is how to access the variables contained in each character's sub-class when referencing the "charStatManager" script from other scripts. I've attempted the following method to access the sub-class variables (Stats Manager (period) Character (period) Stat) but keep getting an error, and my searches for a solution have come up short:
public class AddHealthAndDisplayStrength : MonoBehavior {
private charStatManager charStats;
void Start () {
charStats = FindObjectOfType<charStatManager>();
}
void Update () {
charStats.Tom.HitPoints += 10;
tomAttackText.text = charStats.Tom.attackVal;
tomDefenseText.text = charStats.Tom.defenseVal;
charStats.Dick.HitPoints += 10;
dickAttackText.text = charStats.Dick.attackVal;
dickDefenseText.text = charStats.Dick.defenseVal;
charStats.Harry.HitPoints += 10;
harryAttackText.text = charStats.Harry.attackVal;
harryDefenseText.text = charStats.Harry.defenseVal;
}
}
And the error I get is...
Cannot reference a type through an expression; try 'charStatManager.Tom' instead
Is there a way to access a Script's sub-class's variables so that they can be altered? Would I be better off making individual Script files for each character instead? Is there a better way other than Sub-classes to organize multi-character information like this? (I've read about Lists and Dictionaries but couldn't grasp them right away, at least in the context I'm trying here.) Again, total newbie, so I welcome constructive criticism with open arms. Thank you in advance :)
First of all: Do the three characters all have the same characteristics or are there still individual ones added? This is important to answer your question meaningfully
Yes, all characters have the same exact same characteristics: HP, max HP, Attack and Defense.
Answer by UnityCoach · Jul 26, 2018 at 01:17 AM
Ok, let's try to explain this simply...
A subclass is a class, nested in another class for the sake of cleanliness. What you are trying to do here, is to have a class that references sub-class instances, but you are declaring them sub classes. A) it's not necessary and confusing B) class definitions don't instantiate automatically
So,
public class CharacterStatManager : MonoBehaviour
{
[System.Serializable] // make this serialisable if you want to save or edit this in the inspector
public class Character
{
public string name;
private int hitPoints = 50; // default value
public int HitPoints
{
get { return hitPoints; }
set { hitPoints = value; }
}
public int attackVal = 10; // default value
public int defenseVal = 10; // default value
public Character (string name, int hitPoints, int attackVal, int defenseVal) // class constructor
{
this.name = name;
this.hitPoints = hitPoints;
this.attackVal = attackVal;
this.defenseVal = defenseVal;
}
}
// this array of Character classes will store the data
// and will be accessible from other classes
// as characterStatManager.characters[x].hitPoints, etc..
// you could also store it as a List, or Dictionary using names for keys
public Character [] characters = new Character []
{
new Character ("Tom", 50, 10, 10),
new Character ("Dick", 50, 10, 10),
new Character ("Harry", 50, 10, 10)
}
}
or
List<Character> characters = new List<Character>();
characters.Add (new Character (("$$anonymous$$", 50, 10, 10)));
characters.Add (new Character (("Dick", 50, 10, 10)));
characters.Add (new Character (("Harry", 50, 10, 10)));
or
Dictionary<string, Character> characters = new Dictionary<string, Character>();
characters.Add ("$$anonymous$$", new Character (("$$anonymous$$", 50, 10, 10)));
characters.Add ("Dick", new Character (("Dick", 50, 10, 10)));
characters.Add ("Harry", new Character (("Harry", 50, 10, 10)));
This method actually works beautifully, and the Array/List is perfect for accessing and altering character stats from other scripts. Thanks!
Answer by Imanob · Jul 26, 2018 at 01:11 AM
Does charStatManager have any need to inherit from MonoBehaviour? From this piece of code it seems like there's no need, so you can change it to
public class charStatManager {
...
And initialize charStatManager in AddHealthAndDisplayStrength as
charStatManager charStats = new charStatManager();
And the rest should be fine.
Or you can just do as the error message says; change charStats.Tom.attackVal to
charStatManager.Tom.attackVal
and the rest accordingly. I'd see if the first option worked first, though.
I'm no pro at this, but these might get you somewhere
I tried taking out $$anonymous$$onoBehaviour from charStat$$anonymous$$anager but since I have another script that references charStat$$anonymous$$anager using FindObjectOfType(); (I have an empty Game Object in the scene with charStat$$anonymous$$anager attached to it) I got an error message.
And ironically enough, when I do as the error message says and change "charStats.$$anonymous$$.attackVal"to "charStat$$anonymous$$anager.$$anonymous$$.attackVal" I get another error message stating that "An object reference is required to access non-static member 'charStat$$anonymous$$anager.$$anonymous$$.attackVal"
Answer by Kaskorian · Jul 26, 2018 at 01:22 AM
Either way, I would advise against your approach, especially because you say that there will be no differences between the stats of each character.
There are two possible ways in my opinion
First option: All characters are equal
public class CharacterControl : MonoBehaviour
{
public List<Character> characters = new List<Character>() { new Character("Tom"), new Character("Dick"), new Character("Harry") };
}
public class Character
{
private string name { get; set; }
public string Name { get { return name; } }
private int hitPoints = 50;
public int HitPoints
{
get { return hitPoints; }
set { hitPoints = value; }
}
public int attackVal = 10;
public int defenseVal = 10;
public Character(string name)
{
this.name = name;
}
}
Second option: The characters will get individual characteristics in the future
you can create a C# Script in which you define all your different charaters
public class Character
{
private int hitPoints = 50;
public int HitPoints
{
get { return hitPoints; }
set { hitPoints = value; }
}
public int attackVal = 10;
public int defenseVal = 10;
public Character()
{
}
}
public class Tom : Character
{
///
/// special attributes
///
}
public class Dick : Character
{
///
/// special attributes
///
}
public class Harry : Character
{
///
/// special attributes
///
}
CharacterControl:
public class CharacterControl : MonoBehaviour
{
public List<Character> characters = new List<Character>() { new Tom(), new Dick(), new Harry() };
}
In addition, I would always recommend you to use individual scripts for individual classes. One exception is the listing of characters in option two (because none of the classes inherit from MonoBehavior, the script does not have to be named like the classes, you can call it quite simple Characters). If you use sub classes, then only if it has decisive benefit for the class in which you create them.
LG Kasko ;)