Gamasutra: The Art & Business of Making Gamesspacer
The top 5 things I've learned as a Unity developer
Printer-Friendly VersionPrinter-Friendly Version
View All     RSS
April 23, 2014
arrowPress Releases
April 23, 2014
PR Newswire
View All





If you enjoy reading this site, you might also want to check out these UBM TechWeb sites:


 
The top 5 things I've learned as a Unity developer
by John Warner on 09/10/13 04:05:00 am   Featured Blogs

The following blog post, unless otherwise noted, was written by a member of Gamasutra’s community.
The thoughts and opinions expressed are those of the writer and not Gamasutra or its parent company.

 

Unity is a fantastic game development platform for many reasons, one of which being the clean, accessible way its component-oriented platform is designed.  For example, it's very easy to slam together some code and have a simple working prototype running in a day or two. Despite its versatility however, I've found over the years that there's a few practices that work particularly well with Unity. 

With my new game, The Fall, I've taken many of these practices and combined them. The result has been a very smooth development process that has been quick and easy to work in and has created relatively fewer bugs that my last games.  To help celebrate my announcement of The Fall and help plug its new Kickstarter campaign, I'm writing this article to share some of my favorite design practices that might help you, with your game.

If you get some value out of this article, please check out The Fall on Kickstarter!

1: Think of your code as a long term company asset

A great programmer once told me that when you write code, you should consider not just its value as an asset to the project you're working on, but as an asset to your business. For example, in The Fall, I have a dialogue system that can display a conversation between two players with avatars:



This dialogue system is written in a way that's completely independent and requires very little set-up in Unity. I can, with very little work, take this dialogue system and plug it into any future game that I want to make. Simple adjustments to it's OnGUI() function could re-skin what is essentially a perfectly functional dialogue system that could theoretically work in most cases, right out of the box. Needless to say this saves a lot of time and money, and the increased speed and ease also aides the creative process as well.

Remember: If you're going to invest the time to write code, you should be adding value to your business and creative process as well!

2: Use global class instance variables

This design pattern has helped me the most in keeping my components separate and clean.  The idea here is for each or your major scripts, you can set a global variable that points to a specific instance of that script, so that you can access that instance anywhere without having to cross-wire scripts in the inspector.  Here's how it works, more or less:

Inside my main DialogueSystem.cs script, I have a variable at the top, that has the same type of it's containing class, written as follows:

public static DialogueSystem instance;
or in JavaScript:
static var instance : DialogueSystem;
 
Then, in the script's Awake() function, you simply write:
instance = this; 

You then simply attach this script to any object in your scene, and when Unity loads that scene, that particular script instance will set DialogueSystem.instance to it's self. Why is this helpful? Well, it means that if I want to access my dialogue system, from anywhere in my game, all I have to do is type:

DialogueSystem.instance.SomePublicFunctionName();

And Unity will know that I want to call a function on the particular instance of the DialogueSystem script in my scene. 

Important note -- This design pattern intends that you only have one script instance in a given scene. Therefore, this works very well for large components, such as a dialogue system, but I would imagine it would be useless or problematic to use on objects that could be instanced multiple times in a scene. If you're interested in a more safe implementation of this pattern, you can Google "Singleton" - the implementation in this article is more simple, for accessibility's sake.

3: Use Callbacks (delegates or Monobheaviour.SendMessage())

This one is a little more complicated if you're a beginner. Consider this:

Lets say we have an NIS (non-interactive sequence) where we want the player's character to walk a few steps, stop, enter dialogue with an NPC, and then return control to the player once the dialogue has ended.  Well, because of point #2 in this article, we know that we can simply activate the Dialogue System from an NIS script by calling

DialogueSystem.instance.SomeFunctionToActivateDialogue() 

