- In this video we'll
have a look at creating one of the classics of gaming. Turn-based combat. Turn-based battle systems
have been part of gaming since the very beginning. And games like Civilization,
Pokemon, and Final Fantasy, are known for this
particular style of combat. So let's try creating a
simple, yet solid turn-based combat system in Unity. But first, special thanks to InfinityPBR
for his support on Patreon. And this video is sponsored by Milanote. Milanote is a tool for
organising your creative projects into free-form visual boards. It can be used for any creative project, but it's particularly
well suited for the messy, early stages of video game development. It's just a perfect
place to store your ideas and make sense of them as they grow. You can get started
with Milanote for free. And I've actually used it to plan out the turn-based battle system
we're going to be making in this video. In fact, let me just jump
right in and show you. So as you can see, I've gone ahead and set
up this board in Milanote on creating a turn-based battle system. And I've gone ahead and
created four columns. One for the UI. As you can see this links
to a separate board. And in here we have a bunch
of concept art for the UI. And I've been really inspired by Pokemon, especially some of the newer
versions with a bit more colour. And of course the old Final Fantasy games. Also I have a to do list for the UI. And as you can see, I've gone ahead and
crossed all of them out. And that's actually because
I prepared the UI beforehand. It's really, really simple. In fact, let me just go into
Unity here and show you. All I have here is just the main camera
with the green background. And then I have a UI canvas. And in here we have an enemy battle HUD. Which is just an image with
a name text, a LevelText, as well as a UI slider for the HP. And I've simply copied that
for the player battle HUD. As well as created a dialogue panel. Which again is just an image
with a dialogue text object. As well as two buttons, one for attacking, and one for healing. If you've never worked
with UI in Unity before, don't worry we of course
have plenty of videos on the subject that will teach you how to create simple UI like this. I've gone ahead and put one of them inside of the board here actually, and we'll have links to
plenty in the description. I also have a column for the environment. I want to keep it simple. Just have two units,
a player and an enemy. And remember you can always add more to the system afterwards. So I've gone ahead and created
a simple background already, as you can see. We just need to add two battle stations. Which is what I've chosen to call these two patches of grass here. So inside of Unity, all we need to do is just
find a sprite that we like. I've gone ahead and created a simple grass patch sprite here. And I'll of course include all sprites along with the finished project
in the description as well. So let's just go ahead and drag this in. And as you can see, that
creates a sprite renderer. I don't want this to be UI, I want it to be an actual game object. And let's just place it
right above our HUD here. And let's duplicate it and
move one down here as well. I'm also just going to select these two and set their order in layer to minus 10. This way when we place in units, they're actually going to appear on top. Let's rename the first battle station to EnemyBattleStation. And the second one to PlayerBattleStation. And if we have a look in our game view, that looks really cool. The only thing that I'll note about the way that I've set up the UI is that if we select our canvas. As you can see, I've set the UI scale mode
to scale with screen size. And this just means that
if we resize our game view, our UI is going to scale with it. Which is really nice in this case. So we have now added
our two battle stations and we can check that off as well. And I've also gone ahead
and created a column for gameplay. Our combat is of course,
going to be turn-based. And what this means is that we're handling one turn at a time. In other words, we can introduce the
concept of a game state. So in my game I want to have five states. You can easily add more
for increased complexity, but I think these five are
pretty good starting point. We have a start state. This initialises to combat
and sets up all the units. We'll then have a player turn, where the player can choose
between different actions. After that we'll have an enemy turn, where the enemy chooses their actions. And we'll loop between these two until the game is either won or lost. We also make sure that whenever
we transition from one state to another, for example
the player takes its turn. We then want to make sure
to leave plenty of time for the player to take in what's happening before we transition to the next state. So that is kind of the basis of how our gameplay should work. In fact, we can see it in
action in this GIF from Pokemon. So that is kind of the basics of how we want our gameplay to work. Now how do we lay this out with logic? Well, if we have a look
at the core systems that we're going to need, we're definitely going to
need some kind of unit script that we can put on the enemy and the player. That has information about their stats, such as HP and damage. As well as name and level and so on. We'll also have a battle system script, which handles all of our game states. And finally, we'll have a battle HUD script that is responsible for
updating our unit UI. In this example, we give the player two actions. An attack action and a heal action, but you can of course add more. All right so with that explanation, that's jump right into it. And let's have a look at
creating our first core system, which is the unit. So inside of Unity, let's start by creating our enemy. Let's right- click and go Create Empty to create a new object. Let's call it Enemy. Let's reset the transform. And if we just have a look
in our scene view here, we can now see that
this is an empty object. I'm just going to go
ahead and place it on top of the battle station so that we can see what it's going to look like. Let's then add a sprite to our enemy. So I'm going to go under Sprites, and I have one here called Dwayne. And I'm simply going to take Dwayne and drag him under the enemy object. As you can see, we'll need to reset the
transform again here. And I want to move him up to make sure that he's kind of standing on
top of the pivot point here. So that once we spawn him in on top of the battle station, he's going to be actually standing on it. And it's not just going to
snap to the centre of him, which would look really weird. Remember when doing this
to always be in pivot mode. If you're in centre, you won't be able to see the difference. We then go ahead and create
a unit script on our enemy. Let's hit Add Component. Let's type Unit and hit Create and Add. And let's double-click to
open this up in Visual Studio. And this script is actually
going to be really simple. We can go ahead and remove
our two functions here. We don't need those. Instead what we want
are a bunch of variables describing our unit. So let's create a public
string with the unit name. Let's have a public int
with the unit level. And let's also add in damage. So we'll create a public int
with the amount of damage our unit we'll be able to do. As was a public int for the max HP. And let's also have
one for our current HP. This way we can keep track
of our HP during the fight. And if our unit is maybe already damaged when it enters the fight, we'll be able to control that as well. So let's save that. Go back into Unity. And right away we can
fill out these variables. So the unit name here
is going to be The Rock. Let's give it a level of say two. A damage of five. Let's set the max HP to 30, and the current HP to 30 as well. All right so now that
we've created our enemy, we can go out and turn him into a prefab. So let's just drag him
into the project panel. And there we go, we've now made a prefab out of him. And we can go ahead and
remove him from the scene. The reason we're doing this
is that we want to be able to load in different units depending on who we're fighting. And let's actually go ahead
and do the exact same thing with our player. In fact, we can just use the enemy here as a base. So let's go ahead and
rename him to Player. Let's move him down
here to where the player is supposed to stand. Let's drag him into the
project panel as well. And this way we can create
a new original prefab. There we go. So we now have both an
enemy and a player prefab. And in fact, we can double-click
on this player prefab to go into prefab editing mode, which is pretty cool. And here we can remove the Dwayne graphic and let's instead dragging a rock. I think the players should be a rock. That's just inherently cool. And let's reset that transform here. Let's drag it up and place it so that it kind of aligns
with the centre of our object. There we go. And let's go ahead and
rename the unit here to Actual Rock. Let's set the unit level 999. This is a beefy rock. We'll set the damage to 10. The max HP to 25. And let's say our current HP is only 20. So we've taken five damage
before this fight started. And let's exit prefab mode up here. And we can now remove this
prefab from the scene as well. Awesome. So with that, we've actually gone in
and created both our enemy and our player units. We'll add a tiny bit more
to the unit script itself, but the base of it is there. And we can now move on
to our battle system and defining all of our game states. So let's go into Unity. Let's create a new empty object. Let's reset the transform and let's name this Battle System. Let's drag it to the top here so we can always see it. And let's add a new component and call it Battle System. We'll hit Create and Add and open it up in Visual Studio. And we're going to need
our Start function, but we can definitely get rid of Update. Now before we get started
on an actual logic here, we need to define the different states that our game can be in. And to do this we'll use something called
enums or enumerations. These are perfect because they allow us to define different states, and then create a variable that can always be only
one of those states. So we'll start by defining them. We'll create a public enum up here. Notice that I'm doing
this outside of the class. And let's call it BattleState. We'll then open and close
some curly brackets. And a lot of people put a semi-colon here. You should not do that because we are not
calling a function here. We're defining an enum. And in here we'll put a START state. We'll put a PLAYERTURN state. An ENEMYTURN. A WON and a LOST state. And now inside of our battle system, what we can do is now create
a public battle state, and just call it state. And now we can set this state
equal to whatever we want. So inside of our Start, once we load up the battle scene here. We're simply going to set
state equal to BattleState. And here we get all the states. And we of course want
to choose START here. So you can see how easy
it is to keep track of our states this way. And in fact, if we save this
script and go into Unity, we'll even be able to
preview our different states and see what state we're currently in inside the inspector. Really, really cool. So now that we are in our start state, we can go ahead and set up the battle. So let's create a SetupBattle function. And let's create that down here. Void. SetupBattle. And in here we of course
want to spawn in our units. So we'll create a reference to them. We'll create a public game object. Let's call it player prefab. And we'll create a public game object, enemyPrefab. And where do we want to spawn these in? Well we want to spawn them
in on our battle stations. So we'll create references to those too. We'll create a public transform. And this is just a
transform, not a game object. Because we just need the location
of these battle stations, not the entire object. And this is going to be
the player battle station. And we'll of course also have one for the enemy battle station. Then when we set up the battle, we can go ahead and instantiate or spawn in a player prefab. As child of, and on top of, the player battle station. There we go. And we can do the same
thing with our enemy prefab on top of the enemy battle station. And if we save that and go into Unity, we can drag in our player prefab, our enemy prefab, as well as our player battle station, and our enemy battle station. And on our prefabs here we want to to make sure
that their position is set to see zero, zero, zero. We'll do that with the enemy as well. Just so that when we spawn them in, they'll be right at the
centre of our battle stations. And if we now hit play, as you can see, we're now
spawning in our units. Awesome. Of course currently we don't know anything about our units through script. We're just spawning in the objects and nothing is really happening on the UI. So let's go ahead and change that. So, first of all, we can get a reference to what we're spawning in by creating a game object variable here. We'll call it the playerGO or player game object and set it equal to the game
object that we spawn in. And what we can then do is actually get the unit
component on that game object. So we'll do playerGO.GetComponent of type Unit. And we want to go ahead and
store this in a variable because we'll be referencing the unit a bunch of times whenever
we need information about health and so on. So let's go to the top here
and create two variables. These don't need to be public. We don't need to see
them in the inspector. We'll just create a Unit, playerUnit. And a Unit, enemyUnit. And then down here we
can simply set playerUnit equal to player game
object.Getcomponent Unit. And we'll do the exact
same thing with our enemy. So game object, enemyGO equals the instantiated object. And we'll set enemyUnit equal to enemyGO.getComponent
of type Unit. There we go. And what this allows us to do is now get information about our units. In fact, let's go ahead and
display the enemy unit name to the player. We access this by simply
going enemyUnit.unitName. So let's go ahead and put this unit name inside of our dialogue text right here. Of course to do that, we need a reference to
this text object here. So inside of our script, we go to the top. And because this is UI, we need to include the
UnityEngine.UI namespace. And we can then create
a public text variable called dialogue text. Then down here, we can simply set dialogueText.text equal to enemyUnit.unitName. And let's just add a tiny bit to this. Let's just say a wild. And then we'll insert the enemy unit name, approaches. There we go. So if we save this now and go into Unity, select our battle system and remember to drag in our dialogue text. And hit play. A wild The Rock approaches. Awesome so we're now
gathering all this information about the units that we're loading in. And we have total control
or where we place it. So let's go ahead and
place this information on the HUD overlays. And we could do all this
through the BattleSystem script, but that would get very long. So let's go ahead and split
it into a separate one that we place on our battle
HUD objects themselves. So I'm assuming you're going
to select like these two. And that's create a battle HUD script. Again let's double-click it to open it up. Again, we can go ahead and
remove the two functions here. Let's create a public Text. And again, remember this is UI so we need to use UnityEngine.UI. And this is going to
reference our nameText object on the UI. We'll do the same thing
with our levelText. And we'll also create a public slider to control our HP slider. We then create a function that is going to update these UI elements. So let's create a public void. And we're making this public so that we can call it from
within our BattleSystem script. And it's just name it
something like SetHUD. Of course we need some information about what we should set it to. So let's just take in a
unit and call it unit. This way we have access to
all the information we need. And here we can then
just set nameText.text equal to Unit.unitName. We can set levelText.text
equal to let's put level. And then plus the unit.unitLevel. For the HP slider, we can set the maxValue
equal to the unit.maxHP. And hpSlider.value we'll set equal to unit.current HP. There you go. Of course, we probably want to update the HP a bunch of times every time
someone attacks or heals. And so let's just create
a quick function for that that only updates the HP. So let's do a public void. SetHP. This is simply going to take in an int with the HP. And here we can just set hpSlider.value equal to that value. Cool. So that's actually it for a battle HUD. All we need to do now is
go into our BattleSystem. And in here we need to create a reference to each of the battle HUDs. One for the player HUD
and one for the enemy HUD. So we'll just create a public BattleHUD, call it playerHUD. And a public BattleHUD called enemyHUD. And inside of our SetupBattle function, we then say playerHUD.SetHUD, and we'll pass in the playerUnit. And we'll do the same thing for the enemy. So enemyHUD.SetHUD enemyUnit. There we go. Let's save this, go into Unity. And you can see both of the battle HUDs now have some variables
that we need to fill out. So for the enemy battle HUD let's drag in the NameText. LevelText. And the slider. And we'll do the same thing
for the PlayerBattleHUD. And for our battle system we just need to drag into two battle HUDs. Awesome. If we now hit Play, we can see immediately our HUD updates to show the names of our two units, the level, as well as our current HP. Awesome. So we can check off our battle HUD here. And I think it's time to dig into some of the player actions. So inside of our script
here in our battle system, let's have a look at what should happen when we're done setting up our battle. Well, at this point, I think we should go ahead and transition to the player's turn. So we'll simply add a line at the end here that says state equals
BattleState.PLAYERTURN. And we can call a function
called PlayerTurn. And let's go ahead and create that. So we'll create a void PlayerTurn. And for now all we want to do here is just make it clear to the player that he can choose an action. So let's set our dialogueText equal to something that suggests that. Let's just put choose an action. There we go. Of course currently we're
calling the SetupBattle, and we're saying that a
wild enemy approaches. We're then updating our HUD and straight after that
we're calling our PlayerTurn. And all of this is going to happen inside the Start method. And that's not really something we want. We want to add a bit of delay
here as we talked about. So how do we do this? Well to wait in code, we use coroutines. Now we use coroutines quite
often here in the channel, but if you've never seen one before, the syntax is a bit frightening. But just think of them as functions that are running separately
from everything else, which allows us to pass
them whenever we want. So to turn this SetupBattle
here into a coroutine, we replace the void with IEnumerator. Again, I know the syntax is weird. And now before we go ahead
and change to the player turn we can put in yield return new. WaitForSeconds. And here we can input
the amount of seconds we would like to pass. So I'm just going to
to put in two seconds. Now whenever we are calling a coroutine we need to add a tiny bit of code. We need to add StartCoroutine. And then wrap our entire
function call in that. So that's all the syntax we need. I know it's a bit weird, but
it's always the same way. So you can just have a look
at what I'm doing here. We're just calling StartCoroutine. Then the name of the function. We're replacing void with IEnumerator. And then we're putting in a yield that waits for two seconds. So with that, if we save and go into Unity and hit play. As you can see a wild The Rock approaches. And after two seconds,
it says choose an action. And we now either press Attack or Heal. Of course, currently nothing happens. So let's go ahead and add
some logic for the buttons. Let's start with the Attack button. So to do that, we go into our script. And we'll create a new function here called OnAttackButton. And we want to trigger this function whenever the OnAttackButton is pressed. However in order to do
this through the UI, we need to mark it as public. And what we want to do here is to check if it's currently the player's turn. So if state is not equal
to BattleState.PlayerTurn, then we'll simply go ahead and
return out of this function. We don't want to do anything more. But if it is. Well then we'll continue down here. And then we'll call some kind
of PlayerAttack function. In fact let's make this a coroutine so that we can pause during our attack. So we'll do StartCoroutine
around that function call. And let's go ahead and
create the function as well. So we'll create an Ienumerator. We'll call it PlayerAttack. And here we want to damage the enemy. We then want to wait for a few seconds. So yield return new. WaitForSeconds. I'll put in two again. And then we want to check
if the enemy is dead and change state based on what happened. So we'll do that in a sec. But for now, let's just make sure that
this function is triggering. So if we save this
script and go into Unity. we now navigate to our UI. Let's find the dialogue panel, and here have the combat buttons. I'm going to select the AttackButton. And under any UI button
there is an OnClick event. Here we can choose what happens when this button is clicked. I'm going to hit plus. I'm going to drag in the Battle System. And let's go under the
BattleSystem script. And here we can now call
the OnAttackButton function that we just made. Awesome, that is now going
to trigger that function whenever we press this button. Of course we probably want
to make our PlayerAttack actually do something other than just wait two seconds. So let's have a look
at damaging the enemy. Well this is actually fairly easy. We have a reference to the enemyUnit. And so we can simply go in here and we could actually
modify the HP directly, but it's better practise
to create a function that does this. So let's create some kind
of TakeDamage function that takes our player unit's damage. So playerUnit.damage. Let's go ahead and create
this function here. So let's go into our Unit script. And in here let's create
a public void TakeDamage. This is going to take in an
int with the amount of damage. And it's then going to
subtract that damage from our current HP. So minus equals. And in the case that our
current HP reaches zero, we want to let our battle system know that this unit has died. So we want to go ahead
and say if our current HP is less than or equal to zero after we subtract this damage, well then we want to return
either true or false. So true if the unit has died, and false if it hasn't. So we'll go ahead and
change the return type of this function from void to bool. And we can now return true. And if not, then we can return false. So this function is going
to subtract it the damage, check if this unit has died
and return true if it has, or false if it hasn't. And this way inside of our battle system, we can now gather this
information in a boolean. So we'll create a boolean called isDead and set it equal to the
result of this function. And then down here when we
check if the enemy is dead, we can simply go if isDead. Well then we want to end the battle. And if it's not, well then it's the enemy's turn. There we go. We also just damaged the enemy so we need to update the enemy HUD. So we'll go enemyHUD.SetHP. and we'll pass in the enemyUnit.currentHP. And let's also update the dialogue text. So let's go with dialogueText.text equals the attack is successful. Then if we die, we'll change the state to BattleState.WON. Because we just killed the enemy unit. And we'll call some kind
of EndBattle function. Create this in a sec. And if the enemy isn't dead, we'll go ahead and set state equal to BattleState.ENEMYTURN. And we'll start a coroutine with some kind of EnemyTurnFunction. That we'll also create in a sec. So let's start by creating
the EndBattle function. Void EndBattle. Again you could turn this into
a coroutine if you want to. But I don't need to here because I'm simply going to
update the dialogue text. So if state is equal to BattleState.one. Well then we'll go ahead
and set dialogueText.text equal to you won the battle. And if not, and the state is equal
to BattleState.LOST. Well then we'll display you were defeated. And then I'd probably load
out of the battle screen and so on, and so on. So that's it for our EndBattle function. Now let's do our EnemyTurn. Again this is a coroutine
so let's do an IEnumerator. Call it any EnemyTurn. And now in here you can
definitely add some kind of AI to determine what the enemy does. If he also has an attack and a heal, you might want to attack if he has a chance of killing the player. Or heal a few times he loses health. You can put in what every
logic you want here. For now we can just make
him attack every time. So to do that let's
create some dialogue text that says that the
enemy unit is attacking. So enemyUnit.unitName attacks. We'll then wait one second. And that will damage the player. So playerUnit.TakeDamage based on the enemy unit's damage. Again, we want to check
if the player has died. So bool isDead. We want to update the player HUD. So plaerHUD.SetHP. Based on playerUnit.currentHP. Let's wait one more second. We can just copy this line here. And then let's determine whether
or not the player's dead. So if he is dead, then we can set state
equal to BattleState.LOST. And again, call the EndBattle function. And if not, then we'll set state equal to BattleState.PLAYERTURN. And called the PlayerTurn function. There we go. That's an enemy turn. So we display in the
dialogue that he's attacking. We wait one sec. Then we damage the player. You wait one more second. And then we determine if he's dead or not and change states. And with that, we should actually be able to
go into Unity and hit play. A wild The Rock approaches. We'll choose the attack action. The attack is successful. And as we can see the rock
loses health, it attacks. We lose health and we're
back to the player turn. And we'll be able to continue like this until either we or the enemy dies. So we'll go ahead and
attack it one more time. And we won the battle because its HP is now zero. Awesome. So that was the battle system
and all the game states. That was it for the unit
and the attack action. And we can just go ahead and
add a heal action real quick, just for fun. So doing this is much easier. We simply need to duplicate the OnAttackButton function here. And let's call it OnHealButton instead. We only do this if it's our turn and it's going to start a
coroutine called PlayerHeal. And all this is going to
do is be an IEnumerator called PlayerHeal. And of course we need to heal the players. That's go into our unit and create a heal function. Public void heal. It's going to take in an amount. And it's just going to increase our currentHP by that amount. And if the currentHP gets
greater than the maxHP, well then we'll simply set currentHP equal to the max HP. Then inside of our battle system, we can call the playerUnit.heal. Let's just heal by five points. We'll update the UI. So playerHUD.SetHP. PlayerUnit.currentHP. We'll update the dialogue text. You feel renewed strength. Wait two seconds and
change to the enemy's turn. And that's it. We can now save that, go into Unity. And here we of course want to make sure to select the heal button
and add an OnClick event to that as well. We'll find our BattleSystem OnHealButton function. And if we now play. And it's maximised the game view here. We can choose, of course
the attack action, that still works. We take some damage from
the attack, from the rock. We'll press Heal. And we immediately regain some HP and we feel renewed strength. And there we go we've now
created turn-based combat with different actions and an enemy. And it's all working. Awesome. That of course means that we
can check off the last thing that we needed to do here. And there of course a bunch of ways that you can expand upon this. You can change the UI based on game state. In fact, let me just go ahead
and add some of those here. So I'll just drag in a column. Let's call it making it cooler. I'm just going to add in some bullets that you could add. You could change the UI
based on the game state, similar to what they do here in Pokemon. You could add animations
to units and health bars. I think a good example of this
is definitely Final Fantasy, where you can see that there's
all these kinds of animations going on whenever someone attacks. In fact, let's just go ahead
and drag that right in here. You could add more actions
for the player and enemy. Add more units by adding some kind of
unit select game state. And of course you can integrate it further into your main game. If you're not sure about
where to go from here, you can always take out
this really cool video I found by Code Monkey that shows a lot of the animation stuff and even has some UI
overlays for showing damage which I think is really cool. So I'm just going to to go ahead and add that in here as well. So anyway, there's plenty
opportunity for you to go nuts with it from here. That's pretty much it, this video. If you enjoyed it, make sure it's subscribe and
ring their notification bell so you don't miss the next one. Also, don't forget to check out Milanote. Simply click the link in the
description to get started. On that, thanks for watching. And I'll see you in the next video. Thanks to all of the
awesome Patreon supporters who donated in October. And a special thanks to InfinityPBR. Lost to Violence, Loved Forever. Ruonan, Chris. Jacob Sanford, faisal marafie. Peter Schwendimann, Leo Lesetre. Dennis Sullivan, Alison the Fierce. Stig Christensen, Kirill Svidersky, Gregory Pierce, Naoki Iwasaki, TheMightyZeus, Daniel Dusanic, and Erasmus. You guys rock.