JavaScript Game Tutorial - Advanced Techniques

Поділитися
Вставка
  • Опубліковано 16 січ 2025

КОМЕНТАРІ • 89

  • @Frankslaboratory
    @Frankslaboratory  2 роки тому +5

    Part 1 here, have fun! :D ua-cam.com/video/c-1dBd1_G8A/v-deo.html What else should we implement

    • @cwlindWX
      @cwlindWX 2 роки тому

      Great stuff Frank! Whether in this series or somewhere else, it would be cool to see how an area or world map is slowly revealed as the player moves around. I was watching this video (ua-cam.com/video/6CKW7tLv5e0/v-deo.html) and he uses the P5.js library. And I thought, I bet Frank don't need no stinkin' library! (Since you are the canvas master! Nothing wrong with using libraries!). Anyway, I watched that video and wondered if you wanted a challenge or video idea :) Thanks again!

    • @Frankslaboratory
      @Frankslaboratory  2 роки тому +1

      @@cwlindWX Hi Clark, I could do that scratch card effect with vanilla, it wouldn't actually take much more code than using a library. Not sure how I would implement this particular effect into a game. I could for example do that with each level you uncover a bigger portion of the game world. I will put it on my list, let's see if I can include something like that in a future project, thank you for the idea.

    • @abitala
      @abitala 2 роки тому

      Thank you very much, Frank, for a useful and unique course, you opened the world of web game development to me)
      I noticed one thing about fps control that might be helpful:
      when we check "if (timer > interval)..." we get error in one deltaTime iteration
      Because, for example, fps = 20 => interval = 1000/20 = 50
      And if 16.666666 * 3 then we get 49.999998
      It's almost an early 50, but we technically need another iteration.
      So I suggest "if (timer >= interval - deltaTime)..."
      Found by accident while debugging player teleportation and mana replenishment timers hah
      Thanks again for your work, I wish you good luck in the growth of the channel) 🔥

    • @javifontalva7752
      @javifontalva7752 Рік тому

      ​@@Frankslaboratory Maybe making a platform game would be cool.

  • @carltone
    @carltone 2 роки тому +2

    Frank, love the code refinements, I always learn something new from your excellent tutorials. Thanks for sharing your knowledge!

    • @Frankslaboratory
      @Frankslaboratory  2 роки тому

      Thanks Carl, I'm explaining some things in this series I haven't shown before, let's see if it's still beginner friendly, maybe my future projects will have to be a bit simpler. Glad you found some value

  • @nicklansbury3166
    @nicklansbury3166 2 роки тому +1

    Another masterpiece. Thanks Frank. Enjoy your weekend.

  • @PhorssaOneDev
    @PhorssaOneDev Рік тому +1

    Hi Frank, I completed this part a few days ago...thank you!Very informative. I am HOOKED! 😀

  • @christopherc4526
    @christopherc4526 2 роки тому +1

    This channel is a great find. Thank you for these excellent tutorials. Wishing you great success.

    • @Frankslaboratory
      @Frankslaboratory  2 роки тому

      Hi Chris, nice to meet you, glad you found some value!

  • @phoenixxofficial
    @phoenixxofficial 2 роки тому +2

    A lot of great information, wonderfully explained with useful on screen notes to help with understanding - good job as always Frank! (:

    • @Frankslaboratory
      @Frankslaboratory  2 роки тому +1

      Hi Phoenixx, glad you find my new teaching style useful, still improving it :D

  • @palmpixiplus
    @palmpixiplus Рік тому

    This finally made Enums make so much sense to me. Thank you so very much!!!!

  • @souerico
    @souerico Рік тому

    Just discovered the channel! It is amazing!I'm learning a lot! Thank you so much!

  • @CodingBill
    @CodingBill 2 роки тому

    I love the way you teach things :)

  • @lexart1
    @lexart1 2 роки тому

    Díky. Skvělá práce. Skvělý tutoriál.

  • @TheLegendOfNiko
    @TheLegendOfNiko 2 роки тому

    Thank you so much mate. I’ve been looking for a way to create this for months !!

  • @techtime3125
    @techtime3125 2 роки тому

    Dude I started this series when I started learning js but i didnt understand anything now i am much advanced and I restarted this, dude the way you explain and the easy way you code i love that

    • @Frankslaboratory
      @Frankslaboratory  2 роки тому

      It feels good when you see yourself progressing doesn't it. I usually have to do each new technique 3 to 5 times before it starts making sense to me. Practice is important. Have fun with the project

    • @techtime3125
      @techtime3125 2 роки тому

      @@Frankslaboratory Yeah Agreed

  • @javifontalva7752
    @javifontalva7752 Рік тому

    This is my next challenge. Bring it on!

  • @AshTech-Designs
    @AshTech-Designs 2 роки тому

    Thanks , You always deliver

  • @marcus_lyn
    @marcus_lyn 2 роки тому +1

    random small improvement I found: this movement code for the background causes a small stutter when we reset the image back to x=0, this is because the game speed pushes x by 3 and sometimes pushes x past the ultimate width, so when we get set back to 0 you can see the stutter, we also did not account for the gamespeed in this scenario.
    To fix this, in the update method for Layer class, I instead increment x by the width of the background image, and I also subtract the game speed to keep moving seamlessly. code:
    if (this.x < -this.width) this.x += this.width - (this.game.speed*this.speedModifier);

  • @barryglibb1448
    @barryglibb1448 2 роки тому

    Loving this series so far, and indeed all your videos having recently discovered your channel. I'm a JS developer of business applications with some 15 years experience and it's nice to be able to follow along with your well-written and explained code to use my skills in a different way. Great job! +1 sub, +1 notification from me.

    • @Frankslaboratory
      @Frankslaboratory  2 роки тому

      Hi Ben, nice to see that my videos could be interesting even for experienced developers. Appreciate your support, thank you for letting me know you found some value!

  • @scottatkinson7649
    @scottatkinson7649 Рік тому

    Hi Frank, I'm loving your tutorial and learning so much. You started mobile controls but how do you add different states on mobile.

  • @funnyanimalworld7579
    @funnyanimalworld7579 2 роки тому

    amazing video and explanation

  • @DannyHille
    @DannyHille 2 роки тому +1

    Tip: when using "Enum types" like states, you can use Objet.freeze to ensure the values doesn't change: like this: const states = Object.freeze({SITTING:0, RUNNING:1});

  • @Avinashkumar-zz8qi
    @Avinashkumar-zz8qi 2 роки тому

    Nice video sir. Thank you for the tutorials.

    • @Frankslaboratory
      @Frankslaboratory  2 роки тому +1

      Happy to help Avinash, comment 5 sec after release haha, nice

  • @evaristocuesta
    @evaristocuesta 2 роки тому

    Excellent!!

    • @Frankslaboratory
      @Frankslaboratory  2 роки тому +1

      Hi Evaristo, I used state design pattern only because of your advice, otherwise this code would look very different ! :)

  • @sertansantos3032
    @sertansantos3032 2 роки тому

    First, thanks for all the effort Frank

  • @anaccount687
    @anaccount687 2 роки тому +1

    How did you do the energy?

    • @Frankslaboratory
      @Frankslaboratory  2 роки тому +1

      It's just a simple object and a couple of if else statements. I'm doing a replenishing ammo in the next class releasing next week, it's the same thing, I will explain it there.

  • @Radu
    @Radu 2 роки тому

    Thanks! I'll need to use that deltaTime technique at some point. Just one question: doesn't this make it refresh slower than the frameInterval? (because you use if(this.frameTimer>this.frameInterval). It would be nice to see a plot of the this.frameTimer values as they accumulate over time. I assume the average value to be something like (frameInterval+deltaTime)/2.

    • @Frankslaboratory
      @Frankslaboratory  2 роки тому +1

      Yes. This technique is not completely accurate because, there is a leftover part of deltaTime value after every reset. For complete cross device behaviour that leftover value would have to be accounted for but I think for the purposes of a project like this it works well enough.

    • @Radu
      @Radu 2 роки тому

      @@Frankslaboratory I see. Thank you, Frank!

  • @kamalkishior6383
    @kamalkishior6383 2 роки тому

    Thank you Sir,
    :)

  • @jeesjans9676
    @jeesjans9676 2 роки тому

    thanks!!

  • @dinhson9588
    @dinhson9588 Рік тому

    hi teacher, im doing same with you but my player not moving when he standing ?? maybe my chrome have problem??

  • @ap666-o8h
    @ap666-o8h 2 роки тому

    Hi Frank,
    Awesome course, i'm followig it and I'm enjoying it very much.
    I just have one question, why do we need to set up a server? I've tried launching the game without the server, just opening the index.html file and it does not work. I'll thank you if you can clearify this.

    • @Frankslaboratory
      @Frankslaboratory  2 роки тому

      Hi Aitor, I briefly mention the reason in the beginning, it's because we are splitting code into modules, multiple files, and we are exporting and importing. This only works when run though a server. If you want it to work locally you would have to put all javascript into a single file. it could be challenging if you are a beginner because the order in which you declare classes is important, they don't hoist

    • @ap666-o8h
      @ap666-o8h 2 роки тому

      @@Frankslaboratory thank you very much, Frank. Very well explained. I watched both videos in their entirety and missed that comment, my fault 😅. Keep up the good work!!

  • @programer115
    @programer115 2 роки тому

    hello teacher, the tutorial was very good, the game is beautiful🧐

  • @cosmincosmin4451
    @cosmincosmin4451 2 роки тому

    Can I find jobs in this direction? JS 2d games? Or is it just for fun?

    • @Frankslaboratory
      @Frankslaboratory  2 роки тому +1

      There are more and more companies doing 2D browser games. If you're good with JavaScript you can get many jobs. Also the logic is easily transferable to other programming languages if needed. When you get a job in a good company they don't care what language you know, as long as you are good at it, they will train you in their specific stack when you join

  • @technoinfoworldwide2329
    @technoinfoworldwide2329 2 роки тому

    is this game series finished?

    • @Frankslaboratory
      @Frankslaboratory  2 роки тому

      Almost, there will be more episodes to finish the full game

  • @h4m2_
    @h4m2_ Рік тому

    how do you cap the fps so the game doesn't move as fast. I'm getting 144 fps because of my monitor and I find it way too quick.

    • @Frankslaboratory
      @Frankslaboratory  Рік тому

      Using delta time you set timer and interval for serving animation frames. I'll do in in the project I'm releasing this Friday

    • @h4m2_
      @h4m2_ Рік тому

      @@Frankslaboratory omg thank you so much for the quick reply. I'll try it right now! Doesn't this just cap the fps of the sprite?

    • @h4m2_
      @h4m2_ Рік тому

      @@Frankslaboratory I see we also are not using deltaTime in the update class in player.js. I skipped the states etc as I plan to use a still image and not animations etc.

    • @Frankslaboratory
      @Frankslaboratory  Рік тому +1

      @@h4m2_ deltaTime can cap anything, it just measures milliseconds so you can use that to trigger periodic event to cap fps of a sprite on a single object or of the entire game, it's the same technique, just needs a small adjustment. In the class I just finished filming I used it that way so that it caps everything. It will cover high refresh rate screens

    • @h4m2_
      @h4m2_ Рік тому

      @@Frankslaboratory thank you very much for this amazing content. I'm looking forward to Friday now!

  • @VeGaDrOnE
    @VeGaDrOnE Рік тому

    I followed along, step by step, but when it's time to see the images scrolling in the background i see my character in a perfect white void 😅 i think the problem is here:
    update(){
    if (this.x < - this.width) this.x = 0;
    else this.x -= this.game.speed * this.speedModifier;
    }
    with this function, if i console log the array entries with:
    console.log(this.backgroundLayers[0].x, this.backgroundLayers[0].y);
    i noticed that the x is NaN and so the program dosen't draw the images. I checked your code and my code several times but it's EXACTLEY the same. How it's possible that is NaN?

    • @Frankslaboratory
      @Frankslaboratory  Рік тому

      Its NaN because one the line where you are calculating that x value, one of the operands is undefined. You need to track that logic until you find where you made a typo

    • @VeGaDrOnE
      @VeGaDrOnE Рік тому

      @@Frankslaboratory I assigned this.x = 0 in the Layer class constructor and then i used:
      update(){
      if (this.x < - this.width) this.x = 0;
      else this.x -= this.game.speed * this.speedModifier;
      }.
      i check if is NaN, i opened the object in console, the problem is the x NaN and the entire update method give me undefined. If i took out the minus sign before the first this.width in the if condition x is 0 and the images are there but dosen't move.

    • @VeGaDrOnE
      @VeGaDrOnE Рік тому

      YES! I did it you
      you were right there was a typo! Thanks!

    • @Frankslaboratory
      @Frankslaboratory  Рік тому

      @@VeGaDrOnE glad you worked it out, nice! :)

  • @PopLll-lo9ot
    @PopLll-lo9ot Рік тому

    Hi can someone help me in console say currentstate undefined please someone help me

  • @Kucingku46
    @Kucingku46 2 роки тому

    Request tutorial idle game with js

    • @Frankslaboratory
      @Frankslaboratory  2 роки тому

      Hi Rifan, what are some examples of idle game genre

  • @jasmin8501
    @jasmin8501 2 роки тому

    Hello, how are you??
    ..excuse me, do you have a Java language course?

    • @Frankslaboratory
      @Frankslaboratory  2 роки тому +1

      Hi Jasmin, I only do JavaScript, for Java there are some other experts here on UA-cam

    • @jasmin8501
      @jasmin8501 2 роки тому

      @@Frankslaboratory
      Can you advise me how to make an application for student absence please

  • @nyupyu
    @nyupyu Рік тому

    My dog jumping soo fast on 165hz refresh rate screen and I can't find solution. Someone know what should I do?

    • @Frankslaboratory
      @Frankslaboratory  Рік тому +1

      You can use delta time to throttle the entire animation loop and max it at around 60fps. I did it in the game tutorial I released last week

  • @vxngp
    @vxngp 2 роки тому

    I hate you. Now I feel not to have hours in a day to play with this new knowledge, lmao

    • @Frankslaboratory
      @Frankslaboratory  2 роки тому +1

      Hi Ivan, there are indeed many use cases for this technique. For example player can have a special animation loop that plays once when entering or exiting each state, if you have sprite sheet for that. Also it can be used to create pause/play/menu functionality when applied to the main game object. I might show how to do all of that later.

    • @vxngp
      @vxngp 2 роки тому

      @@Frankslaboratory Thank you so much for the ideas and for your free content. I've learned so much from you :)

  • @ZilaAi96
    @ZilaAi96 Рік тому

    Bro dog animating too fast how can i slow it

    • @Frankslaboratory
      @Frankslaboratory  Рік тому

      You can control frame rate with delta time calculation. Comparing old and the current timestamp. I do it in most of my game dev classes, didn't do it in this one

  • @CSEGNaveensaireddy
    @CSEGNaveensaireddy 2 роки тому

    Hi sir please make this game installable

    • @Frankslaboratory
      @Frankslaboratory  2 роки тому +1

      Hi, this is a browser game, not sure if JavaScript can do installable games, probably you need something like C+ for that?

    • @CSEGNaveensaireddy
      @CSEGNaveensaireddy 2 роки тому

      Ok Sir

  • @atticusyong2927
    @atticusyong2927 Рік тому +1

    Can someone help me? My code not working...
    background.js
    class Layer {
    constructor(game, width, height, speedModifier, image) {
    this.game = game
    this.width = width
    this.height = height
    this.speedModifier = speedModifier
    this.image = image
    this.x = 0
    this.y = 0
    }
    update() {
    if (this.x < -this.width) this.x = 0
    else this.x -= this.game.speed * this.speedModifier
    }
    draw(context) {
    context.drawImage(this.image, this.x, this.y, this.width, this.height)
    context.drawImage(this.image, this.x + this.width, this.y, this.width, this.height)
    }
    }
    export class Background {
    constructor(game) {
    this.game = game
    this.width = 1667
    this.height = 500
    this.layer1image = document.getElementById('layer1')
    this.layer2image = document.getElementById('layer2')
    this.layer3image = document.getElementById('layer3')
    this.layer4image = document.getElementById('layer4')
    this.layer5image = document.getElementById('layer5')
    this.layer1 = new Layer(this.game, this.width, this.height, 0, this.layer1image)
    this.layer2 = new Layer(this.game, this.width, this.height, 0.2, this.layer2image)
    this.layer3 = new Layer(this.game, this.width, this.height, 0.4, this.layer3image)
    this.layer4 = new Layer(this.game, this.width, this.height, 0.8, this.layer4image)
    this.layer5 = new Layer(this.game, this.width, this.height, 1, this.layer5image)
    this.backgroundLayers = [this.layer1, this.layer2, this.layer3, this.layer4, this.layer5]
    }
    update() {
    this.backgroundLayers.forEach(layer => {
    layer.update()
    })
    }
    draw(context) {
    this.backgroundLayers.forEach(layer => {
    layer.update(context)
    })
    }
    }
    player.js
    import { Sitting, Running, Jumping, Falling } from "./playerStates.js"
    export class Player {
    constructor(game) {
    this.game = game
    this.width = 100
    this.height = 91.3
    this.x = 0
    this.y = this.game.height - this.height - this.groundMargin
    this.vy = 0
    this.weight = 1
    this.image = document.getElementById('player')
    this.frameX = 0
    this.frameY = 0
    this.maxFrame
    this.fps = 20
    this.frameInterval = 1000/this.fps
    this.frameTimer = 0
    this.speed = 0
    this.maxSpeed = 10
    this.states = [new Sitting(this), new Running(this), new Jumping(this), new Falling(this)]
    this.currentState = this.states[0]
    this.currentState.enter()
    }
    update(input, deltaTime) {
    this.currentState.handleInput(input)
    // Horizpntal Movement
    this.x += this.speed
    if (input.includes('ArrowRight')) this.speed = this.maxSpeed
    else if (input.includes('ArrowLeft')) this.speed = -this.maxSpeed
    else this.speed = 0
    if (this.x < 0) this.x = 0
    if (this.x > this.game.width - this.width) this.x = this.game.width - this.width
    // Vertical Movement
    this.y += this.vy
    if (!this.onGround()) this.vy += this.weight
    else this.vy = 0
    // Sprite Animation
    if (this.frameTimer > this.frameInterval) {
    this.frameTimer = 0
    if (this.frameX < this.maxFrame) this.frameX++
    else this.frameX = 0
    } else {
    this.frameInterval += deltaTime
    }

    }
    draw(context) {
    context.drawImage(this.image, this.frameX * this.width, this.frameY * this.height, this.width, this.height, this.x, this.y, this.width, this.height)
    }
    onGround() {
    return this.y >= this.game.height - this.height - this.game.groundMargin
    }
    setState(state, speed) {
    this.currentState = this.states[state]
    this.game.speed = this.game.maxSpeed * speed
    this.currentState.enter()
    }
    }
    playerStates.js
    const states = {
    SITTING: 0,
    RUNNING: 1,
    JUMPING: 2,
    FALLING: 3
    }
    class State {
    constructor(state) {
    this.state = state
    }
    }
    export class Sitting extends State {
    constructor(player) {
    super('SITTING')
    this.player = player
    }
    enter() {
    this.player.frameX = 0
    this.player.maxFrame = 4
    this.player.frameY = 5
    }
    handleInput(input) {
    if (input.includes('ArrowLeft') || input.includes('ArrowRight')) {
    this.player.setState(states.RUNNING, 1)
    }
    }
    }
    export class Running extends State {
    constructor(player) {
    super('RUNNING')
    this.player = player
    }
    enter() {
    this.player.frameX = 0
    this.player.maxFrame = 8
    this.player.frameY = 3
    }
    handleInput(input) {
    if (input.includes('ArrowDown')) {
    this.player.setState(states.SITTING, 0)
    } else if (input.includes('ArrowUp')) {
    this.player.setState(states.JUMPING, 1)
    }
    }
    }
    export class Jumping extends State {
    constructor(player) {
    super('JUMPING')
    this.player = player
    }
    enter() {
    if (this.player.onGround()) this.player.vy -= 27
    this.player.frameX = 0
    this.player.maxFrame = 6
    this.player.frameY = 1
    }
    handleInput(input) {
    if (this.player.vy > this.player.weight) {
    this.player.setState(states.FALLING, 1)
    }
    }
    }
    export class Falling extends State {
    constructor(player) {
    super('FALLING')
    this.player = player
    }
    enter() {
    this.player.frameX = 0
    this.player.maxFrame = 6
    this.player.frameY = 2
    }
    handleInput(input) {
    if (this.player.onGround()) {
    this.player.setState(states.RUNNING, 1)
    }
    }
    }
    script.js
    import { Player } from './player.js'
    import { InputHandler } from './input.js'
    import { Background } from './background.js'
    window.addEventListener('load', function() {
    const canvas = document.getElementById('canvas1')
    const ctx = canvas.getContext('2d')
    canvas.width = 500
    canvas.height = 500
    class Game {
    constructor(width, height) {
    this.width = width
    this.height = height
    this.groundMargin = 80
    this.speed = 0
    this.maxSpeed = 4
    this.background = new Background(this)
    this.player = new Player(this)
    this.input = new InputHandler()
    }
    update(deltaTime) {
    this.background.update()
    this.player.update(this.input.keys, deltaTime)
    }
    draw(context) {
    this.background.draw(context)
    this.player.draw(context)
    }
    }
    const game = new Game(canvas.width, canvas.height)
    console.log(game)
    let lastTime = 0
    function animate(timeStamp) {
    const deltaTime = timeStamp - lastTime
    lastTime = timeStamp
    ctx.clearRect(0, 0, canvas.width, canvas.height)
    game.update(deltaTime)
    game.draw(ctx)
    requestAnimationFrame(animate)
    }
    animate(0)
    })

  • @javifontalva7752
    @javifontalva7752 Рік тому

    This is my next challenge. Bring it on!