But how do we know when the dialogue has finished, so that the NIS script can return control to the player, or do something else that we want? Well, we can use a callback. When we first call DialogueSystem.instance.Whatever(), we can pass that function some parameters that it can use when it's finished to notify the script that called it in the first place. There are a few ways of doing this. I very much prefer using Delegates in C#, because they're a little cleaner, but if you use Javascript, they're not an option.

Delegates (C#)
Think of delegates as variables that basically point to a function. Using delegates, you can pass function A to function B as a parameter, so that function B can call function A when function B completes. I won't get into the details of creating delegates here, but it's a fairly simple process and this is a good place to get started learning:
http://msdn.microsoft.com/en-us/library/ms173171(v=vs.80).aspx
If I get some requests, I'd be happy to write a more detailed tutorial.

MonoBehaviour.SendMessage(string)
Unity provides some callback functionality using its SendMessage function, that can basically call a function in a script, with a string that is the function's name. For example, lets say we have a script named "Foo" with a function named "FooFunction". Inside another script, we'd need a variable that points to an instance of our "Foo" script, lets say we call that variable "ourFooVariable". We could then call

ourFooVariable.SendMessage("FooFunction");

We can use this for callbacks because we can pass an instance of a script and a function name to another function. For example, in Javascript:

Script A:
-----------
function Start(){ 
ScriptB.MyFunction(this, "MyCallback"); // 'this' means this instane of Script A
}
function MyCallback(){
//This will get fired after script B is finished.
}
------------
Script B:
------------
function MyFunction(callback : MonoBehaviour, cbName : String){ 
//do some stuff 
//..... 
//call back to script A: 
callback.SendMessage(cbName);
}
----------- 

Using callbacks in conjunction with global class instance variables can help you create components that are more or less independent. In The Fall, when the player is in an NIS and the dialogue system needs to be triggered, the NIS simply calls the dialogue system and sends it a callback, and then does nothing as the dialogue system works. When it's finished, the dialogue system runs the callback function in the original NIS and the NIS then goes about it's business. Nothing needs to be cross-wired. No work in the inspector is required to get these systems to play nicely together. No NIS scripters need to mess with the dialogue system to get it to work nicely with their code. It just works.

4. Get scripts to disable and enable themselves.

Lets look back again to our dialogue system example. In The Fall, when the dialogue system is enabled, it draws to the GUI, all the time. I have no checks in the script to see weather or not it should be displaying the dialogue, it simply always does it. This works because the dialogue system is able to enable and disable it's self, and this works well because of points #2 and 3.

When I activate a dialogue in my dialogue system, the first line of code is for the dialogue system to enable it's self:

this.enabled = true;

When the dialogue has completed and the callback has been sent, the last line of code disables it's self:

this.enabled = false;

This way the dialogue system doesn't take much in the way of resources and simply sits there and shuts its mouth, so to speak, until it's needed.

5. Try to get away from using Update for everything -- try using coroutines.

A very common design pattern with unity development is to put simple code in a function that runs every frame, when it really only needs to be run once in a while.  For example, there's a popular Fade-In-and-Out solution that checks, every frame, weather or not it should be making the screen black, and then moves a number between 0 and 1. It does this every single frame, always, even though the vast, vast, vast, vast majority of the time, this doesn't need to be considered at all.

There are lots of times when you want a script to wait for a long period of time, and then do something gradually on command. I have found that Coroutines are often the best way of making this happen.

Here is a simple primer on Coroutines in unity

Basically, with Coroutines, you can get unity do something over several frames, and exit when it's done. Instead of having a fade-in-and-out script that's always updating, you could create a coroutine to fade the screen in or out, which would simply stop on completion, so Update isn't running constantly like the faucet in the kid's bathroom.

In JavaScript, a simple coroutine might look like this:

var fadeAlpha : float = 0;
function FadeIn(seconds : float){ 
while(fadeAlpha != 1){ 
fadeAlpha = Mathf.MoveTowards(fadeAlpha, 1, Time.deltaTime*(1/seconds)); 
yield; 
}
}

If this function gets run, it would change the value of fadeAlpha to 1 over how ever many seconds you tell it. You would then use that fadeAlpha value in a similar fashion to the script in the above link, in an OnGUI function.

Putting it all together

Lets consider a FadeInOut script, using all of these ideas. We create a FadeInOut script and plunk only one instance into a scene and disable it. Make sure the script has a static variable called instance, and when the script runs it's Awake() function, it sets the instance variable to it's self. 

Next, we create a few functions in the script similar to the one above, only that enable the script in the first line of FadeIn(), and disables the script in the last line of FadeOut();

If we want, we can implement a callback system, but this script is probably too simple to warrant it.

Then, if we ever want the game screen to fade out, we just call FadeInOut.instance.FadeOut(1); and the game will fade out over one second. When we want it to fade in again, We can call FadeInOut.instance.FadeIn(1) and the game will fade back in over 1 second.

This way, we've created a simple FadeInOut script, that works completely independently, doesn't waste resources, and can be plunked into any scene of any unity game and work with no setup or cross-wiring in the inspector what so ever.

Conclusion

Creating modular bits isn't just good for the sake of organization, but it also creates value for yourself over time. I'm sure there are lots of other design patterns to aide this process.  I hope that you got some value out of this and that my descriptions weren't too confusing. If you liked what you read, or have a question, please leave a comment and I'll do my best to respond. 

Don't forget to check out The Fall on Kickstarter! I could use your support :) 


Related Jobs

Square Enix Co., Ltd.
Square Enix Co., Ltd. — Tokyo, Japan
[04.23.14]

Programmers
Treyarch / Activision
Treyarch / Activision — Santa Monica, California, United States
[04.23.14]

Production Coordinator (temporary) - Treyarch
Vicarious Visions / Activision
Vicarious Visions / Activision — Albany, New York, United States
[04.23.14]

Senior Software Engineer-Vicarious Visions
Chukong Technologies
Chukong Technologies — Menlo Park, California, United States
[04.22.14]

Developer Relations Engineer






Comments


Nelson Ribeiro
profile image
Very informative and helpful. Also The Fall is looking great, best of luck!

MrPhil Ludington
profile image
Great, simple, useful example of how to program in Unity! Good work! PS You should mention that using #2 is away to avoid using GameObject.Find() which is a terrible thing to call because it performs so badly!

Brandon Mason
profile image
I have to disagree with a few of your points.

Using global variables and singletons everywhere can make a project extremely complicated when you have multiple developers on a project. It gets even more confusing if you walk away from it for a few weeks. This is one the fundamental philosophies of object oriented programming that you're violating and encouraging other people to do so as well. Singletons have their purpose for a system that isn't going to be created more than once or for something like an object 'manager' and that can eliminate the need of static/global variables.

You seem to be convinced that coroutines are a god send so much so that you want to replace Update loops with them. I can understand that some behaviors don't need to occur every frame, but the flaw with coroutines is that they execute ONLY when there is a free cycle. So if you have a coroutine wait for five seconds, if the processor is busy when those five seconds are up it will not continue until the processor has freed up. A better practice for that would be using Invoke or Update. I don't know why you want to avoid using update, it's not like its going to slow down your game (even if it's on an old smart phone)!

