I’m making an RTS-style game, where you can choose a weapon from a GUI, and click on a unit to activate it.
For this I’m trying to create a weapon manager script, where I can input weapons in the inspector, and add common variables like damage, fire-rate, range etc. Each weapon will have a separate script or method, for how it should work. I’m considering putting this inside the WeaponManager, but I’m not sure if it’s better to have smaller scripts for each weapon
I have a GameManager singleton, which works fine, but I’m stumped on how to instantiate and read from the WeaponManager class.
I want to do 2 things:
- Create a GUI by looping through all children of weapons in the WeaponData class
- If I activate a weapon on a unit, I want to be able to change the parameters of the weapon, to see this change in realtime. I guess I need to read from weapons on runtime.
Currently both WeaponManager.cs and GameManager.cs are attached to an empty gameobject, and I added the children of weapons in the inspector, but it seems wrong.
I’m sure I’m missing something fundamental, but I’m a C# noob, and very thankful for any tips.
Here’s my code:
//WeaponManager.cs
public class WeaponManager : MonoBehaviour {
[System.Serializable]
public class WeaponData {
public string name; // Sniper
[Range(0,100)] public int damage; // Damage per hit
[Range(0,100)] public int fireRate; // Shots per second
[Range(0,100)] public float range;
}
public WeaponData weapons;
}
//GameManager.cs
public class GameManager : MonoBehaviour {
public static GameManager Instance { get; private set; }
public WeaponManager weaponManager;
void Awake() {
if (Instance == null) {Instance = this; } else if (Instance != this) {Destroy(this); }
DontDestroyOnLoad(gameObject);
print(weaponManager.weapons); // This doesn’t work..
}
}
Well for starters. WeaponManager has only 1 WeaponData in it. Yet it’s called ‘weapons’, implying plural. Did you mean to make that an array, or a list?
Good point, at some point in my code I could click an icon and create multiple weapons, but now I can’t, so I might have made a list before somehow. Now I changed Line 12 of Weaponmanager to:
List weapons = new List();
So now I can add multiple weapons. But I still think the structure of the variables/classes is wrong. Shouldn’t I instantiate this somehow in the GameManager, so I have a copy of this list, that I use and modify for my other tasks?
When I move this line to GameManager, I get ‘WeaponData’ is not a known identifier. I assume I need to access it somehow. I tried WeaponManager weaponManager = gameObject.GetComponent(); and making the Weaponmanager static**.** Weaponmanager is a script in the same game object but then it says `GameManager.weaponManager’: cannot declare variables of static types.
I’m considering making also the WeaponManager a singleton, but I’m not quite sure how to read and change the variables on the fly…
Now that WeaponManager is a singleton, the serialized fields doesn’t show up in the inspector anymore. I can read the variables that I declare in code from GameManager with WeaponManager.globalVar.
I used the same type of singleton as the GameManager.
I tried another one from http://wiki.unity3d.com/index.php/Singleton but then I had to type WeaponManager.Instance.globalVar which seemed a little clunky.
Here’s the new code for WeaponManager as a singleton. Why doesn’t the fields get serialized and how can I fix it?
using UnityEngine;
using System.Collections.Generic;
public class WeaponManager : MonoBehaviour {
public static WeaponManager Instance { get; private set; }
public static string globalVar = "hey";
[System.Serializable]
public class WeaponData {
public string name; // Sniper
[Range(0,100)] public int damage; // Damage per hit
[Range(0,100)] public int fireRate; // Shots per second
[Range(0,100)] public float range;
}
[SerializeField]
public static List<WeaponData> weapons = new List<WeaponData>();
void Awake() {
if (Instance == null) { Instance = this; } else if (Instance != this) { Destroy(this); }
DontDestroyOnLoad(gameObject);
}
}
If I remove static on a var, i can see it in the inspector, but then I get An object reference is required to access non-static member `WeaponManager.testing’. Hmmm…
I think I managed to solve it after reading countless forum posts… yay! I think this is a simpler singleton, and I’ve seen everything from simple to much more complex, but I don’t really know why I would need that. Feel free to comment on how this can be made better:
public class WeaponManager : MonoBehaviour {
public static WeaponManager wm;
[System.Serializable]
public class WeaponData {
public string name; // Sniper
[Range(0,100)] public int damage; // Damage per hit
[Range(0,100)] public int fireRate; // Shots per second
[Range(0,100)] public float range;
}
[SerializeField]
public List<WeaponData> weapons = new List<WeaponData>();
void Awake() {
if(wm != null)
GameObject.Destroy(wm);
else
wm = this;
DontDestroyOnLoad(this);
}
}
And now I can access it from GameManager with print(WeaponManager.wm.weapons[0].name); and any values I enter into the inspector is updated right away.