JavaScript Fighting Game Tutorial with HTML Canvas Chris Courses・2 minutes read
Chris hosts a coding tutorial on creating a fighting game, starting with basic mechanics and transitioning to sprites and animation. The tutorial covers game design, coding setup, player and enemy movement, animations, health bars, attack mechanisms, and implementing GSAP for smooth animations.
Insights Chris is hosting a tutorial on coding a fighting game using basic mechanics and rectangles. Project setup involves creating folders and files like index.html and index.js within a web directory. A canvas element in index.html is essential for the game to function. A class named "sprite" serves as a blueprint for player and enemy objects. Implementing movement using velocity properties and gravity for sprites. Utilizing event listeners to control player movement with keys. Introducing collision detection and attack mechanisms for player-enemy interactions. Implementing health bars, timers, and animations for player and enemy characters. Get key ideas from YouTube videos. It’s free Recent questions How to create a basic fighting game?
By following a tutorial on coding mechanics.
How to animate sprites in a game?
By looping through frames continuously for movement.
How to implement attack animations?
By adding specific frames for attack actions.
How to handle health bars in a game?
By adjusting div elements with GSAP for smooth animations.
How to deploy a game project online?
By using Netlify for hosting and connecting to GitHub.
Summary 00:00
Creating a Fighting Game Tutorial with Code Chris is hosting a tutorial on coding a fighting game, starting with basic mechanics using rectangles. The rectangles will be transformed into sprites with animations for fighters and backgrounds. Interface design will be refined to prepare the game for web deployment. Project setup involves creating folders and files, like index.html and index.js, within a web directory. A canvas element is essential in index.html for the game. A JavaScript file, index.js, is created to handle coding for the game. Canvas size is set to 1024 by 576 pixels for compatibility with various screen sizes. The canvas background is set to white for distinction from the browser background. A class named "sprite" is created to serve as a blueprint for player and enemy objects. The player object is instantiated with a position at the top left corner of the screen. 11:28
"Sprite class creates player and enemy" To define a player's appearance, a draw method is created within the sprite class. The draw method utilizes c.fillRect to draw a rectangle representing the sprite. The sprite's position is determined by the x and y values passed through the constructor. The width and height of the sprite are set to 50 pixels wide and 150 pixels tall. The fill style for the sprite is set to red to differentiate it from the canvas background. An enemy is created by duplicating the code for the player, with a position set to x: 400 and y: 100. An animation loop is established using window.requestAnimationFrame to continuously call the animate function. Velocity properties are added to the sprite class to enable movement, with x and y velocities set to zero initially. Position and velocity properties are passed through a singular object argument for cleaner code management. The update method is created within the class to update properties and move the sprite downwards, with a velocity of 10 pixels added to the y position per frame. 23:08
"Control sprite movement with velocity and gravity" To stop sprites from moving, set velocity to zero. Change static value to velocity for both player and enemy sprites. Use object-oriented programming to change individual object properties. Add height property to sprites and set it to 150. Write an if statement to stop sprites from falling past canvas bottom. Create gravity by adding acceleration to y velocity over time. Set gravity value to 0.2 to start. Use event listeners to move player left and right with keys. Set player velocity on x-axis to move left or right. Avoid setting velocity to zero in key up event to allow continuous movement. 34:33
"Game Controls and Player Movement Optimization" Default setting for referencing object D is pressed equal to false In the animate function, if key A is pressed, set player's x velocity to -1 If key D is pressed, set player's x velocity to 1 Need to set keys A and D pressed to true when keys are pressed down Set keys A and D pressed to false when keys are lifted up To ensure accurate movement, set player's x velocity to 0 before setting it to -1 or 1 Implement a variable to track the last key pressed for accurate movement If key A is pressed and last key is A, move player left; if key D is pressed and last key is D, move player right Add a jump effect by setting player's y velocity to -10 when key W is pressed For enemy movement, set keys arrow right and arrow left pressed to true when respective arrow keys are pressed, and set enemy's y velocity to -10 when up arrow key is pressed 46:07
Enhancing Game Mechanics and Controls Press arrow right key to set enemy velocity.x to 1 Ensure keys arrow right and arrow left have pressed properties set to false Test arrow keys functionality by holding down left or right arrow keys Set player and enemy velocity x to 0 to stop movement when no keys are pressed Refactor player code to remove last key variable and use player.last key instead Increase movement speed by changing velocity values to 5 pixels per frame Adjust gravity value to control falling speed, set to 0.7 for quicker descent Increase jump height by setting gravity to 20 when pressing w or arrow up Create attack mechanism by activating a rectangle on spacebar press Detect collision between attack box and enemy by comparing positions and widths 57:18
Player Attack Collision Detection Implementation Introducing a property called `this.width` set to 50 for the player's width. Replacing the static 50 with `this.width` for drawing the player. Ensuring collision detection on the x-axis by checking the player's attack box against the enemy. Implementing collision monitoring on the y-axis to accurately detect contact. Setting conditions to confirm collision by comparing attack box positions with enemy positions. Adding a property `isAttacking` to the player to indicate when an attack is active. Activating the attack state with a method and a timeout to limit attack duration. Enabling attack initiation by pressing the space key. Resetting the attack state after detecting a successful hit on the enemy. Adjusting the display of the attack box to only show during an attack. 01:08:41
Rectangular Collision Detection for Game Development Replace "player" with "rectangle 1" and "enemy" with "rectangle 2" for a reusable rectangular collision function. Implement rectangular collision detection for attack boxes and fighters/enemies. Use the rectangular collision function to detect collisions between attack boxes and fighters/enemies. Modify collision detection conditions to utilize the rectangular collision function. Implement enemy attack functionality by setting "enemy is attacking" to true when the down arrow key is pressed. Ensure enemy attack success by checking for collision between enemy attack box and player. Create an HTML interface for health bars and a timer using div elements. Utilize inline styles to set background colors, heights, and widths for the health bars and timer divs. Use the "display: flex" property to align health bars and timer divs horizontally. Set the width of health bars to 100% to allow them to expand based on the canvas size. 01:19:48
Styling and Manipulating Elements in JavaScript To prevent an element from shrinking within a parent with a display of flex, set the flex shrink style to zero. To center child elements vertically within a parent div with display flex, add the align-items style set to center. Adjust the display property of a parent div to inline-block to ensure it only takes up the width of its children. Add padding to a container div by setting the padding property to 20 pixels on all sides. Use the box-sizing property set to border-box to prevent padding from affecting the overall width of elements. Add an ID to the enemy health bar div to reference it in JavaScript for health deduction. In JavaScript, select the enemy health bar and adjust its width property to decrease health visually. Create a new div with position absolute to overlay the health bar and indicate the original health amount. Set the position absolute div to cover the full width and height of the parent div by adjusting top, right, bottom, and left styles to zero. Subtract health points from the enemy health bar based on the enemy's health property rather than a fixed value. 01:30:53
"Implementing Player Health Bar in Game" Each hit on the enemy subtracts 20 hit points from enemy.health. The health bar is adjusted to reflect the new percentage after each hit. To display the percentage correctly, add a string of percent. Copy the enemy health divs and replace them with player health divs. Change the id to player health for the player health divs. In index.js, detect collisions when the enemy attacks the player. Subtract 20 hit points from player health each time the player is hit. Adjust the player health bar to decrease from left to right. Set the parent div's display to flex and align children elements to the right. Add a background element with a width of 100% and a yellow color for the player health bar. 01:42:25
"Display text based on game outcome" To hide text, set its display to none and delete display flex. In index.js, when playerhealth equals enemyhealth and the timer runs out, select text using document.querySelector. Add an id "display text" in index.html to select the div. Change inner html to "tie" and set display property to flex to show text when timer runs out. Use an if statement to show text only if timer is equal to zero. Add an else if statement to show different text if playerhealth is greater than enemyhealth. Refactor code to remove duplicate lines and make it more efficient. Determine winner based on player and enemy health, displaying appropriate text. Stop the timer when a player wins by using clear timeout function. Download background image from itch.io, resize it, and insert it into the game folder for use. 01:53:39
"Refining Sprite Class for Image Rendering" To insert an image into a game, the sprite class can be utilized for background images, fighters, or other images. The sprite class is currently multifunctional, handling fighter-related tasks, but it's recommended to separate it into a distinct class for rendering images. A new class called "fighter" is created to handle player-related functionalities, while the original sprite class is refined to focus solely on image rendering. Unnecessary functionalities like attack methods, health, color, attack box, etc., are removed from the sprite class to streamline it for image rendering. The classes are moved to a separate file named "classes.js" for better code organization and maintenance. The classes.js file needs to be referenced in the index.html file to ensure its availability for use in index.js. The player and enemy instances are updated to utilize the new fighter class instead of the sprite class. A background image is rendered on the screen using the sprite class by passing the image source and position as arguments. Utility functions like decreased timer and determine winner are moved to a separate file named "utils.js" for improved code cleanliness. Adjusting the gravity logic in the fighter class allows for the player and enemy to stop falling at a specified distance from the bottom of the canvas. 02:04:44
Creating Animated Shop Sprite for Background To eliminate remaining space, subtract a smaller value like 97, then refresh to ensure the object touches the floor. The background sprite is successfully created, allowing movement across the background. Proceed to work on the shop sprite with animation, utilizing the shop.png image from the image folder. The shop.png image contains multiple instances of the same image, differing only in the smoke stacks for animation. Create an animation by looping through frames continuously to give the illusion of movement. Place the shop image in the designated area within the background for animation. Scale up the shop image to fit the area by adjusting the width and height in the sprite class. Modify the scale property to ensure the shop image is appropriately sized compared to the background. Crop the shop image to show one frame at a time for animation, adjusting the crop location, width, and height accordingly. Ensure the crop width and height are based on the number of frames in the image to maintain proper scaling and animation. 02:15:27
Animating Samurai Mac in Shop Game Set frames max to 6 in index.js for the shop's frames. Adjust the x-coordinate of the crop mark in closets.js to move the square through the sprite sheet. Calculate the width needed to move the crop mark by dividing the image width by frames max. Ensure the background image is displayed by adjusting the crop mark for it. Implement frames current to control the movement of the crop mark for animations. Increase frames current over time to animate the shop. Slow down the animation by adjusting frames hold and frames elapsed. Obtain fighter sprites from itch.io for the player, specifically Samurai Mac. Incorporate the idle animation of Samurai Mac into the game by extending the sprite class. Inherit necessary properties like image source, scale, and frames max for the fighter class. 02:26:35
Setting Properties in Parent Constructor for Fighter Class Properties for parent constructor set within `super` Parent constructor takes one argument, an object Properties to set within parent constructor listed out Properties to set: `image`, `scale`, `frames max`, `frames current`, `frames elapsed`, `frames hold`, `position` Issue with `image` not defined, corrected to `image source` Issue with `frames current` not defined, corrected by setting it to 2 frames Static values copied to `fighter` class to resolve issues Refactored `fighters` to take `image source` for player `Image source` set to `samurai mac` idle.png for player `Frames max` set to 8 for `samurai mac` fighter `Scale` property set to `2.5` to make fighter bigger Offset property added to move sprite to top left corner for collision detection Offset values adjusted to remove padding around sprite `Animate frames` method created to avoid code repetition `Animate frames` method used in `update` function for animation Error with `player 2` image source commented out to prevent errors `Sprites` object added to `fighter` class for different sprites `Idle` and `run` sprites added with `image source` and `frames max` specified 02:38:04
Sprite Animation Loop with Dynamic Image Switching To change the idle to run, count the frames in run.png, which is 8 frames. Switch between sprites by setting the image to the desired sprite. Create a new image object based on the sprites to switch between them. Loop through the sprites object to dynamically create an image property for each sprite. Set the source of the image to the sprite's image source. Ensure to declare sprite as a constant for the syntax to work. Determine when to switch between running and idle sprites within the animation loop. Set the player image to the running sprite when moving left or right. Switch back to idle when no keys are pressed. Add a jump sprite with 2 frames and switch to it when the player is moving upwards. 02:49:37
Implementing Jump, Run, Idle, and Attack Animations To implement a jump sprite, cut two lines, select the player dot switch sprite method, and call jump. Running the jump case in classes.js executes the code within it, switching the image to a jump image and setting frames max to 2. Ensure frames max is set within each if statement for run and idle, using brackets for multiple lines. Change jump to run for frames max property, ensuring correct frame rendering. For idle, set frames max to the idle sprite's frames max property within an if statement. Include a conditional in the jump case to set the image and frames max only once if the image is not the sprite's current image. Reset the current frame to zero when switching between sprites to avoid blank spaces during animation transitions. Add a fall animation by creating a fall sprite with an image source and frames max, and switch to it when y velocity is positive. Fix animation flashing by setting the player's position to prevent rapid switching between idle and fall sprites. Introduce an attack animation by adding attack one to the sprites object, switching to it on spacebar press, and preventing sprite switching until the attack animation completes. 03:01:25
Implementing Game Animations for Player and Enemy The text discusses implementing animations for different actions in a game, such as idle, run, jump, fall, and attack. To add an attack animation, a conditional statement is included to control the attack action. The process involves setting up sprite properties for the player and enemy characters. Different sprite sheets are used for the player and enemy characters, with specific frames for each action. The text details changing references from one character to another in the code for proper sprite display. Adjustments are made to ensure the sprites are correctly positioned on the screen. The text explains how to switch between different sprites based on player actions like running, jumping, and falling. Instructions are provided for implementing enemy sprite animations based on movement and actions. The process of setting up attack animations for both player and enemy characters is outlined. Details are given on setting up attack boxes to determine when attacks hit and affect health bars. 03:12:53
"Fine-tuning Attack Mechanics for Player and Enemy" Width of attack box set to 160 initially, adjusted from 200. Health bar decreases when attacking enemy, not when not touching. Health bar should decrease only on fourth or fifth frame of attack animation. Condition added to subtract health only when player frame is at four. Player's attacking status set to false after animation completes. Player's health not subtracted if attack misses enemy. Attack box for player 2 adjusted to align with sword swing. Attack box width set to 170, x offset adjusted for accuracy. Enemy's health only subtracted on frame two of attack animation. Attack boxes removed to ensure attacks work without being visible. 03:24:21
"Character animations and death in game" The attack animation overrides all other animations when a hit is taken. The code overrides animations within the "switch sprite" function. An if statement checks if the current image displayed matches the sprite's "take hit" image. Another condition checks if the current frame is less than the frames associated with the "take hit" sprite. A new sprite, "take hit," is added for the character Samurai Mac. The "take hit" animation for Samurai Mac includes a white silhouette to indicate being hit. The death animation is added when a character's health reaches zero. The death animation includes seven frames for Kenji and six frames for Samurai Mac. The "switch sprite" method is updated to include a case for the death animation. A property "dead" is added to prevent movement once a character dies. 03:36:16
Enhancing Game Interface with Color Modifications Change background color to red for health representation Adjust enemy health color to red as well Search for Tailwind color palette for color selection Choose indigo color with hex code 818cf8 for enemy health Modify player health background to indigo color using the same hex code Darken the timer background to black to reduce emphasis Decrease timer height to 50 pixels for less prominence Change timer text color to white for visibility Add a 4-pixel white border to player health and timer bars Ensure indigo bar is always on top by adjusting parent div height 03:47:13
"Import GSAP, animate health bars, deploy" To import GSAP into a project, ensure the version is 3.9.1 and copy the script tag link provided. Paste the copied script above custom scripts in the index.html file to import GSAP. Locate where the health bar is decreased in index.js and use GSAP's method "two" to animate it. Use GSAP's "two" method with the element to animate (enemy health) and the property to animate (width). Replace document.querySelector with GSAP's method to animate the health bars smoothly. Copy the GSAP animation for enemy health and apply it to player health by swapping the element names. Ensure the correct health bar is referenced for animation and delete unnecessary code to streamline the process. Push the project live using Netlify by creating a GitHub repository, copying specific commands into the terminal, and connecting the project to Netlify for hosting.