I felt obligated to post here because although a lot of my co-workers and programming friends strongly disagree with those two points the only comments here are people agreeing with you.

With that being said I agree with some of your other statements.

Unity scripts can easily be designed to be truly modular so that you can move components from one project to another as long as your code is structured with that in mind. You'll want to be careful with that though because planning too far ahead of time like that can end up destroying your project before it's even started!

C# is the best language for Unity because of delegates and that would be my main point of discussion for people who don't use c# to switch.

Scripts disabling and enabling themselves can be debatable but I've used this myself from time to time so I agree with that point.

Michael Bartnett
profile image
You seem to have confused coroutines with threads.

How often a coroutine is called depends on what you return on the yield. A "yield return null;" will always return on the next frame after Update has been called on all scripts. A "yield return new WaitForFixedUpdate();" will always run after the next FixedUpdate. This is a Unity-managed scheduler, not the system scheduler.

John Warner
profile image
Hey Brandon, thanks for your reply. I'm still relatively green myself and I really dig critique like this.

Valid point on using global variables, and I have no doubt that they might turn into a nightmare on larger projects-- but I think most unity developers, including myself, tend to have relatively small projects - I haven't really run into problems yet... but famous last words I suppose. Also, I find that this design pattern allows me to build components that speed up prototyping on my other projects. I throw a script into a scene and can access it directly. I'm not sure if I see the point of having an ObjectManager for something like that -- enlighten me? If I'm up to my eyes in shit and don't know it, I'd certainly like to :)

