- Home /
Can't modify Struct variables C#
Hello,
I have a struct called WeaponType, and in it I have approximately 10 variables.
Upon calling "WeaponType.CurrentWeapon.Ammo = ," I received an error that I couldn't modify the value because it wasn't a variable.
Okay, well that's fine. So I added a function called SetAmmo(int amount) where I thought I would modify the value directly on the struct.
With that function I'm able to "change" the value from the same to the same.(no actual change is noted) Later found out this is because of the fact that it's like a skinwalker from Supernatural and created another instance of itself. (okay, bad reference)
After doing research on it, I don't know how to change it from "mutable" to "immutable," mainly because I don't know what that means.
Can anyone shed some light on this please?
Please provide the code showing the deceleration of WeaponType.
Also, where are you accessing WeaponType.CurrentWeapon.Ammo? I'm guessing from another script.
Id so, please show the code referencing the script.
WeaponType is a struct inside of the Weapons class.
public struct weaponType
{
/*
* This struct will contain the different weapons. Will only hold a raw value for the data, and $$anonymous$$AYBE a function or 2.
*/
#region Weapon Variables
private GameObject _sparkObject;
private bool outOfAmmo;
private string _name;
private float _accuracy;
private string _type; //Weapon Type
private bool _playerCanUse; //If the player is allowed to use the weapon
private bool _isEquipped; //Checks if the weapon is equipped or not
private int _currentAmmo;
private int _maxWeaponAmmo;
private int _totalCurrentAmmo;
private int _numberOfClips;
private int _clipSize;
private float _weaponDamage; //Base Weapon Damage
private float _reloadTime;
private float _speed; //Time interval between shots
#region Getters and Setters
public GameObject sparkObject
{
get{return _sparkObject;}
set{_sparkObject = value;}
}
public string name
{
get{return _name;}
set{_name = value;}
}
public float accuracy
{
get{return _accuracy;}
set{_accuracy = value;}
}
public string type
{
get{return _type;}
set{_type = value;}
}
public bool playerCanUse
{
get{return _playerCanUse;}
set{_playerCanUse = value;}
}
public bool isEquipped
{
get{return _isEquipped;}
set{_isEquipped = value;}
}
public int currentAmmo
{
get{return _currentAmmo;}
set{_currentAmmo = value;}
}
public int maxWeaponAmmo
{
get{return _maxWeaponAmmo;}
set{_maxWeaponAmmo = value;}
}
public int totalCurrentAmmo
{
get{return _totalCurrentAmmo;}
set{_totalCurrentAmmo = value;}
}
public int numberOfClips
{
get{return _numberOfClips;}
set{_numberOfClips = value;}
}
public int clipSize
{
get{return _clipSize;}
set{_clipSize = value;}
}
public float weaponDamage
{
get{return _weaponDamage;}
set{_weaponDamage = value;}
}
public float reloadTime
{
get{return _reloadTime;}
set{_reloadTime = value;}
}
public float speed
{
get{return _speed;}
set{_speed = value;}
}
After this, I then create an instance of the struct by calling
"WeaponType _currentWeapon = new WeaponType();"
Then I encapsulated it:
" WeaponType currentWeapon get{return _currentweapon;} set {_curentWeapon = value;}
Then I access it in another script by using a GetComponent of the Weapons script : " Weapons weapons = GetComponent();"
If I try to access the weapon.currentWeapon.currentAmmo, It doesn't work, but if I do it in the initial "Weapons" script, it does.
In another script, "Action$$anonymous$$anager" I use a function called shoot.
void shoot()
{ if (weapon.currentWeapon.ammo > 0) { weapon.currentWeapon.ammo -= 1; //At this point I get an error } }
Are both scripts on the same object?
You know you need to write it like so GetComponent(); right?
One script is on the main GameObject, the other script is on a child object. I use a public GameObject set to the non-child object to receive the components.
the way that's set up is:
public GameObject weaponReference;
private Weapons weapons;
Awake()
{
weapons = weaponReference.GetComponent<Weapons>();
}
Aside from that though, I think the problem may have to do with me encapsulating the actual weaponType variable ins$$anonymous$$d of making it public..
Answer found... ish.
It WAS the fact that the actual weaponType was encapsulated. If I removed the encapsulation and left it strictly as a public variable, then it works.
On that note, though, is it sound to do so?
I'm guessing you are drag'droping the object with the Weapons script.
When you are trying to call the weapon type, it should be: waepons.weaponType.Ammo and so on.
Answer by whydoidoit · Mar 26, 2013 at 11:29 PM
You cannot modify the values inside a struct returned from another component the way you are - and for good reason. A struct is passed by value.
When you do this:
WeaponType currentWeapon get{return _currentweapon;} set {_curentWeapon = value;}
You return a copy of _currentWeapon.
So if you were to do someObject.currentWeapon.maxWeaponAmmo = 5 - you would be doing that on the copy that only existed while that line executed and was immediately thrown away afterwards. So the compiler realises that this isn't smart and refuses it.
Either
Make it a class which won't have that problem
Take the value into a local variable, change the property and set it back. That way you update the copy and assign the copy back.
var weapon = something.currentWeapon; weapon.maxWeaponAmmo = 5; something.currentWeapon = weapon;
Note that structs can be a lot slower than classes because of all of the hidden copying.
I just noticed that you have just made it a public member - that will also work (because you have direct access to the copy). Structs are generally a dangerous thing to use (weird copy issues, copy time, lack of serialization support) and in real .NET would be reserved for special cases. The fact that they are stack allocated makes them popular in Unity due to Unity/$$anonymous$$ono's ridiculously poor implementation of Garbage Collection Generations that means big GC spikes that should not happen when disposing of short lived classes.
This doesn't look like a short lived object - if not it would be better off as a class.
Thanks for the overview of issues with Structs... that information was kind of left out when I read a few months ago that "Structs are just smaller classes that can hold values and functions!"
Tried to avoid using a new class for this, but it seems like that won't be happening lol.
Thanks again, truly enlightened me.
Yeah it's those techy details - especially for ex C++ programmers where they are almost identical to classes.
Utility things (think Vector3/Quaternion etc) that you create and use everywhere for a few instants and then forget about should always be structs in Unity.
If it lives for a significant time it should probably be a class.
It's all the intermediate things which are a problem!
Your answer
Follow this Question
Related Questions
Multiple Cars not working 1 Answer
Distribute terrain in zones 3 Answers
Flip over an object (smooth transition) 3 Answers
Selecting Structs from dropdown menu in inspector. 1 Answer
Finding struct values by string 1 Answer