0
\$\begingroup\$

I have asked questions for this project before, but the jumping physics are a bit messed up. I cannot jump unless I hold down the W key, and then it just teleports me upwards. Does anybody know how to fix this glitch? Here's the code:

var canvas = document.getElementById("canvas")
            var ctx = canvas.getContext("2d")
            var x = 1
            var y = 0
            var xPos = 0
            var yPos = 0

            function updateVariables() {
            x = x * 0.9
            y = y * -0.9
            y = y + 0.5
            xPos += x
            yPos += y
            }

            function clear() {
            ctx.clearRect(0,0,600,600)
            }

            function Draw() {
            collisionCheck();
            clear();
            ctx.fillRect(xPos,yPos,10,10)
            ctx.fillRect(0,canvas.offsetHeight * 0.7,600,200)
            window.requestAnimationFrame(Draw)
            }

            function collisionCheck() {
            if (yPos > canvas.offsetHeight * 0.7 - 10) {
                yPos = canvas.offsetHeight * 0.7 - 10
            }
            }

            function right() {
                x = 2
            }

            function left() {
                x = -2
            }

            function jump() {
                y =+ 20
            }

            function detectKeys() {
                document.onkeypress = function (e) {
                    e = e || window.event;
                    console.log(e.key)
                    if (e.key == "d") {
                        right()
                    }
                    if (e.key == "a") {
                        left()
                    }
                    if (e.key == "w") {
                        jump()
                    }
                }
            }
            

            window.requestAnimationFrame(Draw)
            setInterval(updateVariables, 1)
            setInterval(detectKeys, 1)
<canvas id="canvas" width="500" height="140"></canvas>

\$\endgroup\$
2
\$\begingroup\$

A glaring math problem pointed out by DMGregory is that you're multiplying your y position by -0.9, meaning it's oscillating between positive and negative. That's probably a good brunt of why jumping doesn't work, even ignoring the other problems below.

A few other problems, most JavaScript/Web specific:

First, your detectKeys doesn't at all do what you think it's doing. It's just registering a callback on onkeypress. It won't actually read any keys at that time. The event handler will get triggered when a key is pressed. And since you're re-registering this over and over again via setInterval, you're registered multiple handlers, which will all get called whenever a key is pressed. You just want to register the handlers once at the beginning of the game and never again; the callbacks will be invoked when a key is pressed so there's no need to keep polling. The callback will be called only when the key state is triggered (I'll address that below).

Second, document.onkeypress isn't what you want anyway. It is triggered when you first press the key and is automatically repeated based on the browser's/OS's key repeat rate. You want to use onkeydown instead.

Third, and going back to how you're using the callbacks, you're only applying movement when the key is triggered (first pressed, or on the key repeated rate because you're using onkeypress). You want to store the input state (e.g. whether the player is trying to move left/right or is trying to jump) and apply that state, rather than directly responding to keyboard events. This means using onkeydown/onkeyup to update some state variables and then reading those state variables in your game loop.

Fourth, you have a typo in jump. You wrote y=+20 instead of y+=20. What you wrote is equivalent to saying y=(+20) or just y=20.

Finally (from what I see in a quick perusal), the way you're trying to do the game loop is wrong. You have draw correctly keyed to requestAnimationFrame, but your updateVariables should be as well. setInterval is not a good function to use in general for this kind of stuff, because the interval is non-reliable (it might be more or less frequent than requested or be skipped periodically, etc.). Make just a single update function that is scheduled via requestAnimationFrame, and then have this update function call your updateVariables function and then the draw function. You'd also insert a new function here that reads those keyboard state variables and applies the requested movement. I'd further add that you want to use a time delta (because you can't predict the framerate that requestAnimationFrame will run at) when applying your physics/movement code so that you get smooth and predictable movement; you can calculate a time delta via the performance.now call.

I'd highly recommend that you read over some tutorials like https://codeincomplete.com/posts/javascript-game-foundations-the-game-loop/ and https://codeincomplete.com/posts/javascript-game-foundations-player-input/ (perhaps that whole series) which will cover all these topics with code samples.

\$\endgroup\$
  • 1
    \$\begingroup\$ The repeated flipping of y = y * -0.9 looks questionable too... \$\endgroup\$ – DMGregory Apr 22 at 11:08
  • \$\begingroup\$ Hah, nice catch, I totally didn't even notice that one. :) Will update answer with that note. \$\endgroup\$ – Sean Middleditch Apr 24 at 2:20
0
\$\begingroup\$

For just fixing the jumping you only need to change a few things. I put a comment in the code wherever I changed something. There are other things that could be nice to change, but you only asked to fix the jumping so here it is. Good luck with your project!

var canvas = document.getElementById("canvas")
var ctx = canvas.getContext("2d")
var x = 1
var y = 0
var xPos = 0
var yPos = 0
var onGround = false; // keep track if you're on the ground, so you cant jump mid-air
function updateVariables() {
    x = x * 0.9
    // y = y * -0.9  // removed line because it did many weird things with the y velocity
    y = y + 0.05 // changed from 0.5 to 0.05 otherwise it went back down way too fast
    xPos += x
    yPos += y
}

function clear() {
    ctx.clearRect(0, 0, 600, 600)
}

function Draw() {
    collisionCheck();
    clear();
    ctx.fillRect(xPos, yPos, 10, 10)
    ctx.fillRect(0, canvas.offsetHeight * 0.7, 600, 200)
    window.requestAnimationFrame(Draw)
}

function collisionCheck() {
    if (yPos > canvas.offsetHeight * 0.7 - 10) {
        yPos = canvas.offsetHeight * 0.7 - 10
        onGround = true; // new line
        y = 0; // set y speed to 0 when you hit the ground
    }
}

function right() {
    x = 2
}

function left() {
    x = -2
}

function jump() {
    if (onGround) { // check if you're on the ground before jumping
        // y =+ 20 // old code removed because y is negative in the up direction
        y = -2; // set y velocity to a negative number to jump up.
        onGround = false; // make so you cant jump again mid-air
    }

}

function detectKeys() {
    document.onkeypress = function (e) {
        e = e || window.event;
        console.log(e.key)
        if (e.key == "d") {
            right()
        }
        if (e.key == "a") {
            left()
        }
        if (e.key == "w") {
            jump()
        }
    }
}


window.requestAnimationFrame(Draw)
setInterval(updateVariables, 1)
setInterval(detectKeys, 1)

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.