My understanding is that there is a resource footprint associated with having an Update function, even if it's blank with nothing in it, but for the love of me I can't find the thread where this conversation took place now that I'm looking. I do find Coroutines more pleasing to read and useful for NISes, but that's another issue I suppose. Also, like Michael pointed out, my understanding was that coroutines continued as expected consistently after a yield command. They bloody-well better. We live in a society, gd it.

Luis Deliz
profile image
Very informative post. Extra tips: Avoid foreach loops, they generate 24bytes of trash data per loop. Use for loops instead. Also avoid object.tag == "string"; object.CompareTag("string") is more efficient.

Juan Mora
profile image
In defense of the foreachs (because they are very cool):

1. It only applies to code executed frequently (for example, every frame). In general, this kind of little optimizations, when done over code you run only very few times in an entire game session, are a waste of your time.


2. This specially applies if you're targeting older mobile devices, and/or if your game is very sensitive to framerate spikes (like a rhythm game).

On the other hand, we have this soccer game with lots of foreach and all kind of allocations frame-by-frame (very weak, I know, but it's because it was targeted to pc-only at the start of the project, and we didn't care about garbage collection too much).

In this soccer game, running on an ipad 2 (our weakest target device), garbage collection spikes are barely noticeable by players (of course you can see them clearly on the profiler). And on newer devices like ipad 4, you can't really tell if there was any garbage collection at all.

John Warner
profile image
Luis, I did not know that! Thanks :)

Ted Brown
profile image
Thanks, John!

As an aside, how do you manage memory limitations when using singletons, since Unity can't know ahead of time what will be in memory (since they aren't linked in the inspector)? Do you have a test case that loads all possible singletons into a single scene, and test it on the target platform? Or is there a cleaner method?

John Warner
profile image
You're quite welcome! and no, I don't, but I don't use the pattern too much anyway. I use Singletons for major objects, such as input managers, and of course my dialogue system, shown above; I only really ever use it on objects I call regularly and repeatedly.

Nathan Middleton
profile image
I was taught and have subsequently had reinforced, the idea that global variables are generally not a good idea.

a quick google brings up http://www.c2.com/cgi/wiki?GlobalVariablesAreBad but it looks as though some of those points are less applicable to managed languages.

I've used singletons on occasion but generally I'll go with an some sort of DI/IOC.
I'm not sure how useful DI/IOC is in unity however as I've not tried it yet.

Have you run into any issue with the use of globals variables?

edit: also meant to say the rest was very helpful, I've just not seen globals advocated for unity before(then again I've not seen alternatives advocated either)

Michael Herring
profile image
It's not that advice against globals is less applicable to managed languages, rather the fact is that they're less applicable to game development. And anyway, globals are not always the same thing in practice as singletons.

Ultimately, if a system is designed to stand alone and never have multiple instances, there is no problem with having a global instance. Like all things, the key is *moderation* and using things the way they are designed to be used (and yes, of course, designing those things well). Global variables are not bad design by default in game development, especially when they're really just singletons.

