Learn JavaScript By Building Games | How To Make A Game With Vanilla JS [Frogger]

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments

This is awesome thank you

👍︎︎ 7 👤︎︎ u/SpiderGaming0 📅︎︎ Jul 25 2020 🗫︎ replies
Captions
[Music] in today's creative coding tutorial we are going to learn how to make a game with javascript we will practice from the web development techniques by building a complete polished program from scratch with more libraries i will explain every line as we go along you can use this on your website or in your portfolio hope it helps you to get the coding job you want hi coders welcome to another episode of my creative coding series where we learn javascript by building games and interactive animations all from scratch with no libraries the skills and techniques i'm about to teach you today will help you to build your own unique games faster but you can also apply them in any other javascript project we are using pure vanilla javascript so everything we learn here are transferable skills i had a lot of fun building this one i've hidden around 20 easter eggs with references to famous movies and tv shows and some additional pop culture references on top of that if you can spot some of them let me know in the comments some are quite obvious some are a bit more hidden it could be on cars hidden somewhere in grass flying above or swimming underwater speaking of things swimming underwater do you see the fish swimming um right here do you know how to make a ripple effect like that with html canvas if you know what technique i used to build this leave a comment in the video description before you watch the video and you get a point if you don't know i will show you how to build this entire game from scratch right now hi if this is the first time we're meeting my name is frank and i'm a self-taught front-end web developer i worked in a supermarket and call center here in london while studying javascript in my free time i've been through many interviews for a self-taught junior position until i got hired if you want to talk about any of that and exchange our experiences leave a comment i will leave some links for udemy courses that help me a lot in my self-talk journey in the video description down below so if you're interested you can check it out my goal with this series is to learn and practice vanilla javascript techniques while building fun projects from scratch with no libraries and no frameworks we will build the base game skeleton quite fast and then we will spend some time adding graphics animating spreadsheets and giving our game polished professional look if you followed my vanilla javascript series everything we do today should be very familiar to you but since it's around 20 videos full of creative coding tutorials i assume most people who watch this video will not have watched all of that so i will explain everything line by line as we go along today as i always do today we are going to take things we have learned in this series so far and create a bigger polished game you can show off on your coding portfolio or personal website you can also use this as a base for your unique game project we'll focus on collision detection sprite animation frame rate optimization and keyboard input but every technique we learn can be used for other web development projects as well not just for games let's have a quick look at the game we are building today it is a remake of classic 1981 konami arcade game called frogger it received a popular sequel for pc and playstation 1 in 1997 and there are multiple clones like go chicken go as you can see we have a frog starting down here on a rubbish field side lane it needs to cross three lanes of traffic and river to escape to the forest the main game loop is that every time you manage to get your frog across you get one point game speed slightly increases and another frog spawns down here looking to escape from dirty side road to the nature the game gets gradually faster let me know what's your high score you managed to get before the game became too hard how many frogs did you save some of the graphical details are included this time when frog hops over dry road it leaves small clouds of dust behind moving over the river leaves water ripples yes we will do some fun particle effects again today we will add multiple layers of graphics so grass here on the bottom and tree in the top right corner are placed over the frog so you can hide there we also have snails randomly hanging around here and here what else butterflies are randomized as well game will load between one and seven of them uh up here somewhere around the flower patch this is a busy city so we have planes birds and other magical creatures flying overhead you can see the shadows and there are things swimming underwater so keep an eye out for that i have around 30 randomized cars in my game maybe more i had a lot of fun hiding easter eggs and movie references all around the place i've recently discovered this channel with many game tutorials anna is a talented programmer and most importantly she picks great projects for her videos you might want to check it out and subscribe to her link in the video description one thing i notice is that she doesn't use canvas but she animates html elements which is great to practice the dom manipulation techniques and take advantage of built-in css transitions on canvas we have to write more algorithms animations with canvas have to be done more manually there is no built-in ease in transition for example each approach has its pros and cons and i think we should know both i will use dome manipulation to build this game with you soon if you get value out of my content hit the like button please and consider subscribing let's start coding we will work with three types of files as usual index html style css and i will separate javascript code into six separate files for clarity you can also write all the code in one file as long as you keep it in the same order i will use multiple canvas elements to create layers all wrapped inside the div with a class of wrapper i do this to easily organize our sprites and layers we want dust particles to be under the frog we want the frog to be under cars but on top of locks and turtles and so on there are other ways to layer sprites but i think this is the easiest and the most intuitive way so let's go with it i will create i guess five canvas elements not sure if i will even need the fifth one let's see how we get on i will also link all the script files order of these files is very important here the first one will be setup.js which will contain canvas setup global variables and references to the sprites we use basically all the things that are needed all around our application frogger.js will contain code to create and handle player character particles.js will create dust trail under the frog when it's on dry land and ripples chest will create water ripples when we move over the river area obstacles js will handle cars locks and turtles and utilities js will contain all the other bits like animation loop and event listeners in style css i give wrapper a border 5 pixels solid block and i center it exactly in the middle of the page both vertically and horizontally by using the absolute position centering trick top 50 left 50 position absolute with 600 pixels height 600 pixels transform translate minus 50 minus 50 i target all canvas elements and i set them to position absolute background blue just to see what we're doing top zero left zero with hundred percent height hundred percent and now i can remove the blue background again for the wrapper i set background to image background png you can download it in the video description in setup.js i target the first canvas with document getelementbyid canvas1 and i save it in a variable i call canvas ctx1 will be equal to canvas getcontext2d canvas width is 600 canvas height is 600 as well i do this for all the other canvas elements let's declare our global variables this is a grid based game one imaginary cell in our grid will be let's say 80 x 80 pixels keys will hold whatever key was pressed on keyboard for now i will set it to an empty array score will be 0 at first we will also count collisions just for fun we will also count our frames so we can add triggers and write statements like for example do something every 100 frames and so on gamespeed will increase slightly whenever we score a point let's start at speed one particles array will hold all particle objects for dust effects max particles will limit how many we create to prevent performance issues let's add maximum to 300 ripples array will hold water ripple particle objects cars array will contain our randomized cars logs array will contain turtles and logs maybe even crocodiles basically the things that are floating in the river in frog.js i create javascript class constructor is a mandatory method every class needs to have it runs only once when the object created by class is initialized and its only job is to create a new blank object and assign it values and properties as declared here in the blueprint so in the blueprint i set this.width and distort height actually i know i will be using spritesheet for our frog character so i might as well set it up now sprite wave is width of one frame in our character sprite sheet our sprite sheet has two columns and is 500 pixels wide so width of one frame will be 250 this dot sprite height a sprite sheet is 1000 pixels high and it has four rows thousand divided by four is 250 this is quite big so let's scale it down i want our frog to be five times smaller this dot width is sprite width divided by five and this dot height is sprite height divided by 5. i drew the frog myself you can download it in the video description if you're using your own sprite sheet you can just calculate width and height of one frame like i just did our blueprint will also need x and y coordinates where the frog first appears on game load let's put it in the center of the page at the bottom this dot move in will be false at first this will prevent the frog from moving across the screen too fast when we hold down arrow keys each press will trigger only one jump to the next grid cell this dot frame x and this.frame y will as usual hold coordinates for current frame within the sprite sheet and we will change these values dynamically to animate the frog we'll also need update method let's just put console.log statement in there for now and a draw method will draw sprites on canvas here i need to think about our layers canvas 1 will contain particle effects canvas 2 will have logs and turtles canvas 3 will have frog canvas 4 will have cars and any other overlays like grass at the bottom and 3 in the top right corner i'll show you when we get to it so frog will be on canvas 3 so ctx 3 first style is green and for now let's just draw a rectangle i pass it x and y and width and height from frogger class constructor i will also create a variable called frogger and this will be equal to new frogger the new keyword calls its associated class constructor and makes the constructor create a new blank object and fill it with values as defined in blueprint on lines 3 to 11. with this basic code in place we can create animation loop in the very last javascript file i create a custom function and i call it for example animate first i will clear the canvas ctx clear rect and i pass it canvas dimensions to clear the whole thing between every animation frame after it's clear i wanted to call draw method from frogger object we have just created objects created by clash constructor of course have access to all associated class methods i will also call frogger update now i run request animation frame built-in function and i pass it the name of its parent function animate this way animate function will just run its code and on the last line it will just call itself again create an animation loop through programming principle called recursion which simply means function calls itself over and over i declared animate so here on line 8 i also call it to kick off the animation loop it doesn't work yet let's see why in setup.js i made a mistake you can see i named all variables canvas i need to rename them we can't have multiple variables with the same name so canvas 2 canvas 3 canvas 4 and canvas 5. now we can see the frog yes it appears static but it's actually drawing and clearing the canvas over and over inside the animation loop to make it move we will need event listeners i create event listener for key down event and inside a callback function if you remember online 28 in setup.js file we created an empty array called keys this array will hold whatever key we press on keyboard at first i set keys to an empty array in case it holds some values from before now i do this weird thing when i say keys square brackets e dot key code equals true basically i'm just adding whatever was pressed into the custom keys array this entire keyboard input section will be very similar to what we did in the second episode of the series where we built a star wars gamer boilerplate i will explain all of this again but if you want more details you can watch the video today i will do this part a bit faster so we can focus on other fun features so if we press 37 or 38 or 39 or 40 which are key codes for arrows on keyboard we will call custom method on frogger object called jump this method will just animate the sprite sheet i haven't declared it yet so in frogger.js inside frogger class constructor i declare a new method called jump and let's just put a console lock in there for now i can see that works great click the like please if you're getting value out of my tutorials in update method i say if key 38 was pressed which is an up arrow key inside i put another if statement if moving is false i will explain this in a second then this dot y minus equals great grid is a custom variable we declared in setup js it is equal to 80 pixels so frog will jump 80 pixels up when we press up key i will also set move into true in utilities.js i create another event listener for key up and here i just delete the key that was released from keys array and i also set frogger moving to false so initially moving is false when we press up arrow key you can see i set move into true on line 18 and this statement is only entered when moving is false as declared on line 16. so every time we press the key frog will jump up once it will not keep moving when we hold the key down it will only ever jump once every time we tap a key then when we release the key key up event will set move into false as declared on line 20 in utilities js this will allow frog to make the next jump whenever a key is pressed i hope i'm explaining this right now i set another if statement for down arrow key when key 40 is pressed and this.moving is false and another if statement to prevent frog to leave the screen only if this dot y is less than canvas height minus this dot height times two actually let's join these two if statements into one i will check if this dot moving is false here within the same statement so only if these conditions are true this dot x plus equals grid grid is 80 pixels so frog will jump 80 pixels down and i said this dot moving to true to stop it from moving further if user holds down the key only when key up event occurs this.movein will be set to false again and frog can make another jump let's do the same thing for left key key code 37 also i will merge these two if statements on line 22 into one we are still checking for the same things i'm just cleaning up the syntax i will delete it this bit and i will copy this syntax now i change key to 37 which is left arrow we will check if player hasn't gone past the left edge of canvas by saying this.x is less than this dot width if player x is within canvas area and if moving is false this dot x minus equals grid and this dot moving is true same thing for right arrow key code 39 this time we are walking to the right so the plus direction on the horizontal x-axis x plus equals great and we check if this dot x is less than canvas width um canvas width minus this dot width nope still too far canvas width minus this dot width times 2. great work we have implemented keyboard controls now you can see i'm hoping around the canvas along invisible grid with cells 80 times 80 pixels i will not put limits when player moves past the top edge because that's how you score a point when the frog escapes through the forest you will see in a minute inside the custom update method on frogger class i create another if statement that says if this dot y is less than zero when the player moves past the top edge of game area we run function called scored we haven't declared it yet so in utilities.js i create a new function called scored in setup.js we created variables called score and gamespeed every time scored function runs we will increase score variable by 1 and game speed by 0.05 i will also reset the frogger to its starting position so frogger x is canvas width divided by 2 minus this dot width divided by 2 which will center it in the middle horizontally and frogger y is canvas height minus this dot height minus 40 which will position it 40 pixels from the bottom edge of canvas we didn't reset y oh it's because i need to say frogger with and frogger height since i'm referring to the frogger object from the outside i only use this keyword when i refer to it from inside of frogger class now it resets when the scored function runs what now let's create some obstacles in obstacles.js i create es6 class called obstacle with capital o constructor will expect 6 attributes x and y coordinates width and height movement speed and type you can see the syntax is slightly different than with frogger class constructor that is because we are passing all these values as attributes to the constructor from the outside so all the constructor is doing here is assigning attributes we pass to it to properties on the new blank object it creates i'm saying take x that was passed as attribute and assign it to x property on this new blank object we are creating right now obstacles will also have a custom draw method whenever i say custom i mean it's not built in javascript method so you can name it whatever you want as long as you refer to it with that name when you call it later so let's draw them on canvas one at first ctx1 i will call fill rectangle and pass it x y width and height from constructor blueprint update method will just move obstacles horizontally so this.x plus equals this.speed tans gamespeed because we want the game to speed up as the score increases the slowly increased difficulty we speed on line 32 in setup.js and it increases by 0.05 every time we score a point as declared online 25 in utilities js i cannot do plus game speed here i need to do multiplication multiplied times game speed because this dot speed can be positive or negative number because some cars are moving to the right along the horizontal x axis which is in a positive direction and some cars are moving left which is in the negative direction that's why we need to multiply times game speed to keep the same plus or minus value if we just did plus game speed and current speed was -1 we would go from negative to positive numbers and all cars would eventually start moving to the right which is not what we want we want to keep the same direction that's why we multiply here i step out of obstacles class and i create a new custom function called init obstacles here we will go lane by lane and add new obstacle objects to our cars array and log the array so for lane 1 i create a for loop that runs twice we will add two cars to cars array i call push built in array method which takes whatever we pass to it and pushes it to the end of the array so i pass it new obstacle new is a special keyword which calls class constructor on associated javascript class and creates a blank new object and assigns its values and properties as declared inside in this case on lines two to eight we can see that on line two this constructor expects six attributes x y width and height speed and type so when i call it i need to pass it these values here to handle horizontal spacing between individual cars i create a temporary led variable called x and i set it to i times 350 we are inside the for loop so i stands for zero then for one then for two as the for loop cycles so each time we generate new car its x value will be different first it's zero times 350 which is 0 then it's 1 times 350 which is 350 and so on so each time this for loop runs we push one new obstacle to cars array it expects six attributes so x will be this temporary x variable we just created y will be vertical position we are placing cars on the first plane from the bottom so y will be canvas height minus grid times two and i also have to do minus 20 because bottom margin is a bit larger to allow space for some nice roadside images later obstacle class constructor also expects width value which will be size of the grid 80 pixels and height will be great as well grid is a variable we declared in setup.js and currently it is equal to 80 pixels speed will be plus one so we will be moving to the right and type will be car we will use type later when deciding what sprites to draw so now i call init obstacles to fill array with obstacle objects for lane 1. i also have to create custom handle obstacles function which will cycle through the entire cars array so for loop here and for each object in the car's array i will call its associated update and draw methods as usual this is actually all we need to do in utilities.js inside animation loop i call handle obstacles the sequence how you call things here inside animation loop is important for things that are on the same canvas element i will call it after we draw an update frogger and we are animating two cars in lane 1. let's make them different color with fill style blue on line 23 the third value we pass to obstacle class constructor stands for width as you can see on line two so if i want to make the cars wider i can make the width this dot great times two that looks more like a car now also notice that cars drive past the right edge of canvas and never come back so on line 16 inside custom update method i say if this dot x is more than canvas width plus this.wave meaning if the car has driven past the right edge of canvas and is completely hidden now this dot x is equal to 0 minus this dot width which will reset it behind the left edge like this you can also play with these values look at what happens when i change speed here time to add more cars lane two will also have two cars so for loop that does two cycles horizontal spacing between the cars will be 300 this time cards array push and we pass it new obstacle which expects six attributes again x will be the temporary x variable from line 30 y will be canvas height minus grid times three because we have moved one lane up minus 20. with is grid times two height is great speed is two type is car we are moving to the right notice what happens when i pass negative value as speed cars start moving to the left which is great but the problem is that they don't reset anymore i have to do the reset check a little bit differently if this dot speed is more than zero which means for cars moving to the right we use this code to check if the car disappeared over the right edge and resets it behind the left edge else which means in this case speed is less than zero so for cars moving to the left if this dot x is less than 0 minus this dot waist if the car has moved past the left edge of the game area and completely disappear behind the edge we reset it by saying this.x equals canvas width it will move it behind the right edge let's add this dot width here to give the car small delay before it reappears again now we can go to init obstacles custom function and add lane 3 so again i create a for loop that will run twice every time it runs it pushes new obstacle object to cars array spacing between the cars will be 400 pixels for example and i pass it here as the initial x coordinate vertical y position will be canvas height minus grid times 4 minus 20. width will be grid height will be great speed is 2 and type is car ok let's make it wider which will be grid times 2. if you want to add a bus or truck you can also do grid times 3 here so far all three lanes had obstacles with a type of car lane 4 will be another for loop that runs twice and creates two obstacle objects horizontal spacing will be 400 pixels we are now in the river area so far we have pushed everything into cars array things that float in the river which includes logs and turtles will all go into logs array so logs array push new obstacle and since we are in the river now vertical y position will be canvas height minus grid times 5 minus 20. i always do -22 make up for the slightly increased bottom edge width will be grid times 2 height will be great speed will be -2 because the river will be flowing to the left and type of obstacle is log which means piece of wood i need to fix my syntax here i add bracket and i pass a value for x coordinate to be calculated on line 47. now i go inside custom handle obstacles function and same as i did for cars array i will call update and draw for each element inside logs array i need to do it like this in a separate for loop that cycles through the entire logs array lane five will be turtles we can hop on and they will give us a ride let's add three of them because they will be smaller and we will push them into locks array i want them to be closer together so spacing will be 200 pixels i pass our temporary x variable y position will be canvas height minus grid times 6 minus 20 width will be grid which is 80 pixels height will be great as well so we will have a square speed is 1 because turtles are slow and type will be turtle here we go we are making progress let's add another background layer i will bring all these images into the project here in setup.js as usual when i want to bring a new image onto the canvas i create a variable and i assign it to new image then i set its src property to a path to the image this depends on how you organize your folders and project structure in my case background underscore level 2 src is equal to background underscore level2.png i will provide you with some sample images in the video description or you can draw your own if you want now in utilities.js inside animation loop on canvas one so ctx1 i called built-in draw image method it has three versions we are just drawing an image that's the right size for our project so i can use the shortest one or the middle version actually i will use the middle version which takes five attributes the image you want to draw x and y coordinates and width and height of the image you can adjust and stretch the image by changing width and height values i just wanted to cover the entire canvas so width is canvas width and height is canvas height the image variable was named background underscore level 2 and i need to remove quotation marks since it's a name of a variable not a string we have two layers water layer is all the way down on the bottom this time i use css to draw it and on top of that on canvas one we have background level two which contains sideline three lanes of traffic and green riverbank on top i separated the background images mostly because i want ripples water ripples to appear on water when frog jumps over it but i don't want them to be spilling over the grass and road area with background separated like this i will be able to draw the ripples on top of river image but under the road i noticed that the green square representing our frog disappeared i will just go back to animation loop and draw the background image before i draw the frog so the frog will be drawn after on top of it now the frog is back let's hide the obstacles for a while by commenting out handle obstacles in animation loop inside utilities.js file now i can see the road so we can draw some dust particles i will bring another image to the canvas ideally all these images will be on a single sprite sheet but i don't want to make this tutorial any longer by showing you how to do that in photoshop i will show you next time so i create another variable called grass and i set it equal to new image this will be the top environmental layer the image contains grass on the bottom and tree canopy with shadow in the top right corner so i say grass src is passed to the image in my case grass png because the image and this javascript file are both in the same folder in utilities.js inside animation loop i bring the image into the project again by using built-in draw image method this time we will draw it on canvas 4 so it's on top and image variable is called grass as we just declared in setup.js you can see that frog is now under grass and under the tree and and even the shadow of the tree is cast on our frog when we are by the edge now to draw the dust particles when frog is hopping over dry road in particles.js i create javascript class called particle with a capital p we will use this to build many similar particle data objects and push them into particles array so we can use that information to draw them on canvas constructor will always run once for each particle at the point when it is called with the new keyword it will hold blueprint information and based on this it will just create each randomized particle this time constructor will expect two arguments for x and y position we need to pass that from the outside because we want x and y coordinates to always be under the frog as it moves around so when we call it we will pass it fox current x and y from the outside then i just tell constructor x coordinate property on this object you are creating right now is equal to x that was passed as an argument same for this dot y this.radius on the other hand will be randomized internally here inside the constructor radius will determine size of particles i want it to be a random number between 1 and 20. particles will also slowly fade so we will need opacity property at first i set it to 1. i also want the particles to slowly spread from under the frog in random directions to give them random direction of movement i need to specify how i want them to move along horizontal and vertical axis so direction x will determine random horizontal movement speed for each particle it will be a random number between minus 0.5 and plus 0.5 minus numbers will make particles go to the left plus numbers will make them slowly drift to the right from their original position which is under the frog i do the same thing for vertical y axis minus numbers will make particles move up plus numbers will make the particles go down i create another custom method i call draw its job will be just to take values for each particle and draw a circle there particles will be drawn under the frog so let's try ctx3 and draw them on canvas three and for fill style i use rgba color declaration where the last fourth value is for alpha opacity when you want to draw a circle on canvas first you need to call begin path think of it as a pencil touching down on canvas to start a drawing built in canvas arc method will draw a circular path based on angles we pass to it as arguments so i pass it x and y coordinates radius start angle and end angle these specific values for start angle and angle will draw a circle i call ctx fill to fill the path with color and i close path custom method i call for example update will run every frame and it will move particles along x and y axis based on values in direction x and direction y variables this could be positive or negative number as declared on line 7 and 8 so particles will slowly drift in random directions away from the frog i step outside particle class and on the top level i create a custom function i call handle particles inside i create a for loop that will cycle through the entire length of particles array for each particle we will call its update method to calculate current position for each frame of animation and draw method to draw a circle there at this point particle's array is still empty i only want dust particles to appear when the frog jumps around so outside the for loop i create an if statement that checks if keys 37 38 39 or 40 were pressed these are keyboard arrow keys if any of these keys are pressed it means the frog is moving at the same time i only want the dust particles to appear over the road not when we hop over the river so i also check if frogger y vertical position is more than 100 and for performance reasons i don't want to have more than 200 dust particles in my particles array so i check if length is less than 200 if all of these conditions are met we enter the if statement and create a for loop that will run let's say 10 times each time it runs we call unshift built-in array method on particles array unshift method takes whatever we pass to it in brackets as attributes and places that to the beginning of the array we call it on so i pass new particle the new keyword which is a special command in javascript and it will go to line 2 and run code inside particle class constructor constructor's job is to create one new blank object and assign it properties and values based on information we specified between lines 3 and 8. and this is how javascript esx classes work that's all you can now see on line two that our particle class constructor expects two arguments for x and y coordinates so down here on line 32 i pass it frogger x and frogger y because i want all the new dust particles to appear wherever the frog is jumping at the moment to run this code i go to utilities.js file and i add handleparticles function we just created inside the animation loop so it will run for every frame of animation over and over it kind of works you can notice a couple of things first of all new particles appear in the top left corner of the frog not in the middle also once we reach 200 particles new particles are not appearing anymore because we reached the limit to fix that i go to particles.js again and inside handleparticle's custom function i create another if statement i check if particle's array length is more than max particles mux particles is a variable i declared on line 35 in setup.js file and it is currently set to 300. if particles array is more than 300 particles we create a for loop that runs 30 times and each time it runs we call pop built-in array method on the array pop method just remove the last item from the array so here i am saying if we have more than 300 particles remove 30 particles in one go for this to work i also need to change condition on line 35 which currently adds new particles only if particles array is less than 200 i change it and i say only add new particles if particles array length is less than max particles plus 10. we want to have a little space there you'll see why in a minute i move this if statement back outside as it was before it should work now yes so now every time frog moves we are adding 10 new particles on line 35 and if we have more than 300 particles we are also removing 30 old ones on line 29 i want the particles to first appear exactly in the center under the frog their initial position is wherever frog is at the moment as we pass it to the new particles constructor frog takes up rectangular area and rectangles on canvas are drawn from the top right corner declared by x and y coordinates going to the right down as declared by object's width and height that's why i can adjust these values here on lines 3 and 4 by adding some value to x and y property to push the center point where particles spawn a little bit to the right and a little bit down i also want particles to slowly become invisible for that i will use opacity property i declared on line 6. on line 11 where we set fill style color for particles i will just change rgba color declaration slightly and instead of having fixed opacity value here i use string concatenation to add dynamic variable from line 6 into the color declaration now it's dynamic and i can manipulate it with javascript in update method for every frame from each particle's first appearance as long as its opacity is still more than 0.1 i will reduce its opacity by 0.9 i need to do this as an if statement because if i accidentally make opacity go to negative numbers we will get an error and entire game will stop these numbers will have to be tweaked the way it is now it just jumps straight from 1 to 0.1 immediately that's wrong i also want to reduce radius so as long as the radius is more than 0.15 for every frame of animation reduce the radius by 0.14 same thing like with opacity we need to make sure we never get negative numbers radius otherwise we will get an error i can also see we are generating dust particles over water i can calculate exactly at what vertical coordinate i want to stop drawing them but i think it will work if i just change it like this a 100 to 250 yes it works only generate dust particles if frog's current position is more than 250 pixels from the top i also want to create water ripples when we move over water inside handle particles i create another if statement again i check if any arrow keys were pressed which means frog is movement so key 37 38 39 or 40. at the same time i only want to create ripples if frog is moving over the river so frogger y is less than 250 pixels from the top inside the if statement i create a for loop that will cycle 20 times and we will call unshift this time on ripple's array which will store our water ripple particles and shift takes whatever we pass to it and places that in the beginning of the array we call it on so i pass it new particle which we'll call particle class constructor on line two it expects two attributes i want the ripples to start under the frog so again i pass it frogger x and frog y as coordinates i originally created ripples.js file but now i'm thinking we will just do all of this here in particles.js i will need the same functionality here we have four dust particles so i copy for loop that cycles through the array and calls update and draw method and i also copy the if statement that checks if we have more than 300 particles and if so it removes the old ones using arraypop method i change all references to particles array and replace them with ripples array and i also change max particles which we set to 300 and i replace it with number 20. we don't need that many ripples so now on line 48 for loop cycles through ripple's array and calls our custom update and draw on line 52 if we have more than 20 ripples we remove 30 old ones on line 58 we check if arrow keys are pressed and if frog is over the river and if so we add 20 new ripples to the array i might have to adjust these numbers later i will see how it works out i'm getting an error because here on line 60 i call new ripple but it's actually new particle because that's what i called the javascript class here on line 1. now it works we of course don't want water ripples to appear the same and have the same behavior like dust so i will have to create another custom method on particle class called ripple which will replace update method i want the water ripples to start small and grow until they reach certain size if this dot radius is less than 50 this is the radius plus equals 0.5 if i do that the circle will grow just to the one side i want it to grow from the center so i also have to be pushing it slightly to the left and up by saying this dot y minus equals 0.1 this dot x minus equals 0.1 and as i said in the beginning some animations and transitions you get built in with css you actually have to build manually with canvas maybe there's a better way to do this i can't think of it now but this will work another if statement where we check if opacity is more than zero we decrease it by a very small amount so our white ripples slowly disappear on line 58 instead of calling update method which handles dust particles i call ripple method we have just created we are getting there we are still using the same draw method we used to draw dust to draw water ripples that's why you see circles filled with a gray color i will have to create different version of this method so new custom class method called draw ripples let's change rgba color declaration to white now i go down to line 67 and instead of draw method we use the draw dust i will call draw ripple it is fill in circles but i actually only want to stroke it so on line 31 i change fill to stroke and on line 28 i change fill style to stroke style i will go to utilities js and move handle particles after frogger draw so we see the ripples on top of the frog and i can center it better back in particles.js i change ctx3 to ctx1 it doesn't place particles back under the frog which is a drone on canvas 3 so now i know there is an error somewhere with canvas layers and how they are stacked on top of each other i will find it but for now let's just make sure the ripple circles are centered i will change values here on lines 37 and 38 get in there how about these values let's use even smaller numbers it's starting to look all right on line 70 i reduce the number of ripples we remove down to five maybe even less on line 41 i increase how fast we reduce opacity to make the ripples disappear faster i kind of like these values of course i don't want ripples on the riverbank so on line 75 where i check if frogger's current position is less than 250 i also check if it is more than 120 maybe no 100 will work yay we have ripples as we jump over water you can see the ripples spill over the riverbank and road even though i draw them on canvas one which should be at the bottom of our canvas stack under the road image so where is the bug if i go to animation loop and i draw background level 2 after handled particles water ripples work well but the dust particles disappear so i assume they are now drawn under the road image our layers don't stack properly i will find the back eventually let's just continue i will clear all five canvases between every frame of animation this is not necessary for parts of the game that don't need to be redrawn when they don't animate i will show you some optimization techniques for this later on line 42 in particle.js file i slightly increase this number to make ripples disappear faster just for clarity i'm going to separate handle particles into two functions handle particles will take care of dust and handle ripples will contain code that manages water ripples animation in utilities js inside animation loop i will call handle ripples which are drawn on canvas 1 then i draw a background level 2 image which contains road and riverbank and then i call handle particles to draw dust on canvas 3. if i do this the layers stack properly but reorganize an order in which you draw things here in animate function should only be necessary if you draw everything on the same canvas which we don't we have five canvas elements so order here should be irrelevant it is not irrelevant so it means i made a small mistake in setup.js and i am drawing everything on canvas one somehow in utilities js on line 14 i uncomment handle obstacles to make cars locks and turtles visible again sorry my screen recorder froze so i have uncommented line 14 in utilities.js and obstacles are now visible in setup.js on lines 2 7 12 17 and 22 i am assigning all context to the same canvas variable declared on line 1. i can't do that i need to assign context to each individual canvas like this now we fixed our strange stacking issue everything works yay i will draw obstacles on canvas 3 so it is visible over the road image i'm drawing on canvas too time to start counting score in utilities.js i create a custom function called handle scoreboard it will be on the top layer so canvas 4 ctx4 fill style will be black and font let's say 15 pixels verdana i will try stroke text and i want to outline word score at coordinates 265 and 15 which should be roughly in the center so i will also declare stroke style and i set it to black all i have to do to draw it is to call handle scoreboard inside animation loop up here for the actual score number i will change font to 60 pixels verdana and this time i will call fill text i want the text to take value from score variable we declared on line 29 in setup js and x and y coordinate will be maybe 270 from the left on the x-axis and 65 from the top on the y-axis now i make the font smaller again 15 pixels verdana and i will stroke text that says collisions and i concatenate value from collisions count variable at coordinates 10 and 175 this will show how many times we were hit by a car or fell into deep water it's a bit strange that frog in this game can't swim but i didn't make the rules i will also display current game speed using game speed variable we declared in setup.js and i draw this text at coordinates 10 and 195. in frogger.js on line 38 there is this small if statement that says if this dot y is less than zero meaning if frog jumps past the top edge of game canvas run custom function i called score that function is declared here on line 34 in utilities js and every time it runs it increases score by one increases game speed slightly and resets frogger to the starting x and y coordinates we can see it works but gamespeed is giving us a very long number i can change that by calling two fixed built-in javascript method and i pass it one doing this gamespeed will only show one number after the decimal point like this much better every time gamespeed variable increases it increases movement speed of cars floating locks and swim in turtles because we are multiplying their x horizontal position by game speed inside obstacles js on line 15. i can test if it works by manually changing value in gamespeak variable online 32 in setup.js file right now we can just jump through cars and nothing happens let's set up collision detection everything is a rectangle so today we will do collision detection between two rectangles i will make it into a reusable function a little bit of functional programming can be good since we do so much object-oriented programming with all these classes and particles so the idea is that we have a reusable function that takes two arguments first and second so for example frogger will be first and car one in obstacles array will be second then we will just run this for the entire car's array and we check if frogger collides with any of the cars i want the function just to return true or false and since we are checking collision between two squares i can do this thing where i first check for scenarios where i know for sure that these two rectangles don't collide and i return opposite of that by using exclamation mark let's just write this out first it's much easier than it sounds i will explain it once we write it if first dot x is more than second dot x plus second dot width i note that the rectangles are far enough on the horizontal x-axis and i know for sure they don't collide that's all i need to check if this condition is true i already know there is no collision so i don't even need to check the rest also when first dot x plus first dot wave is less than second x i also know they don't collide and i don't need to check anything else or when first dot y is more than second dot y plus second height also there can never be collision or when first dot y plus first dot height is less than second dot y if any one of these four statements is true our collision function will be true but i am using exclamation mark on line 55 to turn it into false because or operator will just return true if any one of the statements involved are true if any one of these statements are true it means there is no collision so we want our collision function to return false that's why i'm using exclamation mark to return the opposite on the other hand if all of these four checks return false it means the two rectangles are overlapping the function will want to return false but i am converting it to true by using exclamation mark so collision will return true sorry double negative sometimes takes a bit of concentration to realize what's going on so let me say the same thing again using different words if any single one of these four statements is true we know for sure the rectangles are not overlapping or operator will return true and we turn it to false with exclamation mark because they are not overlapping so we want collision to return false on the other hand if all of these four checks are false we know implicitly that these two rectangles must overlap because otherwise one of these statements would be true if they were not overlapping if all four are false we know we do have a collision the statement wants to return false but i convert it to true use an exclamation mark and our collision function returns true this is a really great way to do reusable collision detection if you get this you will become really efficient game developer maybe you want to re-watch the last minute of the video it helps to hear it again for this to work as a reusable function the objects you compare as first and second need to have x y width and height properties associated with them so keep that in mind obstacles and frogger have these attributes as you can check in their constructor methods i can now use the collision function we declared i need to run it for every frame of animation so for example here in obstacle js inside handle obstacles i check for collision with cars by creating a for loop that cycles through the entire cars array and i say if collision between frogger and cars 1 cars 2 cars 3 as the for loop goes if the collision returns true we will draw collision image i have it on sprite sheet so i will need to use the longest version of draw image method i had an entire episode about this but i will explain it again right now a bit faster the first attribute is the image you want to draw i haven't declared it yet but i will call it collisions the next four attributes are area from the source image you want to crop out so source x source y source width and source height i know my sprite sheet is 100 times 100 so the image is second from the top so x is zero y is a hundred width is hundred height is hundred and the last four attributes are where on canvas you want to draw that cropped out image i want it drawn uh wherever the frog is at the moment when it collides so frogger x frog y and i scale it down to the size of 50 times 50 pixels for width and height so if collision between frogger and car occurs draw the second image from collision sprite sheet where the frog is right now and then we call custom reset function which will reset our game i need to bring that image into the project so in setup.js i create a variable i call collisions and i set it equal to new image collisions src is collision png you can get sample image in video description or you can draw your own now i refresh the game in utilities.js i create a custom function called reset game when frog gets hit by a car or falls into deep water i want to reset its x and y to the starting position i can just copy that from scored function i'll also reset score back to zero increase collision count variable by one and return game speed back to one now when frog gets hit by a car collision image quickly flashes before the frog gets reset you can also see i have another image we can use when frog falls into deep water it's time to replace the blue rectangles that represent cars locks and turtles with images and animated sprites i will use sprites for turtles because they move their flippers as they swim locks and cars will be static images but you can use the same technique and add animations to them as well if you want in obstacles js on line 11 inside custom draw method i say if this dot type triple equals turtle we pass this dot type as the last attribute to our obstacle class constructor it's either a car lock or turtle this is what we need that property for to differentiate between cars logs and turtles i could have also just do something like 1 2 3 but this is easier to read and understand if this dot type is turtle on canvas 1 we call draw image in setup.js i will bring new sprite sheet into the project cons turtle equals new image turtle src is turtle png it will be a simple sprite sheet with two animation frames and four different colors for turtles while we are here i can also bring the log image here and cars as well ideally all this would be in a single sprite sheet i will show you how to merge images and map sprite sheets in some later episode i will also create a variable called number of cars and i set it to the number of rows we have in the car sprite sheet we'll use this to randomize what car appears when they reset when they move past the edge and come again back to obstacles js on line 12 i want to draw an anime turtle from the sprite sheet again the longest version of draw image built in method it takes 9 attributes image you want to draw 4 attributes for the area you want to crop out from the source sprite sheet and another attribute to specify where on destination canvas you want to draw that cropped out image onto i'll also call fill rectangles so we can see if hitbox area matches the image to make sure when we jump on the turtle we don't fall into the water i will call fill rectangle before i call draw image so it will be under the turtle image i can see the turtle spreadsheet i'm using is 140 pixels wide with two columns 140 divided by 2 is 70 and height is 280 pixels with 4 rows 280 divided by 4 is also 70 so one frame is 70 times 70 pixels so in draw method i crop out rectangular area from the source sprite sheet at 0 0 coordinates going to 7070 this will crop out one frame the one frame from the top left corner the last four attributes are where on the destination canvas i want to draw that cropped out frame onto so i just want to draw it wherever the turtle is swimming at the moment so this dot x this dot y this is not waste and distal height i comment out lines 15 and 16 to only show turtles we are still not drawing them in setup.js online 51 the name of turtle's sprite sheet is actually turtles.png and i misspelled src yes in obstacles class constructor i will add two more properties that will help us to navigate within the sprite sheet as usual this dot frame x will be x coordinate of cropped out frame frame y will be vertical y coordinate on a line 15 inside raw image method instead of hard coding coordinates 0 0 which always give us top left image i will set x coordinate the distort frame times 70 and y coordinate to be this dot frame times 70. if this dot frame x is more than one set it back to zero we will just cycle between frame one and zero horizontally else this dot frame x plus plus now our turtles are animated but you can see they all move at the same time which looks very robotic to desynchronize them i can create another variable called randomize and i set it to random number between 30 and 60. and i use math.floor because i don't want decimal points in setup js on line 31 we have a variable called frame so in utility gs i go inside animation loop and i increase frame variable by 1 every time the loop runs now i can use this in obstacles js on line 15 i say if frame modulus 10 is 0 only then increase frame x modules operator gives you remainder so for example if frame is 12 then frame modulus 10 will be 2 because 12 divided by 10 is 1 and 2 is the remainder basically i'm saying do this every 10 frames actually this code needs to be outside the if statement i can remove the black rectangle now now the turtle frames animate every 10 frames here on line 10 we have our randomized variable which is a random number between 30 and 60. on line 15 i replace 10 with this.randomize and now each turtle will move its flippers at different pace on line 20 i say else if this dot type is log this time we have just a single log image so i can just use shorter version of draw image method the first attribute is image we want to draw so log as we declared it on line 54 in setup.js file and the next four attributes are just x y width and height so i take that from the obstacle object that was easy now we draw the cars i say else meaning if type is the last remaining option which is car i call draw image built-in method again car variable is the image we want to draw as we declared in setup.js it will not animate but we want to pick up random car from a big sprite sheet full of cars so same as we did for turtles i will use the longest version of draw image method let's just scrop out one frame at first to see how it works x and y is 0 0 width is grid times 2 and height is great these values depend on what size is your sprite sheet you are using my sprite sheet is exactly the right size we need so i didn't have to calculate frame size here the next four values determine where you want to draw it so that's this dot x this.y this dot within this.height nice i want to pick a random car from the sprite sheet so i create a new variable called car type and it will be a random number between 0 and number of cars variable we declared in setup.js on line 58. this will be the number of rows in our sprite sheet so in this case i put number three because the first row is zero so zero one two actually i will put down number three because we will use math.floor which will round it down in obstacles js on line 24 i leave x as zero and y coordinate will be dot card type which is at the moment a random whole integer between 0 and 2 times this dot height height of the grid is 80 so y coordinate will be 0 or 80 or 160. now we are copying out random cars you can see that the middle lane of cars is going backwards that's why i need the second column in my sprite sheet for cars facing the other way on line 31 where we check if this dot speed is more than zero i also set this dot frame to 1. then on line 24 i can say that x coordinate we crop out from the source sprite sheet will be this dot frame x times this dot width now we have all the cards going backwards i actually need to set this.frame to 1 for cars with speed less than 0. those are the cars moving left along the horizontal x axis that's it nice on line 32 we check if obstacles move past the right edge of canvas i will also randomize car type so every time car moves off screen it will randomly pick different car from the sprite sheet before it appears again i do the same for cars that move past the left edge by adding the same line of code to line 40. you can add more cards to your sprite sheet i might show you how to do that in photoshop a bit later on line 24 i will draw a black rectangle under the cars just to check the collision area it needs to match the image of the car as closely as possible we don't want the frog to be hit by invisible margin around the car i think this is good we are moving on the grid so it will work i also need to write code for collision with locks and turtles it will work differently because we need to jump on the log to get across the river first i check if the frog is in the river area we don't need to run collision detection with locks and turtles if we know frogger is not moving over the water so only if frogger y is less than 250 and more than 100 i go to setup.js and on line 33 i declare a global variable called save and i initially set it to false frog will be only safe if it's colliding with log or turtle otherwise we assume it fell into deep water back in obstacles.js i set save to false in case it was set to true somewhere else then i run a for loop that will cycle through the entire logs array which holds our locks and turtle objects for every element in the array same as we did for cars i will run custom collision detection function we wrote earlier we want the frog to be able to write on floating objects to be attached to them i say if rock collides with analog or turtle start adding speed of that particular log it's colliding with to frog's current horizontal x position small mistake on line 92 i run this code when frogger y is less than 250. yes now we can ride around on locks and turtles i also set save to true to make sure the game resets when we fall in deep order i say if save is false call custom reset function we wrote earlier also i feel there should be water ripple animation when we sync so i just create a for loop that will add let's say 30 ripples i do the same thing we did before by calling unshift on ripple's array a new particle and i pass it for greg's and for the y coordinates to tell it where i want to draw it that works well done what happens if i sit on the lock too long and it takes me off screen okay good the game resets as well that's perfect let's replace the green square with frog from a sprite sheet in frogger.js down on line 41 inside custom draw method i call draw image and i pass it frogger i haven't declared that yet so in setup.js i bring progress sprite sheet image into our project const frogger sprite is new image i can't just call it frogger because i use that variable name for frogger data object already frogger sprite src is equal to frogger png in frogger.js on line 44 i pass 0 0 and xy coordinates for frame we want to crop out from the source sprite sheet we also have sprite width and sprite height variables we declared before so i use these here for width and height in setup gs on 962 i need to make sure the path and name of my sprite sheet is correct i actually named it frog underscore sprite sheet and in frogger.js inside draw image method i need to replace frogger with progress pride because that's how i named my image variable we are drawing something in the top left corner of canvas i need to add four more properties and use the longest version of draw image method so that javascript understands i want to crop out one frame only the longest version of draw image method takes nine attributes image you want to draw is the first one then the next four specify what area you want to crop out from the source sprite sheet and the last four are where you want to place that cropped out image on canvas i just want to place it at wherever the frog is at the moment so this.x this.y this.width and this.height it's very small so we can scale the spritesheet by changing the last two values if i say this.with times 2 it will stretch it horizontally but if i also say this at high times 2 i successfully scaled it you have to be careful when you do this because scaling the sprite usually moves it outside its collision detection area in games this is also called the hit box i uncomment line 43 so we can see the green rectangle which represents the object we run collision detection for so we need to make sure frog image is aligned over that area as closely as possible i will move it 25 pixels to the left horizontally by saying this dot x minus 25 and also vertically this dot y minus 25 now it's aligned i just want to make the frame dynamic depending on frog movement so instead of hard coding x and y coordinates we crop out from the source image to zero zero i change x coordinate we crop out to this dot frame x times this dot sprite width i also change y grouping coordinate to this dot frame y times this dot sprite height now up here in update method where we check if key 38 which is an up arrow key was pressed i want frame x to be one which is the image of frog jumping up frame y will be 0 to give us the first row on line 47 inside custom jump method i say if this dot moving is false this dot frame x equals one else if this dot frame x is one this dot frame x is zero i just want the jump animation frame to quickly flash i'm not happy with this let's see in update method if down arrow key is pressed i set this dot frame y to 3 because that's the bottom row in the sprite sheet and we count from 0. left movement will have this dot frame y equal to two and right movement will show the second row so number one because we start counting from zero because image is cropped out from the top left corner of cropping area now we can move in all directions and the frock is correctly facing that way i can remove the green rectangle under the frog by removing fill rectangles from draw method on line 46 also in obstacles js i can remove black rectangle from under the cards by removing fill rectangle call online 24. this is a long video let me just hack it in utilities.js line 33 whenever key up event fires i will set frogger frame x to zero and it works there is of course much better way to do this i might release a second part where we optimize this code add more graphical effects easter eggs and maybe some more game mechanics if you want the challenge you can try and draw a shadow under the frog when it hops over road and the riverbank or you can take an image of star or crown and draw it on frog's head when it reaches score over 20. you can also add water jets on turtles because at that point there will be moving quite fast little hint on how to do this is just to go to draw method where we draw frog or turtle and right after draw image you place an if statement that checks what the current score is if the score is over 20 it draws a particular image on top of rock or turtle at their specific coordinates so you pass it this dot x this dot y you might have to adjust the size and coordinates slightly for it to look good and fit well with the underlying image like we did when adjusting frog hitbox area we can also introduce other features like random shadow flying overhead you have to hide from dangerous creatures swimming underwater we can add more cars different skins for our frog and so on if you want me to show you how to do all of this let me know and i will do a part two also if you did code along well done this was a long video let me know in the comments if you finished the tutorial i'm not sure if this is too long or if some of you like more complex fun projects like this did you try to add any additional features to the game what other projects are you working on anything interesting let's discuss all of that in the comment section down below click the like please see you next time
Info
Channel: Franks laboratory
Views: 21,972
Rating: undefined out of 5
Keywords: Learn JavaScript By Building Games, How To Make A Game With Vanilla JS, how to make a game with javascript, how to build a game with javascript, vanilla javascript, franks laboratory, how to make a game, javascript tutorial, web development, javascript project, html canvas, canvas, html5 canvas, javascript animation, creative coding, html tutorial, frogger
Id: GXvNEwu9cgM
Channel Id: undefined
Length: 78min 35sec (4715 seconds)
Published: Sat Jul 25 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.