[MUSIC] Hi, everyone, I'm Jeremy Gibson Bond, and welcome back to the Unity Certified Programmer exam preparation course. In this video, we're going to be looking at the solution to the bonus challenge you had of animating that LevelAdvancePanel that transitions between levels in AsteraX. Let's take a look at what we're talking about. Here I'm going to click Start, and you'll see that the level text fades in, then the info text fades in, it fades out, and the level text fades out. And we've got that nice kind of bounce to the level text as well. Let's take a look at how that works. Here in the LevelAdvancePanel script, you'll see there are lots of difference states set up in the enum, eLevelAdvanceState. So each of these different states is kind of set in here, I have a set state machine. However, you could, if you wanted to spend a lot more time on this and make it more flexible, so you could use it across multiple games, for instance. You could create, say, a class that stored information about what you wanted to transition and how you wanted to transition it, and stored information about what step to go to next, or maybe you could store them in a list. There's lots of different ways that you could do this. You'll notice as well these two values, fade time and display time, which both default to one second. And back in Unity, we actually still have them set to one second as well. What this means is that it will take a full second for all the fade in aspects to happen. That's the text fading in and popping in, and the background fading in, and all that kind of stuff. Then it will display for a second, and then it will take a full second for everything to fade back out with the various animations that we have. So at the top of the awake method, we first set the private singleton S. Then we get the image component that we know is there because we required it. And then we go through and grab components out of the different sub-game objects or child game objects under this panel. This includes the text that says level, which is the level text. It includes the info text, it includes a transform on the level text, and it includes the image that's the background or the frame around the info text. As you can see, later in the same method for each of these we double check to make sure that they exist, and we log a warning if they do not. Then the final thing that we do is we call SetState with the idle state. So we're moving from the none state to the idle state, which just gets this ready to accept new transition calls. Here in SetState, the first thing we do is we set the start time of this state to real time. Now, real time is a property that I created, and all that it does is it gives us Time.realTimeSinceStartup. Honestly, the only reason that I made this is because Time.realTimeSinceStartup is really long and it was forcing a lot of lines to go off screen, which was bad for me showing to you in this video. So I made a shorter version as a property, you really don't need to do this yourselves. Back in SetState, when we set the state to be idol, the first thing we do is we make the game object inactive. This makes the entire LevelAdvancePanel invisible and it stops it from receiving updates, fixed updates, and other things like that. The next thing that happens is we call the idle callback delegate. There are two delegates on this. One delegate is called whenever we reach the display state. So whenever the fade in is done, and it's going to show a static screen for a second. This is called because that is exactly the right time for AsteraX to create all of those new asteroids and all of these other kinds of things that could cause a little glitch in our frame rate if it was happening while we were doing the transition. So we do the cool looking transition, then, when it's just showing a static screen, we do things that might mess up the frame rate because no one will tell because it's a static screen, and then we fade back out, and the level's ready to go. Now, the idle callback is called when we're done with the whole transition. So we transition, we fade in, we display for a second, we fade out. And then the LevelAdvancePanel goes back to its idle state, at which point it calls the idle callback. And you'll note that idle callback is called once, and then nullified. So we're ready to start the next level, that gets sent back to AsteraX and tells it to start the level. And then we nullify it so we don't accidentally call that again. Now, it should be pointed out here that delegates are multicasting, so that means you could register multiple methods to be called as part of that delegate, and they all would get cleared when we set idle callback to null. Down at the bottom of the LevelAdvancePanel script is AdvanceLevel, which is a static method that is called by AsteraX whenever it wants to advance the level. And there are two things that are passed in, which are those two callbacks, the display callback and the idle callback that I mentioned before. These two callback methods get assigned to the two different delegates, and then we set the state to fadeIn. Here we are in the SetState method where we were setting the state to fadeIn. The first thing we do is set the game object to active, making it appear again, making it receive updates, those kinds of things. Then we set the level text. So the level text needs to say something like level two, and the info text needs to say the number of initial asteroids and the number of sub-asteroids or children for each one of those asteroids. Next, we set the initial state of all of these different components that we have access to. So we clear the color of the background, the info text, and the info frame, and we set the scale of the level rect transform for the level text to be 0 in the Y dimension, making it invisible because it's completely flat. Next up, we set the stateDuration to 0.2 times the fadeTime. So the total fadeTime is 1, meaning that 0.2 times 1 is 0.2, of course. But we're making this 20% of our total fade time. So rather than set each individual thing in the inspector, we just set the total time we want it to take. And we're going to have the first part take two-tenths of that time, the middle part take six-tenths, and the final part take two-tenths, adding up to a total of one second. And the next state is set to fadeIn2. So whenever we're done with this 0.2 seconds, we'll automatically advance to fadeIn2. Let's look at the update where that happens. Here in update on line 195, we set u, which is that linear interpolation value, it's sort of a standard name for the linear interpolation value. Two, the amount of time that has passed since our start time divided by the duration that we want. So if, say, a tenth of a second has passed and our state duration is 0.2, then our u value is going to be 0.5 or one half. If the u value exceeds, then we move that it's time to move on to the next state. So we set to moveNext to true, and we also set the u value back to 1 to avoid any extrapolation that we don't want to experience. You'll notice as well that on line 202, u1 is set to the value of 1 minus u. 1 minus u is used a lot in linear interpolation. And so I just simplify it into u1 so it doesn't have to calculate it over and over again. Slightly further down, you can see that in the fadeIn state, all we do is set the background color to fadeIn in opacity. So the u is applied to the alpha value of the color for the background color. At the bottom of the update method, if moveNext is true, we SetState to the nextState, which in this case will be fadeIn2. Here in fadeIn2, we set the initial state of everything. We set the color of the background to black, we set the localScale of the level rect transform to 1, 0, 1, and we clear the infoText and the infoFrame color. Now, this is kind of redundant. We just did this in the fadeIn SetState. But the reason we're doing it again is because if somehow something happens and we get asked to jump into a state without the previous state having taken place, we want to make sure that we reset everything to where we need it to be for the beginning of this state. So it is slightly redundant, but it's kind of a security measure to keep us from screwing up in some other way. We set the fadeIn time to 0.6 or six-tenths of a second, and we set the nextState to fadeIn3. Similarly, you can see in fadeIn3 that we set the initial state of everything to be where it will be at the end of fadeIn2. And we set the fate time to 0.2, which is the remainder than initial full second time, and then we set the nextState to display. When we enter the display state, that's when we go head and send that display callback that we talked about. And then we wait a second, and we go into the three fate out states, where we kind of reverse everything we did for the fateIn states. Now, down in update for each of those, you can see that fadeIn3 is just a color transition like we've done before. Display doesn't do anything, it just waits around. But here in fadeIn2, there's something interesting, and that's what causes the Y value to kind of do this for the level text. So let's take a look at this LevelTextYScaleEffect. Here you can see that that scale effect takes the u value which ranges from zero to one, it multiplies it by pi, and then takes the sine of that. And so the sine of pi is going to go up and down over the course from zero to pi, which is our zero to one multiplied by pi is zero to pi. So that gives us this. And then we add u, which runs from zero to one like this. So when you add this to this, you get this bounce, which is exactly what we wanted for that Y scaling. I have found that I I use sine and cosine a lot when dealing with linear interpolations that I want to kind of bounce and move, and have some easing and things like that. This is because sine and cosine can convert any number into something that moves in a smooth way from zero to one, or one to zero, or has some bounce to it. And so I encourage you to play around with that if you ever want to add some character to your transitions, like the character that we added to this level text transition. There's not much left to say about this, except you can see when we set state to fadeout3, the nextState is the idle state. And then that jumps us back to the top and fires off that idle callback. So that's it for the solution to your bonus challenge here. I hope you enjoyed you, and I will see you in the next video. [MUSIC]