Transcripts
1. Frogger Intro: All right everyone,
in this section, this is actually a module
from a larger course, and here we're going
to go ahead and create Frogger in order to
help you learn how you can make games
using the Gatto engine by recreating a
classic game from, I believe it was the '80s. It's been a long time. But you can see with this we're going to get player movement. Music We've got some wind
zones, collision detection. We're going to be able
to use tile maps. Understand how tile maps work. We have visual
representing time. We have sponsors going on.
We have collisions going on. We have some physics
happening we got keeping track
of lives and score, as well as some
background multipliers. We've got a lot of
things going on in this simple little
classic game here. So I hope you enjoy
as we move forward. And you should hopefully at least have a basic
knowledge of programming, if not of G D script
going in that will help you with keeping up and
not getting lost as much.
2. Download no Setup: Welcome future developers. If we're going to be developing things using the Gatto engine, either video games or
desk Cop software, first thing we're going to need is well, the Gatto engine. So let's take a look at how we can go ahead and get
this downloaded. Now, the first thing or the
first way I should say that we can get this is to download Gatto from the
official website here, simply go to goto engine.org. All like we see here.
Right here on the screen. And once here, you'll see the download section up
at the top of our screen. As well as two download
buttons in the center. We have the LTS, which is three point and the
latest, which is 4.1. We will be using the latest
version, which is 4.1. There's nothing wrong with
the three point x version. It's still being developed on, and it is the long term support. However, if you were to use it that version while
following along, there may be some functions or some things that we
write that might have different names or potentially not even exist in
the old version. So just keep that in mind,
and because of that, I would recommend
that you do use the 4.1 version as we go through. All right. So this is
the stable version and 4.1 came out. So you can either
hit the download latest button or the
download tab at the top. Both of them will bring
you to this screen here. All right. So go ahead
and to download this. All we're going to need
since we are going to use the GD script
programming language. All we need is the
standard version here with the blue button. And the difference between
this one and the.net version is the.net version
also supports C Sharp. And if you were to use that, then you'd have to scroll
down and also pick up the.net that is required
in order to use it, as well as preferably
external programs to Rachel Codin it's just a whole
lot of extra things that we don't need when going
through this course. So if you want to get
it from the website, you can go ahead and just
hit that Goto engine button there for 4.1 on the
standard version. Now, there is a second way
that you could get this. And that would be from Steam. You can come over to
Steam and go ahead and download it from there
if you would like, and that is going to give
us the standard version. By default, Steam version does not have the dot p
version available. So you don't have to worry
about any confusion with that if you go ahead
and get it from Steam.
3. What we will make: All right, this week we're
going to kick things up. An option, instead
of going off of just some texts like
we did last week. This week we're going to
be creating or recreating an old two D game from
the '80s called Frogger. Now this is going to give
us a chance to work with a two D player
controller collisions. Maybe we'll get into some
particles we can work with responds as you see. If you've never played Frog before or you've
never heard of it. You see here we're
going to be working with UI for our
heads up display. We have points that we're
going to need to keep track of my mouse there for a second. But not only that, but we're also going to see, is it going to show it here we have a certain amount
of prog per player. Obviously we don't
have coins in, but this is essentially the game Here we have two
little safe zones. In this little purple area, we have a road in
the middle that has five lanes of traffic
alternating back and forth. If the frog gets hit
by one of these cars, they die and the player loses a life. They make
it up to the top. They can hop on the
turtles and logs to make it across
into the safe zone. If they land in the water, that's a fail as well. Which I guess now that you
think about it doesn't make too much in the way of
sense since it's a frog. But there you go.
That's the idea of what we're going
to be creating, and that's what frog is, if you've never played
it or heard of it.
4. Creating the Background: All right, so let's go
ahead and get a jump. Start on creating Frogger. The first thing
you're going to do is make sure you download the assets and just go ahead and move that sprites folder
into your project. Again, I just created an empty folder
specifically for Frogger, but I would recommend that you create a new
project for this. That way you can
export it without having any issues in the future. All right, so the first thing
we're going to need to do, especially since our
sprites are so small, is we're going to
need to shrink them. Or not shrink them,
but shrink our screen down to more of the
arcade cabinet size. To do that, we're
going to head on up to project and go into
our project settings. All right, so it should start just like this with the advanced
settings turned off. And you'll see on the
left hand side just going to go down to the display section and go into window. And we're going to
set the width to 336 and the height to 240. All right, this is an
arcade cabinet screen size. The screen resolution for this, and it's going to be perfect
for our small sprites. All right, once you go
ahead and set that, you can go ahead and just
close and you'll see our little blue box
has gotten much smaller than what it used to be. The first thing we're
going to do here is we're going to
create the background. So we're going to create
all the road, the water, the purple median
that they call it, the scoring area that we
have to get our front to. We're going to get all
of that stuff set up. That way we can jump right into getting our game
play and all that that set up and running in
the next following videos. All right, so we're going
to need a two D scene here. Let's click on two D, and this will give us a node
two D for our root node. If you want to go ahead
and rename that, you can. You can name it
Maine if you want. Game Manager, Doesn't
really matter. If you really want,
you can just leave it as the default name. Going to leave me
as default for now. In order to create this
in our little background, I'm going to create
a new tie map. I'm going to hit the plus
button and we're going to go and select Tile Map
from the drop down, see in our curtain node. Select tile map. Go ahead and double click that
and select that. Now I have mind set up here. I'm going to go ahead and just delete all of these. 1 second. All right, so you should look like this when you have
tile map selected. If you don't have a select,
go ahead and select it. What we're going to
do is head on over to the right hand side. We're going to go to
the tile set here. It stays empty at the moment, but what we're going to do is click on it and go
to new tile set. And then click on that tile set, and that'll bring us here. Now what we need here is we're going to need the
little goal area, the water, the road,
and the median. If we go into our
sprite and scroll down, we will see home,
median, road, and water. If you just hold control, you can select all of these
at one time like this and just go ahead and drag
them into our tiles box here. All right. Before we can
actually use them here. As you can see, we can't
click on anything. What we want to do, I'm just going to scroll in
there with my scroll wheel, or you can plus a minus. The first thing
that we need to do is make sure we're on
the set up tab here, select our water, and
we can click on it. And now we have this
orange box around it. That means we have a tile
that we can now use. I'm going to do the
same thing for road, median home, Brow
straight across. Now home is a little bigger. I'm thinking it might be
one bigger than that. Let's see, what do we got? 2062 big. How's that? I think that'll do. Perfectly fun. All right. They ever go? I've got a 16 by 24
here for this tile. All right, so now if we click
on tile map at the bottom. Our screen down here. We should now be able to click on and start drawing
our sprites. Click on my median, Click on my purple tile here. Just drag one row
across the bottom. Go to my road, we got
five layers of traffic. We need five rows
of our black beer 4.5 If we refer
back to our image, we then have another
layer of purple, five layers of water, 12345. Then we have a layer of water that fills
underneath of our home. Let's do one more layer there. Let's grab our home. Just go ahead and
click on one spray, and drag your mouse across
so you can select all three. Let's place it. Oh, look at that. We seem to have this issue.
Well, what's going on? We are replacing our
water tiles here. We don't want to do
that. We need to actually draw this
on a, another layer. And I'm just going to
go ahead and finish filling that up with our water. All the way up to the top
of the last two lines. I'm going click on our
home section here. And we don't want
to replace these, we want to build on top of it. You'll notice here on the right hand side
of our tile maps, we have something
that says layer zero. And if we have a drop down,
there's nothing else there. What we want to do is go to our inspector of our tile map, open the layer section, hit add new elements. Now we actually have a
second layer back in the tile maps with our
home row selected. We can go to the dropdown
layer and hit layer one. Now we can actually
draw directly on top of it without
affecting our final. We've got seven
across with this. Just to make sure self our rose, 1235, looks good to me. If we click back on our No TD, nothing is great out. Here's what we're working with. If you remember, when we're
looking at the Alpro set up, what it looks like, we
actually have our score. That information is set
up right at the top here in this empty blue area, this empty water space, we have our logs, turtles that jump across that
help us jump across here. Inside of these
little blank areas in home is where we can score
points by getting our frogs. Purple is safe and our black road is where our
cars are going to spawn. All right, we now have
our background all set up just like that. Pretty easy to get going. The new tile map is real nice to quickly get
up and going with this. We didn't used to have layers. Now that we do that makes setting things up like
this much easier. All right, that's
our background, Let's go ahead and jump
into the next portion.
5. Creating the Player: All right, let's go ahead
and create our player. But before we do, I'm going
to go ahead and save this. It's going to control
S. Go into my frog or holder and save my
scene real quick. All right, so for our player, our player is actually
going to have its own scene that we bring in. So we're going to click on the plus right up top
here or add new seam. We're going to go to other since this is a player that we
need to have control over. This is going to be
a character body two D. This used to be
called a kinematic body. In other engines you may hear
people refer to it as such, but here it is now called
a character body two D. Now this character body, we have this yellow triangle here
that gives a little warning. It just tells us that our
node doesn't have any shapes. It can't collide with anything. It's got no collision
for now, that's fine. Use that to floating there. What we're going to do is
we're actually going to go go and add a,
another node in here. And what we want to
add is a sprite. Two D. We want to add
an animated sprite. We want our sprite
to be animated. We do have two frames for this. Let's go ahead and do
an animated sprite. Two D on the right hand
side in the inspector. Let's open up the animation
section versus sprite frames. Let's click on it and
do new sprite frames. Then let's open those sprite frames up just by
clicking on it. All right, let's have
our default animation, which I'm going to go ahead and rename that to just be idle. Then we're going to add a new animation with this
little icon down here. I'm going to rename
that to Jump A Idle. Selected. I'm going to bring
in Proger idle and G, jump. We're going to
bring in Proger Id, then our jumping icon Proger, and now we should be
able to go between the two whenever we want
to play these enemies. All right, if we play there, we're jumping, we're doing
our little bouncy bounce. You might notice that the sprite is a little blurry up
here in our renderer. But down here we can see it's supposed to be nice and risk. Well, to fix that,
we can go ahead and we can just select all of our sprites here at one time. From our file system go
to the left hand side to the import isn't going to be an import moved this let me just go ahead and let
you know where that part is. All right, so if you head on
into your project settings, where I go head on into your
project settings and locate the rendering and
texture section here in advanced settings on or
do we need it on this? No, we don't need it on that. We want a default
texture filter here, change it from
linear to nearest. Go ahead and close
that, and you'll see your sprites go much sharp. If you're going to do
pixel art like this, this is the default you want to set you in your
project settings. And now we have a
nice sharp Roggio. That's all we really need. We don't need to worry about the collision or detection or
anything like that for now. We'll worry about that when
we get to that portion. So I'm just going to go
ahead and ha, to save this. And I'm just going
to call this player. Now if I go into my main scene with my node two D selected. I can click on not this
plus for a new node, but the chain beside it. That'll let us instance
in a scene that already exists for us. That's going to be
our players scene. Now we can go ahead and grab it and we can bring
this little guy in. We can play, we can do whatever we want to
do with this little guy. So let's see what's
our transform. We know this is in
values of 16172, wouldn't it would be 176
if we're on values of 16. And I'm just going to
move my little froggy up. Here we go. Be a little more
centered with that. Now I have my little frog in my main scene with my background
and he's ready to go. All right, that'll
do it for this one. We have our player set
up as much as we need at the moment that we'll jump into the next one where we will address doing
some player movements.
6. Player Movement: All right, let's go ahead
and we're going to create the movement for our little
froggy to be able to move up, down, left, end, right. To start off, we're going
to need some inputs. Now if you want to
use the arrow keys, then I down, I left, and I right already exists, but I want to use WASD. So I'm going to go
up into my project and go to my Project Settings, and I'm going to go into
the input mapper at the top, add a new action. And I'm just going to type
in add left and right. Now for each of
these actions here, I'm just going to go to
the right hand side and hit the plus button up. I'm going to hit
the plus. I'm just going to press on my keyboard. I'll show you what
that looks like, what you'll be
seeing from there. Let's see, this is
this window here. I'll bring that up
above. Here you go. I just hit the key
and we have that. We hit okay, we go to down. Hit the plus, press S key again. A left and D for right
now we have up down, left and right for our controls. We can close out of there. Our player is going
to need a script. And I'll take a note here on
my animated sprite on jump, I didn't get rid of
the first sprite, so I'll just have this
one with his legs spread and put a script on side of our character body two
D on our players scene, we just have an
empty one like so. Now what I'm going to
do is I'm going to create a function
called movement. So this is just so we
can keep everything clean and organized and keep all of our movement
in one location. We're going to do
to take input here, we're going to use
the if statement in the same if statement
we've been using a lot. If then we want to access the input object or
the input class input, then we want to check action. We want to go with release. Just released or just pressed. Either one will work for
this game, specifically. If we go is action pressed, then that is while the
button is held down. Just pressed and just
release means, well, just press is when as soon as the button gets activated
when you press it down. And release means the block of code is going to execute when
you lift your finger up. I'm going to go with just
press, let's try that. I'm going to use the button and this is a string that
should have popped up. You automatically,
this was a colon. So we can go inside to it
and create the code block. All we're going to do is
we're going to do two things. We need to move our little rock, we need to move
it up the screen. And we're going to go up by one block and everything
is split into 16 16 block or 16 tile size. So we're going to move
our froggy up 16 blocks. In this case, we're going
to get our position. If it makes a little
more sense to you, you can say self position because you're moving your
self that this script is attached to right now. That's going to give us an x and a y ordinance that has two
numbers associated to it. If we click on our
character body and look inside the inspector
under transform, you see we have an
X and a Y and these correspond to the location
that they are on the screen. If we click onto our main scene and go to our character body, you'll see it's position
is 169.2 33 in my case, this is where we're
starting from. And we're going to be
adding or subtracting from this for
either the X or the Y to get our movements
since we want to go up. When we press up, we're going
to be affecting the number, We're going to say position. We're on ourself, we want to get the position property
and then we want to get the number of it to
go up the screen, we actually have to subtract. So we're going to say
minus equals that. We could say this is equal
to our position y number, is equal to position
y minus some number, which our number in this
case is going to be 16. If we were to just leave it
like that and run our scene. Well, how unfortunate
our little froggy doesn't move. Why
doesn't it move? Hopefully you cued on or grasp that before I
hit the flight button. We're never calling
our movement anywhere, so we're never actually
checking for any of this stuff. For that, we're going to
just stick it inside of the process function here. Movement and now
it's being called. Oops. At least it would, if we could spell it
correctly. There we go. If we try running that now and hit the up button,
which for me is W, you can see we're going
ahead and we're moving our 16 blocks at a time. We win. We got one
little froggy up there. Now of course, the problem
is we're still moving, but we can't go backwards. We have no animation
or anything. Let's get our animation
working there. How do we play our animation? Well, if we look at
our player scene, we can see from
our script we can, we can follow this
one line easily, just one level to the
animated sprite two D. Let's get that node. The way I've shown that before was using this dollar sign.
It would be the easiest. As soon as you start typing animated sprite,
it's going to pop up. Remember that's only
animated sprite two D because that
is the name of it. If I were to name this banana and very por spelling of banana, then that's what
I'd have to type in here in order to access it. I'm just going to reset
that name back to Deft. All we're going to do is
we're going to call on it. Play, Play. You'll see the animations
that we created pop up. We're going to use jump. We try that now
just with that one edition of our line, whoops, we have to actually play this
scene and not our player, you can see we go into our jump, but we're stuck in our jump. Now, that's a little
disappointing. How can we fix it? How
can we go back to normal? Well, we can set it so that
when our animation completes, then we return back
to our idle form. In order to do that,
we're going to have to access the animated
sprite of our player. Go to the right hand
side to the node tab and we're going to connect a signal that this animation finished. If we just double click that, we'll get a pop up to
connect a signal here. We're just going to
select the character body two that our script is on
and hit the connect button. It's going to hold all to use
my arrow keys to bring it up whenever our animation finishes playing this block
of code is going to execute. Now what we want to
happen here is we want to return back
to our idle state where our frog is
just sitting there. The same thing.
We're going to get our animated sprite two D, we're going to call play. That's going to be
idle if we try that. Now what do we again if we play the right scene,
how we attempt that. Now we see we now have this little jump that's appear as we pulling
across the water. That's awesome. Now the thing is our idol is going to be playing
constantly at this point. Our idol plays and
then it finishes. And because it finishes,
it's going to play, no, that's not really
going to be an issue. That could be something
to keep in mind going forward to solve this issue. We can actually fix
this with an if pick. And as you can see my
little output there, I was checking things
and I'll show you how to do that.
I'll clean that up. All we have to do is we can
check animated sprites. Want the dollar sign there? If animated sprite
two D Animation. No, what was it called? Well, if we go into
our animated sprite, and by the way, you
can access this, if you just hold
control and you click on the animated sprite
two D here in our code, then it'll open up the
documentation page for Here's what we're looking
for here. Get animation. We want to get animation. As you see that
wasn't popping up. Sometimes it's useful to
check out the documentation anyway we want to do if animated sprite
two get animation. If we were to take
a look at that, the current animation of
the sprite frames resource at the value is changed. Frame counter, frame
progress or reset. But what we want to do is we want to get what
this animation is. That's basically return to us what animation is playing
or currently selected. So we're going to use the
double equals because we want to compare whatever gets returned to us and we
want to write jump. Then when we play our idle, we're just going to
tap that in one, so it could be
inside of our lock. Now we're basically
going to check when our animation finishes. If the current one is jump, then we're going to play idle. If we run that, there we go. We have our little boing. It looks exactly the same, but we're not going to
be constantly playing the idle animation
over and over and over when the idle
animation plays. Remember it plays once
and then it's done. It's not looping. If yours, for example, is looping for whatever reason, the go ahead slick
your animated spray. And if it's looping, you
can see our mouse here. That's because
this is turned on. So you just go ahead and click it turned off, so
it's white like that. If it's blue, then it's on. If it's white, it's off. Now when our animation finishes, after we jump, we're going to check if our
current animation is jump. If so, then we'll play
idle when idle finishes. This if statement will not be true because when
we get animation, it's going to be idle, not jump. Since that is no longer true, we're not going to
do anything else. We're not going to keep replaying idle over
and over this time. It's a small difference, one
of those things that are on the back end that the player
is never going to notice. Like I said, in a
small game like this, it's not going to make
that big of a difference, if any that is noticeable. But it's something worth
knowing going forward. But when you do want to make
bigger and bigger games. All right, so let's
go ahead and we can now get our button. If we just copy and paste this, we can get L if instead of an if we want our down
pressed instead of up, we want to plus 16 instead of -16 Because if
minus is going up, then plus is going
to take us down. So now we can go up
and we can go down. Now our little froggy
doesn't turn around at all, which is a little disappointing. But we can easily fix that by adding one
more line in here. We can do that by talking about its rotation before we jump, we can get self rotation. If we take a look at our player, we go back to our player scene, click on our character
body inside the inspector. If we come down, we see
we have rotation here. Rotation is in radians
rather than degrees. What we can do is we can
say rotation equals. We can use this function that's built in called deg two red. That might have changed here. It looks like it has. It looks like it's
been renamed here, deg two d, It's got the
underscores in it now. Then let's take one argument
in the form of degrees. If we say 180, that's going to be
a full turnaround. We turn right, that's
going to be 90 degrees. If you turn left, we're going to be
-90 Either way, we have to get to positive
180 or negative 180. I'm just going to go
with 180 degrees here. This function is going to
convert this 180 degrees into radians so that it can be assigned to
our rotation here. Now, one full
rotation in radians is 3.14 and this is
where pi is from. This would be the
same here, 180. As if we were to just copy this. Say rotation equals
pi divided by four, then that'll give
us one rotation. Pi divided by two, that'll give us half our rotation
here in radians. If I were to show you that
with pi divided by two, there we split down
the other way, maybe it is a little
more than two. Now, I don't normally
use radians myself. We can see divided by four. We get this little
awkward angle. It can be a little awkward when dealing with
radians at times, which is one reason why I
prefer to use degrees to radian just because
it's something I can work through
a little quicker. As you see, there we go.
We flip the face down. Only now we're not
facing back up. So now we have to fix
that inside of our code. We'll just do the same
thing when we press up, we set our rotation to zero
if we were to play it. Now, here we go. Now we can jump up
and we can jump down. Now what if we want to
jump left and right? Well, we can get those
with two more LCs here. I'm just going to
space these out to be a little more legible. Here we go. Starting on our second here, we're going to say
if action is left, instead of modifying
the y value, we're actually going to
modify the x of our position. Because x is left and
right, if we're going left, we have to -16 here,
degrees to red. Well, we could set this to 270 just to stay on the
positive side here. Which means our last L here. When we press right, we're going to modify the X
position instead of the Y, we're going to plus 16. If we're moving right, we're going to be rotated
at 90 degrees. We go ahead and try that now. Should see. Now we
can jump around in all four directions
we can get around. If your frog is placed
in the correct location, you should be able
to land in all of these little home goals here. No problem without going over. Here you go. Now we go
to keep our position. Well on the screen
would be nice. We can worry about all
that stuff later on. For now, we just have our movement going around and this vehicle is
getting low long. I just wanted to keep movement
in its own little section. Here, there we go. We can run around as our own little frogging
Boeing. Boeing. But all right,
there you have it. We can now go ahead and move on to the next section of our code. I think next we're going to, I think we're going to
create our vehicles and have them start going
across the road here.
7. Creating the Vehicles: All right, today we're
going to go ahead and create the
vehicles to go across. Now we have a couple
of different ones. Let's see how many we have here. Inside of our sprites, we have five different cars. There we go. And some of them go left, some
of them go right. And they're already facing
in the direction that they want. That's great. All we have to do is create them and have them move
across our screen. All right, let's go ahead and create a new scene with our
plus button here at the top. For our tabs, we're going to go to other node
and just like our player, we're going to use the
character body two D here. We're going to give it a sprite. In this case, since we
have no animations for it, we're just going to use
a regular sprite two D, we can go ahead and assign a
one of first sprites to it. Now in this case
I went ahead and selected the little truck, but of course you can pick
whichever one you want. Specifically, I'm using
one that's moving left. At the moment,
that's worth noting. I'm going to change
this name from character body two
D to be truck. I'll save that as
my truck scene. I'm going to need
a little more now. We're not going to use
a collision shape, although we are going
to have some type of collision be able
to happen here. Because obviously
our frog has to get squished in some
way if it gets hit. To prepare for that,
I'm going to create an area two D that's
just going to pretty much allow me to have a
predefined area that I can check to get that area
with area two D selected. That's now where I can bring
in the collision shape. Now the collision shape has
this little triangle on it, giving us a warning
collision shape selected. We move to the right to our shape section and
we create a new one. That's just going to be
a new rectangle shape. Now we don't use
complicated shapes such as using the polygons. Instead, use polygon with shape with some of these
basic shapes here. Because the temple your shape is the better it's going to be
in terms of performance. However, the more
complicated a collision is, the more accurate
it's going to be. It's a balance that you, yourself would have to work out. But in this case,
luckily for us, we can just use these
rectangles and that respond, especially since for recreating
an older game like this. All right, now that we have our collision shape
like this, and again, if you didn't catch
that, just make sure your rectangle is
covering everything. Every part of the truck here. Now our truck is actually
going to need a script on it. I'm going to add one
to it, and instead of calling it the truck script, I'm going to call it
the vehicle script. Now the reason why
we're going to call it the vehicle script
is because we're going to be able
to use this script on all of our vehicles. Now to do this we're
going to a variable. For us what this is going to do, this export keyword is going to allow us to change
inside of the inspector. Let's go with the
at sign export and we'll create a variable and
we'll call this direction, it's going to be an integer. By default, we can
just send it to zero or we can send it to one. Doesn't really
matter in this case. If you save that and
select your truck again, you should see direction inside of your inspector on
the right hand side. Now in our case, we're going to need to be negative
one because we're going to move means we're going in the
negative direction. I just went ahead and set
that to negative one. Now in the process function, we're going to have our
character is correct, but our truck move. Then in order to
move, we need to have something called moving
slide or moving collide. Either one will work in
order to have movement. In my case skin moving slide. Moving code is
just fine as well. Pretty much just defines
what happens when two Physics bodies collide with
each other right there. Either smack up against
each other and stay there, or they can slide
along each other. In our case, it
doesn't really matter since we're just
going to be using the area to determine if our frog has been
hit by the truck. Now we have moving slide. We can't just play it now, because we still have to
control this movement. I'm going to have a, another
variable here called speed, which will also be an integer. I think. I'm going to set this. We'll try eight now. We'll see how quick that moves. That might be a
little too quick. I'll actually try it with two. Now that I think about it, All we're going to do is
we're going to change the velocity and we want
to change the x number. Just like position, we have both an x and a y
When it comes to velocity. Velocity is going to control our object moving consistently. Let's go to velocity as of four, interesting, maybe capital V because I know there
is a built in one. Pretty sure here, it's
low, right there. I must have just put a typo
in there. But there we go. So we can just do velocity x this time. We're
going to say equals. We're not going to
say minus or plus, because this is going to be
dependent on our direction, say speed times direction. We're going to move
along the x axis, so we're going to
be moving left and right at the rate of speed, which is two right
now times direction. Right now we're at minus one. So it's going to be two
times minus one and that's going to give us a negative two and should
have us move left. We went in the inspector and we change it to a positive one. Then that should
be two times one. Bring in a positive two and have us move in
the right direction. I'm just going to set
mine back to minus one. I'll go back to my
main scene and just bring a truck in to
take a look at it. I'll just set it right here. Play the scene and
see if it moves. We can see it's moving, but it's moving way too slow. We're going to have
to tweak that. Let's go back to eight. Maybe eight was good. Try that. Eight is not good, but
it is much better. Let's see, do we want to
be moving at 16 pixels? 16 looks good, although that looks like it
might be pretty easy. Maybe we want to increase that. Keep in mind we can
always come back to this, and since we're using the
speed on all of our vehicles, we could easily adjust this and tweak it once we actually have all five lanes being
used up for vehicles. Let's see, with 32, 32
is looking nicer here, I think 32 is where
I'm going to leave it and tweak it later on. Maybe you want to go to 48 or I don't think we're
going to be able to get to something like
64, but you never know. I suppose I'm just going
to use 32 as my base. All right, so we have a truck
moving in one direction. Now we can create our
other vehicles as well. Let's see, we have two more that move left and two
that move to the right. Let's see what do we have here. And we're going to
go to the left. So we're just going to pretty
much repeat this process and use the vehicle
script on all of them. All right, I've gone
ahead and as you can see I've made my other
four car scenes here. All I did was come in, adjust the collision
shape if I needed to replace the sprite with
another one of our cars. And then if necessary, taste the direction for
minus one to positive one, that controls all of our cars. And I went ahead and I placed them approximately to
where they would be here, just so I can test
and take a look. As you can see as we run it, our cars go ahead and drive and they go across the screen in the appropriate
direction and they never collide each other. Awesome. Now all we need is
more cars that span. We don't want to
place these consists, except we have to
place them manually. Then we have to just have this huge list
of cars that we have no idea how long it's going
to be for them to spawn. Or how long it's going to
take for the player to either run out of lives
or complete the level. What we're going to do is
create spawners for these cars. All right, these spawners
are basically just on a set time spawn the vehicle. We could have five
different spawners if we want to, one
for each lane. Let's see, I think that's
what I want to do. I think I'm going to have
five different sponsors that way they can all
have their own times and if you wanted you could
just have set as spawn limit, one time limit for all vehicles. That's perfectly fine as well. I'm going to go ahead and
create one and this is just going to be a basic no two D. I'm just going to call this Sp. Do we want to call
sponsor one here? Yes, go sponsor one and this
is going to control my top spawns up here and I think I'm going to use this as its base location as well, so I'm just going
to get a good spot. And since this is the truck, I'll bring it back
to there and that'll show me that the truck
spawns on this position. It'll be right
there on my spawn. I'm going to create
a new script. This is just going to
be a spawn script. Once again, we're going to use
this on pretty well every, all of our spans
that we create here. What do we need to
do? Well, we need to wait a set amount of time. It's going to delete this
common out of there. As well as the one down
here on line nine. All right, so we need to
wait a set amount of time. That time should be random then based on that spawn in our case we're going
to be loading the truck. I'm going to go ahead and do
variable here for my truck. That's going to be
a pre load here. Mr. means we're just going to
load the scene beforehand. That way we can use it, we can instance it in at any point. So I'm just going
to grab my truck from my file system
and drag it in. That way we have the correct
location here to the scene. With this, I'm just going to show you what
the one vehicle here, because then we
just have to come in and we can tweak this. Show you how we can export. Well, that way we
can actually use this script on everything
instead of making multiple scripts just because
of one variable difference. I'll show you that. But first let's get
this up and running. What we're going to do,
we're not going to use this process at all. We're actually going to
create a function called spawn vehicle In here, we're where we need
a random number. Let's go ahead and
call time late time. Just call it wait time. We'll set a float and
we'll set this equal to, let's see, a random
integer and not mistaken. We could just do something
like this and that would work. I don't think we have
to use Rand range, although I could be incorrect on that. All
right, there we go. Since I want to
double check that, just to be safe, I'm
going to hold control. Click on Randy and that's going to open
me up to this page. And yes, I did this correctly
by using percent 20. In this case, a GC
is going to give us an titubetween 0.19% 100 will give us 0-99 And if
we do percent 100 plus one, that would give us a
number 1-100 In my case, if I do three, then we're going to have
a wait time of 012. I'm going to add one to that. Now we have to wait
at least 1 second, and between truck spawns
it's going to be 12-3 We can see how this looks. We could always
adjust this later. Now our wait time we have that, now we have to actually
wait this amount of time. We'll say wait, we have to get the tree
in order to do this. The await keyword
here means we're just going to wait for this. In our case, it's
going to be a timer, but this could also
be waiting for a signal to be sent out. But right now we're going to
say a get tree create Tim. This is going to be
our wait time here. Our random wait time
that we have time, we're away for that time
out signal that gets sent out when our Tim ends. Which will be based
off a random number, a random amount of seconds. All right, so once that's done, we can create an instance
of our truck, of our, we'll say VT for vehicle VI
for vehicle instance equals, in this case we're
going to say truck but should change it to vehicle Truck instantiate and then we'll add it to
our spawners self, a child to add it
into the scene. And I All right, let's see how this works now. It's not going to because
we didn't call it. Let's go into our
ready function here and our spawn vehicle
function that we created. Let's try it now. There we go. So we had another
truck spawned in, and we're not going
to have anymore because we're only
spawning at once. What we can do from there
is after we add child, right after we add the
truck into our scene, we just have it
recursively call itself. It's going to cause
an infinite loop. It's going to keep,
it's going to spawn a vehicle and do nothing
and then spawn a vehicle. When it's done with that
spawn another vehicle, it's done spawn a vehicle
and it's always going to be a random number every time that we have to
wait in between spawns. If we just take a
look at it now, we can see they're fairly
consistent in its spacing. And then that was a
much larger spacing. We got a really close
spacing on that one. It looks like percent three plus one might be the shortest
that we want to go, but there you go.
It's up to you. That's a lot of
close ones together. It's up to you if
you want to tweak that a bit, play with it at all. And up to you how you want to
have them spaced out there. Now, the reason we
don't have to set its position is because we're adding it as a
child to my spotter. And the spotter is right here, since the truck here is
at 00 in its position. The truck here is at 00
in its position here. And we can see that if
we go to transport 00, it's going to be exactly
the same as it's parent, which in this case is
going to be sponsor one. Where my sponsor one here is that it's going to
spawn in that location, just off screen enough. Now, how can we
change this script to run to be able to use it
for any of our vehicles? What we need to do to make this work for all
of our sponsors, that we can have as little
work as possible here. Well, first off, I'm going to change my variable name from truck vehicle because
now we're going to use it for more than one
vehicle, not just the truck. That means we're going
to have to change it down here in our spawn from truck instant to
vehicle instantiate. We want to have this
variable exposed inside of our inspector so we can tweak
it on a per node basis. Here we're going to do the
at signed with export. Now what are we going
to export here? Well, we could just
leave it as such. And this will just work if we
look inside the inspector. But if you want to get specific, this is called a pack seen, that's how you
would export this. Then we could even just
delete the pre load here, we just have a sign, our vehicle and declared
as a pack seen. Now if we click on our
spawn and our scene here, we can just open the vehicle and say New pace or we can load. Obviously we would want to load. But to save some
time, we can just go into our file system, grab our truck, drag it in, and drop it in there. If we run this, we'll see our trucks spawn
just as they should, just like they did before. All right, perfect. If we were to grab,
say, let's see, Car one is also going to
the left, let's grab car. Replace that scene in there,
and take a look at it. There we have it.
We got it working here with a different vehicle. All we have to do is
change this one out. That's a lot of cars in a row. There again, I can come down
to you tweaking things, but there you have it. I'm going to go ahead
and replace this one with truck again and
stop that from running. Now, I can go ahead and
I can make more spans. I do, we do history
and mismatch. That's interesting. I'm not
doing anything with history. I'll just use control D there. And this one is sponsored two. So I'll just come on down, make sure that lines up that this is going
to be car three. I'm going to look
for my car three, scene and drag it in. Go ahead and take
a look at that. There we go. We have our
trucks and our car spawning in at our different
intervals. Fantastic. We can do the same thing
for our bottom here. I'll duplicate that
one more time. And I'm just
duplicating that with control D with spawner selected. And I'm just going to pull that down here for this vehicle. This one is just, I'll pull car in here, we take a look, we see all of our cars
going to the left are all spawning in correctly. Fantastic. Now we
just got to get the two over on the right.
The same thing. I'm just going to
duplicate my spawn here and just drag it over
to the left hand side. And then I adjust it here. Our position that
should be good. And that is car my car Fc would duplicate it one more time and mass it up here
for my car two scene. All right, now should be
able to come in here and delete all of these
temporary cars and trucks. If we run it should be
working perfectly fine, spawning all of our
vehicles in there. We have it now. We can run around
with our little, yeah, our say,
little froggy here. There we have it now. We just need a way to hop across this water
so we can get in there of a way for our little
froggy to get squished. I think we'll handle
the squishing. Next time we'll get
player death in here.
8. Player Death and Respawn: All right, so how
are we going to get our little froggy to get
if he gets hit by a car? Well, the first thing
I did is I added a collision shape two D to
cover the size of my froggy. We're going to use that in order to determine
if you got hit by a car in combination with the area two D that
is on our vehicles. Inside my animated sprite, I created a new
animation called Death, and I brought in the
frog dead Sprite. Now that we have that we
also need on our vehicle, we're going to have to add
in a signal connection here. And the one that we're going
to want is body entered. We could come through here and connect them one
by one on all of our vehicles or we could save a little time and connect it
through through the code. I think that's what
I'm going to do here, just that way we saved
a little bit of time. Now let's take a look
at how we would connect this signal through the code
instead of the interface. The easiest way for
us to set this up is as you see in the following, inside the ready block here, that error is just because we haven't created
that function yet. We see we grab our area two D because that's what's
sending the signal, the signal name which
is body entered, you can see that on the right. And we're going to connect that signal with the
connect function. Then we create what's called a callable and pass in a name. And this name is going to
be the name of our function that we want to call on. Player hit, Frog hit. You can go with that is what
I'm going to call mine. Now all we have to do is
just come on down and create a new function for Funko. This function also passes
in a piece of data. If we take a look
at the body entered signal here on the
right hand side, we see it passes in the body
and that is a node two D, it's going to be a two
D node of some type. We have to put that
argument in node two D. And just like that that should now connect the signal for all
of our vehicles. And to test this out, we can
go ahead and print body. And we'll see this
something I've also done is I
changed my player. I've renamed my player from character body TD to be player. Then I've had to go
into my main scene here and replace it so that
the name was updated. Now if we go ahead and run this, we should have a body get printed out every time
we get hit by a vehicle. So let's test lane one. Yeah. Lane two, Yeah,
Lane three, Correct. Lane four. Our last lane, the
truck. Here we go. All of our vehicles
are detecting when we get hit and we can see we have a lot of vehicles
there with this time, that might be a good amount. Or maybe you want to increase the minimum spawn between them. Again, completely up to
you and how you want to go about it, go about yours. But with that, all of our
vehicles have now been connected and set up to
squish our little frog. The reason why I told you I
read my character Body TD. For the player to play, I'm using a capital Is
because we're going to use this name on our vehicle script. We're going to say if and then passing a spring here, player. So we want to see if this string is inside of another string. And the string we want
to check is body name. Now remember body is whatever object we
just collided with, Whatever body just entered
our vehicles area. The name property of
it is going to give us whatever this name is here, which in our case is player. See if our name is player
instead of body name. We could just do a double equals if we wanted
to be an exact name, it's completely up to you. In this case, it shouldn't
affect anything. We end our statement
with our colon. Drop down to the next line. Now we can execute
our piece of code. What do we want to do
when our player gets it? Well, we're going to call the death function on our player. Now, this function
doesn't exist yet, so we're going to have
to go create that. But body death if you want to have an extra case. Security here. You can say if body has method can pass in
the string of death, then we can tap body
death in one more. We can go like this and
this will avoid an error. If we were to go
ahead and run this, you see we're not going
to have any errors here. Because we're basically
saying, okay, we're saying if we collided
with the player here, player, if that body has
this function, then call it. Right now it does not
have that function. If you wanted to put
that extra layer of security in there by
using has method, you can certainly do that. I'm going to go into my
player now and create this function bunk death. We're not passing any
arguments in with it. What's going to happen
when our player dies. But we need to play
our death animation so we can get our sprite corrected. Let's go
ahead and do that. Animated sprite two, play death. Let's take a look at that now. What happens when we
get hit by a vehicle? A poor little frog
crossing the street? Okay, so we see you die and then we one or sprite
is the wrong way. It's not facing up
the way it should. Let's correct that. After that, we're just going to set its rotation. And we've
already done this. When we press up, let's add
that into our death function. Here we take a look that should
now be acting right flat. We're in position awesome. Now what you can't see
is we're constantly being collided with because our collision shape keeps
hitting these cars. And not only that, we
can also keep moving, so we can't bring the being
and we're alive again, we have an unkillable frog. All right, one prof matter time. Let's stop our collision
from happening. And we can see this,
and I'll show you that if we come into
our player hit and I'm just going to go ahead
and print out squished frog. You can see that even
though we're dead, we're still getting
squished, squished frog. And we're going to keep getting squished even though
we're already dead. We don't want this to
happen because this might just keep
subtracting lives from us, depending on how far
apart the spawns are. Let's go ahead and fix
that on our player. To do that, we're going to get ahold of our collision shape
that we created, the collision shape two D that
we added onto our player. And we're going to
use something called called deferred on it. What this essentially going
to do if we take a look, is calls the method
on the object during idle time
always returns null, not the methods result. There you go. Our keyword here is calls it
during idle time. So it's going to call
this whenever we pass in, when it gets the next
chance that it gets, basically instead of trying to call it now when it might not be able to stamp functions, it is going to tell you to
do that before we call that. You don't have to delete them. I'm just going to show
you here the error. If we come in here and I
go disabled equals true, we're going to see we're going
to run into an error here. It doesn't prevent our
game from running. Let's see, we got
squished twice. Our disable isn't
working for 12. If we go into our debugger
and look at errors, that's going to tell us that we can't change the state while flushing queries
use call deferred. So it's specifically
telling us to use that, that's why we're using
call deferred here. Call deferred in
here is going to be a string of what we want to do. In this case, it's going
to be set disabled. That disabled takes
a second argument and this is going to
be what we said to, in our case, it's going
to be set to true. Now if we look at this,
that error is going to be gone and we're only going to
get squished to one time. There you go. It's not going
to pop up anymore inside of our code if you're worried
about call deferred. When we get hit by
a close range of vehicles such as when
it's like three back to back, we can
take a look here. It's already been
disabled before the next vehicle
even touches us. All right, so now we
can actually die here. What we have to look at is
how do we get ourselves back. Right. Now we're just an
unkillable frog because we can't
collide with anything. So we have to fix
that with our death. We have to have a
respawn of some sort. We need to make sure
that we can only move if we are alive. Deal a little more
than intended there. All right? We need to keep
track of whether or not our frog has been a
live or is alive. We can do this with a
simple function that just checks if alive or if dead. Based on that variable, we
can either move or we can't. For this, we're going
to use a set of states, which is going to be an enum, as you can see here
from the example here. We can use these enums to
hold specific pieces of data. I suppose you could say, It's basically like a list of options that we can select from. It makes it easier when it
comes to checking things. You can see this when it
comes to basic form of a state machine which
is used for characters. For example, if you played Grand Theft Auto
Five for example. You have different
controls when you're on foot compared to when
you're in a vehicle. That's because you're on foot. Controls would be one state. Swimming would be another state. In a car would be one state, in an aircraft would be
another state, et cetera. We're going to use this to know when we are alive and when
our froggy has been squished. In order to create
this, instead of using the Var keyword, we use enum. The name of the enum, which says is going to
work like a state machine, I'm just going to call it state. And then instead of
using equals or colon, we just jump straight
into the curly braces. Traditionally, from
what I've always seen, these are always going
to be in capital, So I'm going to have a live the drop to the next line, dead. These are our two states, alive and dead alive will
be the default state here. We're going to create
a new variable called current state. We're just going to declare this as being a state, one
of our states here. All right, now
with our movement, all we have to do is
check if current state is equal to two
equals state alive. And then tab our movement in. Now we can only move
when we're alive. Now when we die, we
have to tell it that our current state is now
being set to equal dead. If we run this now, we
should not be able to move. Once we die and get
squished, there you go. We got all squished
in and we can't move. Now all that's left
is for us to go ahead and create the respawn. Let's create a Respawn functions once we have lives in here. This is where we're
going to check if the player has lives left. We're going to call
this. All right, let's go with how do we respond? We're going to need to set our
collision back to working. So we're going to need to call deferred in our collision shape. And instead of setting
it to disabled, we need to set it to false so that it is
no longer disabled. We need to change our position, self position and we
need to reset this to where our starting position
is going to be at the moment. That is 169.2 33. I'm just going to
copy this value real quick inside of my main
scene. I'm going to add a. See what did they rename it? Here. Here we go. It was renamed to mark two D, and just give me 1 second. I'll get that up for you. There you go. So we're
going to use a marker two D. I'm going to set
its transform for now. I'm just going to
paste the value in, going to set it to
the same position that our frog is starting at. I'm going to call this
player spawn location. Now when we respond we can to self dot position equals our. Player that's not going
to fill out for us. I'll just have to type it in, player spawn location position. This should happen
pretty instantly. So let's go ahead and
go up to our process here we're going to
form another check, LF current state is
equal to state dead. We can call respawn. This should spawn right back in the beginning
where we started. If you get killed, we
seem to have what is. Oh that's fair. Players spawn location, We can't get access
to that because we actually have to go up the tree to remember who our player, and the player does
not have direct access to this players location. Here we need to go up, follow this line and go up one and then that takes
us to this node two D. And then no two D then has
access to a players spawn. We have to go up on the
way we can do this is a few ways we can go ahead
and do get parent get node. This get node is just a long form of
writing that dollar sign. Then inside would be a string or the path directly
to Playerspalocation. Alternatively, to keep
this a little short, we can just do get node. We can pass in things. We can say use one dot which
is equal to writing self. Or we can do two dots which is equal to that get
parent we just deleted. And you can see that as a
much we can say do this with get parent player
spawn location. All right, that should fix that. Now when we get squished, you see we get right back
to the beginning on. We can't move yet
still because we do have to set our
current state. Remember we can't move current
state equals state alive. And not only that,
we have to set our animation back
to being our idols. We'll get our animated sprite
to play our idol sprite. Set it back to normal
when we run it. Now we can't really tell when we get respond to. What I'm going to do first
of all is I'm going to use calder and set that down after everything else because I notice we're
getting squished twice. So we'll see if just moving
that line, we'll fix that. It does not. Okay, not a problem. We'll just have to
have a small timer, for example, afterwards. Which is fine. All right, so let's
see, what did we need? Our dead symbol isn't working all too well
because we died. We're instantly respawn. We can't tell anything
that's going on. What we're going to do is
inside of this respawn, wait, we do what we did before using get tree
and create that timer. We'll set it to 1 second. That feels like a long time. And the time out signal
1 second may feel like a long time here in an
old game like this split. And then we respond. Awesome, Now we're getting
squished multiple times there, which is a little unfortunate. I'm just going to come
down here and create another small timer for 0.5
And I'm going to see what I can get away with or how small I can shrink
this through testing 0.5 we can get away with it. I'm going to try 0.2 I can get away with 0.2 We may even be able
to get away with 0.1 having that really
short delay here. There we go. Now we have that 1 second
that our death image is going to be on the screen of our poor little
squished bronchi. And then the resp happens. Awesome. Now, if you wanted, you
could set this number into a variable up here to respond
Tim, or respond time. And that'll be your time
in between your responses. Now for me I think I'm just
going to leave it at one. That's not a problem.
I don't think I'm ever going to want
to tweak that. Now, if you notice here, when I was going if
I sit right here, I might get squished by the
car underneath no fine, but I did get squished there
when I turned to the side. I might want to tweak my
Y position a little more. I might want to tweak my Y
position a little more there. But that's going to come down
to just playing around with the position and
that just a little more, but no problems. But that'll do it for this. We now have our player death and respawn system happening. We don't have any lives
going on right now, but we'll get to those lives
when we get to our section. But with that take care, there was a lot of information
that we went over. I hope you're ready
for moving on to the next section of the game. That is.
9. Water Death: All right, so let's make it so that when we jump
into the water, we die and have to respond. Well, to do this, we could do this a
few different ways, but the easiest way then, I'm going to say for
us to go about this, since we are using a tile map, is to take advantage
of that and use the tile map to tell us what
tile we are standing on. If we are standing on the
water, then we'll die. If not, we'll be
fine to do this. Let's head on into
our layer script. Close on the other as we'll
go into our player script, what we're going to need is a new variable to hold
our tile map here. Now we don't have to
set this at the top, but we don't have to constantly
set it in our function. We're going to make either all let's just get this and we're going to use the
keyword on ready. All that means is the
variable that we're going to make would be the same as if
we set it here in the ready. If we said for example
number equals ten, it would be the same thing as if we created number and then set it to ten down here
inside of the ready block. That's all on ready
means this is useful for when we
want to get ahold of specific nodes that are
inside of our scene. In our example, we want to
get ahold of that tile map. Here we're going to
do var tile map and we're going to set that
equal to yet parent node. Of course it is currently
just called tile map. Now remember what I said I think it was in
the last video. Instead of using
get parent here, we could shorten this
down in our get No, just to do and have the same
equivalent of get parent. But then I'm going
to do that just to keep things again
a little shorter. All right, so now we
have our tile map. Now what we want to
do is we want to check what tile we
are standing on. I'm going to go ahead and
create a new function here. I'm going to call
this check cell ID. That's going to give
us a void turn. What this is going to
do for us is we will basically use it to first get the position of the cell that
we're standing on. So we're going to
say bar map Pause, which will be set
to our tile map. Local to map. And then this will
take a position, and that position
is just going to be the position of our player. Now local to map is just
going to give us back a position which will be the position of the cell
that we are standing on. The cells would be each
of these orange squares. Since we're standing on here immediately when
the game starts, it would tell us this cell here, the location of this cell. Then the next variable
we're going to create is going to basically
go in there and say, okay, that's made with this
tile. Now what is that ID? And it's going to give us
back one to get that ID, we'll create a variable here. This is just going
to be tile map. Tile map, Yeah, sell source ID. That's just going to
take two arguments. The first one is going
to be the layer it's on which is layer zero. The second one is going to
be the position which we already got from our
map, a variable here. Now this ID should now be
whatever we are standing on. If we come in and
we print this ID, we just run check, sell ID. Inside of our process, we see one immediately
get printed out for the median to get printed
out for the road, and three for the water. Those we run this, we can take
a look down in the output, we see one get
printed out for our median, two for our road. If I can make it
to the water here, we're going to have one
for the median again. And then three when
we hit the water. There we go. Now we
know that this is working perfectly even if we come all the way
up here because we're checked for layer zero, we're going to three is
going to be our water. Well we know that. Now what
we're going to do is we can now I D is equal to three and this is where
we would kill our player. Then come in, call our
death function here. Now when we touch the
water, we should die. There we go. Now we can die when our player
touches the water. And wait for the respawn. Now this is a, could be a little taxing when we're checking it
constantly like this. No matter what the
next best location would be to call in here
only when we're alive. But even better is we can call it whenever
we actually move. So I'm just going to add this to the bottom of all of
my movements here. Now when I move in any direction is the only time
we're going to check. Instead of spamming it so far. Good, jump up, dead. Wait for response.
Now we move again. All right, so now we're able to drown our frog in the water. And we're able to let our
froggy get squished by a car. All right, so we have
all of our deaths check. Now all that's left for us to
do is to get our platforms working and then get our little wind points at the end by jumping
into the right locations. And then set up our heads
up display with our score. Then I think will be about done. I don't think we're
missing anything after that. Could be wrong. But there you have it. We can now round our froggy with the water and you
now know how to get the ID of whatever tile
your player is standing on. All right, to do
it for this one. I'll see you guys
in the next video.
10. Water Platforms: All right, let's
go ahead and get ourselves our platform set up. Once we have our
platform set up, the only thing we can do or
the only thing we'll have left for these platforms
is basically just swap out the sprites and
to make these longer and shorter through for
my platform here. I'm just going with sprites
set up here that we have. Using the log for this example, the end middle and
the other end, end middle and start. That means I'm
using three sprites here with my main scene. The root of my scene here being a character body that
I've renamed platform. I could rename it
to log if I wanted. That has an area two D with a collision shape
that covers up my log. Here I have connected both the body entered
and body exited signal. Once you have both of
those signals connected, the script on your platform
should look like this. And we are ready to add information or add
everything onto it. With the way that we're
going to do this, we're also going to
be adding things into our script as well. The majority of this work will actually be on our
players script. For the time being, let's go
to our players script and add a couple variables
that we're going to use. First one it's going
to be platform, and that's going to be a lean. And that's just going to
tell or let our water know whether or not we're
safe because we're on a platform or if we're
not on a platform. So called the death
notification. We're going to get
our current platform or platform and that's a character body two
D that we pass in. Then we'll eventually set to it. For now just send
it to know to need a platform direction which is an integer fault we're going to set to zero even
though it shouldn't matter. Again, we're going to use
platform, current platform, and platform direction as our three new variables
on our player script. We're going to go
ahead and move down to our check cell ID. We're going to add
to our statement, so we're going to say ID equals three platform is
equal to false. That way we say if we're in the water and we're
not on a platform, then we'll kill the player. We have our
conditions set there. Let's see for our player. We're also going to check, while we are alive, if our current platform
is not equal to null, which it's only equal to it. For now it'll be an
object assigned to it. Once our player
stands on our log, say current platform
is not equal to null, then we can just go ahead and our position plus equals 0. So we're going to
do a little mass. We need to open and close our parentheses
here because we're going to use the order of operations when it
comes to our math. We're going to say platform
direction times 16. We're going to use
this as either plus one or negative one, just like we did
with our vehicles. And multiply by 16. We're either going to be moving 16 to the left or
16 to the right. And we're going to be
doing this over time, so we're going to
multiply that by delta. This way we're not frame
based were more time based. So the only thing left
for us to do is to set our platform direction. And we can do that via a
function we want to go, Yeah, let's go a set direction. And that'll take a argument of an integer returns nothing. All this is going to do
is he's going to set our platform direction equal to. All right, so now we can head over to
our platform script. We don't need this ready block, we can delete that
inside of our process. We want our log, in my case, to keep moving. I'm going to go ahead
and do position plus equals 16 times delta. That's going to
constantly move it to the right when we enter, when our player enters the area. So we're going to set
platform here to true. And we're going to set
our current platform to our log here. My platform here.
I'm going to say body platform and
set that to true. Now we're on the platform. Body Legos curve. Platform. Yes. Current platform equals L. When body exited, we're
going to do the opposite. So we're going to
set instead of true, we'll set it to false
instead of sell. Set it to no. All right, so what we're doing so far
is when our front jumps on the log which is currently moving to the right
at all times. While it's doing that restart
that our log is currently moving the right by 16 over
time and not based on brains. Now when our player enters the area of our platform here that
they can stand on, we're going to set the platform
variable on our player to true that way when we check the cell ID to see
if we're standing on water platform will be true and our player will
not be killed. Then we're setting the
curve platform variable of our player for the current
platform equal to self, the character body here. That's moving,
representing our platform. Based on that, we'll be able
to move our character here. Current platform is
not equal to null. If we're on a current platform, then we're going
to move our frog in the same direction,
at the same speed. The last thing that we
have left is to actually call this function that we
created, Set direction. Body, set direction,
that takes an integer, which then we'll
move into the right, We'll use positive one. Now if we go ahead
and add the platform to our scene and run it, as you see, there's our log
and if we jump onto it, oh, we ended up dying. There might need to
update this flat. One moment there,
new one, back in. Move on down there.
Give Dad another shot. Okay, I'm dying. So my signals might need to be reconnected. I'll disconnect that And reconnected and I'll do
the same with my exit. Disconnect and
reconnect my body exit and we'll see if
that was the issue. Okay. Hey, I believe
I see what I missed here and we're getting this information a
little too quick. So before we have
our F statement inside of our check cell ID, I'm going to use a wait
and do what we did before with get
tree create timer. And we're just going to
have a small pose there of 0.1 and get that
time out signal. That should fix that for us. Here we go. Now we can jump onto our little
log and we're good. We can jump back and
forth on it and be okay and we're moving and
as soon as we jump off, we're fine to run back to the other side if
we want it still. If we jump in the water, we went ahead and died. All right, how can we
make this script a little more, I guess. A modular in a way, in a way that's going to be more friendly so that we can constantly change
whether we have two sprites, three sprites, one sprite, how big our collision shape is and have all of
that regardless. As well as I guess set our
direction so we can have some moving right and some moving
right or some moving left. Well, we're going to
go ahead and export a direction of an
integer that to zero. By default, we got the word
bar in there. There we go. So now I want to
go to my platform. I can change this to
one instead of zero. We can take direction and pass that in here when we call
set direction plus equals. And we could do the same
thing here where we have direction times 16. We can go ahead and
check and make sure that everything's still working.
We haven't broken anything. Our lock is still moving. We can jump on it and Okay, so we haven't broken
anything yet. That's great. Let's see, What else do we need? Well, I suppose
that would be it. And we can just go ahead and set or create all of our
different platforms now using the same script then when we just create a sonderjust like we did with our trucks. All right, I'll be right back. Why create a couple of these? All right, so I've gone
ahead and I've made long turtles as well and just threw a few
here in the scene. And as you see, go
ahead on this log, jump to the next
turtles, Next one, jump to the right,
up on my turtle, jump on the log,
and I'm ready to jump into what would
be our wind space. All right, our platforms are
certainly working just fine. Now is great. I do want to know I did
add weight for 0.1 on body entered before
changing the platform on our platform script. I do want to take
note of that now. All we need now is our sponsors. All right, so let's go
ahead and create those. We're going to effectively make those just like our
truck ones here. We're going to go ahead
and get ourselves or add on a No two D, we call it platform sponsor. We'll go ahead and
start lining these up. So I have one there, I have one there, I have
one, looks like there. Okay. That look even does that. It's actually a bit
of a weird spot. Yes, go there. And then we need a couple for the
other side, for our hurdles, take it over and one
for hour hurdle. All right. So those look like some
good spawn points. These ones a little close
back. Those ones up a bit. We're going to have something
similar to our truck spawn. I'm going to go ahead
and just copy our truck. Let's see, are those going to be the same different
name, the vehicle? Pretty much. We could
probably get away with just using our
truck script on here. Our platforms would
be named vehicle, but I think I want to
do a different ones because I don't
like the wait time. I don't think that would
be good for the platforms. I'm just going to
use that as my base. I'm going to click on
my platform Spon add a new script in here. I'll go ahead and just paste
in the vehicle script. I'll call these platforms. We will change to platform. Do instantiate for
platform instance self at child I wait time, see this is where the
issue is going to come in. Let's see, we'll go 1-2 and we'll
add three to that. We'll see how that works. Then we'll change this
from spawn vehicle to spawn platform. This one here is going to be our log scene platform scene. The next one again,
it's going to see, go ahead and just
drag my script up and attach them to all
of my platforms. And two is my log scene, three is the log platform. And then 45 will be my. All right, so if we now get
rid of these platforms, move my player to be
underneath the bottom so the C can sit on top. Let's see if these working. Yeah, get all the way
across, there's my turtles. It looks like we need to
change those wait times. That's going to make
it extremely easy for our player to
just make it across. This is why we wanted to
use a different script from our truck because we're going to need
completely different wait times for the platforms. All right, so let's
try plus ten. This will give us a
variation of 11.12 seconds. Oh, why did I get
between these cars? 11.12 seconds might be too
small of a gap in this case. At this point we're just to
see what fits best here, maybe we'll try 5.6 I'll jump all the way across and we'll see what this
spread is like. But at this point,
you're just pretty much tweaking your numbers
to see what looks good for your platforms and what
looks good for your trucks. Just want to make sure
these aren't going to be completely
consistent the entire time and it does not look like
they are, which is great. Alternatively, if you
wanted to hardcode the a little more or
make them difference, specifically come up here
and do wait time up here. And we'll make it a
float not a flat. Alternatively, you
could do it up here and delete this
line completely. If you wanted to have
a specific amount, you wanted to have control
over the exact amount of time that you waited
per responder. You can do it that way, but I'm going to continue with
this bit of randomizing here. You know what, I'm
going to go ten there. I think that'll do it for this. Because now we've
got our responders, we have our platforms. Everything seems to be up and running. We could
make it across. I guess next we can
do our victory, our little victory up there when we jump into
the correct zone. Let's see, do I
like these numbers? And we jumped into the
water, we died. Awesome. I think I like these
numbers for now, at least. All right, that's it. We're done with our platform
swing and riding them. Next we'll cover the
area where we jump into our wind zone and spawn in
our little home frog there. All right, I'll see you
guys in the next one.
11. The Win Space: All right, for the wind zone, you can see that I've
got a new scene here. And that's just an
area two D with a collision shape and right two D that just has my home
frog here as a texture. It is turned off or visible
is disabled by default. You can do that by clicking
the little eyeball here. Wind space has a script
as well as a body entered signal connected to it
for the script simply, all we're going to do is we
have body wine set to true. Wind zone is a new variable that has been added
to the player body. Current state is
set to body state. When we have a new
state added here, we now have a live dead. And when then all we do is
we get our sprite two D, get the visible property, set it to true on our player to avoid any issues
and to fix a little bug. I pulled right here, LF current state is
equal to state dead. I put our weight, our 1 second of weight
here and pulled it out of the respawn function it
used to be here at the top. I just pulled it
out and moved it up there into our state. That should be all
we have to do now. We can go into our
back to our main scene and import our wind
zone, our wind space. Just bit it on in there. Into each of our little slots. You may have to do some
testing to make sure that your frog is not prematurely touching it
in order to trigger the wind. Here I have mine covering all my areas. If you want to check collision
zones and all these, these debug areas, we just head up to the debug menu at the top. And you'll have
the option to show visible collision shapes if
you do that when you run it, you'll see we can see all of our little collision boxes
here for everything. There we go. If you're accidentally triggering
it or you might be, go ahead and enable that. Take a look yourself. You'll see once we
make our way up, we should have another log. There it is. We can trigger our wind Notice we did not get dead printed out to our
console down there. When our state is
our current state, state win, we respond and then set wind
zone back to falls. Now we're also using wind zone. Down in our cell ID, we added another condition here. If ID is equal to three
and platform is false, if we're on the
water, we're not on the platform and our
wind zone is not true. Or you can say wind
zone is equal to false, that would be another
way of writing it. Then we can call death. If we're not in the wind zone, we're not in the platform
and we're on the water. Then we kill our froggy. Otherwise, our wind
state should be triggered and we can just do a respond without
killing our player. All right. The wind
space is a very simple, very easy to do there. Now, whether you leave
the frog here enabled, the entire time is up to you. If you wanted, you could come
in and add a timer node. You could come in here and add a timer and then set this to, I don't know, we'll
say 5 seconds. Then we can come in, or rather
we can connect their time out signal to our wind
space on time out, we'll set our sprite
two D visible to false. Right after we turn it to true, we can start the time. We can get the timer start. If we were to do this way, which is up to you, this is where a bit of
design is going to come in. How authentic do you
want and how custom do you want to make your
game, et cetera. So my locks And that
starts spawning on, so I can hop on here. We wait to go across. If we use the Tim er here frog, our little home frog is going
to show up for the wind. Then after a few seconds, and it's going to disappear. So you see it up there, and
there it goes, it disappear. If you wanted to disappear like that, that's how
you would do it. We can just just add that
timer into your wind space. Set it in the inspector to
how long you want it to be. Start the timer after you
set the sprite to being visible when the timer
times out, set it to falls. All right, that'll do
it for our wind space. And we just have
to take a look at our heads up display
or hud or gooey, and look at creating
a score system. All right, that's it, and I'll see you
in the next one. We're almost done with creating ourselves
a Frogger clone.
12. Memory Leak Fix: All right, we're not going
to add any features. We're actually going to fix
what would be a crucial prop, especially in a bigger game. Now what we have is a
memory leak in our game. We have this from two points
technically were around ten. But let's take a look, if we go ahead and
play this game, and I'm just going to
pull this out here, I'm going to have to
slide the silver guys. You can see everything spawning
off screen and they come, just look at those cars go, and the platforms up
top will do the same. They're going to keep going and they're going to go forever. They are never going to stop. This is what is
called a memory leak. All, I'll leave it right there just so we
can see that easier. But if I pause this and click on the remote tab here at the
top of our scene tree, which is only available when
the program is running. We hit remote, take a look
at all these cars just in one spawner that still exists even though we probably don't need
the majority of them. The same with all
the other spawners. Our platform, our platform
spawners aren't too bad because they have a much slower spawn rate than the cars. But they're going to go on forever and they're never
going to disappear. They're never going to get
freed up from the memory. Eventually you will have
this tiny game that could take up 128 gigs of
Ram just to keep playing it. It would take a long time, but eventually it
would all add up. Let's fix this crucial, I guess we call it a bug. It is very simple for us to do. We just got to put one if statement inside both
of these scripts. Now the numbers that you pick here will of course
depend on your project. But from what I've
tested out and based off of our window view, a set of numbers that
I'm going to use here. What we're going to
do is right now I'm inside of my platform script and inside of the process here, I'm just going to check
if global position, now the difference
here between and global position is if we
go into our platform here, for example, this is going to be our local position, right? So just the position property. But when we're in our main
scene, above everything else, this is going to be in charge of our local position
that we see on screen, regardless of who the parent is. For example, if we take a
look at our space here, we can see that its position in our main screen here is at 24.45 This is going to be more of a global space, whereas if we go into here, we can see our wind space, our local position
here is at 00. These are two different numbers. Hopefully, that
makes sense to you as to why we're using
global position here. Of course, we want
the X property because that's going to
control our left and right. If our X is greater 436, that's about 100 pixels
off screen to the right, based off where
our sponsors are. This is still gives enough
room to go past that. If our global position
x is greater than 4,436 or global position x is
less than negative 100, we're going about 100 pixels offscreen in left
and right direction. If either of those are true, all we're going to
do is self free. All right, so now we should
see character our platforms, disabling each other or deleting each other
out of our memory. This is only one potential solution for
something like this. Another solution if,
depending on your game, for example, if you're doing something
like a bullet hell, you're going to want
to go with something called object pooling. And we can talk about object
pooling in future video. All right, so I'm
going to go down to my spot here, my vehicles. Let's see, which one
are we looking for here On our vehicle script. There we go. So not on our
spot on a vehicle script. And same thing assigned to the process is going to
paste in the same code. If global underscore position do greater than 436 or global
underscore position x, it's less than
negative 100 self. Now if I go ahead and run this, and we're in the right
scene, our main scene here. I'm going to go ahead and
pause this real quick. Build our remote tree, we can take a look at our regular spawners here where
the cars are going to be. Here's my game window
to pull that out. If I go ahead and let this play. All right, We have
some cars net spawning in here. We can see this here. I'm just going to extend the
window off to the right. I have a mistake there. I seem to have
grabbed Gato instead. There you go. You
can see they're in the remote as well
as visually there. Once you go far enough, they're actually completely
deleting themselves. Now our objects are all being
managed and we can only potentially have so many or so many in our scene
at any given time. You can see the platforms
at the top doing the same, the same things happening off to the left hand side of screening. What we can't see right now. There we go with
that simple one, technically two lines of code. We have our memory, our memory, just leaving my
mind right now, memory leak. It's funny since
we're talking about memory, but there you go. With that, we have fixed
our memory leak issue. I'm going to show
you an issue here. Not really an issue, but just to show you
one more example, here we go to the platform. If we used position instead
of the global position, you're going to see
an example here. If we take a look,
you're going to see, especially with the turtles, you're going to see the turtles spawn right about
this area here. All right? Watch them. They're
coming in when we're using that local
position, there you go. You see they're
disappearing way too soon. They barely get on screen
and they disappear. They get about here,
and they're gone. This is why we have to
use the global position. So I just wanted to
demonstrate that a little more visually for you. There, not redraw Q free, just like I said,
completely destroys the object and takes
it out of memory. All right, so there you go. There's how we can
fix that memory. All right, next we'll be moving
on to the score and hud, adding player lives
and all that in there.
13. Scoring System: All right, in today's video, we're going to go ahead
and add the point system. As you can see here, these
are the rules that we go by. Ten points for each step, 50 points for every
prog that gets in, and 1,000 points for every
time we get five procs in. That's what we need to keep
in mind when we do this. I'm going to start with
creating a global, also known as a singleton
or an auto load script. For that, I'm just
going to right click in my file system and
create new script. And I'm going to call this, I'm just going to keep it
simple and go global. To activate this, we go up
into our project settings. Let's see, do we have that
captured right now? We do. We go, it might be a
little big. There we go. And we go into the autolite, our global script. It'll get the name global by default,
you could change it, but I don't see why we need
to add. And there we go. Now we can use this
script anywhere in our code right now, I think that's where we're
going to hold our score. That's where we're going
to hold our score. If we close that,
we can now open our global script by double clicking it to give
you an example. Here we can come down here, we can create another function
here called print score. I have a variable up
here called score. It's an integer which
say you got 50. The whole point of
this function is just to print the school
with it being a global. I could go into my
players script here. I could just write that name
that we had for that I left, which was called global
for the capital. Then we could use the function we just created, print score. Then when we run this, we'll see that score printed out
here in our output. A global script
contains variables and functions that we can
alter and use within our game, in any script at any point. Let's just go ahead and
we can remove all of that stuff and set score
to zero by default. We're going to go ahead
and have a function called update score. All we're going to do here, we're going to be
printing out our score. Do we displayed on
screen in this video? Now we'll save the
displaying on screen for when we start
covering the Hud. Here we're just going to go
ahead and print the score. When this happens, update score will take the new amount to add the we do score plus equals new amount we can do. Well, let's first make sure
that this stuff works. Every time we hop
we get ten points. All we're going to
have to add this into our movement and
all of our pieces. So we'll go global update, update score, because
we didn't save it yet. Update score, and
pass in ten points. And we'll go ahead and
copy this down into all of our movements and go
ahead and jump in game. And as we move, we should see ten points constantly get added. There we go, 1030, 4050, 6070, 8090, 10110, et cetera. So this is working all of
our buttons. Fantastic. We can just get our
points up like that. The points here are awesome. I just went ahead and get
rid of the other printings. Are there false Just
to clear that up, make it a little easier for you. As we go ahead and run in
there and we run around, you can see in our output our number goes up
every time we move. There we go. It's
working fantastic. Now, we also have to keep
track of how many frogs we get in total. Frogs. Doesn't sound like
the amount that we want. We call it a combo frogs. I don't know. Let's
call it the multi frog. Multi frog, it's an
int, starts at zero every time you add
to the multi frog. All right, we do multi
frog plus equals one. I remember with
every combo of five, we get 1,000 points.
Here's where we go. Multi frog less than five. Then I'll just tap
this line in here. Then we'll just do score
plus equals new amount. We do score plus equals 1,000 we'll get 1,000
If we get five in, that's only going to be if
we get into a scoring area. We can't actually
increase our multirot, go to our wind space and
go into our body entered. This is where we are going
to increase that number. We're going to be global
multi frog plus equals one. And we're just going to
stick it right on in there, inside of our wind space. Then we're also going to call our update global update score. And we're going to pass in
50 because we got a frog in, since we're increasing
our multi frog before updating our score. So we're updating our
multi frog y one. Then we'll check
basically if that is our fifth frog or if that
is not our fifth frog, then we'll do this. We'll just add in that 50. Otherwise we'll add 1,000
And then we actually need to set multi frog back down to zero because that
has to be reset. Let's see if this works. All right, we're all
the way up here. Let's go ahead and
get in the zone. We're up on the log now, we wait for these
turtles to come by little turtles on the
turtle frog in the turtles. So we're going to have 290. We jump on here. Now we go into zone we
should jump up to 340. We went up to 350 on that one because we also moved
at the same time, we got to remember that
we got our ten points. Do this frog or work that way. It's actually been a long
time since the plate, so I'm not 100% sure on that. If that's the case, then
to solve this issue, of course we can just add 40 and then it'll count that plus ten from our jump in there. If we were to go ahead
and jump in that, now it would look like a plus
50 to which like I said, I'm not sure if it
counts that actual jump or in the actual game. Maybe it's something
we can take a look at. Maybe you can just
leave that up to personal choice on whether
or not you want to allow that to effectively
count Froggy died. Said I seem to have a
Brad Frog, here we go. Seem to have gotten
to a little bug by jumping at a weird spot. Now my little frock is fine. This puts us at 05:50 so this next job will
put us at 600. There you go. It's up to you if you want
to do 40 or 50 here. Which basically comes down to
whether or not you want to count that as your main, count that ten as
your main thing. And I just remember we
should probably get five frogs in there to
actually test this. Might go ahead and
just fast forward on the video here in this part just so
we can get five in. All right, I've
gone through it and I did my loop multiple times, five drugs, and went ahead, we got up to 4,800 points. Awesome. Seem to be
working perfectly fine. Our score system works. We got our plus 40 or 50, depending on how you sent with whether or
not you're going to count the extra step as part of your 50 or if you
want to do a 50 additional. On top of that, we have
our ten points per step. Here we have our plus 1,000 every time we
get five multi frogs. Every time we rescue
five of these frogs, all we got our score set up. I guess next we can just
take a look at how to display this and start
getting our heads up display. Hugo all set up.
14. Game HUD Score: All right, let's go
ahead and start creating the game hood for
our game today. We're going to go
ahead and just get the score up here on our screen. For this, I just
went to my No TD and I added in a canvas layer. If I come in here, canvas layer is what
we're looking for, not canvas grew canvas layer is basically going to be
everything that's on top of our game no matter where
it is in our scene. So this is, as you
would imagine, where all of your
hot elements go. If you're playing
say, Dark Soles, this is where your four quadrants
are in the bottom left. For example, if you're
playing Sky Rim, your three health
stamina and Mana bars, W'll be across the
bottom and so on. For us just to do the score
here on my Canvas layer which I renamed to Guy I Stanford Graphical
User Interface. I went ahead and I
added on two labels, Two just regular labels here. And I named it Score label, just has the word
score in it and score text which
just has five zeros. Now the text of both of them were too big
for this project. On both of them, I went
into the inspector down to theme
overrides bond size. My score tech is on size ten and the score
label is on size 12. Now you might notice
that I do have an extra black bar
down at the bottom. I went up into project settings
and in display window, I went ahead and updated
my viewport height, 240-256 There you go. You can see it there. So I added an extra 16 pixels
so I could add the black across the bottom because that's where our health bar is going
to end up being down at, or our Lives bar
in the next video. All right, once we have our two labels here on our
canvas layer for the score, you can't find out where to
change the text for that, it's just select your label
and inside the inspector at the top you'll see the
section there for text, Type in score for one and put in five zeros for the other one. This will give us a good idea on the amount of space
we're going to need. All right, now to
make this work, all we have to do
is add one line to our global script here, outside of our and
our L S block. Outside of both of these. Regardless of how
much points we add, we need to get our
score text label. Set the text to actually display our school since we are coming
from our global script. If I go ahead and run this for a moment and
then just posit, switch over to remote
global is here. It doesn't have
access to anything. We have to actually go
up the tree once to get to root and then
come down to our two D, then down to our gooey. Then from there we can grab our score text since we have to go up and then down we can
go ahead and just get node. And remember, this takes
a string as an argument. And as you can see, we could just write the whole path just Roth, two D in this case. But even then, since we
only go up to one level, it's still faster if
we just do two dots just to go up one and then we come down to our node two D. From there we
access our Y there, we get our score text,
if you're wondering. We're just following
that white line down from our global here where
we're writing this code. We have our two dots, which is the same as
writing get parents. So we go up one to the root. Then we're just following down on every stop
with this white line. We see this white
line comes down and then it goes in points. No two D, that's where
we've written there. We follow the line down again, stops and points in at the Y. We write that for the next stop. Then we come down and
it finally points into our score text.
And we end it there. Whenever you're in
delts, go ahead, click on the node
you're looking for. Just follow that
white line to get your path on the score text. Right, This label type object, we're going to get access
the text property of it. Let me just get the game
off your screen there. I just looked over and
saw that it was covered. Again, we use two dots.
Same as get parent. That takes us up to, up to the root node and we
just follow this white lines, it comes down
points at node two. D comes down points, then it comes down to
points at score text. And we're just following that
path here all the way down. We want the text property of it and we're going to set that. We're going to set
it to our score. However, if we just do this, all those zeros are
going to disappear. As you see, we can't really do much to the score
in this aspect, what we're going to do is we're going to actually turn it into a string with STR and then two parentheses We can write our score
inside of that. That score is now going to be treated like a string
instead of an integer. Now we can do pad, and we can pad it with zeros. We pass in the number five. We're going to have five digits
like we see here, 12345. So we're going to
have these 50 slots. Our score is going to change, but even though if
it just says ten, we're still going to have
all five of these slots available to us visually. It's going to look just
like it would on an arcade. And in a typical scoring system. If we go ahead and play this now we can see our
score there at the top. If we pop around, we should see our score
increasing as it should. That's a lot of cars up there. There we go. Let's follow
this long. Here we go. Let's go get ourselves
some points. Ride the log, ride the
turtles, ride the log. And we can ride the turtles, ride the log and jump home free. All right, so our score system seems to be working
perfectly fine. It's displaying accurately. It's fantastic. All right, the last thing for
us to do at this moment is, well, in this video, nothing. But in the next video, we're
going to go ahead and set up our lives that when
we die we lose a life. And that's going to be
reflected visually on screen by showing how many
lives we actually have left.
15. Game HUD Lives: All right, let's go ahead
and add in our lives now. Our lives are going to have
six lives at the most here. And we're going to go into
our gooey canvas layer. We're going to add a new node, I know that's not visible. Just 2 seconds. There you go. We're going to search
the word texture. We are looking for the texture
progress bar. All right. I'm going to rename
mine to the Lives bar. I'm going to move over to the Textures section in the inspector
for the progress. I'm going to move over the
health bar and into that slot. Set the maxed value again
in the inspector to six. I'm going to set my
current value to six. Now you should see them. I'm going to grab this
little orange handle and pull it up just so it
only takes up space we need. I'm going to bring
it straight down to the bottom into that
empty black space. Those are going to
work as our lives. You'll see as we
tweak the values 6-5 it's evenly split up, so we can easily determine
how many lives we have left. The six, of course,
is going to be our default and we're
going to need to tweak that every time we actually
die in my global here. Again, maybe game manager would make more
sense for a name, but for now it's going
to leave it with that. We're going to go to
lives by default six. I'm going to create
another function, Update Lives, Nothing. And we're going to
fall saved path. Instead of a score text, we're going to get lives far and we're going to access the value property here that
we can see in the inspector. We're going to say
plus equal amount. Amount is going to be a
parameter that we pass in which is going to be an
end when we lose a life, we're going to add
negative one to it, which will make it
go down to five. This also give us the
ability to add lives in future by just putting in a
positive one to gain a life. But also updating that we actually have to update
our lives as well. The same thing plus
equals amount. Now we can go to our player, we can look for our death. There it is on death. We also need to go access
our global script. Update lives and pass in
negative one. That should do it. Very simple, small thing to
do Now when we die on screen, we should lose a life and we should see our life
bar down there, drop down to five. I need to pull this up because you guys can't see the
bottom there. There you go. Let's see if we
drop down to five. There we go, We split. I ran into the back of that car. I was looking at it,
and you only gain points when you move
forward on Frogger. We lose a life when we
go in the water as well. We can go ahead and
update that if you wish. If you want it to be a
little more accurate. We're only going to
update score when we press left and right will
not get us any points. The only pressing forward will, which makes sense
because that is a lot of points you could
rack off real quick. Where's my logs? There they are now
we ride the turtles. Doom on the turtle. I was going to go for the log, but I felt like I was
going to miss it, so I stayed jump
on the log here, and then we'll jump onto
those turtles and we'll make it home free On
this log, we are. All right, awesome. There we go again. We
can lose the lift. Cool. Our live system works. It updates visually on screen. We have the ability to add
in lives in the future. All right, I guess that'll
do it for this section. Unless we want to add live when we get school,
we want to do that. All right. If you want to be able to gain
extra lives when you reach a set amount of points, here's
what we're going to do. We're going to create
a variable called multiplier inside of
our update score. We're going to perform
a new check here. We're going to say score divided by score divided by, we can say 10,000 if you want, times our multiplier is
greater than or equal to one, then this is where we're
going to add onto our lives. So we would need to do lives, normally we would
say plus equals one. But since we want
to cap it at six, what we're actually going
to do is say lives equal. And we're going to use that
function called clamp. Now, clamp allows you to
have three arguments here. The first argument is what you would add instead
of plus equals one. Our first argument here
is going to be one. Then the next argument is
going to be the minimum and maximum that this value can be the minimum,
It could be zero. Our lives will never
go below zero. Here, the maximum number
that we can have is six, so it'll never be a
higher number than six. That's how clamping works here. We can call update
lives with one, right, so we're
going to have a plus one to add on to that what we can actually just move our clamp right
down here inside of our update lives and
replace one with a mount. Then we could probably
get away with not having anything in there,
Not setting it up. Let's just clamping
it down there, Update lives on e. Then we're going to want to increase our
multiplier plus equals one. And the reason why we want to do this because if we don't, we're going to constantly gain a life because our score is
always going to be divisible. Once we gain one life,
every time we move, we're going to keep gaining
it. We want to change this. If we get a life at
every 10,000 points, then we'll get at 10,000 10,000 times one is
still going to be 10,000 then the next time is going to be 10,000 times two, we'll need 20,000 points in
order to get a new life. And then it'll be
30,040 et cetera. If we were to go run
this now with just that, we can see if we run in, we go and lose a life, maybe even lose two. Now we've got to
make our way up, pass through all this traffic. We got to make our
way to this log. Then we can ride the
turtles log again, transfer to the turtles, wait for the log to get up here, and then if our score
was high enough, we should get 10,000 which I didn't change it
now that I think about it. So that's a little
disappointing, but we can check that
real quick just by go into our wind space
and we'll say, hey, we gain 20,000 Now if we were to check
it to gain points on every 10,020 shouldn't
do anything. It should just give
us the one life, which is fine because you
should never get 20,001 dog. Anyway, the most you should
get at one time will be 1,000 What you see as we go, boom, we're almost there. We should see our lives at the
bottom increase, plus one. There we go. So our
lives have increased. All right, so our
lives is now working. I'm going to go
ahead and reset this back down to 40 points. We want to make sure
we can game over. That's going to be. I guess inside of our
global here update lives, we're going to go
ahead and see this. Let us go negative
one by chance. No, it will not. That's perfect. We don't have to
worry about that. We could say if lives, actually we wouldn't have to already because we're
setting it up here. We checked beforehand. So we say if lives, it's less than zero actually
would already be zero. Let's say we have zero lives
left, then we die, right? We're passing another
negative one. We're saying if our
lives are already zero, then we're going to have,
we'd say, game over, but we're just going to reload the scene into a brand new game. If our lives aren't
already zero, then we're going to
come down here and we're going to
subtract our life. For this we just use get three reload currency and that'll be the same as if we
had just started the scene. This if we write in our lives are not getting reset, probably because
they don't reset on Global. Let's find out. Let's go into our ready and let's take a look at
how we debug this, say print lives and we'll
see if that resets. We're getting squished broad. We're never actually getting our ready back and it's
constantly reset itself. All right, so instead
of in the ready, let's print it down here. Trying to figure out why
we're constantly dot here. It resets after two, how are we going 6-0 All right. I'm not sure why, but
the clamp seems to be what was causing that break, which is because there's no real reason from what
I could tell that it should have been jumping from six lives to break down to zero. But that's fine. I just
changed it back to lives plus equals amount now if we run the game and
see if we can run through or back to losing
lives one at a time. Once we get down
three lives to one, here we go into the water. We're out of lives
when we get hit. Next, it's going to be a game over and our
game is going to reset. There we go, we got
a reset of our game. We quickly run across, we can go back to
losing lives again, but there you go.
We have that reset. We now lose lives and display on the
screen appropriately. When our lives are too low, we completely reset the
game and start over again, as well as gain lives every
time we get 10,000 coins.
16. Timer and Bonus: All right, let's get our Tim
Er going now onto our guy. I just added another
label down here with the word time with a override, font size set to 12. I then have a texture
progress bar, just like we did
with our lives here. I changed the fill mode to be right to left instead
of left to right. I'm going to rename
it here, Tim bar. My max value 30, my current value 30. Everything else
is left the same. I turned nine patch
stretch on so I can stretch this bar out
to be whatever shape, length width that I want. And I'm just using the
timer and that I have here, I just drag it in as the progress bar from
the progress texture. There you go. I just
stretch it out, place it down there for
something that looks good. I also have a timer
that I added down here with a script on my
guy and the time out signal here connected to it. This is what we're
looking at here. What we need to do every time, this time or times by default the timer is set to
1 second, which is fine. That's what we want. What
we want to do if we want to get our time or bar and we need to subtract
one from the value, we can just go ahead and grab
it with our dollar sign. Here you get it, since
this is coming from our guy value minus equals one. Now if we were to
go ahead and take a look at that and run that, we should now see our
timer ticking down. Beautiful. That's
exactly what we want. Now we've got to check. We need to check if our, our timer bar value, it has hit zero. If so, unfortunately, our
little frog has to die. That's just how it is
when our timer runs out. Let's go ahead and
get our F node. Remember we're on here, so we're going to have to go
up one for our node, two D, then come back down player. And we're just going to call
our death function on it. Oops. And that should
be two equals, because it's a comparison
if we're to run it. Now when our timer runs out, our little froggy
should just go splat and we lose a life on our hide. Just give it a minute there
for the timer to run out. Now having this timer
here on 30 seconds, I see that my platforms
up top need to be a little faster or at least
a bit of a smaller delay. I think speed might be the better option rather than changing the delay.
But there we go. A little froggy has died. And it keeps dying,
that's not great. We need to actually reset that. Now, once it hits zero
and our froggy dies, let's reset our timer bar. Let's get the timer bar and
set its value back to 30. We can have a brand
new bar filled out. Now, this isn't the only time
when it needs to be reset, it needs to be reset when
we reach the goal as well, we're going to go
ahead and get node go up one, get our gooey, and then get our timer bar
and set the value back to 30. Now before I test this, I'm going to go into
my platform here. I'm going to change this to
32 and double that speed. That means I have to go to
my player and adjust that. Well there is when we are here, 32 now should at least move quicker and hopefully I can get
on without missing. There's the turtles. We need some logs. Thank you. Log. I don't know if
I'm going to make it. I'm not going to make it. I'm going to lose my frog. Goodbye for a hug. I hardly knew ye see, this is going to be
a little difficult. Does our time or not
reset when we splatter? It does not, so we
need to set that as well on our player. Where is it that we die? There's our death right there. And we respond. Oka, Yeah, let's stick it in
depth here again. We're going to go up and
then come back down to our timer bar and set
the value back to 30. That way when we
die that resets. I guess I am going to
change que respawn, the spawner value
platform spawn. I'll remove the plus six. See how that looks now since we have completely new numbers. Okay, that's looking fine. We might be able to
actually make this now. There we go. We made
it in our timer reset. And when we die, our
timer. So reset as well. Fantastic. I can see I still need a bit
of a boost in there. My minimum, I'll do 3 seconds just because I saw quite a bit of overlap
when I ran through there. But we saw the timer is
working perfectly fine now. Now you do, or at least
you're supposed to get a bonus as far as the points go, based off of how much time
is left when you do score. We'll go ahead and
implement that as well. I just got to go
reactivate myself with what the multiplier is. I know it's something times the amount of time that's left. So give me 1 second
there. All right. It's ten times the
remaining time that's left. Let's see when we get
to our wind space, before we reset that, we need to update the
score here again. We're going to add 40, but
then we're also going to add whatever is left here. We're going to say, actually let's put this in its
own variable here. We call it pie bonus. Ten bonus. Pie bonus. Of course, I want to send it to this value times ten
before we reset. Now on our second update
score here we do time bonus. All right, so now we should
have our time bonus in there. So the faster we
can get over there, the bigger bonus we're
going to get up to a maximum plus 300 points. Hypothetically, I mean,
you're not going to get there at 300 or 30 seconds
left because it starts at 30. I might not get there at all. Might be close. I got it. But you can see I got
190 points on that one. All right, there we go. We got the timer in there, as well as the deaths
when the timer runs out, and the score bonus when we still have time or left and we make it to the end. All right, so that's it. I think that might
be it. Or frog. I don't think I'm
forgetting anything here. If that's the end of frog, congratulations you made it
to the end, that's amazing. I hope you guys learned a lot. We went over a lot of things
throughout this project. Variables are working with
lots of different scripts, but we completely recreated
this game from the '80s. And what's great about
these old games, they're fairly
simple in concept, but especially if you're
new to programming, there's a lot that you can
learn from these games. All right. Take care. Have yourselves a
good one and I'll see you in the next week. What? I'm going into a week now. Oh boy, Week four
is going to be fun. We got a lot of things
to talk about in there.
17. Frogger Audio: All, we're going to go ahead
and add in the audio first. So this is going to count
our hopping when we move the background music
and our death sounds. All right for our
background music. We can just go into
our main scene here. Select our root node, which is our node two D, Go ahead and hit the
plus or add a new node. And what we're going
to add is this audio stream player here. Then we're going to go
into our sounds folder, grab the music three, drag it in there, make sure
you turn auto play on. That way we don't have to waste a script and waste
writing code to play it. It'll just start all by itself. Now, warning, this might be
a little loud when starting. If you want to adjust the
audio for just the music here, you can go ahead and
change the volume. D, B here, the lower you put it, the quieter is going to be zero is the default for all of them. However, if you want
to lower the music for all of your audio at once, you can click a little audio tab at the bottom, down there. And here is all of
your audio bus. We have the master here, which if you've
changed audio settings and games before you notice, we have the master slider.
That's what this is here. We can change the volume of this to whatever we would like. If you do want to add
a different audio bus, you can customize your sound effects
from music separately. We can just hit
the add bus here. We'll just rename this to music Now with our audio
stream player selected, you'll notice in the bus
section here on the inspector. We now have a music piece
here from the dropdown. This music will come through this piece of audio first
and then it'll get out, put it to the master
as you would expect a. Right. So it's up to you
what you want to do. I'm going to go ahead
and lower my music to maybe 0.6. Not sure. I'm going to make
sure that you guys are actually able to hear this. Hopefully, this doesn't
hurt anybody's ears. I'm going to hit
play and find out. All right. So that seems like it's
quieter than I am, so I'm going to assume
that that is okay. But if you want, you can
always lower it a little more. I think I'm going to go
with minus ten here. Now the rest of our sound is actually going to
be on our player. Because our player has, the player has the
jumping our player. The other sound effect
need, our other death. The plunk, the
squish, and the hot. We're going to go
over to our players. Same. We're going to add an audio stream player
for them as well. We're not going to touch
anything else inspector, unless you want to
add an audio bus for sound effects and then change
the bus there specifically. That's up to you and again
a personal preference. But once you have an
audio stream player added to your players scene, we can go into your
players script. What we're going to
need to do is set the audio stream by loading in the audio file
and then actually play it. What I'm going to do
is I'm going to go to our death function first, and this is going to have
an ID passed into it. D is obviously going
to be an integer because we're going to
get a two or three. So I'm going to call an
int and I'm going to set it equal to two by default. The reason why I'm using
two is if we go back to our tile map and
take a look at it, our road is ID two. By default it should be our
road. It should be a squish. What I'm going to do
here is we're going to get our audio stream player, Audio stream player stream throughout that stream property. You're on our player,
right, that stream here. And we're going to
set it equal to, and we're going to call load
open and closed parentheses. And inside of here it's
going to be the path to our file two is going
to be our default, that's going to be our squish. So I'm going to get
squash, squash. Wave out of our Sounds
folder and drag it in there. That way I don't have
to write it out. Now what we'll do is
on the next line, we'll say if ID is equal to 33, remember being our water. If we're dying and
it's on the water, then we're going to do
the same thing we did on the previous line
and set our stream. And load in a new file
this time set of squash. We're going to load in plunk. Then outside of
that if statement, all we're going to do
is play our stream. So we're going to
say audio stream player play, just like that. Now if we go ahead and get ourselves squished on the road, we should have one sound effect. And if we go jump in the
water, we should have another. Okay, for now, I'm going
to go ahead and just turn the autoplay off on the
music so we can listen. If we jump in the
water, hit by car. Okay, We have the same
audio playing on both. Well, that's a
little interesting. Why is that? Well, apparently we're not passing in any ID for three. It's never
going to be three. The reason for that,
remember we got to go down and check, sell ID. We are actually checking
if our frog is drowning, that's what we have to
pass in to our death. Now, it did not error
because we told it that if we don't
pass anything into it, used to by default, but since we want
specifically an ID of three, whenever we're in the
water, we have to make sure to pass it in down here in our check cell ID function. Now if we were to do it, we
should have our plunk in the water and
squished on the road. There we go. We know if that's
working perfectly fine. Now the only thing left for
us is to do our hopping. For that, that's just
going to be up in our movement where
we can go check our audio stream and set that audio stream player
stream equals load. And risk going to grab our sound effect and
drag it in there. On the next line
we can just play our audio audio
stream player play. We can copy that into
every button press here. If it's down we can do that. Boom it's left. And if it's right now, if we play it, we should
be able to jump around. Let's go into our main
scene and try that down can show pushed down as
well as ground water, down, down, down,
down, down, down. Awesome. Now all we have to
do is turn the music back on on our main scene
audio stream player, Autoplay, turned back
on just like that. We have the Frogger
game complete with our audio and gameplay. I got hit by the back of the
car there. But there you go. We have added sound to it, and now our game feels
a lot more complete. There's nothing else
we can really do here. You can feel free to
add more onto it. You can try adding pick ups. You can find new sounds
and replace them. Maybe if you want to create your own sprites and use
those to change it up a bit, makes a little more
custom for you. Or if you want to
just keep it as your own little arcade
remake, that's awesome too. But that'll do it for this one. Take care and have yourselves a good one pack
yourselves on the back. We've completed Frogger. Next week I think we'll
start talking about some of the differences and
similarities between two D and three D and
start getting into that.