JavaScript Game Development Crash Course

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
we wanted to build awesome games and master front and web development at the same time in this final javascript and html5 canvas game tutorial i want to show you five techniques i wish i used sooner today we will build a game completely from scratch step by step with no frameworks and no libraries we will learn how to achieve pixel perfect collision detection using colors how to use time stamps and delta time to make sure our game runs at the same speed on different machines we will learn about arrays and i will show you how to remove all the game objects using array filter method and how to use array sort method to create a correct draw order in a 2d game we will also talk about modern javascript syntax and we will learn how to make our animation code cleaner and less repetitive with spread operator i will also share many small tips and tricks as we go along students of today's course will get two premium sprite sheets completely for free kindly provided by this amazing artist check out his website for more click the like please if you are excited and ready to learn let's talk about javascript have fun i want you to build projects you can show off to someone and be proud about so as usual we will build a game and by the end of this tutorial you will have a complete project i learned some of these techniques from my friend raju he has a lot of other cool things to teach you if you want you can go and check out his courses i will link some in the video description some of you tell me that you only make games by animating diffs and other html elements it's a great way to start and learn the basics html canvas can handle many more moving objects at the same time so if you want to try and build games that have a little bit more complexity maybe this is the time for you to give canvas a chance let me show you it is easier than you think to build interactive animated projects with it i will take you through it step by step and help you understand i have a introductory game development series and a beginner playlist where i go slower over all the important techniques if you find yourself struggling at some point or you think i'm going a bit too fast maybe try to watch that one first over there we also create really cool projects but i keep beginners in mind at all times it might be an easier starting point for you and then you will be ready to take on videos like this one and actually properly understand everything i will leave some links in the video description let's go [Music] let's create some ravens i will have an array that will hold all my raven objects it needs to be a led variable not const i will explain why in a minute i create a custom class called raven it will be a blueprint based on which all my animated ravens will be created by javascript constructor will create one blank new object every time it is called and it will assign it properties and values as we define them here it will have width property and its value will be for example 100 pixels height will be 50 pixels this dot x starting horizontal x coordinate will be just behind the right edge of canvas so they can fly across to the left so canvas width vertical y-coordinate will be a random number between 0 and canvas height since rectangles on canvas are drawn from the top left corner going right and down i don't want any ravens to be partially hidden below the bottom edge of screen initial y position will be a random number between 0 and canvas height minus the height of a raven between here and somewhere around here it needs to be in brackets like this to give us the correct range of values direction x will be horizontal speed basically it will be a random number between a 3 and 8. i want ravens to bounce up and down as they fly so the initial vertical speed i call direction y for example will be a random number between minus 2.5 and plus 2.5 minus values will move upwards plus values will move the raven down along the vertical y-axis update method will move the raven around and adjust any values that needs to be adjusted before we draw the next frame at first i will just simply move it to the left so this dot x from line 11 minus equals this direction x from line 13. draw message will take these updated values and any drawing code we put here will represent single raven object visually first let's start with a simple rectangle i call build in fill rectangle method and i pass it x y width and height raven class is complete we have a way to create ravens let's create animation loop i create a custom function i call for example animate it will take argument i call timestamp this will be a numeric value in milliseconds so one second will be number 1000 i will show you exactly how it works any code inside this animate function will run over and over updating and drawing our game frame by frame the first thing we will do between every frame is clear old paint all the drawings from the previous frame so clear rectangle and i want to clear the entire canvas from coordinates 0 0 to coordinates canvas with canvas height we will run some code in between and then at the end we will use request animation frame method that we'll call animate again create an endless animation loop i will console.log test to make sure it works and i also need to call animate like this on the first page load to trigger the first loop in browser console i can see the loop is running perfect it's good to test your code as you go to make sure there are no typos it's safer than to write the entire project and then try to look for bugs there step by step approach will save you a lot of time i can also test if my raven class is working i will use it to create many ravens but i can also just create one i create a variable called raven and i assign it to new raven like this this will create one raven object for me which will have access to update class method from line 16 and draw method from line 19. i call it from inside my animation loop and here's my raven it just flies over once if i refresh the page it flies again this works so far we are doing great instead of having one raven i want to create a new raven periodically and i want to make sure that periodic event is triggered at the same interval on very slow old computers and on brand new gaming super pcs to make sure the timings in my game are consistent and based on time in milliseconds rather than on the power of my computer and its ability to serve frames at a certain speed i will use time stamps i will compare how many milliseconds elapsed since the last loop and only when we reach certain amount of time between frames only then we will draw the next frame it's actually very simple but it might take some time to get used to it if you are a beginner let's do it and see how it works what is happening here we are calling animate using request animation frame animate becomes a callback function on request animation frame method and default javascript behavior for callback here is to pass it automatic timestamp as an argument its value is in milliseconds just so you know where this timestamp will be coming from it's a default javascript behavior when using request animation frame it will pass its callback function in our case animate automatic timestamp argument we will see it better in a minute as the loop runs request animation frame calls animate over and over passing it timestamps my goal here is to take time from the current loop save that value run the loop again with a new timestamp value and compare them to see how many milliseconds it took in between frames i will need some helper variables here time to next raven will be a variable that will accumulate millisecond values between frames until it reaches my interval value and trigger next frame initially it will start at 0. raven interval will be a value in milliseconds every time time to next raven accumulates enough to reach 500 milliseconds it will trigger next raven and it will reset back to 0 to start counting again i will also need variable that will hold value of timestamp from the previous loop the initial value will be 0. inside my animation loop i will calculate delta time this will be a value in milliseconds between timestamp from this loop and saved timestamp value from the previous loop after i used the last time value to calculate delta time i will assign last time variable from line 8 to the new timestamp passed here in this loop so that we have that value ready to compare in the next loop let's console timestamp i can see i misspelled last time here capitalization of letters is very important in javascript you can see in console i'm getting timestamps in milliseconds since the loop started the very first value is a second so it goes like this 7 8 seconds and so on so this is the automatically passed timestamp value here it's generated by default by javascript because we made animate into a callback function on requestanimationframe method here on line 33. there is a way to do this without calculating delta time at all but i haven't tested that and i'm not sure what is the browser support for that technique so let's go with this tested safer solution today i will remove console.log leaving too many console logs in your projects especially the ones running so often like this can affect your performance so keep that in mind on line 6 i have time to next raven variable here in my animation loop i will increase its value by delta time for every animation frame i will console log delta time now again i need to be careful about spelling my variables correctly here i can see that on my computer time between frames is around 16 milliseconds my computer is powerful and it is able to serve a new frame every 16 milliseconds on your computer the number might be different i would actually be very interested to know if it's the same number or a different one for most of you if you are following and coding with me can you leave a quick comment with that number please you can just type 16 if it's the same number or whatever different number you are getting right now so time to next raven starts at zero and is increasing by this value of around 16 milliseconds per each frame on line 7 i created a variable called raven interval and i set it to 500 milliseconds in my animation loop i will say when time to next raven reaches this raven interval when this number that starts at 0 and increases by the amount of milliseconds that happened between frames reaches 500 at that point we will take raven's array from line 10 and use built-in array push method i will pass it new raven which will trigger my raven class constructor create one new raven object and it will push it inside raven's array when that happens i set time to next raven back to zero so it can start counting again from the beginning i know i just said raven a lot time to next raven starts at 0 it increases by the amount of delta time by the amount of milliseconds between each frame which will be dependent on performance of your computer however since slower computers will take longer to serve the next frame their delta time will be a higher number and it will move towards our target raven interval in bigger steps as a result this code will be triggered at the exactly same time on slow and fast computers this is one way how you can properly trigger periodic events in your projects using time stamps this might be a bit too much to wrap your head around if you are a beginner it's one of the reasons i don't always use timestamps in my animation tutorials because i can't really explain all of this in every single video but try to learn it if you can if you still don't get it don't worry i will explain it in future projects again so eventually it will start making more sense repetition and practice is the best way to learn at least for me it is i console cravens and i see nothing is happening even though my animation loop is running it seems that this if statement never evaluates the true so the code inside is never triggered control lock is great for debugging i console time to next raven first oh i can see its value is a non not a number here's our problem why is it this value it must be because we are adding delta time to it here i consolidate delta time and i can see that the first initial value is also not a number delta time is calculated here on line 30 so now i console log timestamp and this is the root of our problem that cascaded all the way through my variables that use each other to calculate their values when the animate loop starts the very first timestamp is undefined because timestamp only gets created on the second loop here on line 39 when we call request animation frame to fix that is easy i just need to give timestamp a starting value on the first call of animate that starts my animation loop here i will pass it timestamp of 0 as an argument awesome that fixed it and since i'm consoling raven's array on line 36 i can see it adds new raven object to the array every 500 milliseconds i remove the console.log we have data for ravens inside the array we just need to cycle through that array through every single raven object and call their update and draw methods so that we can actually see movement on canvas i declared my ravens array here on line 10. inside animation loop i will use this syntax which might be a bit unusual for you here i'm creating so-called array literal by just dropping square brackets like that i'm creating a quick new array on the fly and these three dots are so called spread operator now i'm spreading my ravens array inside this new quick array i just created spread operator allows us to spread iterable such as this ravens array to be expanded into another array let's finish writing this line of code and i will explain why i'm doing that since we are dealing with an array i can call built in array for each method i need to assign it a variable name for each object in this array so we can use it as we iterate as we cycle through it i will call that variable for example object so this object variable now represents each individual raven object in raven's array and i can say for each raven object in raven's array call their associated update method we wrote on line 20. so this line of code will cycle through the entire ravens array and it will trigger update method on all of them since we are inside animation loop this will happen over and over for each animation frame i will do exactly the same thing for draw method from line 23 and we are updating and drawing our ravens awesome now you might ask why am i using this fancy syntax here where i created a new array and i use the spread operator to expand my ravens into that new array just so that i can call update and draw on them i could have just called it on the raven's array directly without expanding it like this the reason i did that is because when i create particle class in a minute i can just spread my particles into the same array along with the ravens as long as my particle class will have update and draw methods to call the code will work and i can call all my classes by just expanding more and more arrays in here i can for example also have an array of enemies obstacles power ups and other elements in my game i can spread all of them into a single array and call their update and draw methods all at once i will show you exactly what that looks like in a minute i think it makes the code look clean and easy to read what do you think on line 34 i'm periodically adding new object into raven's array right now it's an endlessly growing array of objects and on lines 37 and 38 i'm iterating over all of them even the ones that have moved off screen and are not visible anymore eventually this would build up and cause performance issues so i need a way to remove the ones that have moved past the left edge of game area sometimes i use array splice method to do that i used splice in many other tutorials before but there might be a better way to do it using splice while cycling through the array removes objects from somewhere in the middle of the array so then we have to write code to adjust the index to make sure neighbors of that object don't get skipped easier way to discard objects we don't need might be using built-in array filter method we will just run through the array call update and draw for each raven and then we will filter out ravens that have moved past the left edge of screen what does that look like in javascript let me show you i create a new class property called marked for deletion and initially i set it to false in update method i say if horizontal x-coordinate of this particular raven object is less than 0 minus this dot width meaning it has moved all the way behind the left edge i set its marked for deletion property to true inside animation loop i take the variable that holds my raven's array from line 10 and i reassign it to a new array that's why the initial declaration of raven's array needs to be a led variable not const because const variable cannot be reassigned it will be the same array but objects that have marked for deletion property set to true will be filtered out filter method creates a new array with all elements that pass the test implemented by provided function so here i'm saying take raven's variable from line 10 and replace it with the same array but i wanted that array to be filled only with objects for which this condition is true here we have a little bit of double negative sorry the test in my callback function wants marked for deletion value to be false if marked for deletion is false then this condition evaluates as true and this particular even object will not be deleted again and said very simply take raven's array from line 10 delete everything in there and replace it with contents of the same ravens array but only with those objects that have marked for deletion property set to false exclamation mark here means false since we are going to look in raven's array on line 42 i can check in browser console and i can see that number of objects in the array is between 3 and 6. it only contains ravens that are active and visible on screen perfect i remove the console log these ravens look a bit boring just black rectangles let's use animated sprite sheets instead on my class i create a new property called this.image and i set it equal to new image i set source on that new image as ravenpng art for this episode was made by this amazing artist link to his website is in the video description he also allowed me to share this particular spreadsheet completely for free with my students so you can download it along with all other project files in the description for more game art check out his website and support him if you can there aren't many good 2d artists like this and he's one of my favorites i try to buy his game art assets whenever i can i will need a couple of helper properties here this dot sprite width is width of a single frame in my raven's sprite sheet in this case 271 pixels if you are using a different sprite sheet take its width and divide it by the number of horizontal frames maybe it would be easier if you follow along with me using the same sprite sheet and then when you understand the code and it's working for you you can replace it sprite height is 194 pixels on line 31 inside draw method i call built-in draw image method it expects between three and nine arguments depending on how much control you want over the image you are drawing minimum is three arguments image you want to draw so this dot image from line 20 and x and y coordinates where to draw it now it's just simply taking the entire sprite sheet and drawing the whole thing at its original size we can also give it optional width and height arguments which will scale it i need to make sure my brackets and commas are correct here so now it's scaling the entire sprite sheet to fit inside hundred times 50 pixels let's do stroke rectangle here so we can see it better we can also give it a total of nine arguments these additional four arguments will allow us to only crop portion of the image source x source y source width and source height so the longest version of draw image method takes nine arguments image we want to draw x y width and height of area to group out from the source image x y with an height of where to place that cropped out image on destination canvas just group out the first frame now source x and source y is scored in at zero zero source width is sprite width and source height is sprite height you can see our ravens are a bit stretched it's because these initial width and height values are completely disconnected from the actual dimensions and aspect ratio of our sprite sheet i move sprite width and sprite height up here so that we can use them to calculate values that come after width could be for example sprite width divided by 2 and height could be height divided by 2. this works but now all our ravens are the same size and as my friend marcus says multiplication is faster than division so let's create a new property called size modifier and it will be a random number between 0.4 and 1. now instead of dividing it by two i will multiply width and height by this random size modifier value which will make the ravens be different sizes while still preserving the aspect ratio so no stretching this dot frame is the number of frames in our sprite sheet counting from zero so the initial value will be zero this frame this.max frame could be four or 5 depending on how you reset it back to frame 0. let's go with 4 maybe i will adjust my frame reset check to this value in a minute if this dot frame from line 25 is more than this dot max frame from line 26 set this dot frame to zero else increase frame by one to actually reflect this value on canvas i replace source x argument on line 37 with this dot frame times this dot sprite width so it will go 0 1 2 3 4 5 and back to 0 as frame variable cycles on line 32 all the ravens are flopping wings very fast and at the same interval how do we speed up or slow down sprite animation the speed at which the next frame is served and how do we make sure it's consistent across all machines on old slow computers and new powerful ones as well we can do that by using delta time we calculated delta time on line 43 inside animation loop delta time is the difference in milliseconds between last frame and current frame and this value will differ based on power of your computer some computers can surf frames much faster than others since i already calculated this speed at which my machine can serve frames in my game i will just pass a delta time as an argument to my update method here on line 50. that way it will be available up here let's test it i console delta time it won't be available until i passed delta time as an argument here as well now the values are coming through i will need a couple of helper properties time since flap will be zero at first it will be growing by the amount of delta time until it reaches value in flop interval then it will trigger next frame of sprite sheet and reset back to 0. this time since flap plus equals a delta time remember that delta time is the amount of milliseconds between frames so faster computers will have smaller numbers here slower computers will have high delta time values as a result it will reach the target value at the same time on slow and fast computers unify an animation speed across different devices i say if this.time since flap from line 27 is more than flap interval from line 28 only then run this code that handles cycling through frames for this to work every time this condition is met and if statement is entered i also have to reset time since flap back to zero so it can start counting again when to serve the next frame now i can change the value of flap interval and you can see it changes the speed at which we cycle through frames in our sprite sheet 500 milliseconds per frame is very slow five milliseconds per frame is fast faster than my computer can handle since we know my computer can handle to serve next frame every 16 milliseconds as maximum i can also randomize flap interval so that each raven animates at a slightly different rhythm random number between 100 and 200 feels too slow how about a random number between 50 and 100 that feels better quick recap we are calculating delta time difference in milliseconds between last frame and current frame the value of delta time will be different on slow and fast computers to make sure we have consistent in across different machines we have time since flap variable that increases by the value of delta time per each frame until it reaches target value in a flap interval then it serves the next frame resets back to zero and starts counting again preparing to serve the next frame ravens are flying in straight lines from right to left i also created the direction y property on line 21. it's a random number between minus 2.5 and plus 2.5 so summary events will move up and some will move down in negative or positive direction along vertical y axis based on this value inside update method i say this dot y plus equals this dot direction y now you can see some vertical movement it's now a little bit harder to target them making our game more difficult for players one thing i don't like now is how they disappear behind the top and bottom edge i want them to move all the way across the screen and when they touch bottom or top edge of game area i want them to kind of bounce and reverse their vertical movement to the opposite direction i do that with an if statement i say if this dot y is less than 0 or if this dot y is more than canvas height minus this dot height set their direction property from line 21 to its opposite value this the direction y times minus one now they just bounce when they reach edges of the game area let's draw score i create a led variable called score and i assign it to 0 initially i create a custom function called drawscore inside i set fill style to white i want white numbers i call build in fill text method inside i will hard code string score colon space plus score variable we just declared and i wanted a drone on canvas at coordinates 50 75 for example now i just call draw score from inside my animation loop keep in mind since we are drawing everything on the same canvas sequence in which you call this will affect how our game is layered i want score to be behind ravens so first i draw score then i draw ravens it's very small so let's set the global canvas font to 50 pixels impact now it's easier to read i will play with it a bit i can use canvas shadows here but i can also just draw the same text again at slightly different coordinates for example 55 and 80. the first layer will be black the second layer will be white in the game we will have to click ravens before they disappear behind the left edge of screen i create an event listener for click event callback function on event listener has a default access to this event object i assign it variable name for example e it contains information about the click event that happened for example its x and y coordinates in relation to viewport if i console e dot x and e dot y i get coordinates of my click whenever i click somewhere in the game area i promised we would do collision detection by color today to do that we first need to know what color is the pixel we are clicking on i create a custom variable i call for example detect pixel color it will be equal to built in get image data method get image data simply scans area of canvas and returns an array like object called uint8 clamped array it's a simple data structure full of unassigned 8-bit integers it's clamped which means it can contain only integers whole numbers between a certain value range specifically between 0 and 255 let's scan canvas and inspect what it gives us get image data needs 4 arguments x y width and height of area we want the scan i want to scan just one pixel we click on with mouse so coordinates of this click event e.x e.y and width and height of scanned area will be just one pixel we want pixel perfect precision here okay let's just console lock this variable to see in what format get image data gives us the pixel color to make sure we understand how it works if you are getting error at this point keep watching i will explain it and i will show you how to deal with it now whenever i click somewhere on canvas get image data scans area of one pixel directly under the mouse click and it gives us this image data object this auto generated image data object contains three main properties data property which is an array currently it has four numbers inside and within height of scanned area in our case one pixel the way color data is structured here is that each four elements in this data array represent one pixel specifically it's red green blue and alpha value if you use css you know that any color can be created by combining a certain amount of red green and blue the only difference between css rgba declaration and this is that in css opacity is a value between 0 and 1. here opacity alpha is also a number between 0 and 255 0 is transparent 255 is fully visible here for example you can see i clicked and it gave us 0 0 0 for red green and blue and 0 for alpha it means we click somewhere in the empty area keep in mind that canvas is just the ravens and score the rest is transparent rainbow colors you see are on the background and are applied to body element with css we are calling get image data on ctx variable so it is just scanning that particular canvas element it doesn't see anything else some of you might be getting error when you click on canvas and try to run get image data on it we are drawing sprite sheets our raven images on canvas in some browsers you won't be able to call get image data on the same canvas where you draw images it will give you an error that says something like canvas was tainted by cross origin data if you are running your code locally most likely you see that error i'm using local server so i'm not getting that error right now it's a security measure related to cross origin resource sharing apparently there could be viruses hidden in some images and by scanning that image with get image data you could expose yourself to that virus there are many ways to get around this problem and scan canvas without exposing yourself to any potential risks in our case it's simple let me show you but first i will assign a differently colored hitbox to each raven so i want one canvas that has only these hitboxes and no ravens because when i click it i want to get color of that particular hitbox not of the black raven if i create a secondary canvas and i use it just to draw these hitboxes and new images it won't give me tainted canvas error i will explain more as we write it in index html i create an additional canvas with an id of collision canvas in style css i comment out rainbow background for a moment so that it's very clear what we are doing the same as i set up the first canvas i will also set up this new collision canvas be careful here i always make mistakes and typos when assigning multiple canvases like this for some reason i don't know why constant variable called collisioncanvas is document getelementbyid collisioncanvas collisionctx which is context is collisioncanvas.getcontext2d i also set collision canvas width and height just to check i give it red background yes it's covering the entire browser window perfect on my raven class i create a property called random colors at the point where each raven is created i want to roll the dice and randomly give it red green and blue color value we know that color values can be in a range between 0 and 255 so red will be math at random times 255 like this it will give us decimal points i need only integers here so i wrap it in math.floor i do the same thing for green and blue now we have three random values in this array assigned to each raven object i create one additional property called this dot color and here i concatenate rgba color declaration using these values red is random colors index 0 green is index 1 and blue is index 2 plus closing bracket like this to use this color i declare fill rectangle on line 54 and i set fill style to this dot color from line 37. now each raven has a random red green and blue color assigned when it's created by our class constructor and we use these three values to create rgb color for its hidden box hitbox means collision detection area and in our case it's the colored rectangle around each raven we can also do much more complex shapes and still get pixel perfect collision detection but for purposes of this tutorial rectangles are fine i don't want to complicate things too much this tutorial is to help you understand the technique so now each raven has an array of three random values between 0 and 255 and these values are used to draw its hitbox we will use these values kinda as a unique password for each raven we click on canvas get rgb value of that pixel we clicked on using get image data method and we compare them with this random colors property if they all match we know we click on this particular raven this technique has one downside there is a very small chance that there will be two identical colors generated next to each other but since we do random number between 0 and 255 3 times and we only have between 3 and 7 active ravens on the screen at any given time the chances of that happening are astronomically low if you have any math experts who can run the numbers let me know in the comments it will be one in millions possibly billions now i told you what i want to do what does that look like in javascript before we write collision code there is one small thing layers i want big ravens to be up in front and small ravens to be behind to create a sense of depth and correct the draw order in a 2d space right now sometimes you see smaller ravens up front because they are drawn here on line 83 based on the order at which they were pushed into the array on line 78 i don't have to sort them for every animation frame only every time i push new raven to the array i want to sort out all objects in the array by size i use built-in array sort method sort method will simply reorganize order of elements in the array their indexes based on provided check in a callback function it will run through the array and compare every element against every other element and sort them in ascending or descending order ascending order is default it will run over my raven's array and use these a and b variables for each object i can choose many different properties to sort them by today i will choose width because i know ravens in the back will have smaller width than the ones up front i'm just going to return it like this simple syntax and i'm comparing width of every element in the array against the width of every other element in the same array a minus b will sort my array in ascending order based on width which is exactly what i want i want small ones to be drawn first and larger ones to be drawn on top you can read more about built in javascript sort method online we can see that it works large ravens are up front and smaller ones are behind perfect as i said i want to avoid tainted canvas error so i need to make sure i have a separate canvas i can scan color from that doesn't have any images drawn on it i take collision context variable i declared on line 6 and i draw my colored rectangles on that canvas instead by adjusting code here on lines 54 and 55. nice that worked i can see we are not clearing the old paint on that canvas so on line 74 i call clear rectangle on collision context as well now we have two canvas elements one has colored collision rectangle and the other has ravens and score drawn on it on line 68 inside click event listener instead of scanning my main game canvas for pixel data i will scan just collision canvas instead now when i click it will ignore the black ravens and image data object will give me red green blue and alpha value of rectangle i clicked on i will compare it with red green blue value inside random colors property on each raven to know which one was clicked on and then i will set its marked for deletion property to true there are many techniques you can use to compare two array-like objects against each other let's just keep it simple when i click on one of these rectangles i can see the values are inside this image data object on a property called data data is an array with red green blue and alpha value of pixel we clicked on i create a variable to get hold of this array detectpixelcolor.data which refers to this uint8 clamped array with four elements there is also a way to check for collision detection between two objects based on opacity alpha value like this but today we will do collision between point and shape between mouse and ravens i will ignore alpha value from now on and i will just focus on these three values red green blue so this pc pixel color variable holds this data array with four elements i take my ravens array and i call for each on it for each raven object in the array i will check if its random colors property from line 36 if the first element in the array index 0 is the same value as pixel we clicked on at the same time we also need the second and the third element to match if random colors array on my raven matches exactly red green and blue values on pixel we clicked on we know we have a collision index 0 is red index 1 is green index 2 is blue we are comparing the 2. if they match we have collision so i will take that raven object and set its marked for deletion property to true and i will increase score variable by one awesome it works i can click on ravens and they disappear and increase my score i can set opacity on collision canvas to 0 and i can enable rainbow background on body element collision detection still works correctly well done if you followed this far you are doing great what should we do next how about we add explosion animation and sound effect whenever we click on a raven i will just repeat the same pattern we did for raven class i create an array called explosions it will hold all active animated explosion objects i will create a class to create a blueprint for these objects its constructor will expect three arguments x y and size because position and size will come from the outside and will depend on the raven we clicked on this.image will be new image this dot image src will be boom png you can download the sprite sheet for free in the video description sprite width will be 200 pixels sprite height 179 pixels this dot size will be size we passed as an argument on line 61. same for this dot x and this dot y these values come from the outside this dot frame active frame will start from zero this dot sound will be new audio like this this dot sound src source and here as a source you can add any sound you like for example i will go to opengameart.org website i click browse sound effects and i will search for magic sfx special effects [Music] i will choose this pack of four sounds i download it and i will use the one called ice blast i will rename that file as a boom dot wav and i will add it to my project folder you can choose a different sound if you want we can also have multiple sounds and play a random one here it's up to you in update method same as we did before i will use delta time to time my animation we will have one variable to accumulate delta time values called for example time since last frame it will start at 0 then we need a second variable to define limit when the next frame triggers i call it for example frame interval and i set it to 200 milliseconds pass delta time as argument to update method it will be coming directly from animation loop i will show you in a minute this.time since last frame will be slowly increasing by the amount of delta time if time since last frame is more than frame interval 200 milliseconds i increase this dot frame from line 69 by one i also want to play the sound when we are on frame 0 when the explosion first appears there are better ways to do that but for today i will simply check if active frame of this explosion is zero and i take this sound from line 70 and i call build in play method on it explosions will also need draw method which will draw the actual sprite sheet animation we will pass the draw image 9 arguments same as we did with ravens image we want to draw this.image from line 62 four values for area to crop out single frame so source x is this dot frame times this dot sprite width source y will be zero because we only have one row of sprites source width will be sprite width from line 64 and the source height will be sprite height from 965. so now we told javascript what area we want to crop out now we need to give it x y width and height where to place it on destination canvas so this dot x this dot y and this dot size for width and distal size for height as this dot frame variable increases here on line 79 because of this source x property here we will show frame 0 1 2 3 and 4. now where do we trigger this code to create and animate new explosion the best place would be here i think this if statement detects collision by color so when collision is detected i take explosions array from line 59 and i push new explosion in there this will trigger explosion class constructor on line 61. i can see it expects value for x and y coordinates and size because i want explosion to depend on the size of the raven we clicked so here we are cycling through raven's array referring to individual ravens as object i want to pass x y and width of that raven as x y and size arguments here okay that should work i can test it by consoling explosions array from line 59 i can see as i click and hit ravens explosions are being added perfect i made sure my explosion class has update and draw method same as my raven class that's why here on line 123 i can simply just use spread operator and expand the entire explosions array into this array i'm creating on a fly so that i can call update on all ravens and all explosions at the same time like this i do the same thing for draw method on line 124 i like this syntax it looks clean down here i will also remove all the explosion objects from the array using built-in array filter method i need to create a property called marked for deletion on my explosion class for this to work as you can see i'm repeating the same pattern we used for ravens i hope that using the same structure like this helps you to understand and navigate in the code a bit better initially i set it to false in update method i write an if statement if this.frame from line 69 is more than 5 which means after all the frames of sprite sheet have been displayed one by one and explosion animation is complete i set marked for deletion from line 74 to true when i click on ravens sound plays and explosion sprites are animated we are making great progress we just need to polish some details here if i change frame interval on line 73 to 500 you can see it only affects the first frame the rest of animation is playing really fast oh it is because i need to reset time since last frame back to 0 every time so it can count towards the next frame interval over and over to serve next frames 500 milliseconds is too slow let's try 200. i want to align explosion animation better over the raven sprites let's move it a bit upwards by adjusting destination y argument in draw image method i will make it relative to size this dot y minus this dot size this dot size divided by four yeah i think this is aligned well now let's create game over condition on line 11 i create a global variable called game over and i set it to false initially inside update method on ravenclaws i create an if statement if any raven manages to get all the way across the screen and behind the left edge of game area game will end if this.x is less than 0 minus this dot with set game over from line 11 to true and inside animation loop on line 132 i only want to run request animation frame and serve the next frame of our game as long as game over is not true exclamation mark here when raven gets all the way across the screen game over will be set to true and game will stop like this i also want to display game over message same as we did at raw score i will create a function called draw game over first style will be black fill text will be for example game over your score is plus i concatenate score variable i want it in the middle of the screen so x coordinate will be canvas width divided by 2 and y-coordinate will be canvas height divided by 2. now i need to call my draw game over function here in animate if game over is false keep serving the next frame else call draw gameover method to display message and final score it's not centered it's because these coordinates on line 101 mark top left corner and the text goes towards right and bottom from that point same as when you are drawing rectangle or image on canvas with text it's easy to center by setting text align property to center like this yes that worked same as i did with score i want to give it shadow i will use this trick where i draw the same text twice with different fill color and i offset it by 5 pixels nice let's change direction of background gradient maybe 45 degrees 125 degrees let's do a little bit of experimenting now and also to solidify what we learned today i will use the same code pattern we used for ravens and explosions to add particle effects to our game i will go a bit faster now this part is just for fun feel free to run your own coding experiments i create an array that will hold all my particle objects i create particle class constructor will expect x y size and color this will be coming from outside the class and will depend on what raven is leaving this trail and creating these particles it will be shooting from their tails as usual we will create properties for this dot x and this dot y this dot radius since particles will be drawn as circles it will be random number tied to size of a raven let's try this formula and see what it looks like particles will be growing in size so we need max radius to know when to remove them and also at which point they reach maximum opacity it will be random number between 35 and 55 for example marked for deletion as usual will be false at first horizontal speed x will be a random number between 0.5 and 1.5 because i want the particles to slowly drift to the right this dot color will be passed from the outside update method will move particles to the right horizontally it will increase radius by 0.2 per frame and it will check if this.radius is more than max radius if it is it will set marked for deletion to true draw method will just draw a simple circle begin path to start the drawing fill style will be distort color from line 101 arc method to draw a circle i pass it x y radius start angle and ant angle like this and we fill circular path with color we have a class that will serve as a blueprint to create particles i want them to follow ravens as they fly to create trails behind them to do that i go up inside update method on raven class every time we serve next sprite sheet frame at the same interval we are going to take particles array we just created and we will push new particle inside my particle class constructor expects four values to come from the outside x y size and color so i pass it x and y of this raven width of the raven as a size argument and this dot color we use for collision detection rectangles will also be color of particle trail for that particular raven you can see here on line 95 constructor wants these four properties to come from the outside so that it knows where on canvas to draw the particles how large and what color i can see i forgot to declare this dot size here like this it will come from here and it will be used here to make radius of particle circles relative to the size of raven smaller ones should have smaller trails so we have particle class here on line 52 we are creating new particle object and pushing it into particles array inside animate i use spread operator again to expand contents of particles array here so that their update method gets called and i also expanded here for draw method i also need to make sure old particles with marked for deletion properties set to true get filtered out from particles array nice we are drawing particle trails you can see they come from the top left corner of raven hitbox i will adjust that position a bit here inside particle class constructor first i need to move this dot size up so that its value is available for all properties coming after it this dot x will be x passed as argument on line 95 plus this dot size from line 96 divided by 2 to center it horizontally yes this dot y will be y plus this dot size divided by 2. no that's too low this dot size divided by three much better i want particles to be drawn behind ravens we are drawing everything on a single canvas element so how things are layered depends on the order at which javascript cycles through these objects and calls their draw methods for every frame i will change the order here to draw particles first and then ravens and explosions will be drawn over them like this awesome we have a working code let's clean it up in update method on particle class i want radius to grow faster 0.5 0.8 0.5 is fine drawing trail on every single raven can be performance expensive i want a property that will allow me to randomize it and allow me to set what percentage of ravens will have particle trails on my raven class i create a property called this.hessa trail i want this property to be true for a certain amount of ravens and false for the rest as marcus pointed out in my generative art tutorial any conditional expression results in a boolean value so instead of doing if else statement here i can simply just roll dice with math.random mastedrandom called like this will return a random value between 0 and 1. so i call it and i check if that random value is more than 0.5 and that's it it should be true roughly for 50 of ravens this conditional expression results in a boolean value true or false depending on if math at random rolls a random number that's higher or lower than 0.5 i really like this syntax very simple and clean inside update method on ravenclaws i will only create new particles if this dot has trail is true like this now only half of my ravens will have trails i also want particles to animate from fully visible to transparent inside draw method on particle class i set the global alpha property on my canvas to be 1 which is maximum fully visible minus the current size of the particle divided by max size as the particle's radius grows eventually radius will be the same size as max radius so let's say max radius is 30 pixels at that point where the current radius is the same size as max radius we will have 30 divided by 30 here which is one and one minus one is zero particle is slowly growing more and more transparent and at the point when it reaches maximum radius it will be at zero global alpha this formula might be a bit difficult to completely understand if it's the first time you see it but it's very useful we will talk about it again in some other video as you can see global alpha is spilling over and affecting my ravens as well that's an easy fix if you want to change some global canvas properties such as fill style global alpha rotate translate and so on and you want those properties to affect only a single element you draw and not the others you can just wrap that drawing code between built-in save and restore methods save will create a snapshot of current canvas global settings and then we change global alpha here which will affect just this one particular particle and then i call restore to revert canvas settings back to what they were at this point save and restore are especially useful for rotating elements on canvas but you can also use them for other things like this my particles are blinking before they disappear it is because javascript first runs over the entire array before it filters the particles that are too large out and my global alpha formula works only in a specific range between 0 and max radius some particles get outside that range and are drawn fully opaque for a second before they get filtered out to fix it is simple i just trigger marked for deletion a little bit sooner for example by saying max radius minus 5 in my check on line 111 let's make the trail nicer i will add five particles every time instead of adding just one on line 54 i create a for loop like this and i put this code inside if i make radius grow slower trail will be longer because it will take particles more time to reach max radius be a bit careful here not to have too many active particles on screen at once because at some point it will start affecting performance and frame rate i can also randomize the initial x and y coordinates a little for example i can add random number between minus 25 and plus 25. i think it looks a bit more interesting like this i can also add more enemy types for example i can add fast flying bats that will be worth extra score points maybe i want ravens with trails to be worth more score but also have more lives there are many things we can do here if you are still feeling creative check out some of my playlists i have creative coding for beginners game development playlists and advanced animation effects everything which is html css and plain vanilla javascript no frameworks and no libraries check out some recommended courses in the video description i'll see you there
Info
Channel: Franks laboratory
Views: 11,639
Rating: undefined out of 5
Keywords: JavaScript game, javascript game development, javascript crash course, franks laboratory, game development, intro to game development, game development tutorial, game development course, game dev, game development in javascript, javascript games, make javascript games, javascript tutorial, game development for beginners, javascript course, javascript tutorial for beginners, html, html canvas
Id: gCa0z4B-CRo
Channel Id: undefined
Length: 62min 9sec (3729 seconds)
Published: Sat Jul 31 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.