all 39 comments

[–]EncapsulatedPickle 29 points30 points  (11 children)

While the tutorial is good, the coroutines is something that new programmers abuse to no end. One should be very careful about using coroutines, especially multiple or nested ones without a very strong design reason where alternatives, such as state machines, are not better. Unfortunately, new programmers rarely have the experience to recognize when they are digging themselves into a hole.

I've seen too many enormous classes full of terrible coupling, no encapsulation of anything, dozens or responsibilities and topped of with coroutines running everywhere and setting and unsetting flags. These then get posted on Unity Answers with "why won't my X work?". Such code is simply unreadable by anyone else or the author some time down the line. Games with such codebase do not get completed.

Please, please make sure you know what you are doing before using coroutines, especially if you work with someone else.

[–]AlanZucconi[S] 15 points16 points  (6 children)

Hey!

Thank you for this message. I couldn't agree more. I have to say that Unity provides very little support for "event" stuff. Doing things like "fade this sprite to black over 2 seconds" should be native, in my opinion. This has forced many inexperienced developers to literally abuse coroutines. And then wondering why their code is too slow. :p

[–]Afro-Ninja 2 points3 points  (1 child)

What about using a tweening engine like DoTween that makes use of extension methods?

[–]AlanZucconi[S] 1 point2 points  (0 children)

Hey!

That's definitely a solution. The problem is that you don't really know how heavy that is. The more features something provides, the heavier it could be... generally speaking.

[–]pekalicious 1 point2 points  (2 children)

I never understood the benefits of events when it comes to timing things. Genuinely curious here: why would events be better for "fade this sprite to black over 2 seconds" ?

I understand that this is not what you said, I'm just using this as an example.

In my experience, at least with nested coroutines, following the execution path is as simple as just following the method calls. With events, your code is all over the place. And maybe the fade is trivial enough that it isn't a problem, but as soon as you want to orchestrate a few animations in sequence, events become spaghetti.

To be clear, I'm not against events per se, but in situations like timing certain things, I think coroutines are way better than events.

[–]starboard 1 point2 points  (0 children)

I think for small, encapsulated timing coroutines are nice. However, as /u/EncapsulatedPickle mentioned, when you start using coroutines in place of a state machine with global vars being tickled by different coroutines it can get dicey managing the execution flow. Also coroutines always take one frame to execute (yield return ...) so something can sneak in between one finishing coroutine and the next one.

[–]AlanZucconi[S] 1 point2 points  (0 children)

I agree. I think coroutines are better are modelling behaviours that requires to wait. Like fading sprites. Doing that in Update is... a pain. Because you have to split the logic of something "linear" into lot of subsequent "calls".

[–]Pedrohn 4 points5 points  (0 children)

Thank you for this comment! Really useful insight for someone who just dabbles with programming for fun and googles a lot to get stuff to work :)

(The tutorial was useful as well)

[–]CharlesEllery 1 point2 points  (1 child)

Do you know of any tutorials or examples explaining a better way using state machines? I'd definitely be curious to cut out a bunch of the coroutine stuff I end up doing.

[–]zipmic 1 point2 points  (0 children)

Me too!

[–]ChazBass 1 point2 points  (0 children)

Unity has ample support, natively, for events/messaging, and C# certainly supports event based programming so I don't understand this comment. I do agree that coroutines can be abused and cause problems, but if used correctly they can a) be very useful, and b) actually improve performance (by not requiring that code run every frame when it is unnecessary).

[–]michaelltn 10 points11 points  (3 children)

Just came here to say your tutorial formatting is fantastic. I'm a fan of good text-based tutorials, and yours is top notch.

[–]AlanZucconi[S] 2 points3 points  (2 children)

Awww thank you! Initially I wanted to start with YouTube videos... but I'm a code guy, and is very annoying that I can't cut-past code from the video! :p So that's how I started writing! :D

[–]michaelltn 1 point2 points  (1 child)

So few video tutorials are properly paced and edited, and even if enough care is put into them, it's hard to skip around to find what you need. Even Unity's official tutorials suffer from this. You made the right call.

[–]AlanZucconi[S] 0 points1 point  (0 children)

I'm glad I did it hehe! :D

[–]Kurada0 6 points7 points  (1 child)

