Okay, so today we're going to be building a game of Mario in pure JavaScript, HTML, and CSS. No fancy
frameworks, no Canva, no, we're doing this to actually practice our JavaScript
skills. So, this is the finished game. We've got a little game of Mario. We have Mario himself. He can jump. He can
kill the evil little mushrooms. And he can bounce into surprise blocks, which will either give him a mushroom in which
he grows bigger for a certain amount of time, or get coins. So, it's a surprise each time. We of course also have pipes
to let him go to next level. So, yes, we're going to have two levels in here. But don't worry, this game is all about
practicing your fundamentals and gaining knowledge so you can take this game, make it your own, add as many levels as
you want because you will have the knowledge to do so. So, once again, as a reminder, this is to practice your
JavaScript. Really master your JavaScript. It's going to assume you have knowledge of objects. It's going to assume you have knowledge of JavaScript
methods. If you don't, however, don't worry. Please try to code along anyway. You always have my 12-hour free coding
course which you could go back to. But we do go into these in a lot more detail. Okay? Once again, this assumes a
certain level of JavaScript. But if you're feeling brave, try it anyway. Who knows? You might be a coding prodigy.
And if you're interested in deploying this game onto the internet or deploying anything you want really, I'm going to
show you where to go for that. This is actually outside of the scope of this tutorial, but if you finish this project
and want to deploy it, you could do so with Savala for free. So, make sure to go to the link below and bookmark it.
Simply sign up to the cloud platform and deploy straight from GitHub, GitLab, or Git Bucket in minutes. So, in other
words, save your code to GitHub like so and deploy with Savala onto the
internet. Easy. Whether you're launching your first side project like this one or scaling a serious application with
sensitive data in the future, Savala, which is actually built on Google Cloud Platform and backed by Kinsta, offers
added benefits such as security all-in-one intuitive dashboard. Okay, so
what are we waiting for? Let's get to it. Let's build out Mario. Okay, so let's do it. Let's build a super simple
game of Mario using just HTML, CSS, and JavaScript. No fancy things like Canva.
We're really getting to understand the fundamentals of JavaScript, the language. So, let's do it. So, let's go
ahead and create a new project. I'm going to choose to make this just an empty project. Okay. So, we're really
starting from scratch. I'm going to call this Mariojs. And this lives in a directory called WebStorm projects that
lives on the Ana Kuba username on my computer. So, let's go ahead and create that. Okay. So, there we go. At the
moment, it's just like this. And I'm going to create a new file. This is going to be an HTML file. I'm going to
call it index. We don't need to put the HTML extension because, you know, we selected HTML file, but if you're not,
please go ahead and do that. So, this is what it looks like. I'm just going to call this Mario JS just like so. Here's
the boilerplate code if you don't have yours in your IDE already. Okay. So,
that's what it looks like. Next, we're going to create an app.js file. This is going to be for our JavaScript. So, once
again, I'm just going to do JavaScript file. Call it app. And you can put the extension or not. So, this will now know
to treat this as a JavaScript file. Wonderful.
And next, we're going to have to create a CSS file. So, this is going to be for
our stylesheet. So, we can just select stylesheet. to select CSS and I'm going to call this
styles. So once again, styles.css. So now our code editor knows to treat
this as a CSS file because of that CSS extension. Great. Now let's link them
up. So back in here, I'm just going to use the link element just like so. It's
a self-closing tag and I'm going to do re stylesheet and then href and then I'm
going to link the styles.css CSS file is in the same directory. Okay, so on the same level. So I'm just going to type in
style CSS to get that file name because it lives in the same place as the index html.
Great. And for the JavaScript, well, I'm just going to put a script tag at the very bottom of my body. And instead of
index js, we need app.js, right? Because we need to go to the app.js file. But we
do it after all of the HTML has been read first, which is why this needs to be at the bottom in between my two body
tags. Okay, so great. We're set up. We've linked up all the files. We linked
up the JavaScript file and the styles CSS file. So, we are now ready to
continue. So, in order to make our super simple Mario game, first off, I'm just
going to use an H1 tag. And I'm just going to put simple Mario game just like
so. And let's go ahead and put a mushroom there. So wonderful. That's the
H1 tag. And then I'm just going to use a div. And this is going to have all our game stuff in it. So I'm going to use
the class a class name of game container.
Okay. so that we can essentially style this whole div as some kind of game container essentially. And for now I'm
just going to put in another div and this is going to be the user interface
which is going to hold the score, the levels and the lives. So let's give this the class name of UI. And then in here
I'm going to just put divs. Uh let's put score and then let's use a span to put
the actual score which I'm going to hardcode a zero for now. We're going to pick out this whole element, the whole
span element. Okay. And I'm going to give this the ID of score. So we can
pick that whole thing out and essentially change this zero to be a one or a two or a three or a four. So that's
what I'm going to do. You can keep this as a div or you can put this as a paragraph element. It's really up to you
and how you want to style this. So, we've got the score, the levels, and the lives. So, score, levels,
lives. I will say one thing, it's better to have a P element just in terms of it
being more semantically correct than using a div because essentially it is a bunch of text. So, a P element would fit
much more level. I'm going to hardcode this as one as you don't really start from level zero. and lives. I'm going to
also have quote this to three just like so. Okay, great. I'm just going to move this
over as well for now. In fact, let's just get rid of it. So, wonderful. The
next thing I'm going to do is just lower this once more. Making sure that it is in the game container. I'm going to add
a div. And this time, this div is going to have another div inside. And let's
give this the id of game area.
Just like that. And this the ID of Mario. So this is going to be our little
Mario. Next, I'm just going to add another div. And this is going to be the controls. So class name controls just
like so. And in here, we're going to have a P element. And this is going to
say controls just like that. Another P
element that's going to say arrow key. So this is essentially the instructions on how to move on our board. Move left,
right with the arrow keys. And one more P element and this is going to say down
arrow and down arrow is to enter the pipe. Okay. When on top of it. Great. So
that is our instructions essentially on how to control Mario. And finally, we're
going to have one more. Okay. So, let's close off the game container. And
outside of the game container, I'm going to have another div. This is going to have the class name of game over. So, we
know that if it's a game over, well, let's have the game over appear quite
large. This H2 element is just going to have the words game over. And let's pick it
out. I'm going to give it an ID of game over
title just like so. And then let's use the P element to have score. And once
again, let's pick it out. So, span zero. Let's give this the ID of
final score. Just like that. And then I'm just going to add a button. And we're going
to pick this out later, but let's just have play
again on it. And I'm going to give this the ID of
restart button. Just like that. Great. Okay. So,
that is our index. HTML file. We are really kind of done here. Let's move
over to the styles next because at the moment if we look at this. So I'm just
going to get this up and then we copy the path. Copy the absolute path and
paste it like so. This is what our project looks like right now just with the HTML and no styling. So let's style
it up. So let's go back here. I'm just going to minimize this and let's goes to
our styles.css CSS file and let's start picking stuff out by classes and ids.
First off, however, I'm just going to grab the whole body. So, the all whole body holding everything in. Let's just
get rid of any default margin and padding just in case. And then background. Well,
I'm going to give this a linear gradient actually. So linear gradient, this is a CSS function to bottom as I want the
gradient to go from top to bottom. And then I've already picked out two colors.
Okay, so I want to go from this color to this color. And you get a nice preview of them there. So that is good. We just
need a comma there as well. So all three have a comma in between them. The font
family that we're going to use is courier new. And as a backup, I'm just going to
have monospace. Great. And finally, I'm going to use
display flex to initiate flexbox so that we can
say that everything inside is going to have a flex selection of column. So any
elements inside the body are going to essentially stack up like a column. And then I'm going to also use align items
center to make sure that they're centered. Let's also set the height to
be 100 viewport height in order for all of this to essentially work. Okay, so
now it should all look like that. As you can see, it's centered. It's in a column and it looks pretty good so far. Let's
continue. Now let's pick out the class name of game container. So to pick out a
class name, you know what to do. It's dot game container. And I'm going to go
with background white. Or if you want to keep everything consistent, let's use
hex. So the hex color code for this would be fff as a shortand of fff six
times. So you could just put three fs if you want. And then I'm going to give this a border of three pixels. So three
pixel wide border that is solid, not dotted or anything like that. And black. So again, that's the short hand for
writing black, which in full is three zeros. But that is the short hand. So it will be the same. Next, let's look at
the border radius. So the border radius I'm going to just round off to be slightly curved to be 10 pixels. Now
let's pad it out. So I'm just going to give a padding of 10 pixels as well. And a box shadow. Okay. So a box shadow of
zero on the x axis, four pixels on the y axis, x pixels spread. And then let's
also make it black. So at the moment it looks like this. It's very dark.
However, we can make it transparent. I'm just going to inspect that. Okay. So there we are. You can also see all the
elements here. So at the moment we're starting the game container. If I remove the padding, it will look like that. But we added the padding. And I could just
go ahead and remove things if I want. But I think that looks good for now.
Great. I'm happy with this. Let's continue.
Next. Let's style the element with the class name of UI. So that is this one
here. And all I'm going to do is just use display flex once more. I'm going to use justify
content space between. So that just means that if we look here
now and look at the UI, you will see all that lovely spacing in between. Uh if
you get rid of it, it looks like that. But if you keep it there, it's spaced out nicely. And that's thanks to display
flex. You can't use this without display flex. Okay, great. Let's continue. Now,
I'm also maybe just going to give it a bit of a margin, but only at the bottom. So, you can do so like this. Let's go
with 10 pixels. And then also, I'm going to change the font size of this to be 18
pixels. And the font weight
just to make it a little bit thicker is bold. Okay. I'm also going to apply a
min width to it which is going to be 800 pixels. Meaning that even if you kind of move it
across, let's just refresh this. It will stop at 800. It won't
move this across. The minimum width will always be 800 pixels. Great. And that is
again of the UI element right there. Let's continue.
Now it's time to pick out the game area. So this time we're picking out an
element by its ID. So to do that I'm going to use hash. And that is how we
pick out the game area. Okay. So just like that. Now, the reason I've chosen
to use an ID for this is that we're actually going to be picking this out in JavaScript, too. So, it kind of needs to
be unique. Same for this div right here. Whereas, this is more to do with styling
and how it looks. Okay, wonderful. So, the game area itself, well, I'm going to
go ahead and give it a width of 800 pixels, a height of 400 pixels, a
background. Once again, I'm going to make it a linear gradient to bottom, and
then I've already picked out all the colors. We're going to have a sky, so I'm going
to go with this. And then we're gonna have
the green for the floor. But if you look at
it at the moment, I'm just going to refresh. It looks like this. If we want a hard kind of stop and a chop, well,
what we'd have to do is just add some other things in here. So, it's blue up
to 80%, but then at the same time, 80% I want to turn it to green. So, that
should fix it. Great. I love that. That's a little hack for you. Okay. Now,
the border of this again, I'm going to put two pixels solid. And this time,
let's go with that right there. So, a little bit off
black. And now we get a nice border to our game area. So, this is looking good.
and any overflow if there ever is any. I want it to be hidden. Okay, now let's
look at the players. Well, Mario, we're going to pick him out by his ID in JavaScript, but also I'm just going to
style him up to have a width of 20 pixels, a height of 20 pixels, a
background image. So, I actually made this game a long time ago using a
framework, which I don't want to use today. So, I've already uploaded all the images we need. Please go ahead and take
mine. You can take them from the code that I share later. So that is my little Mario which is in fact 20 x 20 pixels
wide. So this image is that uh and then I think that should be fine. But just in
case I'm going to give a z index of 100 to make sure that it's in front of everything. And for that we need to put
a position of absolute. Great.
So, let's see if our Mario shows up. And there he is at the moment. Wonderful.
Now, we also need something for when Mario is big. We haven't added this in
our HTML. This is something that we will do in JavaScript. So, if an element has
the ID of Mario and the class name of big on the same element, well, then
let's make him big, right? Okay, let's maybe make him 40
by 40 pixels so it's kind of obvious. And the background image that we're
going to use is actually the same. So let's go ahead and get this URL right
here. Great. Now let's get anything with a class name of platform. Okay, because
there could be a few. And once again, we're going to have a background image
for this. It's going to be a URL and it's one that I have previously uploaded
of a platform. So, here it is. Please go ahead and take mine once again. I'm
going to put width and height 20 pixels actually. So, all the elements are kind
of just going to be the same to be honest. So, there's the platform. I kind
of want to differentiate if the platform is on the ground. And I want to use a different background image. So I'm just
going to copy all this and just delete that. And the background image for this
will be here. It's kind of hard for us to obviously
imagine this because we haven't built this so far, but just know that there will be platforms of different types. So
in fact, maybe it's best to just copy all of this. And I'm going to delete that class name. And delete that image.
Okay. So that is kind of our template. And when the platform is also blue, so it has the class name, the element,
sorry, has the class name of platform and the class name of blue. Well, then we're going to have a different URL. So
the blue platform is essentially this image right here. Now let's also
create a enemy. So once again, I'm just going to make the enemy 20 by 20. And
the URL for the enemy is going to be
this. We're also going to have an enemy that is purple for other levels. And so the
URLs of this is going to be a little bit different. Here we go. And we're also
going to have a coin because, you know, Mario uses the coin. So once again, let's just copy this. Everything's 20 by
20 pixels, but the image for this is of a cute little coin. I can't wait to show
you. And for this one, I'm actually going to animate it as well. So animation
coin spin is something that we're going to write. It's going to last for one
second. It's going to be linear and it's going to be infinite.
Okay. So now to define the animation, we're going to need key frames
and then we're going to get the animation name. So I chose to call this coin spin. And at 0% start of the
animation because you know an animation runs from 0 to 100, we're going to transform
just rotate on the Y axis by 0 degrees. And by the
time it's reached a full animation, so the full thing, I'm going to run
transform rotate by y-axis 360°. So it's going to
literally rotate on the y- axis by 360°. Great. And that should have an L there,
too. Okay, we are nearly done. Once again,
I'm just going to copy this because we need the surprise
block which again is 20 by 20 and the URL for this is going to be this right
here. We're going to have a surprise block. However, if it's hit, so if it also has
the class name of hit and on this occasion, it's going to be
this right here. If you are curious what these look like, you can of course just paste them into the browser like so. So,
here it is. Here is my little block that I made ages ago in 2021. In fact, there
we go. That's what it looks like. Cool. We also need the pipe. So, the pipe,
this is going to be again made of the pipe top actually. So, let's
have all the pipe styles. Then we're going to have the pipe top,
right? The pipe bottom, and the pipe bottom,
right? Okay. So, now I could just quickly add all those in. So, the pipe
top, the pipe top, right,
the pipe top bottom.
and the pipe bottom. Right, we should also
maybe encapsulate all of these in one pipe element too. So for this, I'm just
going to say that the width of the whole pipe is going to be 40 pixels and the height of it is going to be
I guess 40 pixels too, right? Because if we have these two stacked up, that
should be good. We can always come back to this if we need. So now all the pipe
elements we're going to encapsulate in one whole pipe element that we will give the class name of pipe to. Great. We
will be coming back to this file once we actually start working with it. I just want to get all the images here in one
place. Next, I'm just going to grab the controls. So simply the controls that we
have here. So this div with the class name of controls and I'm just going to
give it a margin top 15 pixels to space it out. I'm going to align the text in
the center. And let's just change the font size of this to be 14 pixels like so. So that
will now affect the controls here. And they have I think I'm kind of happy with
this. Now next let's also pick out this whole element the game over element by
the class name. So dot game overelement.
Uh and I'm going to give this the position of absolute. So now if we save that it will go from here to here.
Right? It's absolute meaning it kind of overrides everything and appears on top of everything. And if I want to position
it 50% from the top, all I would do is go top 50%.
Just like that. And it will appear 50% from there as the whole element. Right?
So it's here at the moment. I'm also going to make it have a border of three
pixels solid. Let's go with white.
Okay. So there we go. Let's maybe go ahead and
give it a background. We can go with something transparent if
we want. So black is this. And by adding the A, we're giving it a 0.9
opacity. So that's what it looks like. Let's also change the text color to be
white. So, hash FFF. There we go. Let's pad it out a little
bit. So, padding 30 pixels. Border
radius 10 pixels. Text align center.
And let's just make sure it's always always in the front. So, I'm going to go Z index a th00and. Really kind of go
overboard to make sure that it does. Okay. So now with that it will look like
this. And you can change the opacity if you want. If you go 0.5
it will appear a little bit more opaque. So it's really up to you where you want to take this project. Okay. Great. We
can also style the button. So perhaps let's do that. I'm just going to grab
the button. So this button right here with the ID restart button. So
restart button. Let's give it
a background color of hash FF6
B6B. Let's make the color of the font
white. I'm going to go with border none.
Border radius
5 pixels. Font size 16 pixels.
Margin 10 pixels. Just move that up.
So that looks much better. I'm happy with that. We can also add an
on hover effect. So, if we want to change what this looks like if we hover over the button, we can change the
background color if we wish maybe to
FF52 52. So, kind of similar just more.
There we go. Red. I love it. Okay, so that's what it looks like at the moment.
Now, because we will be displaying this game over popup in JavaScript, you can
pick things out by the class name. However, it's best to keep this an ID and keep it unique. So, I'm actually
going to go ahead and change this right now to an ID. Okay, so giving this whole
div the ID of game over, meaning that we need to change it here as well to an ID.
So just change it to a hash. Visually that won't change but for us moving on
it makes more sense when we start working with JavaScript. I love it. Let's do it. Okay. So we will be coming
back to this page as there's a few more things I will be adding. However, for now let's move on to the JavaScript.
Okay. Great. Okay. So first off I'm just going to start with the game constants.
This is going to be things like gravity, jump force, move speed, and enemy speed. So, const gravity
0.5 const jump force
equals -12. We can always change these later if you want to increase the gravity, increase the jump force, or
increase the move speed. Let's make this 2.5. And then we're going to have enemy
speed as well and make this a one. So those
are our constants. Okay, that is something that we use throughout the game and it won't change. Now let's
write some game state variables. So let game state this will change. This will
continues to be updated. So, the game state is going to be an object that's going to hold a bunch of information
such as our score, which at the moment is going to be zero, the level, which at the moment we're going to start off with
one, and the lies, which we're going to start off with being three. Next, we're
going to put game running as true because the game is running. The keys,
which we will come back to, this is essentially the keys that you're going to be pressing on your keyboard. So once
again the game state is just one object that looks like this and essentially is our entire game state for the Mario
game. Now let's define the player object. So let player and once again
this is going to be like I said an object and first of all let's actually
have the element and we're going to assign something to the element value. We're going to go into our document. So
into our document here kind of essentially and we're going to use a JavaScript method called get element by
ID and we're going to look for the element in here with the ID of Mario. So
we're going to grab that whole element by its ID Mario. Okay, making sure to spell it
exactly the same. So now that whole div has been assigned to element which lives in the player object. Great. Let's also
here assign it what we want the x value of the player to be on the game board.
We want it to be 50. The y we want to be 300. So x is this way. Y is that way.
We're also going to define the width here which we know is 20 pixels. But for the JavaScript it doesn't know that. So
we're going to go height and width 20. And then we're also going to have something called velocity. So the
traveling velocity of x the x axis which we're going to start off being zero and
also velocity y which is also going to start off being zero. We'll start off with being
grounded as false because the player is going to drop from the sky big. He's
also going to not be big. So let's start off with false. And there's something called the big timer because if you've
ever played Mario, you should know that the bigness of Mario does run out. Okay,
great. So that is everything assigned to the player object. Great. Let's move on
to the game objects arrays. So let game objects and this is again
going to be an object and in it it's going to hold the game's platforms. It's
going to be an empty array for now. The enemies which is going to be an empty array for now. All the coins in the
game. So here they go. Obviously empty for now. The surprise
blocks again empty for now.
and the pipes empty for now, but essentially that's what we're going to be working with in
this game. Let's make sure to spell surprise correctly.
Great. Okay, we're only going to have two levels in this game. Uh you can
after this I should show you how to make two levels. You can actually go ahead and add as many as you want. So const
levels equals uh and it's going to be array and the first object is going to be our first
level. So in fact maybe let's go ahead and write that level
one and level one consists of platforms. So
exactly like we saw up here, we're now going to actually build this out. So this is going to be an array and my
platforms are going to exist on we're just going to define where. So on
the x axis zero, yaxis 360. We're positioning the platforms. Essentially,
we're going to say this platform has a width of 400 and a height of 40.
And the type of platform this is is going to be a ground platform. Okay, so this makes
sense why here we wrote platform ground.
And next we're going to have the same thing. So once again, I'm actually just going to copy this and we're going to
essentially just change these values here. So let's have one.
Let's have a total of five. Three, four, five. X is going to here be 500. Yaxis
is going to be 360. The width of this is going to be 300. And the height of this
is going to be 40 again. And let's make this a ground platform. The next
platform, we're going to have a floating one. So, this is going to be 200. This,
let's put it 280. We can always change these after we've done it. This is kind of already been planned out by me. Uh,
and the floating one. Visually, it looks the same as the ground one, but for us, it's best to kind of differentiate
these. But however, it does mean that I'm just going to copy this and put floating here. Even though it
looks exactly the same, we're going to have different class names for it so we can differentiate them in JavaScript.
Okay, great. 300, Y 240, width
60, height 20. Again, this is going to be a floating
platform. X 600, Y 280,
width is going to be 80, height is going to be 20, and this again is going to be
a floating platform. So once again, in level one, I've just mapped out exactly where on that level every platform is
going to be. Next, let's map out the, you guessed it, the enemies. So let's
copy that and let's put our enemies in here. Each enemy is going to be an object. It is going to have an xaxis
once more. So 250 yaxis is going to be 344
and then the type of this enemy is just going to be the normal enemy. In fact,
I'm just going to define it as brown. So in fact maybe here also where the
enemies just to make our lives a little bit more clear. Enemy
brown will show up as this and enemy purple will show up as that. So that's
one enemy on level one. Let's just have two. I'm just going to change this to be
550 this time and keep the y axis the same. Next, you guessed it. Let's look
at coins. Uh, and what kind of coins are we going to have
for this? Because there's just one type of coin really. Let's just have an x axis and a y- axis. So that's where my
first coin is going to appear. And then let's have maybe three total. So
one, two, three. Let's change this to be 320 and this to be 620.
Uh, just going to move them around like that. What's next? The surprise blocks. So, in
fact, maybe let's just copy those two things. And there we go. The surprise
blocks. I'm just going to have one here. It's going to show up on x-axis 350,
yaxis 220. Uh, the type of this. So, I'm just going to define what's going to pop up inside. It's going to be a mushroom.
And the pipe is going to show up at 750
300. Great. We haven't added the image of mushroom to our style CSS file, but
we will do that later. Okay. So that is one level. Let's do another one. So
whenever the object finishes, we're going to put a comma and essentially define level
two. So once again, it's an object. And in fact, we could just go ahead and copy all this because that is exactly what
we're going to be filling out. Okay, so let's do it once again. Let's go X,
Y, width,
height, and type.
Okay, so all the types on level two of the platform are going to be blue. And
let's go ahead and have nine, two, three, four, five, 6, 7, 8, 9.
Uh, I have already pre-planned this for you. So if you don't like how this
looks, you can always change the position of everything that you see here. So maybe it was easier for me to
copy here. I am just copying from a pre-made sheet, but I have all these already stored because this took a lot
of time to plan out. I'm essentially just saving you a bunch of time by giving you a kind of already drawn out
level. But like I said, if you want to add more levels, please go ahead and do
so. Okay. In fact, let's just have eight
here. Okay, I'm going to go 360
280 260
240 280 200
200 40 40
40 60 Height 40
20 20 20 20.
Great. Now for the enemies. So once more, we're going to have X Y
type and then let's have three enemies on this level. So I'm going to have one
at 350 3 44 type purple this time. Xaxis
is going to be 650 344. Once again, purple and X here. 570
264 purple.
Okay. So, there we go. Next, let's also do the coins. So, in fact, maybe I'll
just copy and paste all these coins here to save us time. Those are the coin
areas that I picked out. And this time, we're going to have two surprise blocks.
One is going to have a coin and one is going to have a mushroom and one pipe only. So here is the location of that
pipe. Great. So those are two levels. Let's move on. I think it's time to
actually show everything we've done so far. So I'm going to initialize.
Okay, great. So function init
game. That is my function. I'm going to write
another function called load level. And I'm going to look into the game state.
Get the level. Okay. So, if we go into game state right here, game state.le
because there's an object. So, we go into the object by adding a dot to get any of these properties. Games state.le
will give us the value one. Okay, the integer value of one. And then I'm also
going to write another function to game loop. Cool. So let's go ahead and write
the function load level next.
So function load level. And then whatever we pass into here, I'm
just going to go ahead and call it level index.
So in this case, we're passing through a one. This is just a little helper that shows
up which we can disable. Now, first off, I just want to check that if the level index is larger than
or equal to the levels length. Now, there is a bit of an issue
here because imagine we are level two, right? Well, we only have two levels in
our levels array. So technically if we pass through a two that does equal the
length of the levels array which is two which would mean it would be a game over. That is not what we want. So
actually what I'm going to do is just add a minus1
to the level index. So it starts counting at zero. However, let's go ahead and do
that all the way here in the load level function. So that level index is actually being passed through as a zero
now. So if it goes to one, which is essentially level two, it is still lower
than the level's length. So we will be good to play. And if it of course goes over, then it will show a game over.
Okay. So hopefully that makes sense. Now if we are below that and so essentially
level index does not go over the level's length, we are happy to play the game. I'm just going to start off by clearing
the existing objects.
I'm going to write another function called clear level which we have not
written yet. So I'm just going to comment that out for now. And now let's
actually get the level. So con level, let's define it. We're going to go into our levels array
and we're going to pass through the level index. So if it's a zero, we'll get back the first item and assign it to
level. Next, I'm also going to define the game area. And for this, we're going
to go into our document into our whole document here and get the element with
the ID of game area. So let's use get element
by ID and pass through the game area. Easy.
Okay. So now I'm going to also reset the player. So wherever the player is, our
little Mario, I'm going to get the player and get its xaxis because as we know player is an object that we wrote
above and I'm going to assign it to 50. Let's also get y and assign it 300.
Player velocity X is going to be zero.
Player velocity Y is going to be zero.
Player big is going to be false. We're starting off as small. player big timer
will also start off as being zero. Great.
Let's also clear any class names that might be assigned to the player. So, for
example, if he's currently big class name, it's going to clear it to be
an empty string. And we're going to update element position. This is a function
that we are yet to write. And we'll just pass through the player
uh just a few things actually. So the player element
the player xaxis and the player yaxis. So again this is a
function that we are yet to write. So I'm just going to comment that out for
now. Let's move on. So outside of this function, I'm going
write another function called, you guessed it, update element position in which you pass through the element, the
x-axis and the y axis. And I'm just going to grab the element style
left and just use x plus px as we are working
in pixels. So we're getting that element essentially our Mario and using style to manipulate the style position left
and we're passing through whatever that is. So in this case it's 50 50 pixels. We're also going to have to add a
position of absolute to Mario. So let's find Mario here. That's already been
done for us because otherwise we would not be able to add left, right, top and bottom as we are doing now. We've just
added left. And then also let's do top. Okay. And for this it's white.
Great. So we've now written that. Let's uncomment it out here. I'm going to keep
that like that. Okay. So let's give it a go. We are going to have to call this function of
course. So let's start game.
And I'm just going to call that and let's see what happens. Okay, so wonderful. Game loop is not defined.
That is fine. Let's just go ahead and comment out game loop for now. What
we've essentially done is assign an x and a yaxis to Mario. Okay, it is
absolute. So, it's taking in the whole page into account. However, we just want this in the game area. So, let's go back
to styles. Let's find our game area. And I'm going to add a position of relative
to the game area, meaning that Mario will now appear inside that game area
50 pixels and 300 pixels from the top. Great. So, we've essentially kind of
started our game by placing Mario exactly where he is. Wonderful. I love
it. Let's continue. So, let's go back to this file right here. Okay. Now, let's
continue by going back into this function. So, the load level function.
And what I'm going to do is actually create the platforms for this layer. So create platforms
just like so. And I'm going to get the level. And from
the level I'm going to get the platforms. And for each platform
that lives inside of that array, I'm going to
essentially create an element out that data.
So maybe let's call it this platform data instead as it is just a bunch of
data and let's define an actual platform. So remember the data, it had
the X and the Y and the width and the height. We're actually going to use that. We're going to write a function called create element and we're going to
create a div. And that div is also going to have the class name of platform. And
we're going to go into that platform data once more to get the type. Okay. So
whether it was ground, whether it was floating, that is going to be assigned right here. Okay. And the other thing
that we're going to have to pass through is this whole object. And we're going to assign a left side. So that once more
we're going to get that platform data and get X from it and add just the px
string for pixels. And let's do the same for the top width and height. So top
width and height. So platform data Y platform
data width and platform data height.
Next, let's grab the game area that we picked out previously and use the method
of append child to actually add an element inside of it. And we're going to grab that whole platform and just whack
it in. Okay, for each platform. And finally, we're going to save that to
the game objects. Platforms.
We're going to push that into the array. We're going to push in this whole object and it's just going to be the element
which is going to have the value of the platform itself so we can keep track of it. And we're going to also just spill
out any other platform data that we have. And let's also add an ID to this.
I'm just going to put the string of platform in front of it and add the index number. So it be like platform
one, platform two, platform three starting from platform zero of course.
Okay. So let's define that function create element. So once again just do it outside. I'm just going to do it here.
Function create element. And of course we pass through the type the class name
and the styles as an object. So with the element that we pass
through, we're going to use document and create element.
This we did not write. This already exists from the document API. We're going to create a div. Okay, so we're
creating a div in the document and assigning it to the const element. So now let's grab that element
and let's assign that class name which we have passed through into this
function. And then I'm just going to use object assign
and assign it the elements style
with the styles we passed through and then we're just going to return the element itself. Okay, so that is our
function create element which we wrote. Okay, this is not the one from the
document API. This is the one from the document API. You can see we're getting the document object and getting it from
there. Great. So now if we look in here, we have created all those platforms.
However, they're all bunched up here. Why is that? It's because we need to add position absolute to them just like we
have with Mario. So, back in here where we have the platforms,
we're just going to add position absolute.
Okay, for here for this platform, for the floating platform, and the platform
blue. Okay, so now, tada. There we have it. We have just positioned all of them
on our game board. This is looking great.
Let's go back to creating our game. I think next let's write our show game
over function. So I'm just going to uncomment that for now. And once again at the bottom here. So outside that
function let's write function show game over
just like so. And this is going to be easy. We're just going to grab the game state. We have
the game running property on that object. We're going to set it to false.
We're going to get the document get element
by ID. Uh so let's search for the game over
title. Let's change the text content
of it to be well based on if we won or not. So this is going to be a variable
if we won. I'm going to put congratulations,
you won. Otherwise, I'm just going to put game over. Okay, so great. Of course, this is
a variable we're going to have to define. Some other things that we're going to do is I'm going to do get
element by ID. This time, let's get the final
score. And once again, get the text
content. Uh, and we're just going to get the game
state score. Finally also get the
game over style display
block so that we can actually see it. Okay. And the variable one we're going
to actually pass that through into the show game over which means that here
shame show game over is true. We'll actually see that element. So let's hide it as a default.
So, back in here, let's find game over.
And I'm just going to put display none for now. Okay. So, as a default, it
should be hidden. And if we lose, we will display it. Great. The other thing
we need to do is write the function clear level. So, once again, let's go ahead and define define that here.
Function clear level. All I'm going to do is once again get the game area, use
document, get element by ID. Make sure to spell that
correctly. And let's look for game area.
And now let's remove all the objects apart from Mario. So objects values
game objects flat
for each and then let's get each object
and if object element
plus object element parent node
exists well we just remove it. So, this is kind of like a hack way to keep removing, removing, removing until
nothing is there anymore. Okay, great. So, in fact, I don't really
think we need this. We can just do it this way. Let's check that out.
Okay, so we're going to do that. And then finally, let's clear the array so we can start fresh. So, game objects,
platforms, let's reset it to an empty array.
Enemies, let's reset it to an empty array.
Coins, let's reset it to an empty array. Ser
rise blocks, let's reset it to an empty array.
and pipes also. We're clearing everything.
Okay, great. While we are also here, I'm just going
to write the input handling. So, essentially how the Mario moves left and
right and jumps and so on. So, for that, I'm going to get the whole document and listen out to the entire document with
event listener. and we're going to listen up anytime we press the key down
on our keyboards. Okay, pass through an event so we know
which key. So I'm going to also get the game state keys and I'm going to pass
through the E key code that was pressed.
Now I'm also going to listen out to any time the key is relieved. And then I'm
going to put that as false. So we're not pressing down anymore.
Great. However, if we press key down and we do
press the space button. So if E key code equals space, we know this is a jump. We
also want to prevent the default from happening. Okay? Because we're jumping. we don't want to continue moving. Okay,
so for example, if we're going left and right, we would move left to right continuously unless we press a space and then we prevent that default from
happening. So that is our input handling. We also need to handle the
game loop because we want the game to keep looping. So function game loop
if however there is no game state
game running. So the game is not running anymore. It is false. We just want to return out of this. Otherwise, let's
update and request
animation frame
game loop. We of course need to write the update
function as well. The update function is going to be a long one, okay? Because it's essentially
going to handle all of our game logic. So update game logic
function update. So there we go.
Now let's also uncomment the game loop that we put up here
on the game initialization. Great. So this is what our game looks
like at the moment. Can't see much, but we've done a lot of
logic behind the hood. Let's go back to our load level function. Okay, so we're
clearing the level. We're resetting the player. We're creating platforms. There's a bunch more stuff we need to
create. We need to create enemies. We need to create coins. And we need to create supplies box. Create pipes as
well. And the pipe parts. So let's do that now. Okay. So just after we create
the platforms. So that function finishes here. Still inside the
load level function, I'm going to
create enemies. So, I'm going to grab the level enemies
associated to that level. And for each enemy,
let's call this enemy data because it is the XY access data and so on. Just going
to use index so we know which one we are working with.
And what I'm going to do is define our enemy. And for that we're going to use
the create element function that we wrote. So we're going to want to make
sure that this is a div. And then let's pass through the class name of enemy.
You will notice I'm using back text as we are going to use some code in here. We're going to get the enemy
data type. So whether it's brown or purple will be passed through into here.
We'll also then pass through an object that has the left
and the top pixels. So let's get enemy
data which is an integer. Okay, stored under X. And we're just going to get
the string pixels and add it like so. And for the top, we're just going to use
enemy data Y. Okay. So, now that we've created the enemy, we're going to append
the enemy in the game area like we did here. So, append
child pass through that enemy. We're also going to get the game objects.
get the enemies array. We're going to push in this new
enemy or each enemy that we create. So, as the element, let's just pass through
the enemy we created. As the X, we're going to pass through enemy X. That's
pretty easy. As the Y, we'll pass through enemy data Y.
The width is going to be 20 pixels. The width is going to be 20. The height
is going to be 20. We're also going to pass through a direction that we want the enemy to move. I'm going to go minus
one. A speed which we set above as enemy speed.
And let's give it ID. So the ID is just going to be the string of enemy dash. And we're going to add
the index. So starting from zero, we're also going to make the enemy alive true
to start off with. Great. So let's use the same logic to now create a coin. So
after this has finished, so just here we're going to create
coin or coins multiple if there are multiple coins. So once again for the level we
are working with let's get the coins array and for each coin that exists we're going to get the coin data. So the
x the y and the so on let's get its index and then once again let's use the create
element function that we wrote to pass through a div.
And then I'm just going to pass you the type of coin.
And as left I'm going to just put coin data X
and append the string pixels. And then I'm going to also put top
with coin data Y. Okay, great. And once again, let's get
the game area. Use append child
pass through the coin itself. Let's get the game objects coins
push. So we're pushing into that array this object which is going to
essentially represent our one coin. So let's get the element pass through the
coin itself as the x. We're going to just get the coin data
X. The Y, we're going to get the coin data
Y. Width is going to be 20. Height is going
to be 20. Collected, we're going to start off with being false and change it to be true.
The ID, well, we're going to do coin and then the index.
Great. So just the surprise box and the pipes next. So same logic once more.
You'll really get the hang of this soon. Create surprise
[Music] blocks. Let's get the level and the surprise
blocks array. And for each block data, let's
get the index as well. So starting from zero, we're going to use the create
element function we wrote. So this is great function. It's getting a lot of use. And then let's just pass through
the string of surprise block just like so.
And once again, let's pass through the styles. So left is block data X plus pixels,
top is block data Y plus pixels
and then game area append child
the block itself. So it shows up in the game area and then game objects. Let's just update this game objects
surprise blocks
push this whole object to represent one supplies block. We'll get the element
which is the block itself that we defined. The X is the block data.
X. The Y is the block data Y.
The width is 20. The height is 20.
The type is the block data.
Type. Okay. So, that's going to say coin or mushroom. It's not going to look like a
coin or mushroom. It just look like a surprise block, however. And let's start off with it being here as false.
And then let's just give an ID. So I'm just going to go with block plus the
index. So let's just look at this at the moment. Let's see if we made any
mistakes. So enemy here. Okay. So this is looking good. So now if
I refresh this, tada. We get our enemies. We get our coins. We get our surprise block. However, they're just
stuck in here. Why? Because we need to add position absolute to all of them.
So, in fact, let's go back up here.
I'm going to go with enemy here. Enemy here. Coin.
Surprise block. Surprise block. Hit pipe. Pipe top. Pipe
top right. Pipe dot bottom. Pipe bottom right. And great. So now if we refresh
this, they will appear in their correct positions. I love it. This is looking so
so good. Now let's do the pipes. So once again,
right after this, but still in the same load level function, let's create pipes.
Once again, level. So let's get the pipes associated with that level. And for each
pipe data, so the X, the Y, and so on, let's also grab the index.
I'm going to use the create element
function and just pass through that I want to create a div and I want to give
it the type of pipe and these are the styles I want to add. So left is going to have pipe data X plus pixels and top
is going to have pipe data Y. So that's for the whole pipe itself.
However, we need to also create the pipe parts. So
still inside this function, let's define pipe top left equals and create element
once more. This time just going to pass through that. I want to create a div and pipe
top. It's going to be the type. And then let's do pipe top
right. Pipe bottom left
and pipe bottom right. Okay. So pipe top
right pipe bottom is the
style name and pipe bottom. Right.
Great. So now let's append this all to the pipe. So, let's grab the pipe itself
that we created above. And I'm going to use append
child to put in the pipe top left.
We can just use a pend in which we can just pass them all through. Pipe top
right, pipe bottom left, and pipe
bottom right. And once that pipe is created, we get the game area and we use
append child. This is just one to append that whole pipe with all of its four
children. Okay. So it will look like that.
So there's our pipe top, pipe top right, pipe bottom, pipe bottom right, all in
one space. all as children. We're going to have to space them out a little bit.
But for now, let's also get the game object pipes and push
the element
pipe. X is going to be pipe data. X Y is going
to be pipe data Y width is going to be
40. Height is going to be 40 and the ID
is going to be pipe plus the index value. Great. We have
finally finished our load level function. I love it. Let's get to
spacing these out a little bit more. Okay, so back in here, we're going to
have to assign a top and left value for inside the pipe itself. So everything
lives in the pipe. But with position absolute, we can actually position the pipe top, pipe top right, pipe bottom,
or pipe bottom right inside the pipe itself. So that's why I'm going to say top and left zero for pipe top, top zero
and right zero for pipe top right. Then we're going to have pipe bottom as
bottom zero left zero and also bottom right as bottom zero right zero. Okay.
And that simply means that it will position out the pipes so they look more like this. Just going to get this image
to see what that looks like. Okay, so it is cutting off a bit of the image. Pipe
top, right? I'm just going to increase that top to top
320. I think it should be a bit lower. So, let's go ahead and do that. So, here,
where do we add that? Well, it's going to be in the levels. So, where is the
pipes? Let's change that to 320. And it will probably be the same for the second
level, too. So, I'm just going to change that to 320 as well. Great. And that
just means that now it will show up in the right place. I love it. Same for Mario. We can also change where he shows
up. So, maybe let's go with Y 320.
And same for here. When we reset the player, it
should be 322. Okay, so that's where he will be. We probably need to go even lower than
that. So, player Y 340. And once again, at the top, player Y 340 as well. So,
tada. Now he's on the floor. So, if you never need to position anything, that's how you do it. Great. I love it. Let's
continue. Okay. So, now let's write some game logic. So, let's go all the way
down here and once again work on the game logic function. So, first off,
we're going to handle the inputs. We're going to support simultaneous movement and jumping. So, we're going to use the
game state keys for this that have been saved. if and then we're going to look
into the game state object that we have saved above and look at the keys
property and if the keys property contains arrow left so us moving left or
key A because we're going to do the WD movements as well so you can move with
your arrow keys or WD so either one of
those we are moving left. We're going to get the player and
velocity x equals
minus the move speed. Okay, because we are going left. Else
if and I'm simply just going to copy this. I'm going to go arrow right. And then
the key D is for moving right. Then we're going to get the player velocity,
but just move at the move speed. Okay, so we've done left and right. Else
there's just friction. Okay, so we're going to apply friction and friction is going to be 0.8. Okay, but it's going to
multiply. So it's going to get harder and harder to move. Just like that. Friction. Wonderful. So, we've just used
the multiply operator here, too. Next, let's handle the jumping. So, this
handles left and right. And now we're going to
handle jumping. So, once again, still in this function,
handle jumping. Okay. And what we're going to do is say
if and once again game state keys equals
the space bar. So if spacebar is in there and we have to check if the player
is grounded because we don't want to jump mid jump. So we're checking if the player is grounded. So if both those
things are true, we're going to get the player velocity
y this time. and we're just going to assign the jump force constant that we
assigned at the top of our file. Okay, so the player obviously will not be
grounded anymore. So we're going to also assign false because he's in the air.
And I'm also going to apply gravity. So apply gravity
if player is not grounded. So he's in the air. player
velocity y is going to increment. I'm going to
increase it with gravity. So that's the increment operator right there. We're just adding
gravity to it. Okay? And that's going to happen over and over again. Okay? So it will appear that gravity is impacting
the jump. So in the game loop, that is where the update function is being
called. And then in initializing the game. So all the way here the game loop
is being called and down here
the initialize game function is being called. Great.
So now let's just go console logs out so we can see what's going on under the hood. And here just going to console log
out the game keys so you can see which game keys are being pressed and refresh.
So as you can see if you press on the arrow left it will say left and if you let go okay at the moment it's true
because I'm pressing down on it. If you let go it will say false. Okay. And do it for the other side too. Okay. So it's
just collecting every single arrow press you do. If you click the space okay it's true. As soon as you let go, it'll be
false. So, we're just collecting all the arrows there. Great. And that is constant. Wonderful. Let's continue. So,
now we actually need to make Mario appear as if he's moving. And to do
that, well, we're going to have to use the update element position function that we wrote. That will update the
player element position and size. And we're going to just pass through the player element. Okay. and then the
player xaxis and the player yaxis too. So make sure again that is in the update
function after we've written all these if statements. Now if I refresh
uh he's still not moving. Why is that? Let's have a look. Uh because we're just
passing through the player element, the player x and the player yaxis. we've actually updated the velocity which then
needs to translate to the player position. So whatever the player x
position was, we add the player
velocity x and we do the same for the y ais. So
whatever y was, we've add the velocity y to it. And this will essentially update
player position. Okay. So now let's have a look.
Let's refresh. And Mario seems to be dropping somewhere down there. Whoa, there he goes. Let's
inspect where he went. So here is our game container. Here is our game area.
There is Mario. Okay, he's dropping from the top. He's dropping and dropping and
dropping. We need to essentially ground him somewhere. So add a platform
collision. So let's maybe go back and work on that first.
So let's say platform collision.
Uh and then let's do it for every platform. So let platform
of game object platforms. So we're saying for each
platform in the game object platforms. Okay. So this is just an loop that we
are doing if check collision. So this is a function
that we are going to write. I'm going to pass through the player. I'm going to pass through the platform. Okay. So
we're looping. We're looping. We're checking if every single platform that exists against our one player. And if
that is true, we do something. So let's write the check collision function.
Let's do so outside of this game. So here perhaps function check collision.
We'll pass through rectangle one and rectangle two because it can literally be any rectangle. We'll pass through
element one and element two because it could literally be anything. And we're
just going to check the x coordinate of the elements and the width as well as
the ycoordinate and the height to make sure that areas of the two elements
overlap. So we're going to return element 1 x and if it is smaller than element 2
x plus element 2 width and that is true plus element 1
x plus element one width is larger than
element 2 x. So if that statement is true and this statement is true
and let's do the yaxis now as well. So let's check element one. Y is smaller
than element 2 Y plus element 2 height
plus element one Y plus element one height is
bigger than element 2 Y. So again we are
checking if all of these statements are true we know there is a platform
collision that has occurred. Okay. So if platform collision has occurred well
what do we want to do? Check first if the player is falling. So player
velocity y is larger than zero. This means that indeed
they are falling.
So we want to stop them from falling essentially. So player Y, we're going to have to override with platform
Y so that the player stops on the platform. But then we're also going to minus the player height because
otherwise the player and the platform will appear on top of each other. No, we want the player to essentially appear
above it. That's why I'm also subtracting the player height. Now,
we're going to get the player velocity Y and just reset it
to zero. Okay. And then we're going to add player grounded else true. Okay. So that the player will
stop. So now this should fix our problem of the player
falling through. And there we go. So once again, if I
refresh, Mario doesn't fall through the ground now because he is on a platform.
Okay. And now if I do that, he can also move around. So left, right, jump. This
is looking wonderful. I'm so happy with this. We have now made Mario move on our
board. Great. However, look, if we go off a platform, he doesn't appear to be
falling. This is because we need to actually reset before the platform
collision. Let's just reset player grounded to be false so that he
continues falling. As a reset, okay, as a reset to everything. So, by default,
he should always be falling. Okay, wonderful. So now if we do that, he will
fall back down. Wonderful. Let's move on. So now we've done the platform
collision. We're going to use the same logic to do a pipe collision. So
pipe collision. Platform collision. Yeah, it's going to be exactly the same.
So we're going to use a loop for let pipe of game object
pipes if and then we're going to check collision going to pass through the
player and each pipe in the loop. We're going to check each pipe. And if we're
going to check the player velocity
y is larger than zero, this just means we're falling down into the pipe. Okay,
so we've pressed down. We want to fall into the pipe. So falling. Well, then once again we want to get player Y and
then just assign pipe Y to it minus the player height so that the player appears
on the right position and not exactly where the pipe is. So once again we get player
velocity Y and just clear it to be zero again.
And we're also going to ground the player. Okay. So make him stop on top of
the pipe. Wonderful. So that's stopping on top of the pipe. We still have some logic to do
for him to essentially go to the next level. First, however, let's do enemy.
So enemy collisions uh but also enemy movement. So enemy
movement and collisions. We'll do that in one. So once again, let's make a loop
for let enemy of game objects enemies
if no enemy is alive. So we're checking if any
enemies so we're looping again. If the enemy is not alive then you continue
otherwise we get the enemy xaxis
and we use the and operator. So addition operator
to get the enemy speed and multiply by the enemy
direction because it's going to change direction. So this will allow us to make
a move either minus or plus the speed. Okay. Now we need to actually change
that direction. So reverse direction at platform
edges or boundaries. Make sure to spell boundaries
correctly. Boundaries.
So for let platform
of game objects platforms so we're checking the array of platforms
and if enemy so we're still working with one enemy remember this is still in the loop x plus enemy width is larger than
or equal to x. So if that is true, all four of these statements are going to
have to be true to recognize that there is a collision with the platform, an enemy with a platform. So enemy X is
smaller than platform X plus platform
width. So if that's true, and now we're just going to do the same for the Y-axis. Enemy Y plus enemy
height is larger than or equal to platform Y plus enemy Y plus enemy
height is smaller than or equal to platform
Y. Okay. So if all of these things are true, we do have a collision.
So we are on the platform. So I'm just going to say platform on platform true
and I'm just going to create a variable here for on platform just we can store it outside of this loop on platform and
start off with it always being false before checking this loop. Great. And
then we just break out of this. Okay. So now we can write if we are not on the
platform or enemy
x is smaller than equals zero. So at the boundary edge of our game board or enemy
x is larger than or equal to 800. So at the right hand border of our game board,
we know a collision has happened. So let's make enemy direction switch. And a nice way to
switch from essentially one to minus one or minus one to one is
multiply by minus one. Great.
Okay. And now of course we update the element position. So we did it for
Mario. Now we do it for the enemies. So let's pass through the enemy
element. Let's pass through the enemy xaxis. And let's pass through the enemy
yaxis too. So now if we refresh, uh it seems the
little enemies are on the platform. They're kind of overlapping. So I'm just
going to jiggle this a little bit and put minus5 here on the y ais. + five
just to emit that little bit where they are overlapping. And great. Okay. So,
this is looking wonderful. Now, we need to do the Let's check the Yep. And they
bounce back. They changed direction. Let's do the enemy player collision now.
So, let's go ahead and do it. So, once again, still in this function, we're
going to do a player enemy collision. So,
Check player enemy collision.
So we're going to use the same function that we've been doing. Check collision.
We're going to pass through the player. We're going to pass through the enemy.
And if player velocity
y is larger than zero and player y is smaller than enemy
y. Okay. So basically the player is falling because velocity y is higher
than zero and the player is also so this also has to be true. The player is lower
than an enemy on the game board. Right? Because player Y of the player and the Y
of the enemy is what we are checking. Then essentially we are jumping on the enemy. So jump on enemy.
Uh and if that happens then the enemy alive is going to switch to false. We're
going to remove that enemy. So element remove. This is a JavaScript method to remove the element from the board. Then
we're going to do player velocity.
Y is going to be the jump force
multiplied by 0.7. Okay, so the jump force is going to slow down. And then the game state score,
let's just add 100 points. Okay, so 100 points for jumping on the enemy.
Great. else we're hit by the enemy. So hit by enemy.
So then that case we just want to essentially well let's check first if
the player is big right because if he's big he just gets a little bit smaller. So player big is going to go to false.
We're still to write this function but you know we have the big property on the player so it's easy to know what to do.
Player big timer. Let's reset that to zero.
Player element class list.
Remove the class list of big from Mario so he just appears normal. And then
let's check change the player width back to 20 and the height back to
20 because if he's big those should be 40 as well.
Okay. and then else. So if he's not big, we
lose life. But we are yet to write that function. So I'm just going to comma
that out for now. Great. Let's change how I spell enemy
here too. Okay, great. So again still in the
function of the update function
as you can see here we are still in it. We also need to
work on coin collection. So this is another loop for let coin of game
objects coins if
and we're going to check the coin because we're checking all the coins in the coin array. So if the coin is not
collected because we're going to mark it as collected if it is and there is a collision between the player and the
coin. So check collision player coin.
Well then you want to change collected to true, right? Because it is collected
now. And I'm going to remove it. So coin element remove game state score plus 50. So you
only get 50 for a coin. And that is it. Now let's work on the surprise
blocks. So when we interact with surprise blocks. Okay. Uh it seems we
made a little typo here. So let's change that. So once again another loop for let
block of game objects. So prize
blocks. If the current block that we are looping
over because there may be many blocks in the surprise block array. So if the current block we are looping over is not
hit. This means not and we check collision. So we is a collision between
the player and the block that we are currently looping over for and so these
three things need to be true. the player velocity
y is smaller than zero. Block hit equals true. We hit the block
and then we're going to change its class list so it changes visually. Block element class list add hit. So it looks
like it's been hit. Okay. So for now, let's see what hit looks like. Uh,
essentially we're just changing the image here. So that is good. Let's go ahead and try it. So I'm just going to
refresh here for now. Make sure player is spelled correctly there.
So let's just go ahead and refresh for now. So here we go. I'm jumping.
I'm killing the little enemies. I collide with a coin. I get the coin.
We need to update the score, too. And now let's check for a collision. So annoyingly that block is under there.
But amazing. So when we collide with the block, it changes to a hit block instead
rather than one with a question mark. So that is looking good. I love it. We can
of course move that to be here as well. That is something that I will do later on when we are refining the game. But
for now, this all looks good. Let's just check. We can land on the pipe as well.
And we can I love it. Okay, so let's continue. Now, of course, if we hit the
block, we're not quite yet done because if we hit the block, so if block is hit,
we just say true. We can also check the block type because our block object has a type assigned to it if you remember.
And it could be that has the type of mushroom assigned to it. And if it's mushroom, well, you know what to do. We
need to make the player big. So player big is going to be true. Player big
timer we're going to set to 600. So 10 seconds at 60fps.
The player element class list. We're also going to add
so add big to make our player big. So
for 10 seconds our player will be big. Uh let's also change the width of him to
be 40. Actually, maybe let's make it 30. Maybe double is a bit too much. Again, you can rejiggle with this as much as
you like. So, I'm changing the width and height the game state score.
Uh I'm also going to add 100 for getting a mushroom.
Then else if the block type was the other block type
it could be equals. So db equals the string of
coin. Well, I'm just going to add
a score of 50. Okay, great. We should also have
some kind of visual to show that a coin has been hit. We can work on that later,
but for now, let's check if he does in fact become big. So, once again, I'm
just going to refresh. And I think this is a mushroom. Ah,
great. So, amazing. We've multiplied Mario. However, why is that?
It's just looking quite funny that there is four. Let's have a look why. So,
Mario class big styles. Let's search for big. Uh, okay.
30. So, it's up to you however you want to do it. I obviously changed my mind and went
from 40 to 30. Uh, let's have a look. Okay, so there we
go. However, the Mario is not image is not covering the element like I want it
to. Just going to zoom in for you here a little bit. So, Mario big on Mario
itself. I'm just going to do background size cover no repeat.
So, now let's check it out. Tada. There we go. Mar is big. We fixed
that problem. Great. Let's continue.
We have one more interaction to do and that is for pipe interaction
to next level. Okay. So for once again let's
check for any pipes because there could be more than one pipe. Pipe of game objects
pipes. This means that when you create future levels, you don't have to worry about anything. You can add as many
pipes as you want. They all take you to the next level. If player
grounded. So if he is grounded on top of the pipe
and player X plus player
width is larger than pipe
X and player X is smaller than pipe X plus
pipe width and
we want to make sure that he's standing on top of the pipe, the whole pipe. I'm
going to use math abs to get the absolute number. Okay,
like a rounded number and I'm going to get player y + player height minus pipe
y. So, this will help us check if he's standing on top of the pipe is smaller
than five. And we also want to be pressing down, right?
So, game state keys and the current key that's being pressed is arrow down.
Okay, if all of that is true, we go to the next level and call it. Of course,
we haven't written that yet, so I'm just going to comma that out. However, this should be like that. Okay. So, if all of
that is true, then we go to the next level. I love it.
However, I'm just going to go up here because
check for enemy interaction. So, enemy movement and collision. Actually, this
should have inside of it. Check enemy player collision.
not the coin collection or the surprise blocks, however, or the pipe interaction. So, I'm just going to take
those three functions. Close this up now
and paste those three above the update element position still inside the update
function. Okay, so just like that. Please refer to my code that I have
added if you are not sure. Okay, now we're just going to do two more things before we go out of this
function of updating fall death.
If player Y is suddenly larger than 400,
then we lose life. So once again, that is a function that we are yet to write. And finally, let's
just update the UI with the score and everything. things. We're going to use document get element
by id and we're going to get the score so we
can update the score visually. You can use text content to do this
game state score. Okay. So whatever the game state score is is going to be assigned to the element of score in our
UI. Let's do the same for the level and the live. So just change this to level
and this too. lives and then this level. So this is
something that lives inside our game state object and lives. Great. And we
are finally done with the update function. Let's write our next level and lose life functions. Next. Okay. So down
here function lose life. Well the game state does store lives. So we're just
going to minus that from it. And if game
state lives, so for example, you have three lives. Uh this operator will remove one. So it
will come to two lives. And if game state lives suddenly is smaller than or
equal to zero, well then there's no lives, right? So we show game over. And because
we didn't win, we pass through the one variable as false. go back to the game
of a function if you need to see the one variable to refresh your memories.
Else we reset the player position. So player X is going to go back to being 50.
Player Y is going to go back to being 300. Of course, we need to make sure that this is aligned with what we
originally set. Player velocity
X is going to go back to being zero. Player velocity Y is going to go back to being zero.
Player big is go back to being false. Player big timer can go back to
being zero. Player element
class list remove any class of big.
Make sure that is spelled correctly. And let's set the play width back to being 20. And so the same with the
height. Wonderful. So that is our lose life function. We can uncomment where we
have used it. And we're also going to write a function for next level. So this
is going to take us to the next level. And all I'm going to do is get the game state level. So if it's currently one,
we'll change it to two using the uh addition operator. And then if game
level level is larger than levels
length. Well, I think for now we'll just show the game over. Okay. But you can
loop this if you want. You can add more levels. Game over. I'm just going to add
a game over for now. However, uh sorry, this should be course game
state because level lives in the game state object. else we go to the next level. So we use the
load level method that we wrote or function. We get the game state level
and minus one from it. Okay, great. Make sure that
says next level like so. Okay, so now let's uncomment those out. Uncomment
lose life here. Uncomment next level. And
uncomment lose life there. This is looking good. Let's have a go. Okay, so
now if we kill, we get a score of 100. That is great. Let's just check that
works again. So once again, score of 100. And if we get a mushroom
block and turn big again, that has been updated. We are still on level one. We've got three lives. So let's try
go to the next level. So, if we land on the pipe and go down, press down. Tada. We are right here. This is looking good.
However, I'm starting a bit higher. That is something I'm going to have to adjust. Let me just check first.
Okay. So, here something strange is happening. We will have to figure this out. And ta,
congratulations. You've won. So, that's our score. We can play again. So to me
this is looking wonderful. We of course probably need to attach some functionality to the play again button.
So maybe let's write a function called restart game.
Okay. Function restart game. And then all I'm going to do is set the game
state to be whatever it was as well as so once again what I am going to do. So
we can just scroll all the way back here just to make sure that it is the same. We'll get the game state. So this is the
reset essentially. We'll scroll all the way down here
and just paste it like that to make sure it's exactly the same. Well, then also, so just like here,
reset all of these things. So, I'm just going to copy that
and paste it here like so. And now let's grab the restart button.
So document get element by id
restart restart button const restart restart button
and then we'll grab the restart button add event listener click and then call
the function restart game. Okay, just going to move that to be down here.
Wonderful. I'm happy with that. So the X and Y axis after you lose a life is 50
and 300. I just want to make sure that is the same for here. It's actually 340
here. So let's change that down here.
340. And let's try play again. So
great. This is really really fun. Of course, you can mess around with how fast and how slow all these uh enemies
are. So, some of the images are a bit bigger. I'm just going to do cover just
like we did with Mario. So, where is Mario? Cover background repeat on some
of these two. So, on the enemies. There we go. And I believe also
on the pipes. So, pipe top,
pipe right, pipe bottom, pipe bottom, right? Uh, we didn't quite
finish writing this. So, restart game. Yes, reset everything. Let's also get
rid of the game over element. So, still in the function document. Get element
by it game over
style display
none. Make sure of course to do game over exactly how it's written
here. Okay. and then initialize
game again. One thing we can do is actually just simplify this. So remove that and
do that just so it's in the same format.
And great. So now if I get killed
game over play again. Wonderful. So yes, this is looking good. Amazing.
This is super super fun. So now I'm just going to go to the next level and once
again we probably need to put cover fit on some of these images and just
adjust a little bit where Mario is landing. But otherwise this is looking
good. Okay. So back in here I'm just going to add background size cover.
Let's just do it to all of these just to be sure. So it was platform. We need to
do platform background repeat. Let's do it also for the floating
and platform blue. And finally, let's just move the where
this little question mark is displaying. So that is easy. We just go to the game
board. So level one, the coin. Well, there's three. There's the surprise
block. So, I just want to move the surprise block higher and maybe more to the left. So, let's go ahead and do
that. I'm going to go xaxis
320 and then just add maybe 120.
Okay, maybe that's a bit too high. Let's go with 180.
Okay. So, that is looking better. That's how you would move yours around as well. So, if we go here, ta, he is bigger.
And these should be for coins. Just going to change this to background
size instead. Same for the platform ground and put
background repeat. Same for platform
blue. So
background size repeat. Same for here
as well. Okay. And that looks much better. I'm happier with that. Okay. We
have one last thing to do to really take this game to the next level, and that is spawn either a mushroom or a coin. if we
interact with the surprise block. So I'm going to do that. Let's say here.
And the function we're going to write. So function it's going to be called spawn item on box.
There we go. And of course we're going to pass through the block and the type.
So spawn. First we're going to create a new div to
represent the item. So, it's either going to be a mushroom or a coin. So, we're going to use document create
element div. And that div, we're going to assign to the const item. Next, we're
going to grab that item. Of course, at the moment, it's not on our board or anything like that. We're going to add
class list. So, class list add and the type. So, if you remember, the type will
either be a mushroom or a coin. Scroll back to the top if you want to
familiarize yourself with this again. Next, we have to position that item. So, item style on the left, we're going to
assign the block x value. So, wherever the surprise block is and just add
pixels because we want it to be exactly where the surprise block is. So, that is horizontally. And then we also need to
do this on the y axis. So item style
top just like so. And this time we get the Y-axis. So
block Y. However, we want it to be slightly above the block. So exactly 20.
The block is 20 height. So it will show up above the block. And then we add
pixels just like so. And then of course we need to add that element to the game
area so it's visible on the screen. So let's get the game area use the append child method and pass through the item.
Great. Now we're going to create an object to keep track of the items properties and physics.
So const item object equals and then of course we have to
make that an object. So the X is simply going to be where the surprise block con is. So we're going to
use block X. The Y of the object or the mushroom or the coin that's about to sprout on the Y axis is going to be Y
minus 20 because we said we want it to be above the block. The width of it is well going to be 20 because we're
keeping everything consistent. The height is going to be 20 as well. The element is going to be well the item
itself. So this that we created
after all of this has been applied and the velocity velocity
y so how it is falling so the vertical speed we're going to start off with being zero now game area is not defined
we must have picked it out in the scope of another function so I'm going to pick it out here uh let's do at the top so
document element by ID game area so we can pick out the game area of our game
and save as the con game area because that's where we're going to be putting in this item into the game area. Great.
Now, after this object has been written, but still in the spawn item object function, we're going to check if the
type is a mushroom. Because if it's a mushroom, we
want it to do one thing. To be precise, we want it to fall. else if type equals
coin. We don't want it to fall. We actually want it to rise. Uh so kind of
float in the air. So I think that coin is easier. Let's do that first. And
we're just showing something visually, right? So all I'm going to do is let
frames equals zero because we're going to start off with the frame counter
being zero to remove the coin after 3 seconds. And now I'm going to create an interval to animate the coin floating
up. So const float interval equals set interval.
And then I'm simply going to get the item object
Y and minus one to it. So it goes up and
then I'm going to get the item style top. So this is applying it visually,
right? This is not visual. This is the visual part. And I'm going to get the item object Y after I minus one to it
and just add pixels. Great. And then I'll increase frames + one. Now let's
stop it. So if frames is suddenly larger than or equal to 180 I simply want to
clear the interval of float interv
item. So item remove just like that. And I want this
to run every 16 milliseconds. So roughly 60 frames per second. So, I'll just put
that there. Wonderful. So, that is our coin object.
For now, I'm just going to console log out the word mushroom here so we can test it out. So, where do we want to
spawn the object? I'm just going to copy that. Well, I guess after we collide with a surprise block. So, let's check
for the surprise block collision. So, here we go. After block hit true. Yes.
So irrelevant what it is, we're going to spawn an object. We're going to pass
through the block. That's right. And the block type. So the type is actually attached to the block itself.
Great. So let's go back to here. So here we go. Let's test it out.
So let's find one that's a coin. So it should be here.
And great, our coin is indeed floating up. I love it. Let's just check we got
the right amount of points as well. So, let's go back here. 100. And tada. Yes,
we did indeed get points. So, this is looking good to me.
We got 50 for that one and 50 for that one. Everything is looking good. Let's
work on the mushroom next. Okay. So, if mushroom
just going to delete that so we can work with it first. Let's work on showing it visually. So, I'm going to create
another for loop. So, const fall for interval equals set interval
just like so. We'll get the item object velocity
y and this time because it's falling we're just going to use our gravity
const. Okay. So apply gravity to increase downward velocity and then we'll move the mushroom downwards
according to its velocity. So, we're simply going to get the item object again yaxis and add
the item object velocity after we just changed it above.
So, velocity y. Great. Now, let's check if the mushroom has landed on a
platform. So, let's start with on platform being
false to clear everything. and we're going to have to check for a collision with a platform. So once again, there
are many platforms that it could collide with. So let's loop over them. So let's
get the game objects and let's get the platforms array
platform forums and if
okay, so here we're going to do some more logic. We're going to check for a horizontal overlap.
And then we're going to check for another horizontal overlap, but this
time checking the width of the item object itself. Then we're going to check
the bottom of mushroom at the platform top. And then also allow a small
tolerance. So if there is a collision, we know that on platform
has to be true. And then what we're going to do is position the mushroom on
top of the platform and stop the downward movement because at the moment
it's falling. Item object velocity y equals zero. And then we'll break. So
exit the platform loop. Wonderful. But still inside here. So after these two
parentheses, we need to update the DOM element to match the new Y position. So actually show it. So we're going to get
the item style top item object
Y and add pixels to it. So we can see the mushroom visually. And if on
platform form is true, we're going to stop the
mushroom falling. Of course, we also need to clear the interval from running. So clear interval for in
great and we want this to run every 16 milliseconds again. So wonderful. This
looks good to me. The one thing we do need to do is add a mushroom style. So
I'm just going to go ahead and do that now. The style name of mushroom. Uh
let's just copy this. So just like that. and add a background
image. Again, I've already uploaded these onto Imager a while ago.
So, here we go. So, let's test it out.
So, now if I interact with this, ta, a mushroom falls down.
Now, in my game of Mario, I'm just going to actually remove the mushroom when it
hits the ground. I'm happy with this. Of course, you can take this further. Um, I
will leave a little note at the end of this video for you. For now, however, you might be noticing some lag. Uh, for
example, if you're viewing this the next day or in a different browser, I'm going to actually remove the set interval so
that everything is consistent with working with the request animation frame. So this should get rid of any lag
and your Mario should be moving at the same pace. So to do this, all we're going to do is just write a function
called fall like so. And I'm simply going to take everything from the set interval, everything, and remove the set
interval and paste that code. So that is now all in the full function. And I'm
going to remove this two and put request animation frame and pass through and
reverse this. So when we're not on the platform, this gets called. Great. And
let's call the full function. Let's do the same for the coin now. So once again, let's write a function called
float up. And I'm going to remove the frames. I'm going to take all the code from the set interval. Delete the set
interval. And once again, just change this to be requests animation frame and pass through floating up as well as just
make sure that that is attached to the object. So item object was item ob
remove remove this item remove and put that in an else because we need to reverse this. Okay. So I've just
reversed that. This time we're checking if it's above 180. Okay. If it's above
180 we call the request animation frame function. Great. So that is now much
more consistent. I'm just going to add frames to my item object. Okay. And
great. Okay. Okay, so there's one fix we need to do. When we go to the next level
and Mario is big. He appears to be floating. Let's get rid of that. So, let's remove big and reset the player
width and height when he goes to the next level before loading the game.
Done. Okay, good. One more thing we should do. There is a weird glitch. Say
if Mario's big and he gets hit by an enemy, because he gets made small so
quickly, the enemy is still there. So, he loses a life. No, let's get rid of that. So, I'm just going to check if the
player is grounded as well, so not falling. And that should fix that glitch
for us. Of course, feel free to take this further if you want to then have
the mushroom move and Mario chase it and only grow big once he eats the mushroom.
That is totally up to you. I'm just going to stop here for now. My intention
was to of course help you practice JavaScript and take this game, take it
to the next level, add more levels, add different functionality, you name it.
Okay, so please again if you want to fork this project and take it on, go
ahead. It's up to you. Hopefully you're happy with it in the state that it's in. and I produce a cool game for you while
we practice our JavaScript. Okay, so wonderful. I hope to see you
again on here soon.
No comments:
Post a Comment