Nathan Middleton
profile image
IS DI/IOC a viable option in unity for a reasonably sized project ?

Will Corwin
profile image
https://github.com/thirdmotion/strangeioc

We're using it in-house and it's been fantastic. Full disclosure: I've been testing and committing to it since inception. It's very lightweight and I'm happy to answer whatever you need.

/shillover

Emerick Aussignac
profile image
Good tips, I'm using them all the time.
Your use of sendmessage to provide callbacks is very interesting, I'll probably use it later :)

Concerning the global variables, the only real issue is when you have several instances. But for "manager" classes it's very helpful to have quick access to these key scripts.

It saves a lot of time, becauses otherwise, with editor wiring, you're bound to forget one drag and drop, or do a mistake and waste time with errors.

This can be extended to local hierarchie, it can be a lot easier to get refernces with a single getcomponent in awake or start than to set it via the inspector.

Adam Byrd
profile image
Use delegates over SendMessage when possible. SendMessage is comparable to GetComponent, performance wise. Both have to iterate over all components on a GameObject.

John Jennings
profile image
Mad props to you John! Best of luck with the game.

John Warner
profile image
Thanks John! Much appreciated.

Jed Hubic
profile image
Great article. I will be referencing this as I move from Monogame to Unity.

Question: Is there any downside or restriction to using EventHandlers in lieu of delegates? I ask because I've found that having event handlers with custom event args that can be extended has saved me time and precious brain power when I need to add something else to the event args.

Adam Byrd
profile image
EventHandlers are just specialized delegates. I don't know of any downsides, as they just let you skip defining a custom delegate. Personally, I really like using Events and Actions for events.

Casey Labine
profile image
"3: Use Callbacks (delegates or Monobheaviour.SendMessage())"

This depends a lot on how you approach composability in your code and your familiarity with C#. Generally it's preferable to avoid "callback hell," which ping-pongs you around and makes navigating the code base a nightmare for the next person who has to work through it.

C# provides a number of ways to approach the problem more linearly, like IAsyncResult over closures or signal/wait. If Unity is up to date with Mono, you'll have access to more modern patterns like async/await, but the older ones should certainly work.

(From your example it isn't clear why an asynchronous model is necessary in the first place, but I'm chocking that up to you just having more or less pulled it out of thin air.)

Prakash Angappan
profile image
Great tips, thanks for sharing.

Vincent Paquin
profile image
I use a lot of these ideas already, so I approve them all.
But would it be simpler to call
DialogueSystem.SomeStaticPublicFunctionName()
instead of
DialogueSystem.instance.SomePublicFunctionName() ? After all, Unity works a lot like this, with for example the Application class

Dustin Hendricks
profile image
you could turn instance into a static method to avoid the need to attach your DialogSystem script to a GameObject. It would of course still need to be in a Plugins or similar folder to be globally accessable.

class DialogSystem {
static var _instance : DialogSystem = null;
static function Instance() {
if ( _instance == null ) _instance = new DialogSystem();
return _instance;
}
//etc
}

Roberto Caldas
profile image
Some coding practices are so wrong that they should be avoided no matter the size of the project.

Teaching someone to use a global variable that could be set by every other class and initialises itself is very dangerous, it's teaching someone to do the wrong thing. You gotta be a good programmer to afford to be simplistic in your code, creating global variables without creating problems, so how can a beginner that just learned this be discerning and not create a global variable for every bullet shot by the character's weapon?

By the way, is global variable a design pattern?

Using delegates is just another trap if you don't know the lifecycle of the objects involved, so not a beginner task. It's very easy to have MonoBehaviours that should be dead and garbage-collected but are subscribed to someone's event.

