Ok. When I open my project if someone GameObject (or all of them) is not found then it should be created automatically.
For example, I have SceneBuilder as GameObject and it contains all necessary scripts: ObjectsGenerator.cs, PlayerData.cs etc. And if somehow SceneBuilder disappears it must be recover from code. How can I do that?
p.s.: I found only two ways:
creating it from menu [MenuItem("MyTools/CreateGameObjects")], but it not obviously for support.
creating it through [CustomEditor(typeof(SomeOjectScript))] , but it must be already exists in scene (I guess a situation where the scene is completely empty)
p.s.: sorry if the question has already been and I have not found it
updated.
thanks to all. solved something like that
[InitializeOnLoad]
public class Checker : MonoBehaviour
{
static Checker()
{
CheckAndCreateObj();
EditorApplication.hierarchyChanged += hierarchyChanged;
}
private static void hierarchyChanged()
{
CheckAndCreateObj();
}
private static void CheckAndCreateObj()
{
string objName = "OBJECTNAME";
GameObject go = GameObject.Find(objName);
if (go == null)
{
Instantiate(new GameObject(objName));
}
}
}
https://docs.unity3d.com/Manual/RunningEditorCodeOnLaunch.html
You can check it dynamicly in one of your other scripts. You can call it from OnEnable or Start functions. Your MonoBehaviour must contain tag [ExecuteInEditMode] It could be something like this:
[ExecuteInEditMode]
public class YourMonoBehaviour: MonoBehaviour
{
void OnEnable()
{
var myObject = GameObject.Find("GAMEOBJECT_NAME");
if (myObject == null)
{
//Create new GameObject here and add your Component
}
}
}
If you need save some asset links or data in your gameobject with serialization, you can create prefab, cache it and create your object from prefab:
MyObjectType prefabTemplate;
void OnEnable()
{
if (GameObject.Find("GAMEOBJECT_NAME") == null)
{
GameObject.Instantiate(prefabTemplate);
}
}
Related
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 want to keep checking whether a game object will be instantiated.All I have is the gameobject name say 'Model'.If model is active in hierarchy I want to do something.The problem is initially the gameobject is not available.Later only it will be instantiated.How to check whether the gameobject with name is present in hierarchy which will be a clone.
if(gameobject.name=="Model(Clone)")
{
//Do something
}
This will return a null value since it was not instantiated initially.After some time it will be instantiated.
If it was me I would do something like this.
List<GameObject> models = new List<GameObject>;
public GameObject baseModel; //Your model
private void CreateModel()
{
GameObject obj = GameObject.Instantiate(baseModel) as GameObject;
models.Add(obj);
}
that way you can use this.
void Update()
{
if(models.Count > 0)
{
//Do Something
}
}
remember if you are going to destroy the object don't forget to do this.
private void DestroyModel(GameObject obj)
{
models.Remove(obj);
Destroy(obj);
}
This is good practice to assign your GameObject somewhere. lol
Initialize variable Model
Gameobject Model;
The logic assertion will be returned false when Model is not yet instantiated
if (Model != null && Model.name == "Model(Clone)"){//return false
//Do Something
}
Instantiate the gameobject with a name.
Gameobject Model = Instantiate (somePrefab);
The if needs to be placed inside void update(), or looping thing like invoke() which will constantly checking the condition.
It will check the if and return true when Gameobject Model is not null and there's gameobject named Model(Clone)
if (Model != null && Model.name == "Model(Clone)"){//return true
//Do Something
}
if you have an attribute "gameobject" in your code causing the code you provided to throw a null-exception, just do
if(gameobject!=null && gameobject.name=="Model(Clone)")
{
//Do something
}
instead.
If you don't have access to that game object and you just want to detect if it exists yet, try something like
var go = GameObject.Find("Model(Clone)");
if(go!=null)
{
//Do something
}
or if your game object has some script component MyScript, you can do
var gos = GameObject.FindObjectsOfType<MyScript>();
if(gos!=null && gos.Length > 0)
{
// foreach(var go in gos) {}
//Do something
}
Your best bet here is using UnityEvents.
Basically, when you want to run a piece of code, you just register it as a listener to a UnityEvent. So when you do something, say Instantiate an object, you can Invoke that UnityEvent immediately after, and it will run all the listeners that you registered to it, no matter where those pieces of code are in your project.
You first need to write the code that Instantiates the gameobject and Invokes the UnityEvent immediately after (this entire thing is in one .cs file, btw):
public class GameObjectSpawner : MonoBehaviour
{
public GameObject GameObjectPrefab;
public GameObjectEvent OnCreateObject;
private void Update()
{
// Everytime you click your left mouse button
// Only runs once per mouse click
if (Input.GetMouseButtonDown(0))
{
// Instantiate the gameobject...
GameObject go = Instantiate(GameObjectPrefab);
// Then immediately Invoke our event to run all the listeners
// and passing our gameobject to them.
OnCreateObject.Invoke(go);
}
}
}
// This is just so the code that 'listens' to the event can get access to the
// gameobject that just got instantiated.
public class GameObjectEvent : UnityEvent<GameObject> { }
So if you have a code somewhere else in your project that needs to run when that gameobject is Instantiated, that code runs ONLY when your gameobject is instantiated, never before (unless you manually run that code). Registering that code as a listener to the OnCreateObject event is as easy as this (this can be in a different .cs file):
public GameObjectSpawner Spawner;
private void Start()
{
// You can place this anywhere you want to, but we're
// placing this here in Start just to make sure that
// we're already listening waaay before the gameobject
// is instantiated.
Spawner.AddListener(CheckHierarchy)
}
// It doesn't matter if this is public or private,
// as long as it's void and takes in a GameObject as a parameter.
private void CheckHierarchy(GameObject go)
{
// Now we can do all kinds of things to the newly instantiated
// gameobject, like check if it's active in the hierarchy!
if (go.activeInHierarchy == true)
{
Debug.Log("I LIVE!!!");
}
}
There's more to UnityEvents than this, but this is just the gist of it to help you start using it. Good luck!
I have some graph of Node objects, which help represent some internal game state. I want to be able to spawn GameObjects from a prefab, initializing associated Node objects, using the GUI - i.e. someone could extend nodes in the example below in edit mode.
I am not familiar with how to do this in edit mode, instead of instantiating at runtime.
Is this possible, and if so, how would I get further than the below? I am familiar-ish with ScriptableObject but am not sure if it is relevant/necessary here.
[ExecuteInEditMode]
public class UGraph : MonoBehaviour
{
[SerializeField] GameObject nprefab;
[SerializeField] List<Node> nodes;
public void CreateNode(Transform transform)
{
GameObject go = Instantiate(nprefab, transform.position,
transform.rotation) as GameObject;
AddToGraph(go.GetComponent<Node>());
}
public void AddToGraph(Node node)
{
node.Graph = this;
nodes.Add(node);
}
...
Some thoughts around this taken from: https://gist.github.com/Problematic/a14aeb0638a09f378ad3
Lece pointed me towards the following page one extending the editor: https://docs.unity3d.com/Manual/editor-CustomEditors.html
This helped me discover how to use EditorWindow, and activate Instantiate via button press.
public class NodeCreator : EditorWindow
{
....
[MenuItem ("Window/Node Creator")]
static void ShowWindow()
{
EditorWindow.GetWindow(typeof(NodeCreator));
}
....
void OnGUI()
{
....
if (GUILayout.Button("Create"))
{
tempobj = Instantiate(obj) as GameObject;
...
}
....
}
I'm making a game in Unity3D with C# for mobile devices and can't figure out how to check which scene was loaded before the current scene. I need to check this to change the spawn point from the player gameobject. First I added a simple script to my buttons (loadnextscene and loadprevscene)
public class SwitchScene : MonoBehaviour {
public int sceneNumber;
public void LoadScene(int sceneNumber) {
Application.LoadLevel(sceneNumber);
}
}
A second scripts handles the touch input from the user and changes the movement of the player object.
So, for example: If the player clicks on the "load previous scene" button in the second Level to switch to the first level again, I want to set the spawn point of the player object on the right half on the screen and not on the left side like when the game was started the first time.
I tried it with Singleton and PlayerPrefs, but it did not work out.
You need to save the scene number to some variable before LoadScene, then check it after the scene loaded.
The only problem is that this variable will be destroyed after the new scene is loaded. So, to prevent it, you can use DontDestroyOnLoad. Here is what you do:
First, create a new empty game object, and attach the following script to it:
using UnityEngine;
using System.Collections;
public class Indestructable : MonoBehaviour {
public static Indestructable instance = null;
// For sake of example, assume -1 indicates first scene
public int prevScene = -1;
void Awake() {
// If we don't have an instance set - set it now
if(!instance )
instance = this;
// Otherwise, its a double, we dont need it - destroy
else {
Destroy(this.gameObject) ;
return;
}
DontDestroyOnLoad(this.gameObject) ;
}
}
And now, before you load, save the scene number in the Indestructable object:
public class SwitchScene : MonoBehaviour {
public int sceneNumber;
public void LoadScene(int sceneNumber) {
Indestructable.instance.prevScene = Application.loadedLevel;
Application.LoadLevel(sceneNumber);
}
}
And last, in your scene Start() check Indestructable.instance.prevScene and do your magic accordingly.
More info here:
http://docs.unity3d.com/ScriptReference/Object.DontDestroyOnLoad.html
*I did not compile the code, so there may be some errors, but this is the general idea.
Why did the PlayerPrefs approach did not work?
I think its the easiest way to solve your problem.
public class FirstLevel : MonoBehaviour {
public void Start() {
PlayerPrefs.SetString("SceneNumber", SceneManager.GetActiveScene().name);
}
}
And then in the second scene simply read the saved PlayerPrefs
public class SecondLevel : MonoBehaviour {
string PrevScene;
public void Start() {
PrevScene = PlayerPrefs.GetString("SceneNumber");
// if there will be a third scene, etc.
PlayerPrefs.SetString("SceneNumber", SceneManager.GetActiveScene().name);
}
public void GoToPrevScene() {
SceneManager.LoadScene(PrevScene);
}
}
You can solve this problem with a single static member variable in the SwitchScene class. No need for the singleton pattern or DontDestroyOnLoad.
public class SwitchScene : MonoBehaviour
{
public int sceneNumber;
private static int previousScene;
private int oldPreviousScene;
void Start()
{
oldPreviousScene = previousScene;
previousScene = sceneNumber;
}
public void HandleLoadPrevButtonClick()
{
SceneManager.LoadScene(oldPreviousScene);
}
}
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> {
}