In this lecture, we'll look at the implementation of the basic gameplay in our Feed the Teddies game. So let's get to it. As you can see, we have lots of prefabs to support our gameplay, and we have lots of scripts to go along with those as well. So, let's go look at the code for the key game objects without trying to cover everything completely. We'll start with the burger class which is an IntEventInvoker because it invokes Int events. We have some stuff for blowing up and shooting french fries, we cast some collider dimensions, we have some other boundary checking stuff included, we set the health to 100, we do firing support so that we have a cooldownTimer to control our firing rate, and we use this canShoot field to help us do that. Here in the Start method where we initialize a bunch of stuff, we set up the screen coordinate stuff, we cache that collider information, and here's where we use the EventManager. So first, we add a HealthChangedEvent to our dictionary of unityEvents. Remember, this is in the IntEventInvoker class, then we add ourselves as an invoker for that HealthChangedEvent to the EventManager. And then, we also add the GameOverEvent to our dictionary of unityEvents, and then we add ourselves as an invoker for the GameOverEvent to the EventManager. So, the Burger class is the reason that we needed to have a dictionary of unityEvents that have an Int argument rather than just a single field. We also set up our cooldownTimer. So we add a timer component, and we set the duration to what our configurationUtils say, is the BurgerCooldownSeconds, and then we add a listener to the cooldownTimer to listen for when the timer is finished. I made some modifications to the timer for this game, so the timer works much more like a regular timer where instead of checking to see if it's finished on every frame, we just wait for it to tell us it's finished by invoking an event, and we listen for it here. In update, we move horizontally and vertically, and ClampInScreen. And we also adjust to this canShoot field that controls our firing rate. So, if we can't shoot right now, so we're cooling down, but we're not providing any input on the fire access, then we stop the timer, and we set the flag to true again. So, this allows the player to spam the fire button so they can shoot as quickly as they can press and release the spacebar. The more general automatic firing, if we canShoot and there's an input on the firing axis, then we start the cooldownTimer, we set the flag to false, and then we instantiate french tries to shoot. If we have a collision with something, we check to see if it's with the TeddyBear. And if it is, we create an explosion, we destroy the teddy bear, and we call a TakeDamage method that we will look at soon. We also look for triggers, so the burger actually has a regular box collider and a trigger box collider attached to it. And, if in fact we have FrenchFries entering the trigger, we set up an explosion and destroy the french fries. Those are the french fries we're shooting. So if we run into them by mistake, we get rid of them. If it's a TeddyBearProjectile that we've just collided with, then we set up an explosion, and we destroy the TeddyBearProjectile, and we TakeDamage. I wrote the TakeDamage method because we take damage from both teddy bears and TeddyBearProjectiles. The clamping stuff is as you'd expect. When that cool down timer finishes, we just reset the flag to true because we're cooled down and we can shoot some more french fries. And here's that TakeDamage method. First, we set the health to the maximum of zero or a health minus damage. So this keeps us clamped so we don't go below zero in health, and then we invoke this event, the HealthChangedEvent with the Int argument, our current health, and then we check to see if the game is over. And if it is, we invoke the GameOverEvent. Now, we have to provide an Int argument here even though we don't actually need an Int argument here, but that simplified our EventManager because we could have everything that invokes events be an IntEventInvoker, and the unityEvents with one Int argument is the only kind of event there is in our game. FrenchFries are much simpler. We get them moving when we start. FrenchFries might invoke the PointsAddedEvent. So we do the standard create that event here in this object, and then register it with the EventManager. When FrenchFries become invisible, we get rid of them. And here's that RemoveInvoker so that we don't have the FrenchFries script hanging around in that dictionary in the EventManager after the FrenchFries game object it was attached to gets destroyed. If the FrenchFries run into a TeddyBear, that's great. That's what we're trying to do, we're trying to feed the teddies. And so it invokes the PointsAddedEvent to give us points for doing that, it creates an explosion, it destroys the TeddyBear, it creates another explosion, and it destroys the FrenchFries. If you don't destroy the FrenchFries when they hit a TeddyBear, they just tunneled right through that teddy bear and hit another teddy bear if there's one there. And that's fun, but that's not the way it really ought to work. If the FrenchFries are colliding with a TeddyBearProjectile, we destroy both the TeddyBearProjectile and the FrenchFries. And this is actually an interesting gameplay thing because you can shoot those teddy bear projectiles with french fries to protect yourself. There is a HUD in the game, and the HUD displays the score in the health bar and that countdown timer. So, when we start up the HUD, we add a listener for the PointsAddedEvent just in case the score changes. We add a listener for the HealthChangedEvent just in case the health changes. We add a listener for the TimerChangedEvent because we are going to need to know when the timer moves from 30 seconds to 29, for example, so that we can update this play. So we'd listen for that event, and we initialize the timerText.txt. This property to get the score is accessed by our game manager script. HandlePointsAdded adds those points to the score and changes the score text. HandleHealthChanged changes the value of the health bar, which is just a slider. I used a pre-built UI component in this game for the health bar. Of course, you can do something much fancier that moves from green to red, and so on as health is reduced, but I didn't for this game. And when the TimerChangedEvent happens, we change that countdown timer text. The TeddyBear class has some stuff so it can shoot TeddyBearProjectiles. It starts moving as usual, and it creates and starts that shoot timer, including adding a listener, to know when the timer has finished. The StartRandomTimer method is just a method I wrote that sets the duration of a timer to a random range, and then starts the timer. When that shot timer finishes, we instantiate a TeddyBearProjectile and start another random timer. This way, the TeddyBears aren't firing every second, there's some variation in when they shoot and that makes it seem more realistic. And there's that method I was talking about, the StartRandomTimer that sets the duration to a random range and then starts running the timer. The TeddyBearProjectile is also relatively straightforward, so we get it moving at the start. When it becomes invisible, we destroy it. OnTriggerEnter, a TeddyBear could have run into the TeddyBearProjectile, and if it does, we destroy the TeddyBearProjectile and blow it up. If a TeddyBearProjectile runs into a teddy bear projectile which is certainly possible as you have multiple teddy bears shooting these things, it destroys both of those objects with explosions, and that's it. The final class that we'll look at here is the FeedTheTeddies class, so this is essentially the game manager for the game. There's a game timer, so this is that countdown timer that I've been talking about. And it keeps track of the HUD, and we'll see why soon. The Awake method is called before any of the start methods on any of the scripts is called, so we create and start the game timer. And we also add to our dictionary of events, we invoke a TimerChangedEvent, and then we tell the EventManager that we are an invoker for that event. And then finally, we listen for the GameOverEvent which remember, the burger will fire when its health gets to zero. In update, we'd just checked to see if the players trying to pause the game. When the game timers finished, we call this EndGame method that I wrote that we'll get to. When the GameOverEvent is invoked, we also call this EndGame method, that's why I wrote the method. And ending the game sets the high score and tells the menu manager to go to that high score menu. Now, you might be wondering why I didn't just remove these two methods all together, and I couldn't because they have different method signatures. I couldn't just replace them with the EndGame because this one has one Int parameter even, though that parameter is unused. So, this is where I just said, I would have one Int perimeter here so that I could have the EventManager only needs to hold unityEvents with one Int argument, but it's unused here. So the SetHighScore method actually gets the HUD's script from the HUD, accesses the property, remember I show you where that happens, and then it does some stuff with PlayerPrefs. So if there's already been a high score recorded, and this is a new high score, then we set that PlayerPrefs to the current score because it's the new high score, and then we save. And if there isn't a high score value in PlayerPrefs yet, we set the high score to the current score, and save it. That was a whirlwind tour of the classes that we use to support gameplay and there are some other minor changes too, so feel free to explore the code as much as you want to make sure you understand how this basic gameplay works. To recap. In this lecture, we saw how we could implement a variety of gameplay objects, and we also saw how those objects can interact with each other through the EventManager so they don't actually need to know about each other.