Monster shadow

VIDEO

Game Manager - Controlling the flow of your game [Unity Tutorial]

Description:
Controlling the flow and state of your game is a fundamental step of game development. I'll show you how to structure your game logic to easily flow between each state (ie: player turn, enemy turn, victory, etc) and share a few tips along the way.
ADD A COMMENT

Tarodev
Game managers are a vital part of any game. If you enjoyed the video, let me know so I can continue making helpful content :)
Sunrise Sunset
Apologies if it's already been asked, but why is the GameState enum declared outside of the GameManager class?
Wearing Bubbles
Free GameManager in 10 mins. You earned a like and subscribe. No questions ask.
Tarodev
Welcome aboard
Макс Михневич
oh yeah, good old "game manager" approach, pretty common, not necessarily good though when it comes to scaling.
Tarodev
@AlexjW3 yup it's a good thing to think about. Personally it's all about the complexity and scale of your project. I've built a tactics game using just this workflow and it was perfectly fine. The good thing about a full state machine is that you can reuse it in a generic way across multiple systems. What I suggest is using the simplest option, unless you know ahead of time it will cause problems. That's basically the philosophy I use across the board.
AlexjW3
@Tarodev What are your thoughts on using this design pattern vs. a state machine pattern? I build my project with your system, after reaching a level of complexity I'm thinking about rewriting as a state machine.
Tarodev
Game manager should be a pretty simple script which just orchestrates. It shouldn't have any system specific logic, keeping is relatively lean even at large scale. What do you prefer to use for large projects?
1nferno
Great tutorial, many thanks good sir!
Perry Gretton
Hi, Tarodev, that's a great tutorial. I learned a lot from it. I was wondering if you have the code available in downloadable format.
Perry Gretton
@Tarodev Much appreciated.
Tarodev
Ahhh, I didn't realise I hadn't added it to the description. I'm away right now but I'll try remember to put it in. Sorry about that mate!
Will M
learned a lot from this video thank you!
Nikos Paraponiaris
Sad - seems to be such a usefull tutorial.. Also for Begginers like me .. !!! But its an example on a "prefixed Game" that never showed how it works - so that makes it MUCH more complicated for me to understand :( Although Thanx for the Tutorial <3
Tarodev
I see what you're saying and I could have done a little more to simplify it. But the video was not about the game (what you see in the video is the whole game, I made it for this video). Every time I make a tutorial I have to decide if I want to make it visually pleasing and fun to watch or drop-dead boring with no context. I'll keep this in mind though and try to simplify it for new devs. :)
AlexjW3
How would I check the current state during the update method? I understand that the GameManagerOnGameStateChanged function only triggers when the state is changed, there are other functions I'd like to trigger during update only if the state is the correct one.
Tarodev
@AlexjW3 you got it 😉
AlexjW3
Solved: if(GameManager.Instance.State == GameState.StateName){}
LifeMetaTV
So does a game manager replace a game loop?
Tarodev
By game loop do you mean void Update? If so, no at all. If by game loop you mean a place to manage the flow of the game, for example initial setup, player turn, enemy turn, deciding if the game is won/lost, than yes. Think of GameManager as an orchestrator. It's the only place to further the game to the next step. (by game I mean actual gameplay, not main menu, splash screen etc).
GliconCraft
(Sorry ahead of time for the long comment and lots of questions, I segmented them out with numbers highlighting key areas) I'm learning about GameManagers right now and this seems like a really useful tutorial, thanks! But, just out of curiosity, (1) what would the implications be to handle all of these features yourself, using things like variables/properties inside of a GameManager proxy script? For example, setting a public property or field string as the state name, inside of your GameManager proxy script, to "BetweenRounds", then your game objects/scripts check whether or not the state of that public property/field is "BetweenRounds" before doing the performing that code? The reason I ask is I'm much more familiar with that sort of workflow, and if that's something I can do, and it's not unreasonably impactful on the performance, then, (2) is that an acceptable solution? If it's not, and there does happen to be a downfall or disadvantage, then I would have to put my laziness aside and do it properly. Another reason I ask is, the concept of a GameManager seems like a no-brainer when handling multiple elements, but when I looked into it online, I find all sorts of conflicting information, some regarding why Singletons are bad to use in Unity, some how Singletons are good to use in Unity; And one specifically, a Unity help article from 2017 stating how the GameManager workflow is "Incredibly out-of-date", linking to another article that seems to suggest you should use a preload scene instead, somehow. Although, admittedly I didn't read through it in entirety yet, I've attached it below if you're curious: https://answers.unity.com/questions/1124691/creating-a-proper-game-manager.html ((3) It would be nice to hear what your opinion is on that, because if I try to implement an out-of-date workflow then I might end up running into incompatibilities with future features, or dropped support of that workflow)
Tarodev
@GliconCraft Glad to have you on board.
GliconCraft
@Tarodev Thank you very much for your response! I just found you tonight looking for information on game managers, and I also asked a few devs in a discord group, so I got some more advice, it's all helpful. And, I'm glad I found your channel, severely underrated, you have a ton of content that I can already tell is going to be useful in my process, keep up the great work!
Tarodev
I read the post you linked regarding a prescene and I think you may be a bit confused, probably due to naming. So when he's talking about game manager, he's more referring to a full system wide management solution, including sound, scenes etc etc. This video is a manager to control the flow of the actual game and has no overlap to his guide. You would absolutely not want to put this on an object which persists through every scene including menus and the like, you'd want a brand new instance of it each new game. Singletons are very handy and are used widely not just in unity but across all of c# development. Even though his post has no overlap with my video, I'd still like to put my two cents in: Firstly, I hated how he wrote it in such a factual way when it is in fact subjective. Saying that, a single DontDestroyOnLoad created in a _prescene could be beneficial for readability, but honestly doesn't make too much of an impact. The fact he didn't actually make static instances of the systems classes but instead expected the dev to find them by searching the scenes and then setting individual references in every class which needed them shows me somebody told him statics/singletons are bad so he's just avoided them for the sake of doing so. In the end programming has many conventions, but as long as an implementation isn't detrimental to performance or readability, you should follow the design pattern you or your team enjoys.
Marc Lauzon
My only complain here is "For the sake of the tutorial". Even if some parts aren't exactly topic of the tutorial, they could be useful. Annoyingly "For the sake of the tutorial" is used in most tutorials, often not tagged as such, which often lead to bad coding hygiene.
Tarodev
I've been guilty of this a few times. I never like doing it. It's just a way to keep on topic and I figure if somebody wants to know more about it they can ask. But yes, now you've mentioned it I agree it shouldn't be done.
Hoàng Nguyễn
Hello Tarodev, I have a pause/unpause function, should we add them to the game state manager?
Hoàng Nguyễn
@Tarodev thank you, just as you said.
Tarodev
This is a design decision I've gone either way with. In most cases I'd say no. It comes down to a lot of things like if you're setting your time scale to 0, if it's going to be difficult to re-trigger the unpaused state without causing double up, etc.
codename umoja
Why don't you do a tutorial that builds the scene with the firing etc.
Midnite Oil Software
Nice tutorial. I’d like to see some videos demonstrating using scriptable objects for this sort of thing.
Greg Bradburn
@Marc Lauzon Thanks for the reply. I was just starting to dig into ScriptableObjects and it just seemed like something they'd be suitable for. But honestly, it was so long ago I can't remember specifically why I asked that :)
Marc Lauzon
Could you be more precise about what you expect ScriptableObject to do in "this sort of thing"? I do understand that you can plug SO in a state machine, but I'm not sure why you'd want that here, except maybe to subdivide your code, but you don't exactly need SO for that. Only way I can see this is create an abstract SO to inherit from and override "StateEntry", "StateRun", "StateExit" functions. Use some static variable that most of your states need to regularly inspect (reference to stat controllers, player controller, or something). Other than that, have state dependant variables public that you wanna set in the inspector, which is the only reason I see SO used in "this sort of thing", or maybe for difficulty settings then you'd swap "CombatState_Normal" with "CombatState_Easy" or "CombatState_Hard". In the GameManager, have UpdateGameState(newState) call on current state StateExit and new state StateEntry. If current and new state are same, call StateRun.
BannanaChef
Amazing video, love your content
İlyas Köse
This is one of the most valuable unity tutorial on youtube. Such a great explanation. Thank you. At 10:00 what would be different if you used coroutine ?
İlyas Köse
@Tarodev Thank you for your detailed reply.
Tarodev
As a coroutine it'd look more like so: IEnumerator HandleEnemyAttack() { yield return new WaitForSeconds(2); // etc } And it would have been called like so: StartCoroutine(HandleEnemyAttack()); async/await is a much nicer way to handle this type of task. For example, you can't synchronously wait for a coroutine to finish, you'd have to call your continuation code from within the coroutine when it's complete. Coroutines still have their uses, but I find myself using async/await 90% of the time.
SEE ALL COMMENTS


