Lesson 32 - Implementing Powerup State Logic

Tutorial Series: Introduction to Unity with C# Series

Previous Article  |  Next Article


Transcript

Okay, well, we've got our main PowerUp logic in place. So now, the next thing to do, I think, is incorporate some logic to decide what the conditions are for engaging the PowerUpMeter, you know, decrement from it and so on. And then, actually decide what the PowerUp gives us, what kind of game mechanic it introduces. So, let's start in the PowerUpManager by creating a field to store our PowerUp state. So, either on or off ... On, off. What type do you think would best store this information? That's right, a bool. So, let's do that right now. Let's say, "Public bool is powered." We're going to need it to be public, I think, so other classes can access it. And, we'll start off ... When the script starts, we'll just set that to ... Well, it already defaults by default to false in C#. bools default to false. Uh, so, but let's set it explicitly in the start, so we know what it's supposed to start off as. And then here, what we can do is we can make a little conditional block. So, we'll engage the PowerUp under these conditions.

So, if (Input.GetKeyDown()) which I'll talk about a bit in a second how that's different from simply GetKey(). KeyCode... I want to map it to the "Z" key on th keyboard. So, if that key is pressed, and we're not currently in a powered-up state, and, of course, if we have any PowerUpMeter to spend. If we don't, then it won't work, so we'll want to make sure that we have more than 0 in our PowerUpMeter. So, under that condition, let's ... Well, we don't know what it'll mean to be powered up just yet, so let's just start off with ... Let's make comments, say, "Start PowerUp mode" Alright. And, "else if." So, we're going to want to cancel the PowerUp mode if we're already in it, and we press the same key. So, GetKeyDown() Do the same thing, KeyCode.Z. And, of course, we have to be powered-up in a PowerUp state for it to cancel. And, again, we'll determine the logic of what cancelling the PowerUp actually means. We're setting it, I guess, to the pre-powered-up state. We'll figure that out later. Alright. Okay, so, you notice we use the GetKeyDown() method instead of just GetKey() so this method returns true once as soon as the key is pressed. And then, returns false even if you hold down the key. So, it only returns true when and if you strike the key, and then if you strike it again, right?

So, this is very useful for trigger-type behavior. If it were otherwise, if we use simply Input.GetKey() and we held down the key, it would, you know, require you to hold down the button just to keep executing this conditional code block. So, we could do that, but I think being in a PowerUp mode should be more established as a trigger-type process rather than actually holding down a button, and then letting go to not execute that code block. So, that's why we used Input.GetKeyDown() So, what we should do now is create some behavior for the first "if" clause where it evaluates as true. So, we know we want to set the IsPowered bool to true to, you know, start PowerUp mode. And, we'll want to countdown the meter, right? Decrement, in other words. So, but we'll want to put the countdown meter in another if statement that counts down only so long as IsPowered is true. So, let's do this: Simply say, IsPowered = true. And, of course, canceling would be tantamount to saying, "IsPowered is false." And now here, we will determine what it means to be in a powered-up state. So, if IsPowered is equal to true, so, just write down the variable name and it'll read as "IsPowered is equivalent to true." Well, we'll want to decrement from the meter. So say, PowerUpMeter --. and have another conditional that's ... Checks if the PowerUpMeter == 0. And, basically, what that should mean is powered-up state should exit. It should be false, so that's pretty simple. IsPowered = false. Pretty logical stuff, huh?

This is not complex. And well, this is less than ideal, but we'll output it to the Debug.Log(), the PowerUpMeter so we can check that the decrement is working fine just like that. And, just to make it clear, the reason why we checked the powered-up state in a different conditional... You may have thought, "Why not just do it in "the part that checks whether or not "we satisfy those conditions to make IsPowered true?" Well, because, remember, this first "get key down," uh, part of the evaluation, it checks to see if the key is just struck down. So, in other words, this block really only executes on that frame, right? If you keep holding down the key, or, you know, if all these other evaluations evaluate as true, it won't continue to execute this code block. It will just execute on that one frame. But, we're going to want to execute this on successive frames, so long as we're in the powered-up state. Alright, so that's why we did it in it's own conditional statement. Alright, so let's run this now and look at the console to see what's happening with the meter. We give the PowerUpMeter a 50 integer startup bonus. So, we'll see how it decrements when we hit the "Z" key.