Ashkan Saeedi Mazdeh
profile image
Some of the points in the article are really not that right in my opinion.
Using delegates can make it hard to follow code and understand it unless you really know what's going on.
Using singletones can be good for few classes but if possible even fully avoiding them is great. Specially if your game is multiplayer and on the server side of coding you might end up in multiple instances of your GameObject manager and other classes.
Usage of any global variables is a bad practice for intelectual reasons. Because anyone can modify them. These problems become more importantt when multiple people are working on something. Someone might assume the global variable to be X but somone else changed it in his code. They encourage multiple usages for a single variable sometimes in Jr programmers and ... Use them with care and don't advice others to use them.

Creating the most flexible system (like your dialog system) it's not always a good thing. It depends on how much of that you require now and how much will be required in other projects. predictions can fail and you are using your time and budget for it so considering your code your company asset does not mean you should write everything with reusability of the FULL SYSTEM in mind. It means you should make it easily maintainable and extensible which you are somehow disallowing with your other advices.

Emerick Aussignac
profile image
Using global variables is indeed dangerous.
But here it's basically only static references to the manager classes and component.

Maybe a more safe way to do the same thing it to have the instance as a private var, and have quick referecne via static calls, i.e. :

public class DialogueManager : Monobehaviour
{

private DialogueManager instance;

...

void Start()
{
if (instance==null)
{
instance =this;
}
else
{
//either prompt error or destroy..
}
}

public static void DoSomething()
{
if(instance!=null)
{
instance.DoSomethingSelf();
}
else
{
//error, component not in scene
}
}

private void DoSomethingSelf()
{
//stuff
}

}

Jeremiah Goerdt
profile image
Really great article and thanks for writing it. Also, your Kickstarter campaign looks great along with the game. Well done.

I'm curious if the upcoming changes to Unity's GUI framework are going to affect your dialogue system. Is the implementation dependent on the current GUI in Unity?

John Warner
profile image
it is, but the code is simple and I've yet to do any serious branding (menu stuff, etc). If upgrading screws up the GUI then I'll just have to re-build it. It's not going to be a life-altering task. probably a good day and a half of work as I watch Star Trek 8)

Josh Sutphin
profile image
Wow, lots of complaints about the public static reference tip (#2) here. I get the point about exposing that variable to manipulation by other classes: that's bad times. But I think some of y'all are reacting so powerfully against that, that you're throwing the baby out with the bathwater.

The pattern John is describing is incredibly useful. All you need to do to protect that reference from external manipulation, while still retaining the super-convenient access of a public reference variable, is make it a property:

public class MyClass {
public static MyClass instance {
get { return _instance; }
private set { _instance = value; }
}
static MyClass _instance;

void OnDestroy() {
instance = null;
}

void Start() {
instance = this;
}
}

Now anybody can read it just like a public reference, but only the declaring class can write to it:

public class ConsumerClass {
void Start() {
// This works
MyClass.instance.DoSomething();

// This will throw a compiler error
MyClass.instance = someOtherInstance;
}
}

I'd add that you can extend this pattern beyond singleton-type use cases, too. Say you have some enemies, and you want quick access to them from other classes (e.g. to check positions, health, whatever):

public class Enemy {
public List enemies {
get { return _enemies; }
private set { _enemies = value; }
}
List _enemies;

void OnDestroy() {
enemies.Remove(this);
}

void Start() {
if(enemies == null)
enemies = new List();

enemies.Add(this);
}
}

Now you can easily do things like this:

public class Level {
void Update() {
if(Enemy.enemies.Count < 1) {
WinGame();
}
}
}

Properties are your friend. :)

EDIT: Code formatting in blog comments is NOT your friend. Or mine. Or anyone's. :(

