GameManager (singleton) and WeaponManager communication

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:

  1. Create a GUI by looping through all children of weapons in the WeaponData class
  2. 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.