Sure enough, there we go. And, well, I didn't catch it, but I think the public bool here, it had canceled automatically when it reached zero. So, let's just try that again. Yep, there we go. And, we'll also want to try canceling it ourselves before it cancels. Yep. Yep, works well. Okay. Okay, so, this is working, but there's a problem, as you can see, with this temporary output to the Debug.Log() of the PowerUpMeter. But, we have to do this right now because, well, for whatever reason, the inspector, it won't show us the public static field for the PowerUpMeter. It'll show other public fields, but if it's static, it just doesn't show in the inspector. So, this is less than optimal because, as you can see, it will decrement on every frame and spit out the results to the Debug.Log() and overwhelm pretty quickly. But, you know, this is just all temporary until we can find a way to display the meter, which I think we'll do in the next video. So, before we go to fixing that, now let's go on to considering what kind of PowerUp up we can actually implement here. So, how about we slow down the game? Which, in this case, we would just want to slow down the speed of our cube player, as well as the sphere enemies. And we can do this actually very easily by just referencing the speed fields that we used, remember, as a multiplier of sorts to determine how fast our characters travel. So, simply reduce those fields when in PowerUp mode, else when not on PowerUp mode, put it back to its normal speed, right?

So, let's go to the CubeController script and, while we're at it, why don't we slow down the speed of our characters in general because we know the game is going to get pretty overwhelming pretty quick, right? As we're duplicating enemies at a pretty fast clip. And we want to have a fighting chance when things get hectic. So, let's just change the default Speed to seven for our cube, and, for the sphere, let's make it a little bit slower again 6, .06, I should say And since in the PowerUpManager, we're going to want to reference these fields, we're going to want to make them both public static. Static because we're not going to be really able to access the instance, at least not easily. It's just more easier to make it static as we've been doing so far. So, let's make them both public static. Alright, and now we're going to want to reference them in our little logic blocks here in the PowerUpManager. So we want to do it here when the trigger is activated so we don't keep decrementing the Speed. We only, on that frame, as soon as we engage PowerUp, start decrementing. So, let's say CubeController.Speed equals... Now, let's just go to half Speed. Let's make it cut the Speed in half in PowerUp mode. So, let's say CubeController.Speed * 0.5f. Alright, that should do that. And we'll also want to access the SphereController in the same way. So, actually I'll just copy this and we'll make both the Player 1 and the enemies cut their Speed in half. And, well, when we cancel out of this, we're going to want to double it, right? Go back to its original value. So, let's multiply it by two to double it.

Pretty easy. And here, we'll also want to repeat this when it automatically cancels, right? Okay, so let's run this now and see how it works. Now I can't go into PowerUp state without a PowerUp. Leave PowerUp state, go into PowerUp state. Let it automatically leave the PowerUp state. Yep, seems to be working fine. Alright, that seems to be working. Okay, so our logic works, but it's kind of ugly. In particular, the simulated time change mechanic is being repeated in both conditional evaluations. So, what do you think we should do when we see repetition? That's right. We should consider refactoring it into its own method. So, let's do this really quickly. Let's make a method beside Update(). Call it, private void TimeChange() It takes in a float called speedFactor local to this method that we'll pass in where we call this. And we'll basically take this part right here, and it will allow us to multiply by our speedFactor, which will be different depending on if we're entering or exiting the PowerUp mode, right? And, well, we can also just... You can remove this from there, too. We can put it right in here because we know we're going to want to either enter or exit out of IsPowered states. So, you can just really simply do it this way and say, IsPowered = !IsPowered So, it will have a little switching behavior, you know, built into the bool.