Juan Mora
profile image
I was going to point this out too. The global, public aspect of the "instance" variable is read only (for example, it can be a read-only c# property). That makes a big difference from a global variable that can be written to "from everywhere" (try to always avoid the later!). Of course, you shouldn't abuse from this pattern, because, many times, static variables are "funny".

Soeren Bruegge
profile image
How about something like that in Javascript? Is there such an option?

Juan Mora
profile image
About point 2 ("static instances"), I have been thinking a lot about this lately, and for now, I believe it is the best and most simple solution for communication between objects. Any abstract "messaging system", while possibly having its own advantages, will very likely result in data duplication (in the general case, every object will store a copy of the system data it needs to operate itself). And I think very strongly against data duplication in game development. So, "instances" for me, please.

VERY IMPORTANT: never forget to clean-up your static "instance" variables when you switch to another unity scene where you don't need the instance anymore. I usually set it to null on the same class' OnDestroy() event. If you don't, you are very likely to end up having unnecessarily loaded assets in memory (if the instance references an assets, it will remain in memory, no matter if it's not referenced at all in the current unity scene).

About point 5 (Update vs Coroutines), I tend to favor Update for 2 reasons. First, a simple value comparison almost never will hit your performance in any significant way (of course, it will be faster if you don't have it, but still). And second, it's easier to understand and maintain. For instance, an unwary programmer could start a fade-out coroutine while a fade-in coroutine is still running. It certainly will cause some funny behavior.

John Warner
profile image
Good points all around, and great advice on the garbage created by not setting the instance to be null. Thanks!

Michael Bartnett
profile image
Can't argue with #1 (code as a long-term asset) and #4 (scripts being aware and making use of their own enabled/disabled state), good stuff. I have some comments about your other points.

For #2, sometimes singletons are unavoidable in Unity, but they can lead you to some very inflexible code if you're not careful. I had written a big thing about how we boxed ourselves in using one, making iteration on our player locomotion code later in the project extremely tedious and time consuming but ended up omitting it from this comment. Bottom line: you should strive to make it such that you can drop your prefabs into an arbitrary scene and have them start functioning as they would in game.

For #3, I <3 delegates (not so much SendMessage since you lose call trace info and makes debugging a PITA), but make sure you detach all of your one-off events or have the class with the event field set it to null at an appropriate time. Dangling delegate references will prevent garbage collection. Another nice style is passing around a single delegate reference rather than using multicast delegates (similar to Javascript/Ruby/Python). The new Unity Event System they've been demoing solves this problem by implementing weak references.

For #5, just be aware of the overhead of coroutines. They get compiled down to a nested class with a big switch statement containing cases for each yield point. For temporary processes like the fadeout in your example, they're perfect. But if they run frequently enough they're no better (possibly worse? need to profile that) than an extra if statement in your `Update()` method.

Also, fun fact, you can write `yield return StartCoroutine(OmgANestedCoroutine())` and the "parent" coroutine will wait for this new one to finish before moving past this yield.

Another useful pattern you should look into is one where your MonoBehaviour classes are mostly data containers that are composed with plain-old C# classes that implement the more complex behavior. Composability on multiple levels for the win!

John Warner
profile image
Hey Michael, that's awesome, thanks for the tips! I completely agree on your #2 point of course. Yeah, if you can't stick something into a scene and have it work immediately, that's a little sketchy. I'm finding that I mostly use singletons for large components or things that only get one instance in the scene, but this is also why I use the Start() function as opposed to a property. There's a global instance variable on my main character for example, but it can move between scenes and apply the new instance of its self when that area loads. However, if some of the other comments here and on Reddit are correct, that might lead to some garbage collection problemas?

I usually pass delegates as parameters to functions, and leave it at that. Does that cause garbage collection issues?

Interesting fact on Coroutines. Huh.

Thanks for the response!

Michael Bartnett
profile image
If you're passing delegates as parameters to functions, then the garbage problem doesn't really come up. Where it happens is when you have a public event field, and attach a handler to it via the "EventField += MyEventHandler;" syntax. The "+=" operator adds "MyEventHandler" to an internal list inside "EventField," which is what prevents the garbage collector from marking it as ready for deallocation.

John Warner
profile image
got it! yeah, that makes sense.


none
 
Comment: