In Unity, I have
public enum inven {Food,Scissors,Nothing};
public inven held;
How can I access the enum and, more importantly, the information contained in the held variable, from another script.
I tried the Singleton Method:
public class Singleton : MonoBehaviour {
public static Singleton access;
public enum inven {Nothing, Scissors, Food};
public inven held;
void Awake () {
access = (access==null) ? this : access;
}
}
to make global variables, accessed by
Singleton.inven.food //or
Singleton.access.held //respectively
However, that returned "Null reference exception: Object reference not set to an instance of an object."
I also tried using this:
public class Accessor : MonoBehaviour {
void Start() {
GameObject HeldItem = GameObject.Find("Story"); //where story is the Gameobject containing the script of the enum and variable
TextController textcontroller = Story.GetComponent<Textcontroller>(); //Where TextController is the sript containing the enum and variable
}
}
accessed by TextController.held etc, returned that it needed an object reference. What is the proper way of doing this?
Here's how I do my singletons. In my case, it's called SharedData.
using UnityEngine;
using System.Collections;
public class Booter : MonoBehaviour
{
void Start ()
{
Application.targetFrameRate = 30;
GameObject obj = GameObject.Find("Globals");
if(obj == null)
{
obj = new GameObject("Globals");
GameObject.DontDestroyOnLoad(obj);
SharedData sharedData = obj.AddComponent<SharedData>();
sharedData.Initialize();
}
}
}
This script is attached to an object in the first scene that loads, and it is set in the script execution order to go first. It creates a GameObject to attach the SharedData component to, then tells the engine not to delete that GameObject when new levels are loaded.
Then to access it, I do this:
public class Interface : MonoBehaviour
{
private SharedData m_sharedData;
public void Initialize()
{
GameObject globalObj = GameObject.Find("Globals");
m_sharedData = globalObj.GetComponent<SharedData>();
m_sharedData.LoadData(); // This is where I use something on the singleton.
}
}
Related
I have a Manager class and it has lots of variables so I can reference it when I need it.
Will this reduce the performance ? or should I define it
public class Controller: MonoBehaviour
{
public GameObject Manager;
}
public class GetController : MonoBehaviour
{
public GameObject Controller ;
void dosomthing(){
var Ma = Controller.Getcomponent<Controller>().Managet
}
}
TLDR; Getcomponent() calls are expensive. It is OK if used once/rarely, but starts to have an effect when called continiously.
Store a reference (define) to it:
public class GetController : MonoBehaviour
{
// Will show up in unity's inspector.
// Drag-and-Drop the gameObject with the 'Controller' component attached to it.
[SerializeField]
private Controller yourController ;
void Dosomthing(){
var Ma = yourController.Manager
}
}
Also, most things in Unity can be exposed to the Inspector as long as it is serializable.
You can expose a Controller field to the inspector, and drag-drop the same GameObject.This lets you skip a GetComponent call and another define.
I suggest using a singleton pattern for managers.
public class GameManager : MonoBehaviour
{
public static GameManager singleton; // define variable as singleton
public int score = 2; // for example...
private void Start() => singleton = this; // setup single user class instance
}
And in the player class or any other class, call it without redefining it.
public class Player : MonoBehaviour
{
public void AddScore() => GameManager.singleton.score += 1; // add score to manager
}
I have singleton( which is monobehavior also same question for non-monobehavior) which is created at scene 1 , and it created without dontDestroyOnLoad. im calling this singleton from scene 2 , and getting/using the info inside without any problem.I have read something about ghost GameObjects in this case but couldnt find detailed info.
In Scene 1
using UnityEngine;
public class RefreshAccount : MonoBehaviour
{
public static RefreshAccount refreshAccount;
public string aString = "aaaaaaaa";
void Awake()
{
if (!refreshAccount) refreshAccount = this;
else Destroy(this.gameObject);
// it is not labeled as DontDestroyOnLoad
}
(...)
}
Scene 2
using UnityEngine;
using UnityEngine.SceneManagement;
public class testnewscen : MonoBehaviour
{
private void Start()
{
Debug.Log(RefreshAccount.refreshAccount.aString );
}
}
So will it cause any problem/error in the future of this app ?
Will there be any memory problem or performance problem?
If you use this solution, you cannot run scene 2 without run scene 1 before
If you dont need to set serialize variable / game object / prefabs to your singleton (RefreshAccount) I prefer to use non-monobehaviour singleton instead like
public class RefreshAccount {
private static RefreshAccount instance
public static RefreshAccount Instance {
get {
if(instance == null) {
instance = createInstance();
}
return instance;
}
}
}
If you need to use for read some serialize value (variable, config, gameobject, etc.) without behaviour ( awake, update, fix update )
You can use SerializableObject
SerialzpizeObject is similar static class or prefab but you need to use RESOURCE.LOAD to read it
I'm not really sure how to describe it exactly so let me show you what is going on.
I have a PlayerControls script which looks like this (note: I stripped everything except for the necessities).
namespace Player.Controls {
internal class PlayerControls: MonoBehaviour {
public bool IsClimbing { get; private set; } = false;
public bool IsGrounded { get; private set; } = false;
}
}
These variables are set in this class depending if the player is climbing/touching the ground. This script resides on the "Player" GameObject in the scene.
I have another script called PlayerControllerwhich looks like this
using Player.Controls;
public class PlayerController: Singleton<PlayerController> {
internal PlayerStats stats = new PlayerStats();
//PlayerStats nested class (see below)
}
The Singleton class only checks if the generic type is null, if it is, it will use FindObjectOfType to get an instance. This script also resides on the "Player" GameObject.
Inside the PlayerController class, I have a nested class called PlayerStats. It looks like this
internal class PlayerStats : PlayerControls {
public new bool IsClimbing { get { return base.IsClimbing; } }
public new bool IsGrounded { get { return base.IsGrounded; } }
}
Notice this nested class in inheriting from PlayerControls.
The idea is that the PlayerControls class in inaccessible to all other classes except for PlayerController, and any information I want to obtain regarding the player can be obtained by getting the player's instance (via the singleton) and accessing the PlayerStats variable.
For example, assuming the variable inside Singleton which holds the instance is called Instance, one could do PlayerController.Instance.stats.IsClimbing; Everything works as expected, except for one thing.
In the Awake method of the PlayerController class, I do this
private void Awake() {
Debug.LogFormat("In PlayerController Awake(). Is PlayerController.stats null? {0}",
(stats.Equals(null) ? "Yes" : "No"));
Debug.LogFormat("IsClimbing : {0}", stats.IsClimbing);
}
In the output window, it prints
In PlayerController Awake(). Is PlayerController.stats null? Yes
IsClimbing : False
If I also put the same IsClimbing debug in the Update() method, the value is correct for when I start climbing.
So, finally, my question, how can I access the variables of the PlayerStats class with the stats variable if stats is null? I thought it may have been somehow calling straight to the PlayerControls properties, so I changed their names, removed the new inside of PlayerStats and even put a debug statement inside one of the properties inside PlayerStats, and it definitely gets called. For example,public bool IsClimbing { get { Debug.Log("Called IsClimbing inside PlayerStats."); return base.Climbing; } }
If it is getting called and working properly, how can it be null? I asked my professor and he doesn't seem to know why either. What is really going on here?
Edit:
As requested, the Singleton class:
public abstract class Singleton<T>: MonoBehaviour where T : MonoBehaviour {
private static T instance;
public static T Instance {
get {
if(instance == null) {
instance = FindObjectOfType<T>();
}
return instance;
}
}
}
Here is an image of the console output.
Digging around on the Unity forums it appears that the Equals method has been overridden (on Object which MonoBehaviour eventually derives from) which is why comparing a MonoBehaviour to null is not giving you what you might expect. The answer I link to suggests code like this is more appropriate:
stats == null || stats.Equals(null)
For example, If i want to access the integer health in another class, i have to create a reference off that class and attach it to an object either in the inspector or programatically. How come i cannot just access the public integer without attaching the object? Example code
public class Game : MonoBehaviour
{
public int health;
}
public class player : MonoBehaviour
{
public Game gameScript;
gameScript.health = 10; //this will cause nullpointer error if not attached to a gameobject or
//public GameObject test;
//gameScript = test.GetComponent<testscript> ();
}
To be able to access other values in Unity without attaching it to GameObject, you have to make sure that you don't inherit MonoBehaviour. Once you inherit MonoBehaviour, you will no longer be able to access the values or functions in the other script. That's how Unity is made.
So change:
public class Game : MonoBehaviour
{
public int health;
}
to
public class Game
{
public int health;
}
Also you must use the new keyword before you access the value or your class would be null and crash your program.
public Game gameScript;
gameScript.health = 10;
should be changed to something like this:
public Game gameScript = new Game();
gameScript.health = 10;
Since you will be accessing your class from other classes, you need to make your health variable static and access directly. If you don't, you will have many instances of health variable each time you use the new keyword.
By making your variable static, you could just do Game.health = 10; directly without using the keyword or creating another instance of it. Below is an example:
public class Game
{
public static int health;
}
then you can access it with
Game.health = 10;
EDIT:
GET/SET METHOD
public class Game
{
public static int health;
public static int getHealth(){
return Game.health;
}
public static void setHealth(int tempHealth){
Game.health = tempHealth;
}
}
Then to access this from other classes, you could do:
Debug.Log(Game.getHealth().toString());
To Modify,
Game.setHealth(10);
I did compile this but it should work.
Well for this, you have to instantiate the game object, but if you want to just allow it as is change it to: public static int health; or put a getter/setter method to retrieve this value "health". C++ and Java have to have instantiated objects to retrieve from to set a value/ get a value from any attribute.
In Unity, whats a good way to create a singleton game manager that can be accessed everywhere as a global class with static variables that will spit the same constant values to every class that pulls those values? And what would be the way to implement it in Unity? Do I have to attach it to a GameObject? Can it just be there in a folder without being in the scene visually?
Like always: it depends. I use singletons of both kinds, components attached to GameObject and standalone classes not derived from MonoBehaviour. IMO the overall question is how are instances bound to the lifcycle of scenes, game objects, ... And not to forget sometimes it is more convenient to have a component especially referencing other MonoBehaviour objects is easier and safer.
There are classes that just need to provide some values like for example a config class that needs to load settings from persistence layer when called. I design theese classes as simple singletons.
On the other hand some objects need to know when a scene is started i.e. Start is called or have to perform actions in Update or other methods. Then I implement them as component and attach them to a game object that survives loading new scenes.
I designed component based singletons (type 2) with two parts: a persistent GameObject called Main, which holds all components and a flat singleton (type 1) called MainComponentManager for managing it. Some demo code:
public class MainComponentManger {
private static MainComponentManger instance;
public static void CreateInstance () {
if (instance == null) {
instance = new MainComponentManger ();
GameObject go = GameObject.Find ("Main");
if (go == null) {
go = new GameObject ("Main");
instance.main = go;
// important: make game object persistent:
Object.DontDestroyOnLoad (go);
}
// trigger instantiation of other singletons
Component c = MenuManager.SharedInstance;
// ...
}
}
GameObject main;
public static MainComponentManger SharedInstance {
get {
if (instance == null) {
CreateInstance ();
}
return instance;
}
}
public static T AddMainComponent <T> () where T : UnityEngine.Component {
T t = SharedInstance.main.GetComponent<T> ();
if (t != null) {
return t;
}
return SharedInstance.main.AddComponent <T> ();
}
Now other singletons that want to register as Main component just look like:
public class AudioManager : MonoBehaviour {
private static AudioManager instance = null;
public static AudioManager SharedInstance {
get {
if (instance == null) {
instance = MainComponentManger.AddMainComponent<AudioManager> ();
}
return instance;
}
}
If this class is just for accessing global variables then you don't really need a singleton pattern for this, or use a GameObject.
Simply create a class with public static members.
public class Globals
{
public static int mStatic1 = 0;
public static float mStatic2 = 0.0f;
// ....etc
}
The other solutions are fine but overkill if all you need is global access to variables.
Engineers who are new to Unity often don't notice that
you can't have a "singleton" in an ECS system.
It is meaningless.
All you have in Unity is GameObjects, at, XYZ positions. They can have components attached.
It would be like trying to have "a singleton" or "inheritance" in .... Photoshop or Microsoft Word.
Photoshop file - pixels at XY positions
Text editor file - letters at X positions
Unity file - GameObjects at XYZ positions
It is "just that simple".
So, in a game you will have "general" behaviors where there is only "one" of the thing. (So obviously there is only "one sound effects engine" , "one screen", "one scoring system" and so on.) A normal programmer would think of those as "singletons", but Unity just has nothing to do with singletons and no connection to singletons.
So if you have "a tank" or "a tree" of course it's normal you may have dozens of those things. But "the sound effects engine" or "the networking system" are "general, only-one-of-them" systems.
Hence, trivially, in Unity "the sound effects engine" or "the networking system" very simply sits on a game object, and, you (obviously) just have the one of them.
Those "general, only-one-of-them" items just sit on the preload scene.
You absolutely have to have a preload scene anyway, in every Unity project.
(Simple how-to: https://stackoverflow.com/a/35891919/294884 )
In the future Unity will include a "built-in preload scene" - when that day comes this will finally never be discussed again!
(Note - some of the languages you use to compile Components for Unity of course have OO concepts; but Unity itself has no connection to OO at all. Unity is like photoshop. You have "game objects" each at a certain 3D position.)
(Note - in the early days of Unity you'd see attempts at making code, say c#, which creates a game object on the fly, attempts to keep the game object unique, and "attaches itself" to the game object as a component. Apart from being completely bizarre/pointless, just FWIW it's theoretically not possible to ensure uniqueness (actually not even within a single frame). Again, it's moot because in Unity general behaviors just go on the preload scene.)
I wrote a singleton class that makes easy to create singleton objects. Its is a MonoBehaviour script, so you can use the Coroutines. Its based on this Unity Wiki article, and I will add option to create it from Prefab later.
So you don't need to write the Singleton codes. Just download this Singleton.cs Base Class, add it to your project, and create your singleton extending it:
public class MySingleton : Singleton<MySingleton> {
protected MySingleton () {} // Protect the constructor!
public string globalVar;
void Awake () {
Debug.Log("Awoke Singleton Instance: " + gameObject.GetInstanceID());
}
}
Now your MySingleton class is a singleton, and you can call it by Instance:
MySingleton.Instance.globalVar = "A";
Debug.Log ("globalVar: " + MySingleton.Instance.globalVar);
Here is a complete tutorial: http://www.bivis.com.br/2016/05/04/unity-reusable-singleton-tutorial/
This is the setup I have created.
First create this script:
MonoBehaviourUtility.cs
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.IO;
static public class MonoBehaviourUtility
{
static public T GetManager<T>( ref T manager ) where T : MonoBehaviour
{
if (manager == null)
{
manager = (T)GameObject.FindObjectOfType( typeof( T ) );
if (manager == null)
{
GameObject gameObject = new GameObject( typeof( T ).ToString() );
manager = (T)gameObject.AddComponent( typeof( T ) );
}
}
return manager;
}
}
Then in any class you want to be a singleton do this:
public class ExampleManager : MonoBehaviour
{
static public ExampleManager sharedManager
{
get
{
return MonoBehaviourUtility.GetManager<ExampleManager>( ref _sharedManager );
}
}
static private ExampleManager _sharedManager;
}
One way to do it is to make a scene just to initialize your game manager like this:
public class GameManager : MonoBehaviour {
static GameManager instance;
//other codes
void Awake() {
DontDestroyOnLoad(transform.gameObject);
instance = this;
}
//other codes
}
That's it, that's all you need to do. And then immediately after initializing the game manager, load the next scene and never come back to this scene again.
Have a look at this tutorial:
https://youtu.be/64uOVmQ5R1k?list=WL
Edit:
Changed GameManager static instance; to static GameManager instance;
Instead of creating one singleton for each class. I would suggest you to create a generic class for singleton. i use to follow this method which make my life very easy.
For More detail visit here
Or
Create Unity C# class in unity and use following code
/// <summary>
/// Inherit from this base class to create a singleton.
/// e.g. public class MyClassName : Singleton<MyClassName> {}
/// </summary>
public class Singleton<T> : MonoBehaviour where T : MonoBehaviour
{
// Check to see if we're about to be destroyed.
private static bool m_ShuttingDown = false;
private static object m_Lock = new object();
private static T m_Instance;
/// <summary>
/// Access singleton instance through this propriety.
/// </summary>
public static T Instance
{
get
{
if (m_ShuttingDown)
{
Debug.LogWarning("[Singleton] Instance '" + typeof(T) +
"' already destroyed. Returning null.");
return null;
}
lock (m_Lock)
{
if (m_Instance == null)
{
// Search for existing instance.
m_Instance = (T)FindObjectOfType(typeof(T));
// Create new instance if one doesn't already exist.
if (m_Instance == null)
{
// Need to create a new GameObject to attach the singleton to.
var singletonObject = new GameObject();
m_Instance = singletonObject.AddComponent<T>();
singletonObject.name = typeof(T).ToString() + " (Singleton)";
// Make instance persistent.
DontDestroyOnLoad(singletonObject);
}
}
return m_Instance;
}
}
}
private void OnApplicationQuit()
{
m_ShuttingDown = true;
}
private void OnDestroy()
{
m_ShuttingDown = true;
}
}
Here is a simple code taken from Unity Tutorial. for better understanding open the link
using System.Collections.Generic; //Allows us to use Lists.
public class GameManager : MonoBehaviour
{
public static GameManager instance = null; //Static instance of GameManager which allows it to be accessed by any other script.
private BoardManager boardScript; //Store a reference to our BoardManager which will set up the level.
private int level = 3; //Current level number, expressed in game as "Day 1".
//Awake is always called before any Start functions
void Awake()
{
//Check if instance already exists
if (instance == null)
//if not, set instance to this
instance = this;
//If instance already exists and it's not this:
else if (instance != this)
//Then destroy this. This enforces our singleton pattern, meaning there can only ever be one instance of a GameManager.
Destroy(gameObject);
//Sets this to not be destroyed when reloading scene
DontDestroyOnLoad(gameObject);
//Get a component reference to the attached BoardManager script
boardScript = GetComponent<BoardManager>();
//Call the InitGame function to initialize the first level
InitGame();
}
//Initializes the game for each level.
void InitGame()
{
//Call the SetupScene function of the BoardManager script, pass it current level number.
boardScript.SetupScene(level);
}
//Update is called every frame.
void Update()
{
}
using UnityEngine;
public class Singleton<T> : MonoBehaviour where T : Singleton<T>
{
public static T instance { get; private set; }
protected virtual void Awake() {
if (instance == null)
{
instance = (T)this;
DontDestroyOnLoad(gameObject);
OnInit();
}
else if (instance != this)
{
Destroy(gameObject);
}
}
protected virtual void OnInit()
{
}
}
GameManage :
class GameManager : Singleton<GameManager> {
}