|
I have a singleton script to manage the state of a power level. A coroutine within the script regenerates the power back to 100% every second or two if the power level falls below 100%. From what I can tell you can't use a coroutine on a script unless attached to a GO. I get the error "Coroutine couldn't be started because the the game object 'defaultProperties' is inactive!" I attached the script to an empty GO but still have the error if it tries to run the coroutine. Is it possible to create a singleton that has coroutines?
(comments are locked)
|
|
As SpikeX already pointed out calling a co-routine recursively might not be a good idea. Using Singletons for global Behaviour and states is a common software architecture. However, you can only start Coroutines from MonoBehaviours and you can't use the "correct" singleton pattern, as you are not supposed to call or change the constructor of a MonoBehaviour. There are several ways to write a "pseudo-singleton" that is a MonoBehaviour to use with Unity.
That's the easiest way. However you will have to attach this to a GameObject manually in your Scene.
The advanced version will create its own GameObject and attach itself to it as soon as you call it for the first time. This is very convenient and keeps your scene small in the editor. You could also implement something that will remove the object from you scene once it isn't needed anymore (e.g. the coroutines have finished.) All of this information posted was good to know. The pseudo-singleton you suggested works by creating the instance on the Start() event. The wiki that describes singletons could use updating as I tried them all...this added information makes it more clear, especially when dealing with MonoBehaviourss and coroutines. I'm able to use coroutines like I need, a recursive coroutine to regenerate my power level works well...waits a second or two and calls itself again indefinitely. A while loop doesn't give me control over the delay I want.
May 23 '10 at 09:50 PM
chearner
Using a while loop and calling the coroutine from within itself do exactly the same thing. You can just add a yield return new WaitForSeconds(1) into the while loop.
May 23 '10 at 09:56 PM
qJake
Thank you SpikeX, I will try that as well. If anyone knows which method may be the least taxing, it might be marginal but I'm targeting iPhones so any savings is worth the effort.
May 24 '10 at 03:14 AM
chearner
The While is less expensive, because using recursion, for a split second you'll have two coroutines running, and I'm sure that it's more expensive to create a new coroutine than to loop in a while statement. I would definitely go with the while.
May 24 '10 at 10:00 AM
qJake
In the 'simple' version I think it would be better to set the instance in Awake() rather than Start(). Awake happens at creation and Start happens before the first Update. It might sound inconsequential, but it is not. If other scripts are trying to 'find' the singleton in their Start() they may not because the singleton Start has yet to run (Start of different components have no particular order).
Jun 29 '10 at 01:19 PM
Molix
(comments are locked)
|
|
I don't know why you're getting errors, but I see a lot of potential problems with this script. Let me point them out, and we'll hope that one of them was the problem.
Thanks. I was using this a script to manage all my power functions like addpower() reducepower() etc. I wanted to be able to call them from any other script like singleton.instance.addpower(). This would Also need to manage the gui display for a power bar.
May 23 '10 at 09:04 AM
chearner
I don't think you have to do the while true thing for the coroutine. It looks like it is just a recursive function his way instead of a loop. Thanks for some other good info though especially point 2 and 3.
May 23 '10 at 07:25 PM
Peter G
Using recursion where not necessary is a programming no-no. :P
May 23 '10 at 09:56 PM
qJake
Actually there's a lot of no no on while(true) aswell, but I use it all the time aswell ^^
Dec 06 '10 at 12:35 PM
Proclyon
+1 There are several "Singleton" implementations out there that aren't really singletons. That said, I don't think it's the Singleton most people are after but a simple convenient access point to a common script, gameobject or component :) The "Componenton" :)
Mar 16 '11 at 02:01 AM
Statement ♦♦
(comments are locked)
|
|
to make the Advanced singleton work, in the start method, add a call to
then, in the awake method add
when using writing public methods, be sure to add "Instance." to your variables. Also, make sure your public methods are static like this:
Beware that i may have made a few mistakes/type-os, but this is how I have my singleton that uses co-routines setup, and it works as it should. If anybpdy sees a real issue with this, speak up, so we can get this solved once and for all. BTW, I learned this code from looking at other peoples code, so its my turn to pay it forward. That's not really an ideal method, because Awake functions don't run in any defined order, so attempting to access the singleton from other Awake functions can and will fail.
Mar 16 '11 at 01:23 AM
Eric5h5
this is true, but with the code, I have an init() method that i call before using the data. Its not ideal, but it works.
Mar 31 '11 at 05:38 PM
kablammyman
(comments are locked)
|
|
Purely for convenience: In almost all projects: it will be the case that you will have an empty game object attached on your opening scene, for clarity let's call it "holdAll". "holdAll" is persistent throughout the game. Attached to that, you will have many files such as Shopping.js, Analytics.js, Calculations.js .. etc etc Each of those uses coroutines. So they really are best as "normal" scripts attached to an game object. Again, it's inevitable that almost every Unity game has an empty game object ("holdAll") which is persistent throughout the whole game, and you use those various I've never seen a Unity project that does not have that. So, this is all great and normal. But, each time you want to use a routine from shopping.js, you need to make a local variable which, annoyingly, you have to hook to shopping.js on holdAll. Of course, it's much easier to just call ordinary static libraries, like when you use Mathf or the like. Is there a solution? Yes, here's what I do. Make a tiny little class called say "grid": then from anywhere at all in your project, with no further effort, you can just write and so on. Same for all the others (Shopping.js, Analytics.js, Calculations.js etc etc) I want the convenience of just being able to say yield shop.whatever(); anywhere in the project WITHOUT needing an annoying hooked-up local variable "shopit" which leads to holdAll-Shopping.js. But in my opinion there's just no really good, bulletproof, way to make a static/singleton/etc, where it's a "normal" coroutine-based Unity object. So ... for me, this seems to answer all those needs. The only downside is effectively one extra "." when you type grid.shopping. Seems to work ok ? It seems awesome! But I'm still quite clueless if this is really a preferred code design over just instantiating.
8 days ago
Cawas
Not really following you there, dude. Was it a rant? I meant, in your example, with a dontdestroy holdall and basically everything else, except instead of creating
Then instantiate it on the editor and use it anywhere in the class as:
It's just couple of "extra" lines (one for the code, another one for the scene instantiation) but we don't need the grid and it's simpler code design. It probably won't be less work, if you scale up, but maybe simpler to maintain. Not sure. "Still quite clueless if this is really a preferred code design". ;-)
8 days ago
Cawas
lol no rant .. sorry if misunderstood ... if you mean instantiate it in the editor as in drag it to he variable (as opposed to GameObject.Find( ... ).GetComponent(...) .... We almost never do that (other than allowing for the "unity can't find inactive at launch objects" problem) ... regarding the two processes (A) GameObject.Find( ... ).GetComponent(...) and (B) drag to the slot in the editor .... I never or rarely use (B) as it seems immature and you can't just drop scripts in anywhere; regarding (A)-or-(B) yeah I guess the whole policy I outline here is to avoid having to either (A)-or-(B)
8 days ago
Fattie
Cool. :-) Now... You can drop scripts anywhere, what are you talking about? I at least never seem such a situation you can't do it. But I can see 2 problems with using (B) and dragging to the slot in the editor. First it is a mouse procedure and quite painful if needed to be done many times. To this, it shouldn't ever be done many times. Second, scenes are not mergable yet, so it can cause a lot of issues with versioning. To that, use prefabs as much as possible. Should make versioning scenes lot easier. Here, for 48 more hints: http://devmag.org.za/2012/07/12/50-tips-for-working-with-unity-best-practices/ The problem with using (A) and
8 days ago
Cawas
Hmmm, I use B all the time :S Better go get my nappy changed ')
8 days ago
whydoidoit
(comments are locked)
|

Actually, I don't see good reasons to use singleton in C#. http://stackoverflow.com/questions/10129680/what-should-we-use-for-global-variables-on-csharp-and-when-or-why-not
Maybe you could point me otherwise.