I come from Java and I'm picking up C# scripting, I've had this issue for around two days now looking for solutions, I've tried setting the class to an instance and everything. This is for a miniature game project that I am working on with some friends.
Either way, I have StatHandler.cs which handles all of our statpoints... then I have HealthManager.cs which is supposed to handle all of the Health Related stuff.
The problem is, I can't for the life of me figure out how to call the variables such as
public int stamina, strength, agility, dexterity, wisdom;
from StatHandler.cs
I know that in Java it would be as easy as
maxHealth = StatHandler.stamina * 10;
Although, you cannot do that with C#, when creating an instance the code looks like this
maxHealth = StatHandler.instance.stamina * 10;
which provides me with the error
NullReferenceException: Object reference not set to an instance of an object
I've also tried inherriting, by doing this
public class HealthHandler : StatHandler {
but it sets all the values to 0 in the HealthHandler class, it doesn't read anything.
I really just need to figure out how to pull the variable from the other C# files, because this is slowing me way down.
It's actually same as in Java. For non-static variables you need a class instance:
StatHandler sh = new StatHandler();
maxHealth = sh.stamina * 10;
or you can declare variables as static in the class like
public static string stamina = 10;
and then access it
maxHealth = StatHandler.stamina * 10;
In C#, you can't use a value type variable without initialize it.
Looks like StatHandler.instance is static method. You can't use your int variables without any assigned. Assign some values to them.
For example
public int stamina = 1, strength = 2, agility = 3, dexterity = 4, wisdom = 5;
NullReferenceException: Object reference not set to an instance of an object
You need to initialize properly. Seems like StatHandler.instance is static and not initialized.
You can initialize it in static constructor
class StatHandler
{
static StatHandler()
{
instance = new Instance(); // Replace Instance with type of instance
}
}
You have two ways to go here.
Full Static Class
public static class StatHandler
{
public static Int32 Stamina = 10;
public static Int32 Strength = 5;
}
And then:
maxHealth = StatHandler.Stamina * 10; // get the value and use it
StatHandler.Stamina = 19; // change the value
Singleton Instance
public class StatHandler
{
public static StatHandler Instance;
public Int32 Stamina = 10;
public Int32 Strength = 5;
// this is called only the first time you invoke the class
static StatHandler()
{
m_Instance = new Instance(); // Replace Instance with type of instance
}
}
And then:
maxHealth = StatHandler.Instance.Stamina * 10; // get the value and use it
StatHandler.Instance.Stamina = 19; // change the value
// replace the current instance:
StatHandler.Instance = new StatHandler();
StatHandler.Instance.Stamina = 19; // change the value
I think the first one is always the best choice, same result, less complexity.
Related
I am developing a little console game where you go through a dungeon. I'm trying to make a potion system for it, the idea is that when you use a potion, it changes a specific stat of the player.
The stats of the player are stored in a static class called Stats. I want to create different potions from the same class, and change the stat the potion acts on using its constructor method. The way I want this to work is that, when a new potion instance is created, I pass to the constructor a reference to the stat variable, and the constructor will store that reference in a variable, to use it when the potion is used.
I tried using delegates with getters and setters, but it didn't work because they only work with functions. I can solve this problem making a potion id system, or learning to proper use pointers, but I prefer to use only safe code.
My question is: There is a way in c# to store a reference to a variable in another variable?
The Stats class:
static class Stats{
public static int health = 10,
strenght = 5,
defense = 20;
}
The potion class:
class Potion {
int statRef; //This is the "reference holder" variable I was asking about.
int magnitude;
public Potion(ref int stat, int _magnitude)
{
magnitude = _magnitude;
statRef = stat; //Here I want to save the reference to the stat to the "reference holder"
}
public void UsePotion()
{
statRef += magnitude; //Here I want to change the referenced variable's value.
}
}
The main program:
class Program{
static class Main(string[] args)
{
Potion lifePotion = new Potion(Stats.life, 5);
Potion strenghtPotion = new Potion(Stats.strenght, 5);
Potion defensePotion = new Potion(Stats.defense, 10);
lifePotion.UsePotion();
strenghtPotion.UsePotion();
defensePotion.UsePotion();
Console.WriteLine(Stats.health);
Console.WriteLine(Stats.strenght);
Console.WriteLine(Stats.defense);
}
}
Note that a class is a reference type. So, variables of a class type automatically contain references and you can assign the same reference to another variable. You can only create an object (i.e., an instance of a class) if the class is not static. Then you can assign it to a variable.
The fields or properties must not be static. Non static members are called instance members. Each instance (object) has its own copy of the fields and properties that must be accessed through a variable name. Static members, in contrast, are shared among all objects of this type and must be accesses through the class name.
Stats stats1 = new Stats();
Stats stats2 = stats1;
now both variables reference the same Stats. If you make the change
stats1.health = 5;
then stats2.health is also 5 since both reference the same object. But of course, you can create independent Stats objects:
Stats stats1 = new Stats();
Stats stats2 = new Stats();
Now changes to stats1 do not affect stats2.
Note that an important idea of Object-Oriented Programming (OOP) is that objects should hide their internal state, i.e., their fields. From outside the state should only be accessible through methods. These methods ensure that the state is manipulated in an adequate manner. E.g., it could be ensured that the health stays within a valid range.
Properties are specialized methods allowing to manipulate the state of fields. They usually consist of a pair of get and set methods and can be accessed like a field.
Example:
class Stats
{
private int _health = 10;
public int Health
{
get { // called when reading the value: int h = stats1.Health;
return _health;
}
set { // called when setting the value: stats1.Health = 5;
if (value < 0) {
_health = 0;
} else if (value > 100) {
_health = 100;
} else {
_health = value;
}
}
}
}
If a property has no such logic, you can use an auto implemented property. It automatically creates an invisible backing field (like _health) and returns and sets its value.
public int Health { get; set; }
Let us put the things together. Simple example of Stats class:
class Stats
{
public int Health { get; set; } = 10;
public int Strength { get; set; } = 5;
public int Defense { get; set; } = 20;
}
Now you can reference a Stats object in the Potion class.
Because you want to have different kinds of potions, you can use inheritance (another important concept of OOP) to achieve this.
You can declare an abstract base class, i.e., a class that cannot be instantiated and can itself contain abstract members, i.e., members that have still to be defined in derived classes.
abstract class Potion
{
// This is the "reference holder" variable you were asking about.
protected Stats _stats;
// Protected means private and visible to derived classes.
protected int _magnitude;
public Potion(Stats stats, int magnitude)
{
_stats = stats; // Save the reference to the stat to the "reference holder"
_magnitude = magnitude;
}
public abstract void UsePotion();
}
Now the derived LifePotion class as an example
class LifePotion : Potion // Inherits Potion.
{
public LifePotion(Stats stats, int magnitude)
: base(stats, magnitude) // Calls the base constructor.
{
}
public override void UsePotion()
{
_stats.Health += _magnitude; // Change a property of the referenced variable.
}
}
Repeat the same for StrenghtPotion and DefensePotion classes with UsePotion setting the Strength and Defense properties.
The adapted main program
class Program{
static class Main(string[] args)
{
var stats = new Stats();
Potion lifePotion = new LifePotion(stats, 5);
Potion strenghtPotion = new StrengthPotion(stats, 5);
Potion defensePotion = new DefensePotion(stats, 10);
lifePotion.UsePotion();
strenghtPotion.UsePotion();
defensePotion.UsePotion();
Console.WriteLine(stats.Health);
Console.WriteLine(stats.Strength);
Console.WriteLine(stats.Defense);
}
}
Note that you can override ToString in a class and provide your own implementation. Add this to the Stats class:
public override string ToString()
{
return $"Health = {Health}, Strength = {Strength}, Defense = {Defense}";
}
Then you can print the health like this in the main routine:
Console.WriteLine(stats); // Prints: Health = 15, Strength = 10, Defense = 30
C# is an object-oriented programming language. That means it is designed to use “objects”, or in-memory instances of classes, that are responsible for maintaining their own state. Now you don't have to do this, but the more you stray from this design the less the language supports you, and the more work you have to do yourself.
Your design is not object-oriented. There probably isn't a “stats” that wanders around in your game, statting things. It probably isn't static either. Static classes are for concepts that can't change. For example, Math.Sin is static; its meaning can't change and my Math.Sin is your Math.Sin.
Instead of static Stats wandering around, your game probably has characters or Mooks. So make a class for them:
public class Mook
{
public string Name { get; }
public int Strength { get; private set; }
public Mook(string name, int strength)
{
Name = string.IsNullOrWhiteSpace(name) ? throw new ArgumentNullException(nameof(name)) : name;
Strength = strength;
}
}
Now you can create instances of Mooks:
var player = new Mook("Link", 10);
var monster = new Mook("Orc", 11);
Mooks can do things, like attack or drink potions. Potions can do things, like modifying your strength. Each class is responsible only for its own internal state; you don't have potions changing Mooks, only the Mook themselves can do that. Classes do things that change themselves through methods. If you want a Mook to drink a potion you have to create a method inside your Mook class to do that:
public void Drink(Potion potion)
{
switch (potion.Sipped())
{
case PotionEffect.ModifyStrength:
Strength += potion.Modifier;
break;
}
}
Potions don't decide what happens outside themselves, only the class using the potion does. To track the possible effects of a potion, create an enum:
public enum PotionEffect
{
Nothing,
ModifyStrength
}
Potions are other objects, so you need to create another class. Remember, each class is responsible for maintaining its own state:
public class Potion
{
public PotionEffect Effect { get; }
public int Modifier { get; }
public int Doses { get; private set; }
public Potion(PotionEffect defaultEffect, int modifier, int doses)
{
Effect = defaultEffect;
Modifier = modifier;
Doses = doses;
}
public PotionEffect Sipped()
{
if (Doses <= 0)
return PotionEffect.Nothing;
Doses--;
return Effect;
}
}
Now you can create potions:
var strengthPotion = new Potion(PotionEffect.ModifyStrength, +1, 10);
And have mooks drink them:
player.Drink(strengthPotion);
monster.Drink(strengthPotion);
As the title says, I would like to set the maximum value of the skill, stam and luck integers to the value of the related *Max integers. The *Max int values are set randomly during the start up of the program and the regular values are changed throughout the running of the program. There may be a few instances where the *Max value gets increased or decreased during play.
public static int skillMax = 0;
public static int stamMax = 0;
public static int luckMax = 0;
public static int skill = skillMax;
public static int stam = stamMax;
public static int luck = luckMax;
As my knowledge of C# is still in its infancy, I have not tried much. However I have searched far and wide on the internet however and not been able to find anything except for the MinValue and MaxValue fields and this piece of code with no explanation:
protected int m_cans;
public int Cans
{
get { return m_cans; }
set {
m_cans = Math.Min(value, 10);
}
}
Thanks in advance for any advice you throw my way!
Explanation for the code: Cans is a property. Properties provide controlled access to class or struct fields (variables). They consist of two methods called get to return a value and set to assign the value. A property can also have only a getter or only a setter.
The property Cans stores its value in a so called backing field. Here m_cans. The setter gets the new value through the keyword value.
Math.Min(value, 10) returns the minimum of the two parameters. I.e., for example, if value is 8, then 8 is assigned to m_cans. If value is 12, then 10 is assigned to m_cans.
You can use this property like this
var obj = new MyCalss(); // Replace by your real class or struct name.
obj.Cans = 20; // Calls the setter with `value` = 20.
int x = obj.Cans; // Calls the getter and returns 10;
Properties help to implement the principle of Information hiding.
You can easily adapt this example your variables. Often class level variables (fields) are prepended with _ to differentiate them from local variables, i.e. variables declared in methods. Properties are written in PascalCase.
private static int _skillMax; // Fields are automatically initialized to the default
// value of their type. For `int` this is `0`.
public static int SkillMax
{
get { return _skillMax; }
set {
_skillMax = value;
_skill = _skillMax; // Automatically initializes the initial value of Skill.
// At program start up you only need to set `SkillMax`.
}
}
private static int _skill;
public static int Skill
{
get { return _skill; }
set { _skill = Math.Min(value, _skillMax); }
}
Create methods to update values
private static void UpdateSkill(int newValue)
{
skill = newValue;
skillMax = newValue > skillMax ? newValue : skillMax;
}
interface ICar
{
int Speed {get; set;}
}
class IgnitionKey: ICar
{
public int Speed {get; set;}
public void Change ()
{
Speed = 10;
}
}
class GasBrake: IgnitionKey
{
}
static void Main(string[] args)
{
IgnitionKey k = new IgnitionKey();
GasBrake s = new GasBrake();
k.Change();
Console.WriteLine(s.Speed);
Console.ReadLine();
}
Here is my code. Using Change function, I change speed value to 10. But this speed value belongs to interface (I guess). I have a second class that inherits from other class. I want Speed value to be equal to ten.
In main, if I use Console.WriteLine(k.Speed) I can get value 10. But I need to get this value when I use s.Speed. How can I do that ? Is there a way to change the value of first class using second class ?
(Sory for bad English)
In your code, k and s refer do different objects, so changes in one of them cannot affect the other.
You can write GasBrake s = k; to make booth variables refer to the same object, or you may call s.Change() instead of k.Change() to modify s
When you do :
GasBrake s = new GasBrake();
or:
IgnitionKey k = new IgnitionKey();
that is a new object created and it has it's own allocated memory and it's own state which is completely isolated from the other and they don't have any shared state.
As you have two completely different objects being created they both will have completely different state, they cannot share state. For mimicking what you want you will need to use single object but with different type of reference :
GasBrake s = new GasBrake(); // now just one object created
IgnitionKey k = s; // we reference to it using the parent class type
k.Change(); // change it's value
Console.WriteLine(s.Speed); // same value will be printed
now you will see same value i.e. 10.
I am a novice programmer, so sorry if this is a really stupid question. I need to pass a value from one class to another. If I am not mistaken, this would be done through inheritance, but there seems to be something I am missing. Any help would be welcome. I am writing in C# within Unity.
public class baseStats{
private int STAMINA;
public static int Stamina{
get{return STAMINA;}
set{STAMINA = value;}
}
}
The above is a sample of my parent class. Here is my child class:
public class Profile : baseStats {
private static int PROFILE_STAMINA;
private void Stats ()
{
PROFILE_STAMINA = Stamina;
}
public static int profileStamina
{
get{return PROFILE_STAMINA;}
}
}
In a third script I created for the purposes of debugging, I wrote:
public class debug:MonoBehaviour{
void Start(){
Debug.Log(Profile.profileStamina.ToString());
}
}
It says I need an object reference for the non-static field, method, or property
'Profile.Profile.Stamina'. Easy fix: make everything static (I believe I need to make constructors or something like that to avoid having to use static all the time. A little help with that would be great!). Once error-free, I ran the program and the console outputs 0 for my profile stamina. I am really confused as to what is going on. Sorry this is such a long post, and thanks for any help I get.
I need to pass a value from one class to another. If I am not
mistaken, this would be done through inheritance.
No, you don't need inheritance to pass values from one class to another. If you don't know what inheritance is, you shouldn't be using it. It's very likely you don't need it. The-same thing applies to the static keyword. New programmers tend to make everything static when they don't know what the new keyword is used for.
Simply create a new instance of the Stats script inside the Profile constructor script. To use the Profile script, create a new instance of it which will automatically call the constructor that will create a new instance of the Stats script. You shouldn't be doing this with static variables and functions. Totally unnecessary. Values can be passed to another script with auto property or function but my solution used auto property to make it simple.
public class Stats
{
private int STAMINA;
public int Stamina
{
get { return STAMINA; }
set { STAMINA = value; }
}
}
public class Profile
{
private Stats stats;
private int PROFILE_STAMINA;
//Init only
public Profile()
{
stats = new Stats();
}
//Init with Stats stamina and profileStamina stamina values
public Profile(int stamina, int profileStamina)
{
stats = new Stats();
stats.Stamina = stamina;
PROFILE_STAMINA = profileStamina;
}
//Stamina From Profile
public int profileStamina
{
get { return PROFILE_STAMINA; }
set { PROFILE_STAMINA = value; }
}
//Stamina From Stats
public int Stamina
{
get { return stats.Stamina; }
set { stats.Stamina = value; }
}
}
Usage:
public class debug:MonoBehaviour{
Profile profile = null;
void Start()
{
//Creata new profile and set Stats stamina and ProfileStamina stamina values
profile = new Profile(10, 5);
profile.Stamina = 60;
profile.profileStamina = 60;
Debug.Log(profile.profileStamina.ToString());
}
Also take time and learn about Classes,Properties.
You're trying to access a non-static from a static property.
This code is the main problem:
public static int Stamina{
get{return STAMINA;}
set{STAMINA = value;}
}
STAMINA is defined as private int STAMINA. It isn't static. Quite simply, this means that inside every object of the type baseStats you have an int called STAMINA you can fill in. However, you're not working on an object there; you're in a static function, which is something that can be executed without an object. Since there is no object, there is no STAMINA int either; there's no object to get or fill in that property on.
On that note, your function profileStats() has the same issue; it tries to access the non-static STAMINA as well, again without having any kind of object. Any reference to just plain STAMINA is actually to this.STAMINA, and inside a static, there's no this.
I'm not sure what the purpose of this whole setup is; personally I'd avoid using statics containing global data like that. Instead I'd just keep an object around containing the necessary properties which is simply passed on to any functions that need to access the data in it. But anyway, from what I can see, you simply forgot to put static on that private int STAMINA.
Side note: this is completely unrelated to inheritance. Since Stamina is a public static property, and statics can't be inherited (except in some peculiar advanced cases with inherited generics), your "child class" never even needs the parent class as parent, as long as it references baseStats.Stamina instead of STAMINA. This can easily be shown by making both classes static.
I am trying to write some code in C# with unity where i have an object who's position I need to know for my script to work. I was trying to use a pointer as that's what I thought was used. It said i had to use an unsafe tag which made me think i was doing something wrong. I am a little new to this and so far i have most of my knowledge with C++ as that's what i have learned in class. I tried looking it up but i could not find it. this is basically what i have right now.
using UnityEngine;
using System.Collections;
public class SGravSim : MonoBehaviour {
public GameObject moon;
public GameObject earth;
private struct Cords
{
public float* x
{
get
{
return x;
}
set
{
if (value != 0) <== this thing is realy just a placeholder
x = value;
}
}
public float* y
{
get
{
return y;
}
set
{
if (value != 0) <== this this is only in here for now
y = value;
}
}
public void DisplayX()
{
}
}
private Cords moonLocation;
private Cords earthLocation;
private Cords SataliteLocation;
// Use this for initialization
void Start () {
moonLocation.x = moon.transform.position.x;
moonLocation.y = moon.transform.position.y;
earthLocation.x = earth.transform.position.x;
earthLocation.y = earth.transform.position.y;
SataliteLocation.x = this.transform.position.x;
SataliteLocation.y = this.transform.position.y;
}
// Update is called once per frame
void Update () {
Debug.Log(moon.transform.position.x);
//
// Summary:
// The position of the transform in world space.
float yMoon = moon.transform.position.x
print(moonLocation.y);
}
}
I was planing on making the set so that you could not add anything to it.
I guess I could write out the whole earth.position.x thing every time I need to use it I was just trying to see if there was a better way to do it and also a way where I cant mess with the variable as all I want to do is read it.
You can use private set in the automatic properties :
public float X {get; private set;}
This way only your class will be able to set the variable but any other class wouldn't.
You shouldn't use pointers in c# except for really specific cases.
The solution several people gave you here is good:
public float X {get; private set;}
It is called a property and is one of the nice possibilities in c# to avoid creating getters and setters.
You say you have some knowledge in c++, but c# is actually closer to higher languages such as java. You should focus on the Object Oriented way to code and forget about low level pointers, especially using Unity.
You can use:
private float x;
public float X
{
get
{
return x;
}
}
Now you only set x from within your class.
You get the unsafe tag warning, because you try to use pointers, which are actually unsafe. There might be use-cases for that, but in C# you generally use reference types and value types. In C# a struct is a value type, so it will behave differently compared to a reference type, as you can read here, which is also why Gubr has suggested to use a class instead of a struct. Last but not least, there is a difference in how they are stored, just google C# heap and stack.
I haven't used structs that much in C# yet, so I just created a new project and played a bit around.
So I used your code, which also could just look like this:
private struct Cords
{
public float x, y;
public void DisplayX(){}
}
As the others have mentioned, you could leave out the set or make it private and add a constructor. Mind you, a private set doesn't equal to not defining it in auto-properties. Instead, it will create a readonly field. However, you have to call the new operator in both cases to set the value:
private struct Cords
{
public float X { get; }
public float Y { get; }
public void DisplayX(){}
public Cords(float x, float y)
{
X = x;
Y = y;
}
}
And here we create a new Cords:
Cords earth = new Cords(10.005f, 12.689f);