Transcript:

a game manager is a way to keep track of the state and flow of your
game uh as you can see here i've got a
little game set up we've got our players here and the enemies on the right there
with the fire on their head and i can press this
button and my team will attack the other team
but as you can see i can just keep pressing it and overwhelm the enemy
and there's not really much challenge to it so i would like to be able to
firstly i would like to show the player a select color screen so that
they can choose the color of their unit and then i would like to only let the
player attack when it's their turn and then have the enemy attack when it's
their turn and then ultimately either change to a
victory state or a lose state so let's get started
let's create a new object and let's call it game manager
and then a new script by the same name [Music]
and as you can see it's such a common practice that unity detects
the word game manager and if they say it they'll change the little icon to a cog
there put that on your game manager object and
open it up let's start by making a static instance
of this game manager so we can easily grab it from
any where in our game [Music]
just set instance equals this i'm not going to go too much into the detail of
singletons or static instances but for now
you just need to know that it just allows us to grab it from anywhere
so the whole point of the game manager is to
manage the state of your game so that's what we're going to do first
create an enum and call it gamestate and the first state that we want is the
color select screen isn't it so this state will be called select color
and then let's say it's the player turn and then the enemy turn
and then after the player turn enemy turn player turn enemy turn
we eventually will want either a victory screen or a
lose screen now in our game manager let's create a variable of type game
state let's call it state and now we need a
way to actually change the state of our game
let's make a method for that public void update game states
and this method will take in a type game state and we'll just call that the
new state in here we will set our state equals to
the new state and then we might want to run
unique logic depending on the state so let's create a little switch statement
here which takes in the new state and if you press alt enter you can just
generate the switch levels and it will generate all of those for
you and now in here we'll be setting the state
and then we'll come down here and then if we need to run specific logic for
each of these states we could simply add a function here for example
handle select color
and then that will be run when the state is changed
to select color another thing we need in here
is to actually notify anybody who cares or any script that cares that we have in
fact changed the state and this is the new state so we need an
event for that so let's make a public static event
of type action and it will take in our new state and we'll call this on
game states changed [Music]
all right so now that we've got that event let's actually trigger it
after this so we'll do that and we'll send in our
new stage sorry this is actually warning me it's
basically just saying if i trigger this and nobody has
subscribed to it i'm going to throw an error at you
a null error so you can protect against that by just
saying has anybody subscribed if so invoke this function just like that
so now that we've got that when the game starts up
[Music] let's actually call our first state
change let's say update game state and we'll send in our first
state select color okay so easy as that now this is not
actually doing anything right yet because we haven't actually
attached any uh state-specific logic to it
uh so what we need to do first is show uh the player the select color
screen so this event down here let's let's hook
into that event so over in my menu manager i've got a
reference to that color select panel which i showed you at the start of the
video so what we need to do is subscribe
to this game manager on state changed event
so in our menu manager in our awake function let's subscribe to it
game manager on state changed plus equals which is how we subscribe to
events in c sharp and let's create a new method
now it's good uh it's good practice to always unsubscribe from an
event uh when you're finished with it to avoid memory leaks and so on so on
our on destroy event when this class gets
destroyed we will instead of subscribing to it we
will unsubscribe from it just like that so now when game manager
calls this calls this on state changed we're going
to run this function let's change that to state and basically
all we need to do here is if it's if the state is select color
we will show our panel otherwise it's always going to be hidden
so an easy way to do that is just color select panel
set active and if state equals select color then we're going to show it
otherwise hide it okay so now when we start our game up
it shows our color select screen which doesn't actually do anything at the
moment so let's
do something about it on our color select
we can just move my face over here so you can see
you'll see on these on the button events i have
hooked into the unit manager select color function
so blue or red okay so over on our unit manager i've got
this function called select color it takes in the color and basically it
will just say to all of our player units here's a
red material here's a blue material pretty simple um you can just ignore
that though now once the u once the player has
actually selected this color we're done with the select color state
so now we can say game manager instance
update game state and what was our next state
it was the player turn so let's do that let's send in
player turn so now it's going to come down here again we're going to set the
new state it's going to come to player turn
we might need to handle some player turn logic here so let's create a new
function just like that
and then it's going to perform that logic and then come down here again
and trigger the state changed event again so what do we need to do here
well it would be nice to only allow the player to actually press this button
when it's on his turn uh we don't want him to press it when the enemy's
turn is playing that would be unfair so in in my uh menu manager
i've got a reference to that attack button as you can see there
so in our menu manager uh we've actually already subscribed to this event so now
we can say we need to actually change this attack
button to an actual button so let's do that
button attack button and we'll remove that reference
and now we only want to allow the users to press the button
when it's the player turn so we can do attack button
interactable equals and we just say if the state is equal to
player tone also when the player actually presses
the attack button we want to then take it to the next
state we don't want the player to be able to continuously press the button so
as you can see here i've got this attack button pressed and on the attack
button i've just got a button trigger and the
menu manager attack pressed so when the when it's
pressed i'm just i'm just telling the unit
manager to tell all the players to attack
and then i will say the game manager um instance update game state
and now let's say it's the enemies turn in our game manager now that we go into
the enemy turn let's create some logic for that
handle enemy turn uh now in here let's actually make this
an async function and we'll just add a little bit of uh
artificial wait time just so that the player units have a time to attack this
is uh not great design i'm just doing it for
the sake of the tutorial and we'll just do a task delay let's
wait for about actually let's wait for about two
seconds now our enemies can attack so let's say
unit manager instance attack and
we'll say the enemy faction [Music]
let's add another artificial wait time there to allow the enemy to attack
and then here we should then find out if the all the enemies are dead
or all the players are dead so a good way to do that would be a
another state here and we'll just call it decide
and we can add a new case [Music]
handle decide now uh this is not the most performant
way to do it but for the sake of the tutorial basically
what i'm going to do is i'm just going to grab
all the units find objects of type units
i'll say if units any uh unit
of faction basically just looking for are there any units of
enemy and if not if no enemy units will say update game state
and we'll say win victory because there's no more enemies
else if now this is a very sloppy way of doing it but just
just for the sake of the tutorial uh if there are no players left
then we'll say well you lost otherwise let's update the game state back to the
player turn let's also add an artificial weight here just so
that we can see the decide
or else it's just going to flash by our eyes way too fast
all right so let's see what we have made a red team attack
enemy turn over to the side back to player 10
oh look at that damage oh it's not looking good not looking
good 1v3 at least i took one of them out
and i lose so there you go i showed you how to create a game manager
a fundamental of game management i showed you how to run specific logic
for each state and trigger an event which other parts
of your game logic can hook into and run their
own logic a game manager is perfect for keeping
all of your game flow all in one place keeps it neat organized and easy to
debug so if you learn something give it a
thumbs up subscribe and i'll see you next time
you