JavaScript Game Tutorial - Advanced Techniques

Поделиться
HTML-код
  • Опубликовано: 9 окт 2024

Комментарии • 89

  • @Frankslaboratory
    @Frankslaboratory  2 года назад +5

    Part 1 here, have fun! :D ruclips.net/video/c-1dBd1_G8A/видео.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 (ruclips.net/video/6CKW7tLv5e0/видео.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.

  • @PhorssaOneDev
    @PhorssaOneDev Год назад +1

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

  • @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

  • @palmpixiplus
    @palmpixiplus Год назад

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

  • @javifontalva7752
    @javifontalva7752 Год назад

    This is my next challenge. Bring it on!

  • @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

  • @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);

  • @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

  • @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!

  • @souerico
    @souerico Год назад

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

  • @nicklansbury3166
    @nicklansbury3166 2 года назад +1

    Another masterpiece. Thanks Frank. Enjoy your weekend.

  • @TheLegendOfNiko
    @TheLegendOfNiko 2 года назад

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

  • @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});

  • @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.

  • @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!

  • @CodingBill
    @CodingBill 2 года назад

    I love the way you teach things :)

  • @lexart1
    @lexart1 2 года назад

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

  • @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!

  • @AshTech-Designs
    @AshTech-Designs 2 года назад

    Thanks , You always deliver

  • @funnyanimalworld7579
    @funnyanimalworld7579 2 года назад

    amazing video and explanation

  • @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

  • @aitorplaza2560
    @aitorplaza2560 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

    • @aitorplaza2560
      @aitorplaza2560 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!!

  • @sertansantos3032
    @sertansantos3032 2 года назад

    First, thanks for all the effort Frank

  • @dinhson9588
    @dinhson9588 Год назад

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

  • @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 ! :)

  • @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

  • @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.

  • @kamalkishior6383
    @kamalkishior6383 2 года назад

    Thank you Sir,
    :)

  • @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! :)

  • @jeesjans9676
    @jeesjans9676 2 года назад

    thanks!!

  • @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!

  • @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 RUclips

    • @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

  • @technoinfoworldwide2329
    @technoinfoworldwide2329 2 года назад

    is this game series finished?

    • @Frankslaboratory
      @Frankslaboratory  2 года назад

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

  • @ivgadev
    @ivgadev 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.

    • @ivgadev
      @ivgadev 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!