Hey everyone. Today we're going to be building a game of Zelda in pure JavaScript, HTML, and CSS. And no, we're
not going to be using any fancy frameworks. No, we're not even going to be using Canva. This is pure JavaScript.
Okay, and this is to practice your fundamentals. Okay, so this is the final product. We're going to be building this
game. You can see Link here. He can move around. He can, of course, kill the enemies and then move to other levels
once he has killed them, too. Now, these levels will loop because honestly, this
is all about learning the fundamentals. I want to give you all the tools to essentially build this game, but then
take it, make it your own, style up, add more levels. All of this will be possible by the end because this, once
again, just to repeat, is a way for you to practice your JavaScript. Now, once you finish building this project, you'll
probably want to show off to the world. And to do that, you're going to need to deploy it onto the internet. I'm going
to drop a link for Savala, which is a cloud platform that makes deployment super super straightforward. All you
need to do is connect your GitHub, GitLab, or Gitbucket account, and you're basically done. Push your code to the
repository like this, and Savala handles the rest. So, you simply select it from
here, and it deploys to the internet. Easy. And here's the cool part. If you're deploying a static site like this
one, it's completely free. So, follow deploys it onto the edge network so your site loads instantly. No matter where
your visitors are located, whether you're just experimenting with projects like we're doing here, or you're
planning something bigger down the line, maybe with a database, user authentication, the whole nine yards,
you'll be able to do it here, too. So, go ahead and click on the link in the video description to check out Savala
and bookmark it for when you're ready to deploy. Otherwise, let's get to actually
building this thing. Okay, so what are we waiting for? Let's do it. Let's build Zelda. Once you have finished your game,
please do share with me. I would love to see how you have taken this, taken your knowledge and basically improved what
you see here today. Okay, so here we go. Let's do it. I'm going to start off in my code editor, which in this case is
webtorm. Feel free to use whatever code editor you wish. I'm just going to go ahead and just start completely from
scratch. So, let's create a new project. And this is going to be an empty
project. So, let's just go on ahead and do that. I am in my WebStorm directory
that lives on my computer. And I'm just going to call this Zelda
JS and click create. So, that has just created an empty directory for me.
There's no files or anything like that. And I'm just going to create a new file.
This is going to be an HTML file. I'm going to call it index. You don't need to put the extension but you know just
in case you are in another code editor I've done that for you and some boilerplate code has been generated for
me thanks to webtorm. So along with that indexjs file I'm going to have a
JavaScript file. I'm just going to call this app.js and then one more file. It's
going to be a stylesheet. So once again I just put style or I could double click
here and it will just add the style.css CSS extension to let our code editor know to treat this as a CSS file. So, a
stylesheet. So, there we go. Those are going to be my three files. I now have to link them up. So, they all live in
the same directory on the same level. Like I said, it's going to be super simple. So, we're not going to make it
any more complicated than that. I'm going to call this zel davcript.
Just like that. Now, to link up our stylesheet, well, we use the link tag.
So, let's go ahead and do that. It is a self-closing tag that actually doesn't
need this. Okay, it's one of few that doesn't. And then what I'm going to do
is do real style sheet. And now I'm going to link it with
the href attribute. And it's just going to go to style CSS. Okay. So that one
file there. Great. And the script tag.
We're not going to actually link it up in here. I'm going to use the DOM content loaded method. I'm going to
explain that in a bit. So we are done with this setup. At the moment we will come back to it when the time comes to
execute the JavaScript. I'm just going to put some very basic things in the body. Okay. So not much. Like I said,
this is going to be super simplified. I'm going to create a div. And here is essentially, let's give this the class
name of UI. It's going to be stuff such as the player current score, the plane
current level, and the enemy counter. So, these are just going to be simple P tags because like I said, we're making
this super simple so that you can take it and essentially do with it what you want. Okay. So, I'm going to span. So,
the score we'll put here. And then I'm going to break up that P tag with the
span. I'm going to break it up because we want to pick out just this little bit here. Okay. So if I do ID
score, we can just pick out this span element and not affect this score word right here. So that is it for the score.
Then what did I say? I said we're going to have some levels. So level
uh which means this is the ID for picking out the level. Let's start with level one. I'm just hard coding that
enemies. Uh, let's have the enemy counter here. So, enemies,
let's start off with two. So, I've hardcoded that. We can change it with our JavaScript later on. Great. Uh, so
we have this div here and one more div here. It's going to just be for our
game. So, I'm going to give this the class of grid. Okay, because our game grid is
going to go here. And final one is just going to be a P element that says use
arrow keys to move space to attack. So that's our game instructions. And
honestly, that's really it. I feel like we've done everything. So now, if I want
to see this in the browser, I copy the path, copy the absolute path, and just
paste it in like so. So that is what my screen looks like at the moment. Okay,
if I inspect it, you will see that's literally what we have in the body. The div with the class UI, the div with the
class of grid. So we're going to be injecting a lot of elements into this div. Okay, at the moment it's just a div
that is empty. It's going to have so much stuff in there that we're going to inject into it with JavaScript. And of
course, this P element right here. Use arrow keys to move space to attack. Great. So, let's continue. I think next
we should maybe style this up a tiny bit. So, let's go to our stylesheet. So,
let's get up our styles. Okay. So, what I'm going to do is just grab the whole body like so. And again, it's going to
be super simplified. Let's do font family for any fonts that we use. I'm going to use courier
new and then monospace as a backup. So it's kind of retro fonts that I am using
the background color. Uh I'm going to go with hash
one. We're using hex values for this 1 a 1 a2 e. I have picked this out already.
It's a dark blue background. The color of the text is going to be white. So that is a short hand for writing six fs.
It's still white. And now I'm going to use display flex. So this is initializing flexbox. so that I can use
flex direction column to make sure everything in the
body stacks up on top of each other from top to bottom. And then I'm going to align items
center. This is going to center them horizontally. And I'm going to use just spy
content center two to center them vertically. But uh oh, this will not work unless we
have a height. So I'm going to put min height 100 viewport height. So the
height of the browser essentially. Okay. So at the moment it will just look like
this. Okay. So we've added a few things. Let's also
Here's the body. Here's the grid. Here's the UI. Uh I think for the UI
let's do the grid first actually. So, I'm just going to go back to here. Let's
pick out the grid just like so. And I'm going to say that the grid is going to
have a height of 432 pixels. Again, I've already picked this out, a width of 480
pixels. We're going to have each of the grid, because it's a grid based game, right? Made of lots of little squares.
And every single square is going to be 48 by 48 cm. So this means that the
width is actually 10 squares and same for here that's going to be nine
squares. So that is the height and width. Uh for now maybe let's just give
it a box shadow so you can see what's going to look like. So zero and the x-axis 2 pixels on the y axis four
pixels spread. And then the color I'm going to use rgb8 because I want to make it transparent. So 0 0.5
opacity and then inset. And then I'm going to have another one on top. 0 x
axis 1 pixels y axis zero blur and make it solid white in color. So now if you
have a look there's the grid. I'm just going to zoom back out.
Okay. That's what we've created. So it kind of has this 3D effect. So again, UI
grid P element. I think the UI I don't want this to be stacked on top of each other. I want it to be the full length.
So what I'm going to do is go back here and let's grab the UI just like that.
And I'm going to use flexbox to do this again. So display flex. So this essentially initializes flexbox. And I'm
going to use justify content
space between. I'm going to show you what this looks like. Uh we also
actually need to say that the width of the whole UI is the same as the grid. So I'm just going to copy that there.
Great. So now you will see that the UI, there we go, is 480 pixels in width.
Same as this, but the space in between is equal. Okay, that's equal and that's
equal and that's thanks to space between. So display flex made them made
each of the text. So this text this this text appear
on a straight line essentially and then space between spaced that out. If you don't believe me, check it out. So that
was what it looked like without the justify content and without display flex that wouldn't even work. Okay, cool.
Let's move on. So great. Do you know what why I am here? Okay, that is our grid of course.
However, we're going to also say because we already know that every div that we
put inside that grid, we're going to put in divs with JavaScript. I already told you it's going to have a height of 48
pixels and a width of 48 pixels. Okay.
So, we don't have any in there at the moment, but I'm just going to leave it like that
for now. Wonderful. So, now let's get to creating our board. I think that's the
first function that we'll do. So, like I said, I'm going to use document and add
event listener. So, hopefully you've used this method from JavaScript before. Listener.
And then we're going to listen out for DOM content loaded. Okay, so this is
going to wait for the HTML document to be fully loaded before executing the game code. And once it is fully loaded,
okay, meaning that all of this has been loaded. So you can put a script tag here
that's it's kind of the same, but this is a little bit more foolproof because we're saying, oh, wait till everything is loaded.
And then it's going to call this function which is essentially the game code. Okay.
So now what we're going to do like I said I want to inject elements into the grid. So con grid. What we're going to
do is use document again and we're going to use query selector
to look for any element with a class. Is it class name? Class name of grid. You
could use class. We should probably use ID. So, let's look for anything with the
ID of grid because we know that the hash means, but we're looking for an ID.
Great. Okay. So, that also means that we need
to change that here. So, there we go. We're looking for an
element with the ID of grid, an element for an ID of grid, and any div that lives inside of it. Wonderful. Okay.
Okay, so you can use query selector or you can just use get element by ID. It's
up to you. But then we don't need to specify it's an ID because you know that kind of is already doing it for us in
there. So we're grabbing the grid that is cool. Uh while we are here, I'm also
going to grab the spans. So this whole element I can grab by this ID. So let's
go ahead and do that. I'm going to do score display.
Look for element with the ID of score. Let's do the same for the others. So, we
also have the level display and the enemy display. So, look
for level look for enemies. Great.
Okay. So, we've already discussed this. The width of my game grid is 10 squares
which are all 48 pixels wide. Uh in fact I'm just going to define the tile size
here as well. 48. So this is each tile size in pixels which is 48x 48 pixels.
And now what I'm going to do is actually uh well we are going to create the
board. So let's write the function create board just like that. And what
we're going to do is loop essentially. So let's write a for loop for let i
equals zero. And as long as
i is smaller than 9, we're going to increment i
by one. Okay? So, we're actually going to loop through each row first. So, imagine the grid based game is a row. In
fact, maybe it's best to kind of get the layout first of these games so you can
fiction them better. So, let's define maps. So, let's have two, right? Because
we have two levels. It's going to be an array. And my first map is going to be an array that lives inside of an array.
This is essentially our first map. If you want, we can even annotate it. level
one layout and I'm going to do it for you in a way
because usually you just write a string. I'm going to do it visually for you. Uh so let's write the string of the top
row. So essentially what I'm going to do is say the certain things are describe
corner walls and so on. So I've already written this out for us. So, these are
going to be corner walls, meaning that the visuals that you see or saw on the
Zelda have already been planned out. I did this in advance to save you time. A
and B are going to be side walls. C and D are going to be top and bottom walls.
This shape right here, so this is going to be lanterns.
This is going to be fire pot. So this shape right here. This
is going to be a left door. This is going to be a top door. This is going to be stairs.
This is going to be the slicer enemy. This is going to be a skeletal. And then a space is just going to be an empty
walkable area. So using this I'm going to create my map. So let's go with Y. So
this is a side corner wall. Then CC, as we know, this is a top and bottom wall. Then I'm going to put a lantern. So I'm
going to go like that. CC again for a wall. And there's going to be a door. So
that is a top door. CC for walls. And W for a corner wall. Okay. So that is my
first top row with a top door in the center. Now I'm going to do the second
one. So, second row and that's going to be a because that's a side wall. I'm
just going to have a bunch of spaces here. Okay. And a b. So, that's the other side wall. So, great. That's side
walls with an open space. And we said that this was going to be nine squares
high. So, we need nine of this. So, we've already have one row, two rows,
three rows. But, ah, let's have a slicer here, I think. So, let's just put the slicer there. Let's put a comma there,
too. Then we have another one. And this time, we're going to put a lantern here.
So, let's put the lantern there, maybe. Really is up to you where you want to
put this stuff. Let's have another one. But instead of a wall here, I'm going to put a left door.
I'm going to grab this once more. Let's put another lantern. And then
let's put another slicer, but this time I want the slicer
to be here. Okay. And then finally the bottom
row, which is going to be again corner wall, bottom wall, bottom wall, lantern,
bottom wall, bottom wall, lantern, bottom wall, bottom one, corner wall. Okay, so imagine this is my layout.
Okay. If you put it all on one line, it wouldn't look so nice and might be quite visually difficult to really see what's
going on. You'll be like, "What is this?" At least this kind of resembles the map we are doing. So, this is just
for us. Like, the computer won't know any different. This is just for me and you. So, we can kind of see what our map
looks like. Okay. So, now what I'm going to do is actually I'm just going to put
in a second layout, which I've already done as well.
So let's make another array. This is going to be level two layout.
So level two layout. And using the same key, I've just
created a second layout. So now you can actually add as many layouts as you want using the key here. Okay. You can keep
that if you wish. Uh it's up to you. So once again, these are our two levels.
Let's continue. So now I'm going to use those two arrays essentially. And I'm going to loop through each row, right?
Because like I said, this is a row and there's nine rows. Hence, we are looping
nine times. So that's going to loop through each row. Then I'm going to loop through. So this is inside that for let
J equals zero. As long as J is smaller than 10 this
time because there's 10 columns, J increments by one. And for each time
it does this, it's going to create a square. So const square. And we're going
to use square equals document create element. So we're going to create a div.
But uh oh, this is kind of currently just a div, right? It's not even in our grid. We just assign it to the con
square. that square. We're then going to grab and use set attribute. So another
JavaScript method to assign an ID to it. And that ID is just going to be the loop
that we are doing. Uh this unique ID is actually going to be based on the position. So I'm going to get I multiply
it by the width which we know is 10 plus the value of J. So before we start
adding the characters to these squares, I just want to show you what that looks like. I'm going to grab the grid which
we already picked out in the first few rows. I'm going to use another JavaScript method called append child to
put in the square we just created. Okay. So now if I call this function, I'm just
going to do so down here. And now we need to add the script tag to our HTML
document. So instead of putting the script tag here, we're actually going to put it in the head. So I'm going to put
script up here. Just like that.
Source app.js. So now our DOM content event listener
will listen out to when all the HTML elements have loaded and then execute
the JavaScript in a foolproof way. Let's check it out. Tada. So now, like I said,
we've injected all these divs, okay? We've given them ID, id 0, one, two,
three. They're going all the way down, however. So, we don't want that. See? D.
We actually want them to wrap from left to right and then make another one. And another one, another one. So, we do that
with CSS. So, back on the G grid, I'm going to use display flex once more.
Flex wrap. Okay. So there we go. So now it
goes diagally like I wanted on the next row and so on.
And you will see these ids have been assigned to the divs like I did here
using JavaScript using the set attribute. Okay. So if this was zero 0
multiply by width is still zero plus J which at the moment is zero that's zero.
Then of course we're still in the columns, right? And we have to complete all the columns until we move on to I.
So it would be 0 * width is 0 + 1, which
would be 1. 0 * 0 is still 0 + 2 and so
on until we get all the way up to 9. And then this turns to a one. So 1
multiplied by width is 10 plus J, which is zero, which gives us a 10. And so on
and so on and so on. So hopefully that explains it. Let's move on. Okay, so
we've done that. The next thing we're going to do is get the character at this position in the map. And for that,
well, we're going to have to essentially get the levels.
So get the maps here. And inside this function, I'm going to get the current
map. And the current map is simply the maps. And I'm going to open my array.
And we just want the first one, right? So let's also maybe assign some
variables here. So I think what we should do is let's
also collect the squares all in one array as well. So we know what we're working with uh in the JavaScript file,
not just when we look at the game grid. Let score start with zero. Let level,
we do want to start at level one. Yes, but in computing we start counting from zero. So it's going to be index based.
Let player position. Well, now that we have assigned ids to all our divs, I
know that I want it to go in the div with id or index 40. So I'm going to put
it there. Let enemies, we're going to collect our enemies in an array again, just we can keep track of them. And
we'll start off with the player direction being right. Okay. And of course, let
game running. We'll start off with it being true. So when you kind of, you know, just go open
the browser, it's already running. Cool. So now let's use this level variable and
put it through into maps because this will get us back the first map. Zero is
essentially one. it will get us back the first map in our array. So that is the current map that we are working with. So
now if I get the current map and I go into it
right because this is the current map and I go into here that is the first
item and I want to go further into it I do so again just with another array. So
that is how I get the exact character that we want to get at this position in
the map. Okay. So maybe let's just save this as char. So character and we're
going to write another function for this add map element. This is going to process this character to add
appropriate styling to it and so on. So that is something that we are yet to write. So we'll pass through the square
that we are working with. We'll pass through the character and of course we'll pass I and J as the positioning
references. So I'll comma that out for now. So at the moment, yes, we are putting the square in the grid, but like
I said, we also want to save it to this file, which is why I made a squares array. So I'm going to do squares push,
and I'm just going to put in push in that square. Okay, so amazing. If I
console log squares after this whole function has
run, just comment this out like so.
Tada. We get all our divs. This is great. Okay. So, I'm just going to maybe do
that and let's work on our add map element function next.
So, I'm just going to do so
here. So function add map element. Like I
said, we pass through the square, the character, then x and y. We did pass
through an i and a j, but essentially it's the same thing. And this is just going to be one long switch statement.
So we'll pass through the character like so. And if the character is an a, well,
we know this is a left wall, right? because we have our key to refer back to
and in that case we use square class list
and we add a class we are yet to write called left wall. Okay. And then we simply break out
of this. So that's all we're going to do. We're going to do this a lot. So left wall essentially. Let's just go
down here. Just going to zoom out a little bit for you.
and left wall. So, dotle left wall. Well, it's just going to be an image.
So, background image. Now, I've done two things in my
code that I've attached. I've actually added all the images. However, if you don't want to get all the images, that's
fine. I've also stored them on imager. So, here you go. This is essentially a
picture of a left wolf. So, you're more than welcome to take this link. So, you
could do that or what we can do, and I'm just going to do that here in case whatever imager goes down or something.
I'm not sure. I'm just going to make an images folder. And I've already got all
the images. I've downloaded them already because, you know, they are mine. This took me a long time to do. And I'm just
going to whack them in like so. So, here they all are. Okay. So, now you can see
them. There's link. There's some walls. It's really all of them. There's so many. Um, please feel to check out my
code. Okay. So, let's go back. So, like I said, you could do this or you could
just go to images just like that.
Okay. So, left wall we have done. So now
well actually we can go ahead and just comment these out and
ta you will see those left walls are being applied. Great.
Let's move on. Okay. So perhaps I'll just make this a little bit smaller for
you and let's carry on. So this will take a
while. We also have case B. So I don't know how you want to
do it, but we could just copy that. And this is going to be right wall and then break. And then we
have case C, which is going to be a top wall. Then we have case D, which is
going to be a bottom wall. Let's move on. Now we're
going to do W, which is going to be a top right wall. Top right wall. Then we
have X, which is going to be a bottom left wall.
Then we have Y, which is going to be a top left wall.
And then just the bottom right wall, which is going to be a Z. So bottom
right wall. Okay, cool. Now let's do the
left door. So left door. This is going to be this if you
remember from our key. And then the top door was
this little hat. So that is top
door. What else do we have? So maybe it's
better just to do that for copying.
So then we have stairs which was a dollar sign and this
was stairs. Then we have this which was lanterns.
lanterns. Then we have the other side and this was fire pot.
Fire pot. Then we have this which is slicers. So for this I'm
not going to do that. I'm going to actually call a function called called slicer which we
yet to write and pass through the column and row positions.
And then the same for this one. This is going to be for Skeletor. So let's write
a function called create Skeletor. And once again pass through X and Y.
Great. Okay. So now we need to add that here.
So we have the left wall. Let's do top wall. And once again, it's
going to be background image URL.
Just going to do this a few times. So once again, I think it's best to copy
this. We have top wall, we have bottom wall,
we have right wall, we have
bottom left wall.
We have bottom. Right wall.
We have top, left wall.
We have top right wall.
Then let's move up to the doors. So top
door, left door,
stairs, fire, pot,
lanterns. We go. Slicer is going to be coming up.
So once again, that's an image and skeletor.
Uh we're going to have another one which we haven't seen and it's kaboom for the little explosion as well. So now I'm
just going to go ahead and add those images. So once again, they live in images and this is going to be just
maybe just put that in all of these. It's a shame we didn't include that in our copy paste. Images
images. They all live in the images directory.
Okay. So like one big happy family for now. Okay. So left wall we did. Let's do top
wall, bottom wall. So apologies. This is a bit
repetitive, but it's necessary. It's a necessary evil. uh we'll know very
quickly if we got anything wrong as soon as I refresh the page because we've already done all the mapping of the
characters onto the map. So at least that's a positive, right? We're not going to carry on coding and then be
like, "Oh no, we've used the wrong image." It'll be super obvious to us as soon as we finish adding all of these.
So top right wall and then we have the top door. So let's paste that in like
so. Then we have the left door.
Then we have the stairs. Then we have the firepot.
Then we have the lanterns. Then we have the slicer.
And then we have the skeletal. And then we have the kaboom explosion.
So now, tada. This is looking good. And of course, we see we something went wrong
here. So, let's figure it out. But like I told you, super simple to find out. We found that out pretty easily. I do also
have a background. And we do also need to add our little link character. So, let's look at the top right wall first.
So, top right wall. What is up with that? Aha, it's cuz we put a dot. Okay,
so maybe the eagleeyed of you would have noticed that. But there we go. So, that is looking good. Okay, let's also add
our link positions. Even though we haven't actually added link, he will be there. So, we'll do link going left. And
this time I will copy paste everything like so. So link going left
then link going right.
Then we also have link going
down and link
going up. Okay. And once again, I already have
these in my images folder. So there's one, there's two,
there's three, and there's four. And finally, on the
grid itself, I'm going to do background URL
images. And once again, I have an image in here for the background. So, I'm just
going to do that. And I want to make it cover. So, background. I want to make it
cover the whole thing. Background size cover.
Okay. So, now it looks like this. How cool is that? So, great. I think we also
need to give the grid a position of relative as we're going to be putting stuff in there. So, let's add position
relative because we're going to position everything that goes inside the grid and we need to do it based on the grid, not
the actual browser itself. Okay. So, I'm happy with this.
I'm just also going to get rid of any padding. So, padding zero.
Let's make sure that on the divs themselves we also make the images cover them completely. So using backward size
cover and a repeat center just in case.
And we see that we missed a row. So 1 2 3 4 5 6 7 8. Let's go ahead and add
another row. So again, it's so easy to see if you've made a mistake.
Let's go back all the way to the levels here. and level one here. I'm just going to
make sure that this is indeed nine. And once again here, 1 2 3 4 5 6 7 8 9.
Okay, let's change the level to see what the second one looks like. So, I've
just changed that to a one. And this is what our second level looks like. Okay, that is good. Let's go back.
Great. I'm happy with this. So now let's move on. I'm just going to go back to
our create board function for now. And after we've essentially mapped
through all of this, but still inside the function, I want to
create player. Okay. So let's write our create player function.
So all the way down here, I'm going to write a function. I'm just
going to move this up. Function create layer
just like so. Now the main character link, we're going to essentially put him
somewhere on the grid. So let's go ahead and do that. Document
create element just like so. and create a div
const player element. And now I'm going to grab that player
element and use class name to give it the class
name of link going right which we already wrote before. I'm also going to give it a ID
so we can pick it out on the board. element id equals
player. So now once again the grid which we
picked out at the very beginning if we use append child and append the actual player to the grid or player element
that is tada link at the moment is here.
So if we look in the grid, there he is. We also need to position
him. So before we put him in, we need to position him. And what I'm going to do
is essentially calculate and set the horizontal position. So we're going to
get the player element style left.
And using back ticks, I'm going to get the player position, which we know is 40. We set it above modulus width
multiplied by tile size which is 48. Okay. So the player position modulus
width converts linear position to column number. So imagine position is 47 and 47
modulus 10 leaves a remainder of seven right because modulus finds the
remainder. So the remainder would be seven which means the player is in column seven of the grid. Now seven by
itself means nothing. We want to actually not move him to the left seven.
Move him to the left seven multiply by 48 because that is the tile size. So that would appear that he is he is let
me show you first off. However, we do have to set a position of absolute to
link. So maybe let's do it here. I'm going to do it for link going left,
link going right, link going down,
and link going up. So, position absolute is needed so in the grid. Uh,
let's also set the width and height of link. Like I said, everything is 48
pixels. So, 48 pixels. 48 pixels. And then just to make sure he's always in
the front, I'm going to set a Z index of 10. And once again, just in case, don't
think it should make a difference, but you know, just in case your images are different size, we just want to make
sure that it fits in that 48x 48 square. So now link is there.
Okay. and style left is zero pixels at the moment
because console log just get all of this
zero is being passed through into here. Okay, because 40 is our player position
modulus width leaves zero remainder and zero multiply the tile size is still zero. for this is zero pixels left which
is exactly what is being passed through. Great. So now let's do the same for the
top. So player style top and this time again in back ticks.
What we're going to do is calculate and set vertical position. So we're going to
do row multiplied by tile size. However, we're using math floor to essentially
round down. So let's say the player's position is 47 this time. 47 / 10 with
math floor is four, meaning the player is in the fourth row of the grid. But
again, we have to multiply by tile size, so he's in the right place. Great. Tada.
He ends up here. So this is looking really good. We've created our player.
I'm happy with this. Now let's do the same for enemies, right? So, let's do
it. I'm just going to clean this up like this for now. Uh, you can just do player
class name or you can do class list add
and do that if you want. Both are going to give you the same results. Okay? So,
it's up to you. I'm going to do that just because I was doing it all above here. So, let's create the slicer next.
So function create slicer. So once again
we're going to do const element this time document create element and then
we're going to create a div once more. But this div is nowhere at the moment. Okay. Let's also go element or maybe
let's be more precise and call this slicer element just cuz we did so above.
So let's get the slicer element. and do class list add and we're going to
add slicer. So an image of a slicer will be applied and a slicer element once
again style left equals and then let's
do top as well. Okay, so just like that. And for the
left, well, we're just going to use the X that we passed through multiplied by
the tile size. And for the Y or the top, we're just going to use the column that
we are looping over multiplied by the tile size. To position it vertically based on the Y coordinate.
Okay, we are not yet done. However, first of all, we of course need to grab the grid and append
child slicer element just so we can actually
see the slicer. So, let's uncomment that out for now.
So, tada, there they are. However, this has messed everything up for us. Okay,
it's kind of pushed everything out. No, this is because we also just like we did
with link. I'm just going to go to the slicer.
So, here is our slicer. I'm going to grab the slicer and grab skeletor.
And once again, we need position absolute.
Let's assign the width 48 pixels.
height 48 pixels, Z index, I'm going to go with five this
time. And once more, just in case you're using different images or they look funky, I just want to make sure they
cover the whole square. So now that looks much better. Okay, cool. So our
slices are there. The next thing to do is actually make them move. So let's do that now.
So before we put the slicer in the grid, I'm going to actually
create a slicer object with properties. So this is going to be X Y and then direction. So let's start off
with minus one. Type I'm going to go with
slicer. So this is just an enemy identifier really. and then the
reference to the DOM element. Okay, which is going to be the slicer element.
Make sure to spell direction correctly. So direction. Okay, so this is the current position.
In fact, let's just put these on that line. That's the current positions. Uh the X and Y, that's the movement
direction. This will be a minus one or a1. The identifier and the DOM element itself or the reference to the DOM
element. Okay, so we are collecting enemies. So I'm going to just push that
through. Push the
slicer in so we can keep track of them. And we know that's a slicer because in it it will say type slicer. And you can
probably even see the slicer element. Okay, so we're collecting all those enemies. That's good because we're going
to want to know how many enemies we have killed. And now using the same approach
pretty much, we're going to create skeletal. So let's do it. I'm just going
to move this all up here. Function create
skeletor.
You of course pass through X and Y. So you know the drill. Document
Create element div. Let's save this as
skeletor class name. Add skeletor
schedule element style left equals
this. and SC [Music] to element
style top is that this should actually say classless add.
Sorry. And now we can essentially uncomment out
the create skeletal function. Okay.
So now let's also get the grid. Use append
child to push in the skeletor element. We'll also get the enemies
and push in the skeletor
object that we have to make. So, const scal
equals and then let's pass through the current positions direction. Let's also
start off with minus one timer. Okay, because we're going to have a random timer for direction change on this one.
So, let's do math random. Let's call it and multiply it by five. Okay, so this
will change every 0 to 5 seconds, right? Randomly, it will produce a number from 0 to 5. The type is going to be scallet.
And I'm going to pause through the reference to the DOM object. Cool.
So amazing. I think that looks good. Once again, if I just go all the way to
the top and change the level. Tada. There's our skeletal. Amazing. So
now, let's actually make everything move. Let's just change that back to zero. and let's continue.
Okay, so that is my fold create skeletal function. Let's work on the move player
function next. And this is going to be quite a long one, so I hope you're ready.
Okay, so after the create skeletal function, I'm just going to move all this down. It's time to write our
function called move player. And the move player, this is going to handle the player movement. So we're going to
handle it by putting it through a direction. And once again, we're going
to get reference to the player doll element. So we're going to go document getelement
by ID. And luckily, we gave link an ID of player. So we can now pick him out
wherever he is on the game board. So let's also assign this to player element
just like so. And
we're going to get a new position as the current position. So let new position
and we're just going to get the player position which we set to 40 at the top of the screen. So now we're going to
handle the movement based on direction input. So whatever direction we put in, so whether it's left, right, you name
it, we have a case for it. So if he's going left,
we're going to use modulus again. So we're going to check if the player is not at left edge of grid and we're going
to do player position modulus width to give us the column number. So either it's 0 1 2 0 to 9 will come back. And if
the result is zero, it means the player is in the leftmost column and can't move left anymore. So we know where he is.
He's in the leftmost column. So that's how we're going to use modulus to figure out where he is in which column. So if
player position modulus width does not equal zero. So if
he's going left, right, he can continue going left because as long as he's not in the leftmost column, he can go left,
which means we can change the new position and it's simply going to be the player position
minus one. So it appears to be going left. Okay, so great. That's only if it
is not zero, meaning he's not in the already most left hand column. And let's
now get the player element class list add
link going left. Okay. And then we'll change the
player direction to also be left continuously
and break out of this. Now let's do the same for right. So in fact I'm just
going to copy all of this and if right. So this time I'm going to
check if player position modulus width does not equal width minus
one. So width is 10 - 1 is 9. So we know
essentially just like with the left that if the column if link is in a column
that is divisible by nine and leaves no rema remainer he's in the rightmost column but if it's not then he can
continue moving right. So we change the position we change the new position simply by adding one. Okay. And then we
change it to ring link going right. and we change the player direction to right.
So a good example of this is imagine if the player position is 29. 29 modulus
width does leave a remainder. It leaves a remainder of 9. So we know we're at
the right edge. So this does not apply. We don't do anything. However, if position is 25, 25 modulus width. So
modulus 10 leaves a remainder of five. That does not equal 9. So yes, we can continue to move right. Please take this
really slow uh if you don't understand and console log so much of this so you
can see the numbers changing and hopefully you will get it. Okay.
So once again, this time case
up and for this this time we're going to get the player position once again. This
time we're going to minus the width and we're going to check it's higher than or equal to zero. So we're just checking if
the player is not at the top edge. Um, and if the player position is for
example, so what's the top edge? It will be anything. Zero, one, two, three, four, five, six, seven, eight, nine. So
like say it's a nine. 9 minus width is minus one. That's not higher than zero.
So we would just get out of this. However, if player position is 15, 15
minus 10 is higher than zero. So then we can go up one more, which means we change position.
New position. player position
and we minus a whole width from it. Okay, we minus a whole width. We minus a whole 10 squares. Okay, a whole 10
squares. So if we're here, for example, minus 10 squares. So
will take us to here. Okay, so whole width would just mean that we're here. Another whole width would mean we're
here and so on. That's why we're minusing the width. Okay. And once again, we update the
player visually. So, let's do
link going up and player direction
equals up. And you break out of this. The last one
is down. So, I'm just going to copy all of this down. And if player position
this time plus width is smaller than
width multiply by 9, we change the position
again and this time we add a whole width. So, we can go down. So, we're just checking if he's not at the bottom
edge first. Okay. So the position has to be essentially smaller than 80.
And if he's not, well then we change the position to make him move down a whole level. So this time player going down
and then player direction is down. Okay. So I think we should check this
out. So in order to do this, we actually need to hook this up to listening out for
keyboard inputs. So key down is what we're going to listen out for. So document
add event listener
just like so. And we're going to listen out anytime we press a key down on our
keyboard. And then E for event because we're going to know which key we pressed.
And then what do we do? Well, first, if the game is not running,
we don't do anything, right? Because if the game is not running, if it's a game over, we don't want to be able to move
uh link on the board. So, do that. And
then let's use switch again. We're going to pass through the E key code that we
pass that we pressed. So, we're doing a lot of switches in here. case arrow
left. So if you press the left arrow, we move player and we pass through the
direction of left and we break out of this. So now I think you know what to
do. Let's copy this.
Let's have four arrow right. Move player right arrow.
Was it up? Just trying to do it in the same order that we did it before. And down.
We play it down. There is going to be one more case and that is if we press the space bar and then we're going to
spawn a kaboom. So we are yet to write this function. It's just going to go kaboom. Uh essentially when we attack an
enemy. Okay. So let's check it out. Okay. So now if you move and you're not
on here, there's actually a bunch of scrolling that happens here. We don't want that. So I'm also going to add the
prevent default to all of these
because we don't want any scrolling happening. Okay.
So now that shouldn't happen. Okay, cool. This is looking good. So he's
moving up. But that seems to be the only one that is happening.
We just need to actually visually make a move as well. Not just change the new
position. This actually needs to be shown on the board. So I'm also going to
get the player position now and change that to be the new
position. And I'm going to get the player element style
left back ticks. And just like we did before,
position them on the board. Player style top back ticks.
So now he should move. This is looking great. Of course, there are still fewer
things we need to figure out. For example, uh so it all the classes are adding.
This is not what we want to do. We want to completely replace the class. So that is good to know. Instead of classless
add on these, I'm just going to do class name equals to completely override it
and get rid of the other ones. So class name equals class name equals is
necessary for these. Okay, great.
Okay? Because you want to just replace it completely, not add it to a list. So
there we go. So now he will appear to me moving in all these directions. This is
looking great. I'm happy with that. Let's move on. Let's do collisions next.
So I'm just going to go ahead and still in the move player function. So after we
change the direction but before we assign the new position
we're going to check if can move to. So this is going to be
another function that we write and we're going to pass through the new position.
So let's write our can move to function. So just going to comment that out for now.
So let's do so down here.
Function can move to or pass through a position to check that
position if the player can move to it.
Okay. So if position is smaller than zero or we're checking
if the position is outside the grid boundaries right or position is suddenly larger than or equal to
squares length because obviously if it's below zero or longer than the amount of
squares we can we have then no you need to return out of this and we'll return
just a false value. Okay, so can move false
otherwise. So let's get all the squares and I'm going to pass through into that
squares array the position because we need to find out exactly what square we are dealing with. Okay, exactly which
one of these we are dealing with and pick one out to check. Just going to
save this to square as the square we are working with. And we're going to return
true if the square doesn't contain any blocking elements. Okay? So it doesn't contain a wall, doesn't contain a
lantern or anything like that. So we're going to return if the square
class list contains left wall. So we're going to return it
if it actually doesn't contain this. And if it doesn't contain I'm going to put
this on a new line a right wall. And
so once again it's going to be a lot here. Doesn't contain a
top wall and doesn't contain a bottom wall and doesn't contain a top
left wall and doesn't contain a top
right wall and doesn't contain a bottom left
wall and doesn't contain a bottom right wall and doesn't contain
lanterns and doesn't contain a fire
pot. Okay, so those are all the things
that we want to essentially
check for.
Okay. And that's it. That's really our can move to function. Um, there we go. So now we can uncomment
this out and work on it. Okay. So if we can move uh to the new position. So it's
not valid. It's not blocked by wall or an obstacle. So if that is true returns
a true, then we're going to get the square the plate is moving to. So once again, squares, we're going to look into
them. However, we're going to pass through the new position this time. So the new position that we got, and that
square is now what we're going to work with. So whatever the the future position is. And if that square
class list contains left door, then we know that it could be
open. So we're checking for interactive doors that could be opened first. So if that is true, we're just going to remove
it. Class list remove
left door. Okay, so that is one thing that we are checking.
We can also check for level progression triggers such as stairs or a top door. So if
square class list contains top door
or square class list contains
stairs and if enemies.
So all the enemies that exist, right? because we're collecting all the enemies of the level if they suddenly get down
to zero. So there's no enemies. So only if there's no enemies do we advance to the next level. So if we are about to
interact with the top door or about to interact with stairs and there's no enemies left on our game board, then we can progress to the next level. Else I'm
just going to show a message. So show enemies remaining
message and call it. So two functions that we need to write and then we
return. So we exit the function without move moving the player.
Okay, great. So I think this looks good. What do we want to work on next?
I think let's work on next level. So I'm just going to comment that out. So once
again, I think let's do this
here. So function
next level. This is actually going to be pretty easy. We'll just get the level and then
whatever the level is, we're going to add one. And then modulus
maps length. And this is actually going to allow us to cycle through levels infinitely. Of course, when you have
your own levels, you probably won't want to do this. You want to add your own, but for now, I'm just going to make them repeat over and over again. So, that is
a nice way to do this. Okay. And we're going to create board. So, create the
next board. So, great. I think that looks good. We will test that out soon.
We can't really test it out for now because we wrote a condition that we need to kill the enemies first. So,
let's maybe do that next. However, before we do that, I'm just
going to also do the show enemies remaining message. So, let's grab that.
And once again, it's going to delete a few of these
function show enemies remaining message. And what I'm going to do is just grab
the whole grid itself. I'm going to use style filter and I'm going to apply a
different hue essentially. So just a string and this is going to be applied
uh as the style filter. Okay. It's just going to create a dramatic effect of
kind of like a uh brightness. And then I'm going to do
grid style and add a box
shadow. It's going to be 20 pixels blur red. Uh zero on the X and
Y axis for the box shadow. and I'm going to remove it after a certain amount of time. So set time out is the method that
I'm going to use for this. And I'm simply just going to clear those again.
So after a certain amount of time, this is going to go back to just nothing essentially an empty
string. And that's going to happen after 300 milliseconds. Okay. So it's going to
flash red. And then I'm going to actually going to write another function. It's going to be show
temporary message and I'm going to pass through. I'm yet to write this. Defeat all
enemies first.
I want the color to be the text to be red. So I'm going to pass that through
as a string. And I want it last for 2,000 milliseconds. So now I'm going to write this function.
Okay, let's do so here. function
show temporary message. Uh and then of course we do pass through
a message. We do pass through a color and we pass
through a duration. So
I'm going to use document and I'm going to create an element. Once
again it's going to be a div. So, let's go ahead undo that. And I'm going to say
this is const message element just like so.
And I'm going to give it an ID just to make our lives easier so we can pick it out later. Temp message.
And I'm going to get the message element again and use text
content to assign the message that we passed through. and get it again and use
style color and make sure that the uh color of the text is whatever you pass
through. So in this case it's red and once again I'm going to use grid append child as a gentleman. Okay. So again I'm
going to use set timeout because I want to remove it after a certain amount of time. So set timeout
and this simply means that if there is a message element parent
node I want to get the message arament and remove it. Okay, so we it's just
safety check really to ensure elements still exist before their removal. Okay, great. One other thing I do and want to
do and this is just a safety thing is actually check if any message elements
exist. So document get
me by ID and we're going to search for anything
with temp message because we don't want to essentially you know show this if one exists already. So const existing
message we want to clear the existing message. So if there is an existing
message then we just want to get that existing
message and remove it before showing the new message. Okay. It's just kind of like a safety thing. So that duration
now I'm going to pass through here. Okay. And it's going to disappear after that duration. Great.
Let's make sure to spell message correctly here. and existing
existing existing message seems to have a lot of s's.
So let's fix that as well. Great. So that is my show
temporary message function all of that and we use it in the show enemies
remaining message. Okay, let's give this a go. So, for
example, if I try to open this door, it says, "Ah, no, defeat all enemies first." Let's style this message. This
should disappear after 2,00 milliseconds. But, ah, we're getting a
error on line 254. So, like 254 is here. Uh, this should be
removed. Sorry. Okay. So now let's style up this temp message. I'm just going to
grab it and all the way down here. So this time it's an ID and I'm going to
position it. So position absolute
top of the grid 50% because this will be in the grid. Remember we used a pen child grid to put it in the grid. Let's
give it a min width as well of 180 pixels. I'm going to also transform it.
Uh, translate minus 50% minus 50%.
Let's give it some padding. 15 pixels 25 pixels. Border radius just to soften
it by 8 pixels. Font weight bold make sure that it's in front of things. So Z
index 20 pointer
events none then back I'm just going to be RGBA. I want it to
be transparent black with 0.8 opacity.
Okay. So now the temp message. Let's go ahead. Defeat all enemies first. Okay. So
great. I love it. Okay, so this is looking good. Uh, we are able to move
through walls. So, let's carry on working on that and see if you go
through a left door and interact with it, it just disappears. So, it looks like you can go back through there. That
is a useful one for when you want to make more levels. Let's continue.
Okay, so back in the move player function. Ah, it would seem we could only move the player position. So, there
we go. if we can move to the player position. So still inside this if statement we will
put that code. Great. So now tada this
is looking good. We cannot interact with certain things. And if we try go through the door it says defeat all enemies
first and we get this nice glow around it. This is looking great. Now this means we can move on to making a kaboom
to kill enemies. So let's do it. So let's go down here. I'm going to
write it here. So function
spawn kaboom. And this time we're going to
calculate player's current grid coordinates and extract the column and row from linear position for attack
placement. So this just means that we're going to give the player position
modulus width and that is going to be let kaboom
x because we want the kaboom to appear in front of the player. So we're going to have to do a few things. We're going to have to figure out where the player
is and figure out which square to put it in based on if he's facing left, right, up, or down. Uh let's also get let
kaboom y. And this time we're going to do math
floor and pass through the player position divide by width.
Okay. So now we're going to switch and pass through the player direction.
Uh, and like I said, if he's going left, well, then we're going to get kaboom
x and attack one square to the left. So, actually, we're going to minus
one from it. So, wherever the player is, we minus one because that's where we want kaboom x to appear.
And break. And let's do the same for case write kaboom x. This time is going to be
+ one. Let's do the same for case up. This time we're going to get kaboom
y and minus one and case direction down. This time we're going to
add one. And the y kaboom y. Okay. So spawn kaboom. That's it for
checking where the kaboom will show up. So still inside the function. Make sure
you're still inside the function. This I'm going to check if attack position is within the grid grid game boundaries. So
if kaboom x is larger than or equal to
zero and so we've used this logic before. Kaboom x
is smaller than the width plus kaboom y is larger than or equal to zero
plus kaboom y is smaller than nine. So if all
those are true then yes you are within the game grid boundaries and we're going to use document. We're going to create
an element. So you know the drill. Let's create a div. Let's assign this to a
constant kaboom element
just like so. Let's get the kaboom element. Just use
class name and just override it to be kaboom.
Okay. So now once again we're going to get the kaboom element style
left and just assign it the kaboom x multiplied by the tile size
pixels. Make sure that's all in that. And once again kaboom style top this
time. So let's use the y multiply by the time tile size. And now once again,
let's grab the grid append child kaboom element. Okay,
cool. And what I'm going to do is just
this time also I need to remove the
explosion. So set time out. And if
kaboom element parent node exists, then we get kaboom element parent node remove
child kaboom element. Great. And this will happen after 1,00 milliseconds. I
love it. Okay, so there we go. We can close that up now. Uh one other thing we
actually sorry I need to do is check kaboom
enemy collision we'll pass through kaboom x and kaboom
y. So we need to actually check if it worked really. So check kaboom enemy collision. Let's
just tidy this up a little bit. Okay, that looks good. So down here
function check kaboom collision
and we're going to loop through all the enemies that we have collected an array backwards to safely remove items during
iteration. So for let I equals
enemies means length
minus one. I is larger than or equal to zero. We're going to get I and just go
down. So let's get the enemies array and we're
going to pass through I to pick out the enemy that we are working with and I'm just going to save it as enemy.
Then let's get the round enemy positions to the nearest integer for accurate collision detection. So let's get enemy
X. I'm going to actually pass it through a math round
just like that and assign it just to enemy X. Okay, so there we go.
And we have enemy Y, enemy Y.
And if any of these positions, so if enemy x dp equals
kaboom x and
enemy y deeply equals kaboom y,
then we remove the enemy's visual element from the gra grid. enemy element
parent node. If that exists, we get the
enemy parent node and remove child
enemy element. So just like that.
Okay, great. So now let's pass through this in here
and kum Y. So after removing it visually we also need to remove it from the
enemies array. So enemies splice I one and then we increase
the player score. We update displays. So
we update the UI with the latest score and we break out of this.
Okay. So update displays. Now we are yet to write this function.
Okay. So maybe let's do that here. Function update displays.
We're just going to get the store display that we literally picked out at the very very beginning. You're going to use inner HTML to just display the score
and then the level display
inner HTML to display the level plus one. Right?
Because here we're counting at zero, but to the human eye we want it to appear as one. and the enemy display
inner HTML. We're going to get the enemies array and just get the length of
all the enemies that we've collected in there. Great. So, that's really it to update the score. That was an easy
function to write. Cool. Once again, this actually needs to
happen here. So, if both of these equal that. Wonderful. So that is my whole
check kaboom enemies collision method written already. Wonderful.
So great, we're doing that here. We've written the function spawn kaboom.
So now we can comment that out basically where we press the space bar. So let's
go all the way back here to the bottom and uncomment that out. So we should now
be able to spawn kabooms. So ah it spawns there. That's because we need to
do some styling. So here on the kaboom once again we need position absolute.
Let's add a width of 48 pixels
a height of 48 pixels. a Z index of
15. And then once again, let's just do background size cover, no repeat center.
One other thing I'm going to do is just write an animation. Uh, this is going to be explode. That's what I'm calling it.
One second. Ease out forwards is what I'm going to do. And now I'm going to
get key frames explode.
0% transform
scale 0.8
opacity one
and then at 100% of the animation I want to just
transform it to 1.2 two and opacity zero.
Great. So that is my whole kaboom and that is my frames, my key frames. And
this just means if I now press the space bar, tada. Kind of expands and goes
away. I love it. So this is looking good. Let's continue. Let's go back to
our app. Okay. So as we are at the bottom of the file here is the bottom of
our whole file. One things that I would like to do
is also write the game over function.
And we're actually just going to get game running
and assign false. And we're going to use the show temporary
message function that we wrote previously to just type game
over. So we're passing through the string of game over
final score and then we're going to pass through the actual score. Okay. We're
also going to say that we want the text to be white and we want this to last for 3,000 milliseconds. So that's the text
that we're going to show. So we'll leave that for now.
Okay. So we're showing temporary message. We're showing enemies remaining. We're updating displays. I
think what would be good if we start moving the slicer. So maybe let's do that here. Function
move slicer.
Let's pass through the slicer. Let's pass through delta time. So, this is going to handle slicer enemy movement
back and forth. Uh the speed. So, con speed
const speed. But what we're going to do is just going to be 2 multiplied by delta time. You can mess around with
this. Okay, I've already kind of done this. Uh this is essentially calculating speed movement by saying two units per
second scale by delta time for smooth animation. Next I'm going to calculate the new horizontal position based on
current direction. And for this I've already kind of done this. So there we
go. And then I'm going to get the current vertical position as well. Okay.
So this is rounded for wall checking. Now we're going to check for boundaries or wall collisions.
So again, we've kind of done this logic before just checking that we're not on zero or
new x is larger than the width
or then we're going to write a function is wall because we want to check if there is a wall and I'm going to pass
through bar math round. So rounded down new X
and Y. Okay. And then we're going to get the
slicer direction and just reverse it. So this is a nice
way to reverse whatever's there. If it's a minus one, it becomes a one. And if it's a one, it becomes a minus one.
Okay, great. Else we just want to update
position if movement is valid. So slicer x equals new x. Now what we're just
going to update visual position of the slicer element. So you know what to do.
We're going to get the elements star left and update the slicer x with it.
Great. So now let's write the is wall function. So function
is wall. I'm going to pass through the x and the y.
And this is just a function to check if a grid position contains a wall or a blocking element. So first we're going
to convert grid coordinates to array index. So that is how we can do it. And
next we're going to check if a position is outside the grid bound. So this going to return to true if position
is smaller than zero or position is larger than squares
length we return true.
Okay. And now let's get the square element at this position. So once again we go into the squares array to get the
current square. And let's just assign it to con square. And you've kind of already done this before. So this time
I'm going to check if swear contains any blocking elements. So I'm actually just going to copy this
from here.
Okay. So please go ahead and do the same. Just paste it like so. However,
this time we are returning if this is true. Okay.
So if it does contain a left wall
or so let's change all of these to or instead of ants.
Okay there
we go. So that is our iswool function.
And finally, just like we wrote move slicer, we're going to move skeletal. So
maybe let's do that here
function move skeletor
going to pass through skeletor pass through delta
time. We're going to calculate the movement speed. We're going to go with 1.5 units per second, which is slower
than the slicer. We're going to decrease the direction change timer. So, we're
going to randomly move skeletal. So if skeletal timer is suddenly smaller than
or equal to zero, I'm simply going to get the skeletal
direction and multiply by minus one. So you know
that that will change it to a one if it's a minus one and a minus one if it's a one. We're going to get the skeletal
timer and just reset it. So we're going to do math rand done
call it multiply by five. Okay. And now let's essentially calculate the new
vertical position based on current direction. So we're going to do that
by getting skeletal y plus the skeletal direction multiply the speed and that's the new direction that we are going in.
And we're going to get the current horizontal position too. So we're just going to get
skeletal x pass it through math round and assign it to the const x. Once again
just like we did with the slicer we need to check for boundary or wall collision.
So if new y is smaller than zero or
new y is larger than or equal to 9 or is
wall and we pass through x and this time math
round new y then we get skeletor
Just going to copy that to save myself writing skeletor direction
and change it
else skeletal y is just the new y. We update
the position if movement is valid and we have to visually
update skeletal on our game boards.
Great. Okay. So that is all looking good to me.
Correct this to be round. Okay. Correct that from here to be
round. Okay. So we are nearly done. And I'm just going to write one function to bring that all together. So above both
of these, this is the main function that will move the enemy position based on
elapse time. So move enemies delta time and for const enemy
of enemies if enemy
type equals slicer. Remember we added that to the
enemy object then we're going to get the move slicer function pass through the
enemy and a delta time
else if I guess enemy type equals scour
we move sk and pass through enemy
and delta time. Okay, so that is our move enemies
function. Great. So now we have to put this in a game loop.
So all the way down here all the way at the bottom. Let's do
above the game over function
game loop. Let's pass through the current
time. So this is going to be called every frame by the browser.
We're going to get delta time. And delta time is simply
the current time minus the last time divide by
1,000. So this is calculating the time elapsed since last frame in seconds. And then
we're going to update the last time to be from the current time. So current
time is now the last time. I'm going to set let
last time here to be zero. And I'm also going to save the animation ID here. So
that's going to be the ID of the current animation frame request. Okay. So now if the game is running
and delta time is smaller than 0.1,
I'm going to move enemies
and pass through delta time. I'm also going to check player
enemy collision. Uh we have not written this yet, but that is something I'm
going to do. So now that game loop is defined, I'm going to schedule the next
frame. So I'm going to grab the animation ID, request animation, and pause through the
game loop. Okay, animation frame. So
that is looking good. And we're also going to initialize
the game here. here. So I'm actually just going to copy this down here. So this is outside that function. This
should actually be inside this function still. So that is in the game loop function.
So let's write this function as well. So let's just go back up here. Function
check player enemy collision. So this is to check if the player collides with the
enemies. That is something that we are going to write. Great.
Now we are referring to the skeletal element and the slicer element here.
However, if you remember when we created the elements. So let's go all the way
back here. We pass it through as the skeletal element. I think it's easier for us to just pass it through perhaps
as the element Skeletor
element. So we can access it for both enemies. So that is for Skeletor. And
for the slicer again, let's just pass it through as an element just like so.
Okay. And great. So now I'm just going to comment out the check player enemy collision in our
game loop. And if I kill one. Amazing. So, we are
killing the enemies. As you can see, enemies went down to zero. Score went up to two. I've killed all the enemies. And
now I can progress at the next level. So, that is something that we're going to have to work on. But I love it. This
is looking good. Uh, when we go to the next level as well, we should do some
clearing of things. So, let's go back to the create board function all the way up
here. So here is create board and I'm just
going to reset. So reset game running to be
true. I'm going to get the grid inner HTML and just put an empty string.
I'm going to get squares length
and just do zero. and enemies. I will clear again because we're going to start
from scratch. So, this just means that if I now let's kill the enemies. Kill
the enemies. Can't die yet. So, that is good. Okay, that is looking so much
better. I love it. So, one last thing to do and that is check for a collision
with an enemy. Let's go. So, all the way back down here. Yes, I commented it out.
I'm going to uncomment that. Let's write this function which we kind of started doing already
here. So let's uncomment that out. And this time we're going to calculate the
players current grid coordinates. So let's get the player X's by getting
the player position modulus width. Let's also get the player Y by getting the
player position divided by the width pass through math floor. So for example,
if the player position is 84, 84 modulus width gives us a remainder of four,
meaning that player is in column 4. And for this if 84 / 10 rounded down gives
us 8 which means that player is in row 8 four const enemy
of enemies. We're going to do the same. We're going
to round enemy positions for accurate collision detection. So we get the enemy
X and Y. And if, so still in the loop, if
enemy X deeply equals player X and if enemy Y deeply equals Y, it means that
the enemy and the player are in the exact same position. And then we can trigger a game over. Okay. And then
let's return out of this. So that is the whole function really. It was quite a simple one in comparison to some of the
others. Just remove that and let's test it out.
So now I die. We get a game over. I can't move at all. Okay, we should
probably remove that scrolling as well. But this is looking good. Okay, I'm
happy with this. So, we've done it. I think we have finished the game. Really,
this is looking so so good. Let's kill this one, too. Bam. Bam. Bam.
I love it. And then we keep going and going. Okay, great. Let's do some
tidying up next. So, one thing that I do want to do is just get the create board
function. Just remove the console logs. Put the create board function all the
way at the bottom. This is kind of to initialize the game. Get rid of any
extra spacing that we did. So, just like that.
Okay. And I think I'm happy with this.
Okay. So, one thing I've noticed in the move player function, we should also probably call the check
player enemy collision here as well. So, I'm just going to add that there. Also
in my create board function, I'm just going to update displays there too. So when we create player, we update the
displays here as well. In my show enemies remaining function, I
wrote filter wrong for some reason. So let's
change that filter. Just going to change this here to be bigger than or equal to. So larger or
equal to. And that should be it. One last thing I'm going to do is just
do overflow hidden to stop any pesky scroll bars from showing up. Okay, so
that's it. I hope you've enjoyed code along with me. I thought this was super super fun. I love this game of Mario and
I really feel like it has the potential to be an incredible game. Please take it, make your own. I'd love to see what
you make with this. So please do share it with me at me, you know, on Twitter, Instagram. I would love to see. Okay.
So, I hope you enjoyed and I'll see you again soon.
No comments:
Post a Comment