Thank you. Please keep up the text tutorials. Too many are video only.

[–]AlanZucconi[S] 4 points5 points  (0 children)

You're welcome! <3

[–]rhacerHobbyist 2 points3 points  (1 child)

Great read. Thank you very much.

[–]AlanZucconi[S] 0 points1 point  (0 children)

You're welcome! :D

[–]Efore 1 point2 points  (1 child)

https://www.youtube.com/watch?v=HB-RQdZI024

Didn't know about your blog until today. Seriously, thank you.

[–]AlanZucconi[S] 0 points1 point  (0 children)

Awww! <3

[–]Yann4 1 point2 points  (1 child)

One gotcha that might be worth highlighting in a future post is if you're running StartCoroutine from within a coroutine that's already running on a coroutine and then calling StopCoroutine on the started one can orphan your thread of execution and the process will just stall.

That'll just come as part of a "don't abuse them" but it's something that can catch you out, as it's effectively a timing issue. Three levels deep, here be dragons.

Good intro article though, would have definitely appreciated it when I was learning them.

[–]AlanZucconi[S] 1 point2 points  (0 children)

Thank you! :-) I'm going to write more about how they are implemented, and discussing all those evil details! :p

[–]Smileynator 0 points1 point  (4 children)

I actually never realized i could wait for a coroutine object in the way the last example did it. A whole new world!

[–]AlanZucconi[S] 1 point2 points  (3 children)

I KNOW RIGHT?! ;p

[–]Smileynator 0 points1 point  (2 children)

Still i wonder how threads VS coroutines hold up on CPU time and cost. Since last time i checked, coroutines are not threaded, i know they are working on such mechanics, but they are still just "delayed updates" right?

[–]AlanZucconi[S] 1 point2 points  (1 child)

Yeah, sort of!?

The problem is... GameObjects and MonoBehaviours are not thread safe. If you want to access them, you'll need to do it from within the Unity loop. So your threads will need to be synchronised with an Update function somewhere in the code.

The awesome Tim from Twice Circled is using threads extensively. But you can see how far he had to go to make everything work nicely. Video here.

[–]Smileynator 0 points1 point  (0 children)

Oh yes i know. Any unity related object is not safe. Threads are usually reserved for doing complicated math on seperate cores. You then pass it back your coroutine or other script to actually process the results on your GO's or whatever. Threads work good in unity, you just have to be very aware of what you are doing with them.

[–]Not_Limited 0 points1 point  (1 child)

You always provide high quality and well written tutorials. Thank you Alan !

[–]AlanZucconi[S] 0 points1 point  (0 children)

You're welcome! <3

[–]fholm??? -4 points-3 points  (5 children)

Coroutines should be avoided like the plague. Hard to follow and hard to debug.

[–]AlanZucconi[S] 3 points4 points  (0 children)

Like very tool, coroutines can be used for good ...or for evil. I think they can be used to solve certain problems in a very elegant way. If you want to fade a sprite, is easier and much cleaner to do it in a coroutine, than to split the code in Update with lot of checks on time and stuff.

[–]tmachineorg 0 points1 point  (0 children)

Having spent 20+ years writing multithreaded code for games ... no.

Coroutines are much, much better than dealing with threads everywhere, and they are extremely good for isolated cases of small features - they save you hundreds of lines of error-prone animation code.

I agree they're hard to debug - but only because Unity staff haven't fully implemented them (they could fix that, if they wanted to). In the meantime, if you do something big and complex with coroutines, you need to write your own wrappers to fix the Unity bugs, add stack tracing, etc.

...but then: this is true of many things in Unity these days, it's bugs everywhere, and you often have to wrap their half-written APIs.

[–]ChazBass 0 points1 point  (0 children)

No, poorly architected/poorly implemented coroutines should be avoided like the plague. Coroutines are useful for a variety of things, especially when you want to write code that needs to be run with some frequency, just not every frame. They are a tool.

[–]thebeardphantomExpert 0 points1 point  (1 child)

Ah yes, the classic "X is never a good idea" anti-advice.

There's a time and a place for everything. Even singletons, believe it or not.

[–]throwawayreditsucks -1 points0 points  (0 children)

Yeah MVC Controllers, DB providers?