62

I'm making simple game manager. I have a script, which will be accessible from all scenes in the game. And I need to check values of its variables after loading new scene. But my code runs only once after starting the simulation while an object with this script exists in all scenes. What is wrong? Why doesn't it work after loading a new scene?

Zhaph - Ben Duguid
  • 26,785
  • 5
  • 80
  • 117
Amazing User
  • 3,473
  • 10
  • 36
  • 75
  • 1
    The start is only meant to be called once and since you use DontDestroyOnLoad, this one is not happening again. The object stays in all scene because of DontDestroyOnLoad. Not sure why OnLevelWasLoaded would not trigger though. – Everts Mar 09 '16 at 12:00
  • 1
    since The Awake function is called on all objects in the scene before any object's Start function is called. Probably Start function is not triggered because of this situation. Have you ever tried to call OnLevelWasLoaded function? – Burak Karasoy Mar 09 '16 at 12:02
  • 1
    Pls try OnEnable. And look at [this](http://docs.unity3d.com/Manual/ExecutionOrder.html). – Barış Çırıka Mar 09 '16 at 12:16
  • @BarışÇırıka unfortunately id don't work too..and on the first scene it works just because after each load it create a new instance of the object with the script, I need to fix it. So it don't work for `Start` and `Awake` too – Amazing User Mar 09 '16 at 12:26
  • No he can use. But in this code block it seems useless. If you want to apply singleton pattern you can use like this. Check [this](http://wiki.unity3d.com/index.php/Singleton) link. – Barış Çırıka Mar 09 '16 at 12:38
  • dima it's behave is normal. This gameobject wont be created before first scene. But after that this object stays alive so it can observe scene changes. – Barış Çırıka Mar 09 '16 at 12:39
  • hi joe. In editor it is not good. But pls try that programmatically. It works really good. So it's not big problem for me. If you add same gameobject (script) twice with editor ok its problem otherwise no problem at all. And also dont forget it logs: ` [Singleton] Something went really wrong there should never be more than 1 singleton! Reopening the scene might fix it.` – Barış Çırıka Mar 09 '16 at 12:45
  • It's improved version of your links. – Barış Çırıka Mar 09 '16 at 12:49
  • Not sure if I understand you correctly. Do you want to execute some methods when there is a new scene loaded? Have you tried `SceneManager.sceneLoaded` ? (https://docs.unity3d.com/ScriptReference/SceneManagement.SceneManager-sceneLoaded.html) – YAC Jan 04 '18 at 15:10

5 Answers5

124

In every Unity project you must have A PRELOAD SCENE.

It is quite confusing that Unity does not have a preload scene "built-in".

They will add this concept in the future.

Fort now you have to click to add a preload scene yourself.

This is the SINGLE GREATEST MISUNDERSTANDING for new programmers trying Unity!


Fortunately, it is extremely easy to have a preload scene.

Step 1.

Make a scene named "preload". It must be scene 0 in Build Manager.

enter image description here

Step 2.

In the "preload" scene make an empty GameObject called, say, "__app".

Simply, put DontDestroyOnLoad on '__app'.

Note:

This is the only place in the whole project you use DontDestroyOnLoad.

It's that simple.

enter image description here

In the example: the developers have made a one-line DDOL script.

Put that script on the "__app" object.

You never have to think about DDOL again.

Step 3

Your app will have (many) "general behaviors". So, things like database connectivity, sound effects, scoring, and so on.

You must, and can only, put your general behaviors on "_app".

It's really that simple.

The general behaviors are then - of course - available everywhere in the project, at all times, and in all scenes.

How else could you do it?

In the image example above, notice "Iap" ("in-app purchase") and the others.

All of your "generally-needed behaviors" - sound effects, scoring, and so on - are right there on that object.

Important...

This means that - of course, naturally -

...your general behaviors will have ordinary Inspectors, just like everything else in Unity.

You can use all the usual features of Unity, which you use on every other game object. Inspector variables, drag to connect, settings, and so on.

(Indeed: say you've been hired to work on an existing project. The first thing you will do, is glance at the preload scene. You will see all the "general behaviors" in the preload scene - sound effects, scoring, AI, etc etc. You will instantly see all the settings for those things as Inspector variables ... speech volume, playstore ID, etc etc.)

Here's an example "Sound effects" general behavior:

enter image description here

Looks like there's also a "voice over" general behavior, and a "music" general behavior".

To repeat. Regarding your "general behaviors". (Sound effects, scoring, social, etc etc.) These CAN ONLY GO on a game object in the preload scene.

This is not optional: there's no alternative!

It's that easy.

Sometimes engineers coming from other environments get caught up on this, because it seems like "it can't be that easy".

To repeat, Unity just plain forgot to "build-in" a preload scene. So, you simply click to add your preload scene. Don't forget to add the DDOL.

So, during development:

Always start your game from Preload scene.

It's that simple.

Important: Your app will certainly have "early" scenes. Examples:

  • "splash screen"
  • "menu"

Note. Tou CAN NOT use splash or menu as the preload scene. You have to literally have a separate preload scene.

The preload scene will then load your splash or menu or other early scene.


The central issue: "finding" those from other scripts:

So you have a preload scene.

All of your "general behaviors" are simply on the preload scene.

You next have the problem of, quite simply, finding say "SoundEffects".

You have to be able to find them easily, from, any script, on any game object, in any of your scenes.

Fortunately it is dead easy, it is one line of code.

Sound sound = Object.FindObjectOfType<Sound>();
Game game = Object.FindObjectOfType<Game>();

Do that in Awake, for any script that needs it.

It's honestly that simple. That's all there is to it.

Sound sound = Object.FindObjectOfType<Sound>();

Tremendous confusion arises because of the 100s of absolutely wrong code examples seen online.

It really is that easy - honest!

It's bizarre that Unity forgot to add a built-in "preload scene" - somewhere to attach your systems like SoundEffects, GameManager, etc. It's just one of those weird thing about Unity. So, the first thing you do in any Unity project is just click once to make a preload scene.

That's it!


A Detail...

Note that, if you really want to type even less (!) lines of code, it's remarkably easy - you can just use a global for each of these things!

This is explained in detail here , many folks now use something like this, a Grid.cs script ...

 using Assets.scripts.network;
 using UnityEngine;
 
 static class Grid
 {
     public static Comms comms;
     public static State state;
     public static Launch launch;
     public static INetworkCommunicator iNetworkCommunicator;
     public static Sfx sfx;
 
     static Grid()
     {
         GameObject g = GameObject.Find("_app");
 
         comms = g.GetComponent<Comms>();
         state = g.GetComponent<State>();
         launch = g.GetComponent<Launch>();
         iNetworkCommunicator = g.GetComponent<INetworkCommunicator>();
         sfx = g.GetComponent<Sfx>();
     }
 }

Then, anywhere in the project you can say

Grid.sfx.Explosions();

It's just that easy, that's the whole thing.

Don't forget that each of those "general systems" is on, and can only be on, the DDOL game object in the preload scene.


DylanB asks: "During development it's quite annoying that you have to click to the preload scene every time before you click "Play". Can this be automated?"

Sure, every team has a different way to do this. Here's a trivial example:

// this should run absolutely first; use script-execution-order to do so.
// (of course, normally never use the script-execution-order feature,
// this is an unusual case, just for development.)
...
public class DevPreload:MonoBehaviour
 {
 void Awake()
  {
  GameObject check = GameObject.Find("__app");
  if (check==null)
   { UnityEngine.SceneManagement.SceneManager.LoadScene("_preload"); }
  }
 }

But don't forget: what else can you do? Games have to start from a preload scene. What else can you do, other than click to go to the preload scene, to start the game? One may as well ask "it's annoying launching Unity to run Unity - how to avoid launching Unity?!" Games simply, of course, absolutely have to start from a preload scene - how else could it be? So sure, you have to "click to the preload scene before you click Play" when working in Unity - how else could it be?

Fattie
  • 27,874
  • 70
  • 431
  • 719
  • 8
    So in terms of workflow, how does this work? If you want to test the scene you're currently editing, do you then have to go load the preload scene in the editor and hit Play on that, since the preload scene is what has the initial objects that propagate to the subsequent scenes? If so, that seems incredibly obtuse as a workflow. I feel like I'm missing something here. – Dylan Bennett Jul 15 '16 at 20:41
  • 3
    It's a GREAT QUESTION. Yes, it is ***ABSOLUTELY NORMAL*** in Unity that you have to annoyingly click back to the preload scene, to test the game. You are missing nothing. You've completely hit the nail on the head. – Fattie Jul 15 '16 at 20:43
  • 21
    "every Unity project you must have A PRELOAD SCENE" Why? Please explain why. Lazily initialising objects and accessing them from a static class/singleton seems to be easier - especially when it comes to testing scenes, as you can easily start each scene individually. – SePröbläm Nov 05 '16 at 15:26
  • every game (not a trivial test) will of course have a preload scene? why would you want to put the things like sound effects anywhere else? [same discussion](http://stackoverflow.com/a/35524924/294884) It's difficult to "convince you" to do it a way that is incredibly easier, has no spaghetti code (indeed, has *no code!* - how much easier can it be?), and is obvious and sound engineering, is exactly how Unity works, all the GB are together, you can see them, use the Inspector, etc etc. It's like asking "So why use 'functions' instead of 'goto' ?" - heh. – Fattie Nov 05 '16 at 16:10
  • Is there an example available of one of the implemented managers? Like a GameManager class? I'm currently doing it with generic singletons, but I want to switch to this method. What are the requirements of the Managers? A link to an example project will suffice too :) Thanks! – Starfish Apr 18 '17 at 22:22
  • I'm currently developing a RTS game (early-early-stage). My GameManager manages the UI, Pause, Scene switching (main menu to game and back). Are the managers a normal class? Or do I need to create my class like 06:20 : https://www.youtube.com/watch?v=EI1KJv8owCg – Starfish Apr 19 '17 at 08:31
  • hi @Patrick2607 - sure, your class "GameManager" would indeed **be a ordinary MonoBehavior**. Exactly like "Sfx" in the image example above. So, it would be `public class GameManager: MonoBehavior`. It's that simple. Just btw a suggestion is, instead of "GameManager" (which always seems sort of old-fashioned - what else would it be managing?! :) ) just have global behaviors such as say "Scoring", "LapManagement" and so on. As you wish. – Fattie May 01 '17 at 16:37
  • The other alternative to a preload scene is to.... *shock!* not use multiple scenes. I realize that for some game types this isn't possible, but a lot of people I see struggling with scenes are using scenes where they really shouldn't be ("I have a main menu scene and a win scene and a lose scene..." NO, STOP USING SCENES THAT WAY). – Draco18s no longer trusts SE May 01 '17 at 16:39
  • Hi @Draco18s, there are two issues. (1) ***YES, YOU ARE COMPLETELY CORRECT THAT SOMETIMES PEOPLE OVERUSE SCENES***. If you need to have an "opening menu" ....... just have it pop up as a UI panel. No need for a scene. Note however that (2) ***IT IS INCREDIBLY NATURAL TO HAVE A PRELOAD SCENE in games*** in every paradigm, every environment. Even if (for now) you just have one scene, it is just easier to have a preload scene. Then everyone one of your projects for every client will have one; if you ever add a scene, no problem. – Fattie May 01 '17 at 16:42
  • Oh sure, I completely agree that it's a normal thing. That's why I've +1'd your answer. When using multiple scenes you *absolutely* need a "preload" scene to set up your manager objects (I've done it!). Its just that so often you can get away with having a single scene and just enabling/disabling objects to get the same effect. My current project is a single scene, for example. – Draco18s no longer trusts SE May 01 '17 at 16:45
  • Ok so I got the preload scene with _app and my GameManager object in it together with the UI elements. I can use the DevPreload class for my other scenes. Let's say I'm launching Scene1, whereafter _preload (DevPreload) gets loaded. How does it automatically switch back to Scene1 again? This might be obvious but I'd like to be sure. – Starfish May 04 '17 at 21:30
  • hi patrick ... "together with the UI elements" THATS WRONG, sorry for the bad news! :O the preload scene does NOTHING - NOTHING other than the "_app" object and your game managers. have ANOTHER SCENE called perhaps "UX". that will be the "first scene" of your game not counting the preload scene. Makes sense ? – Fattie May 04 '17 at 21:58
  • you absolutely do not launch at Scene1. the preload scene is scene0, and the game will and must launch from there. you dont even see anything in the preload scene - it just immediately launches your "Scene1". Good luck! – Fattie May 04 '17 at 21:59
  • Ah okay I will take that into account, thank you :). So yes I am launching the preload scene at first, but where do I load the next scene (actual game)? Do I load it in the Start() of the _app? – Starfish May 04 '17 at 22:45
  • @Fattie After thinking about this a bit more I can't figure it out. I have GameObjects (Player, pet, inventory, etc.) That I DDOL, this is done in the script attached to that GameObject. So how would I even do this if I have to attach the scripts to __app? They need to be attached to my GameObjects (i.e Player, Pet, Inventory, etc.) am I making sense? I understand how it works for scripts that are not attached to other GameObjects (i.e sounds, states, etc), but I don't see how to use this in the scenario I explained above, since you say "ONLY USE DDOL HERE" – Green_qaue May 30 '17 at 21:32
  • Hi Green, right! On this page I was only talking about your "management" scripts! (Sound effects, scoring, AI, game management, networking - etc etc etc). Regarding your "actual things" ... Player, Pet, etc. I would say, you *usually do not* DDOL things like that; it could be your approach is wrong. However, again, it's unrelated to the issue on this page. (Perhaps, ask a new separate question if you're having troubles withthat ?) Cheers! – Fattie May 30 '17 at 21:38
  • @Fattie I tried adding a Persistent-Scene as you detail here, but it causes some strange behaviour I dont understand. Could you take a look? https://stackoverflow.com/questions/44283615/unity-weird-scene-transition-bug-after-adding-a-persistent-scene-with-a-gamem – Green_qaue May 31 '17 at 13:58
  • 21
    @Fattie I will have to disagree with you on this one. True, a preload scene is sometimes (very rarely) necessary, but for the most part everything you describe is just a lazy way of doing it. The first downside you already mentioned... you always have to start from scene 0. I've made the mistake of developing a game this way, and have lost hours upon hours because of it. ALWAYS develop your game so it can be started from any scene. The benefit of this should be obvious. – Squeazer Jul 06 '17 at 19:11
  • 11
    @Fattie Second, you suggest using FindObjectOfType to get your instances. Yeah, it's dead simple, but yet again, a lazy way of doing it. The call is super slow and even Unity suggests not to use it: https://docs.unity3d.com/ScriptReference/Object.FindObjectOfType.html When developing with Unity, you're offered way too much freedom, so you have to be really careful how you design your architecture. If you're not, you'll run into endless problems later on... trust me, I've been there. There are a lot of good practices for Unity out there, this, however, is not one of them. – Squeazer Jul 06 '17 at 19:12
  • 3
    @Fattie Please elaborate. The only benefit of this that I see is that it's easy and simple to understand for new Unity developers. Have you seen this best practices list: http://devmag.org.za/2012/07/12/50-tips-for-working-with-unity-best-practices/ There are a lot of similar ones out there, but still you're the only one I could find that advocates using a preload scene. Oh, and you mention that Unity will "add this concept in the future". Do you have any blog post or bug report link that you can share about this? – Squeazer Jul 06 '17 at 19:38
  • lol dude, you mention "performance", FindObjectOfType is called ... once :) – Fattie Jul 06 '17 at 19:39
  • 4
    @Fattie What if you're spawning something that needs rapidly? Or in a burst of 1000 spawns? Or any other of the countless scenarios, where new objects are created rapidly? Slow calls like this will in time pile up, especially if you're building for Android / iOS. Even frequent (e.g. in every Update call) use of Camera.main (does basically the same thing) will drastically reduce your FPS on complex scenes. – Squeazer Jul 06 '17 at 20:08
  • hi Squeazer. Spawning (bullets, tanks etc) has no connection at all to what is under discussion here (the general game systems - sound effects, AI, networking and so on). – Fattie Dec 29 '17 at 02:37
  • 1
    how come this detailed and very "up-voted" answer has not been awarded the bounty ? – Mauricio Gracia Gutierrez Jan 04 '18 at 04:05
  • 1
    It's possible to avoid starting at the preload scene and start any scene from unity, whilst retaining the preload logic. I've seen it elsewhere, but couldn't find a reference here. I've placed an example (with the simplest project ever) here: https://github.com/RawToast/grid-game-manager-unity – RawToast Jan 31 '18 at 13:40
  • hey @RawToast. apps simply "have to" start from a preload scene. Like, in an iOS app you couldn't "not" load AppDelegate. Say you're working on GTA. There's no meaningful sense in which you can "not" do all the setup (say - "make the user account" "establish connectivity" "load the meshes from json files" etc etc etc). If you mean simply, **automatically 'go to' the preload scene, very simply to avoid that click while you are using the editor** - then sure. There are a number of popular systems to do just that (since - every single Unity developer has to do it every single time!).... – Fattie Jan 31 '18 at 14:21
  • For further clarity on this issue. Note that, in all but the most trivial test projects: totally setting aside "setup / preload" issues..... in almost every real project there's a "chain" of scenes that run, before, you can get to whatever scene you are working on. Example - there's a scene which "builds your dynamic mesh dinosaurs", or, "where the user chooses their car, before racing". Of course - obviously - it's impossible to go to the next scene, until, you run those scenes!!!!!! So, "starting at an earlier scene" is absolutely normal when working in Unity. – Fattie Jan 31 '18 at 14:25
  • @Fattie is there any way we can exchange contact info for a discussion about this and Unity code architecture for scenes, levels, scores, and game progress etc? I have a fully functioning demo, but can't bind it all together. Designer brains don't scale well. – Confused Dec 14 '18 at 03:40
  • 1
    This is basically the stereotype of the Anti-Pattern "God Object": https://en.wikipedia.org/wiki/God_object - I would not recommend using this as it makes Unit tests hard and integration tests nearly impossible. Also, there is a better solution available with StrangeIoC. –  Apr 03 '19 at 08:55
  • 2
    hi @TLS ! Don't forget Unity is an ECS system (it has absolutely no connection, at all, to OO. Every single GameObject in a Unity scene, is, a "god object" :) ) There have been a couple attempts at "monoBehavior constructors" , such as StrangeIOC, which attempt to change an ECS system, a frame-based system, to a "pure code" paradigm. Since you have raised the issue here, I don't want to just dismiss it, it would take a short discussion to dismiss it! :) (BTW note that if you use strangeIIOC or similar, you have to put the bootstrap on the preload scene.) – Fattie Apr 03 '19 at 10:39
  • @Fattie my impression of necessity of a preload scene is mainly because of networking compensations on initial load, including logins, game state, etc. Although it includes loading assets as well, it doesn't necessarily restrict every other low-latency based games to have a preload scene. I am interested to know what's your take on this? – hiradyazdan Jul 15 '19 at 08:25
  • 1
    hey @hiradyazdan - that's a good point; rather than using the word "preload", you can call it the "DDOL" scene or the "managers" scene. (Due to the structure of Unity, you need such a scene on which to attach your various general behaviors or "managers", amd that's that.) This post and this discussion has absolutely no connection to the (various other) reasons you may or may not need a preload scene in games. indeed note that as I mention in this article, you ***should not*** use the "managers scene" (ie, as discussed here) for the other sundry reasons you need a preload scene in games... – Fattie Jul 15 '19 at 10:43
  • @Fattie I can't agree with *>> The preload scene will then load your splash-scene, menu-scene, or whatever you wish.) <<* because a user shouldn't wait for the splash-scene while preload-scene is loading some assets. The user should see the splash-scene first with some kind of "loading" bar while all those assets are loading. But maybe I understand your scene names differently and you meant the same. – Serg Mar 07 '20 at 09:18
  • Hi @Sergey - good news, you've simply misunderstood me. The "preload" scene takes no time whatsoever, zero, to load. End of story. It simply establishes the patterns for your "general" game objects as discussed. Exactly and literally what I was saying is, say you have to load or process some large assets. Exactly literally what I was saying is don't do that in the "preload" scene, do it in ANOTHER, SEPARATE conventional scene which follows. ie, literally precisely what you are saying! :) – Fattie Mar 07 '20 at 15:23
  • Hi @Fattie, you're right, names associations are sometimes confusing. I think I should read your post again because what I've got from it is that the *preload scene* is where the "immortal" objects *(_app or _audio)* reside, and it carries some stuff like sounds that take time to get loaded. – Serg Mar 07 '20 at 18:18
  • howdy @Sergey ! Right! So in the "pre-load" scene, you would simply instantiate those manager ***CLASSES***. Let's take the example of "sound effects manager". You would have some script of a few hundred lines of code that is your "sound effects manager". Don't forget we're talking about the CLASS (actually a game object component) which MANAGES your sound effects! So in the "pre-load" scene that CLASS fires up. Looking at my post above where it says "It's honestly that simple", from then on until the end of time you reach SoundEffectsManager like that, simple! But ... – Fattie Mar 07 '20 at 20:54
  • .. cont @Sergey that's the SoundEffectsManager CLASS. indeed! Say it only loads one or two tiny sound effects, sure, whatever, you'd just do that then. BUT if it loads megabytes of sound effects (perhaps from the net .. whatever) YOU WOULD INDEED DO THAT IN ANOTHER SCENE! A "LOADING" SCENE !!!!!! Just as you say! EXACTLY as you say!!! So that's it! – Fattie Mar 07 '20 at 20:55
  • @Fattie now it makes sense to me. But I prefer to instantiate classes like `SoundsManager` in the **MainMenuScene** which is DDOL as well but loaded after the **PreloadScene** and while it is asynchronously loading the **PreloadScene** shows some kind of loading-animation. – Serg Mar 07 '20 at 21:42
  • @Sergey - gotchya, but honestly you are mistaken. (1) there is no reason, whatsoever, that a menu scene would be DDOL. it's just a menu scene. (2) to load the SoundManager *class* takes absolutely no time, there is no time issue involved (3) it's regular, normal practice to have all your Managers loaded first before ANYTHING - after all, your "menu" scene *will certainly* need to use a number of your Managers (audio, networking certainly, and so on!) So, cheers for now! thanks for the discussion – Fattie Mar 07 '20 at 21:47
  • @Fattie only the `SoundManager` is DDOL, not the entire *MainMenuScene* - it's just a scene where the `SoundManager` is instantiated and used further in other game scenes. It doesn't only manage sounds, but also loads them. In your example,it is instantiated in the *PreloadScene* but sounds are loaded later in the futher scenes (if I got it correctly). So, the managers are fully initialized at the same time in both cases. – Serg Mar 07 '20 at 22:31
  • @Fattie or I just can't figure out why instantiating the `SoundManager` in the *PreloadScene* is better if it can't be used in any way until it has the sounds loaded in the next scene. – Serg Mar 07 '20 at 22:39
  • well it has to be there and be ready - they ALL have to be there and be ready - when the next scene (say, your Menu or Loading scene) loads. It's that simple! Note that in programming in general, say you say to me "it is incredibly convenient to use functions", I could reply "here's a case where there doesn't seem a reason to". Believe me, once you have any size of game, you'll use a "preload" scene as disacussed, or it will be chaos, heh! Cherers!! – Fattie Mar 08 '20 at 02:58
  • So, as I'm developing, do I have to regularly change a script in _preload to direct the game to load the latest scene I'm working on (so I don't have to go through the whole game to get to it)? I know you put that script that will load the _preload in the currently tested scene, but I'm just wondering how to minimize having extra code hanging around and how to reduce editing code every time I switch scenes I'm working on. Sorry if the question is already answered or kinda dumb! – tempranova Jul 21 '20 at 23:40
  • hi @tempranova , it's not a dumb question! in practice when you're working on a game, say the scenes are: *ChooseVehicle* then *StartingGrid* then *LapOne*. Annoyingly, you cannot actually just run "LapOne" until you have run the other two! Because you won't have a car yet!! But yes, sure, if you (for whatever reason) want to jump to SceneX during development, if that's possible, just change that line of code, cheers! – Fattie Jul 22 '20 at 11:32
  • Thanks. Yes, in our game, we have a suite of minigames inside different levels, so it's possible to do each game separate from the others. so we'll have a script that we change to redirect to the currently worked-on minigame during dev. thanks again for responding! – tempranova Jul 22 '20 at 21:13
  • 1
    hi @tempranova ! you know what I do in that situation. just take 30 seconds to make a quick scene - what I mean is a scene ONLY for like you, me and the other developers! not a consumer scene. just have a UI canvas, 10 buttons on it ... and they load the different minigames! that's really the way to go!! it helps tremendously, it pops up instantly when you hit Play, and you go to the scene you're working on ! I hope the idea helps! – Fattie Jul 23 '20 at 09:59
31

@Fattie: Thanks for elaborating all this, it's great! There is a point though that people are trying to get through to you, and I'll just give it a go as well:

We do not want every instantiation of everything in our mobile games to do a "FindObjectOfType" for each and every every "global class"!

Instead you can just have it use an Instantiation of a static / a Singleton right away, without looking for it!

And it's as simple as this: Write this in what class you want to access from anywhere, where XXXXX is the name of the class, for example "Sound"

public static XXXXX Instance { get; private set; }
void Awake()
{
if (Instance == null) { Instance = this; } else { Debug.Log("Warning: multiple " + this + " in scene!"); }
}

Now instead of your example

Sound sound = Object.FindObjectOfType<Sound>();

Just simply use it, without looking, and no extra variables, simply like this, right off from anywhere:

Sound.Instance.someWickedFunction();

Alternately (technically identical), just use one global class, usually called Grid, to "hold" each of those. Howto. So,

Grid.sound.someWickedFunction();
Grid.networking.blah();
Grid.ai.blah();
Fattie
  • 27,874
  • 70
  • 431
  • 719
Frits Lyneborg
  • 541
  • 4
  • 3
  • 3
    Hey Frits! **You are 1000% correct** :) I guess I invented the Grid.cs idea, which you can see here https://answers.unity.com/answers/663681/view.html It is widespread now. It is precisely and exactly what you describe. *It used to be that I would describe to new Unity users the "grid" system*... exactly what you describe. But I realized over time it is confusing - it's better to simply explain the fact that you have a preload scene. That is the "core" of the issue. Sure, you can add some syntactic sugar later once you're familiar (and if you want to). **Your code is 10000% lovely.** – Fattie Dec 29 '17 at 02:42
  • 1
    Since this QA is so popular, I sent a 100 point bounty here since it is an excellent piece of information, building on this really important QA. Do not spend it all in one place, Frits! :) – Fattie Jan 04 '18 at 16:41
  • Say @fritslyneborg, if you're still reading ..... funnily enough, I do almost exactly the same thing in iOS! Here ... https://stackoverflow.com/q/32660471/294884 – Fattie Jan 31 '18 at 14:32