That's why bools are so useful for this state-keeping type of mechanic. And then here, take this fairly large code block, And actually we can just put... I will lose the comment unless I put it after the TimeChange() call here. But, as you can see now, I can put it all on one line of this method call. So, we'll change the time to 0.5, or we'll multiply it by that amount to get half. And here, we'll just multiply it. Multiply it by 2, so we can get back to our original value, right? And same thing here. A little bit cleaner, a little bit easier to read, and I'll just put a comment. Yeah, I'm calling it, "change time." I know that's kind of a misnomer because, actually, what we're doing is changing the speed of the characters. But, nonetheless, it has the effect of changing time. That's how we'll probably be thinking about it. Let's just quickly try that out to see if it's still working correctly. So not powered up, powered up... Again, another power-up, and let it run out. Great. Alright, well, I think we should probably leave things like this for now. I know we can keep refactoring and going on and on with that, but I want to just sort of keep things moving. And, we can always come back when we're closer to finalizing the project. So, alright, well done. We'll end the video here and tackle the next problem in the next video. Thanks.


Related Articles in this Tutorial:

Lesson 1 - Who This Course is For

Lesson 2 - What to Expect from this Course

Lesson 3 - Installation and Getting Started

Lesson 4 - Starting the First Project

Lesson 5 - Prototype Workflow

Lesson 6 - Basic Code Review

Lesson 7 - Game Loop Primer

Lesson 8 - Prototyping Continued

Lesson 9 - C# Fundamentals and Hello World

Lesson 10 - Variables and Operations

Lesson 11 - Variables and Operations Continued

Lesson 12 - Floats, Bools and Casting

Lesson 13 - If Statement Conditionals

Lesson 14 - If Statements Continued

Lesson 15 - Complex Evaluations and States

Lesson 16 - Code Syntax vs. Style

Lesson 17 - Variable Scope

Lesson 18 - Object-Oriented Programming Intro

Lesson 19 - OOP, Access Modifiers, Instantiation

Lesson 20 - Object Containment and Method Returns

Lesson 21 - "Has-A" Object Containment

Lesson 22 - "Is-A" Inheritance Containment

Lesson 23 - Static Fields and Methods

Lesson 24 - Method Inputs and Returns

Lesson 25 - Reference vs. Value Types

Lesson 26 - Introduction to Polymorphism

Lesson 27 - Navigating the Unity API

Lesson 28 - Applying What You've Learned and Refactoring

Lesson 29 - Constructors, Local Variables in the Update Method

Lesson 30 - Collecting Collectibles, Items and Powerups

Lesson 31 - Spawning and Managing Prefab Powerups

Lesson 32 - Implementing Powerup State Logic

Lesson 33 - Displaying Text, OnGUI, Method Overloading

Lesson 34 - Referencing Instantiated GameObjects, Parenting

Lesson 35 - Understanding the Lerp Method

Lesson 36 - Creating Pseudo Animations in Code

Lesson 37 - Understanding Generic Classes and Methods

Lesson 38 - Animations Using SpriteSheets and Animator

Lesson 39 - Working with Arrays and Loops

Lesson 40 - Debugging Unity Projects with Visual Studio

Lesson 41 - Camera Movement and LateUpdate

Lesson 42 - Playing Audio Clips

Lesson 43 - Routing Audio, Mixers and Effects

Lesson 44 - Adding Scoring Mechanics and Enhancements

Lesson 45 - Scene Loading and Game Over Manager

Lesson 46 - Understanding Properties

Lesson 47 - Controller Mapping and Input Manager

Lesson 48 - Understanding Enums

Lesson 49 - Dealing with Null References

Lesson 50 - Handling Variable Framerates with time.DeltaTime

Lesson 51 - Preparing the Project for Final Build

Lesson 52 - Final Build and Project Settings

Lesson 53 - Introduction to the Unity Physics Engine

Lesson 54 - Understanding FixedUpdate vs. Update

Lesson 55 - Movement Using Physics

Lesson 56 - Attack Script and Collision Events with OnCollisionEnter2D

Lesson 57 - Projectiles and Stomping Attack

Lesson 58 - Parallax Background and Scrolling Camera

Lesson 59 - Infinitely Tiling Background Sprites

Lesson 60 - OOP Enemy Classes

Lesson 61 - OOP Enemy Classes Continued

Lesson 62 - Trigger Colliders and Causing Damage

Lesson 63 - Multi-Dimensional Arrays and Procedural Platforms

Lesson 64 - Finishing Touches

Lesson 65 - Series Wrap


Comments

Please login or register to add a comment