10

Here is how you can start whatever scene you like and be sure to reintegrate your _preload scene every time you hit play button in unity editor. There is new attribute available since Unity 2017 RuntimeInitializeOnLoadMethod, more about it here.

Basically you have a simple plane c# class and a static method with RuntimeInitializeOnLoadMethod on it. Now every time you start the game, this method will load the preload scene for you.

using UnityEngine;
using UnityEngine.SceneManagement;

public class LoadingSceneIntegration {

#if UNITY_EDITOR 
    public static int otherScene = -2;

    [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
    static void InitLoadingScene()
    {
        Debug.Log("InitLoadingScene()");
        int sceneIndex = SceneManager.GetActiveScene().buildIndex;
        if (sceneIndex == 0) return;

        Debug.Log("Loading _preload scene");
        otherScene = sceneIndex;
        //make sure your _preload scene is the first in scene build list
        SceneManager.LoadScene(0); 
    }
#endif
}

Then in your _preload scene you have another script who will load back desired scene (from where you have started):

...
#if UNITY_EDITOR 
    private void Awake()
    {

        if (LoadingSceneIntegration.otherScene > 0)
        {
            Debug.Log("Returning again to the scene: " + LoadingSceneIntegration.otherScene);
            SceneManager.LoadScene(LoadingSceneIntegration.otherScene);
        }
    }
#endif
...
kolodi
  • 1,002
  • 9
  • 16
6

An alternate solution from May 2019 without _preload:

https://low-scope.com/unity-tips-1-dont-use-your-first-scene-for-global-script-initialization/

I've paraphrased from the above blog to a how-to for it below:

Loading a Static Resource Prefab for all Scenes

In Project > Assets create a folder called Resources.

Create a Main Prefab from an empty GameObject and place in the Resources folder.

Create a Main.cs C# script in your Assets > Scripts or wherever.

using UnityEngine;

public class Main : MonoBehaviour
{
    // Runs before a scene gets loaded
    [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
    public static void LoadMain()
    {
        GameObject main = GameObject.Instantiate(Resources.Load("Main")) as GameObject;
        GameObject.DontDestroyOnLoad(main);
    }
    // You can choose to add any "Service" component to the Main prefab.
    // Examples are: Input, Saving, Sound, Config, Asset Bundles, Advertisements
}

Add Main.cs to the Main Prefab in your Resources folder.

Note how it uses RuntimeInitializeOnLoadMethod along with Resources.Load("Main") and DontDestroyOnLoad.

Attach any other scripts that need to be global across scenes to this prefab.

Note that if you link to other scene game objects to those scripts you probably want to use something like this in the Start function for those scripts:

if(score == null)
    score = FindObjectOfType<Score>();
if(playerDamage == null)
    playerDamage = GameObject.Find("Player").GetComponent<HitDamage>();

Or better yet, use an Asset management system like Addressable Assets or the Asset Bundles.

phyatt
  • 18,472
  • 5
  • 61
  • 80
3

actually as a programmer who comes to unity world I see none of these approaches standard

the most simplest and standard way: create a prefab, according to unity docs:

Unity’s Prefab system allows you to create, configure, and store a GameObject complete with all its components, property values, and child GameObjects as a reusable Asset. The Prefab Asset acts as a template from which you can create new Prefab instances in the Scene.

Details:

  1. Create a prefab within your Resources folder:

  2. create a script with contents like below:

using UnityEngine;

public class Globals : MonoBehaviour // change Globals (it should be the same name of your script)
{
    // loads before any other scene:
    [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
    public static void LoadMain()
    {
        Debug.Log("i am before everything else");
    }
}
  1. assign it to your prefab

and you can make it even better:

use prefab and namespaces together:

in your prefab script:

using UnityEngine;

namespace Globals {
    public class UserSettings
    {
        static string language = "per";
        public static string GetLanguage()
        {
            return language;
        }
        public static void SetLanguage (string inputLang)
        {
            language = inputLang;
        }
    }
}

in your other scripts:

using Globals;

public class ManageInGameScene : MonoBehaviour
{
    void Start()
    {
        string language = UserSettings.GetLanguage();
    }

    void Update()
    {
        
    }
}