0
\$\begingroup\$

I am fairly new to game development. I am programming a basic JavaScript canvas game. Whenever I press a key my player goes flying off of the canvas. Here is the controller code

document.onkeydown = function(event){
    if(event.keyCode === 87){
        player.up = true;
    }
    else if(event.keyCode === 83){
        player.down = true;
    }
    else if(event.keyCode === 65){
        player.left = true;
    }
    else if(event.keyCode === 68){
        player.right = true;
    }
}

document.onkeyup = function(e){
    if(e.keyCode === 87){
        player.up = false;
    }
    else if(e.keyCode === 83){
        player.down = false;
    }
    else if(e.keyCode === 65){
        player.left = false;
    }
    else if(e.keyCode === 68){
        player.right = false;
    }
}

if(game.keys && game.keys[87]){
        player.speedY += -0.4;
        if(player.speedY > player.maxSpeed){
            player.speedY = player.maxSpeed;
        }
    }
    if(game.keys && game.keys[83]){
        player.speedY += 0.4;
        if(player.speedY > player.maxSpeed){
            player.speedY = player.maxSpeed;
        }
    }
    if(game.keys && game.keys[65]){
        player.speedX += -0.4;
        if(player.speedX > player.maxSpeed){
            player.speedX = player.maxSpeed;
        }
    }
    if(game.keys && game.keys[68]){
        player.speedX += 0.4;
        if(player.speedX > player.maxSpeed){
            player.speedX = player.maxSpeed;
        }
    }

The above is the controller code... What improvements should be made on the above code.

edit I realize you may need to see the entity creation code

function square(width, height, color, x, y) {
  this.width = width;
  this.height = height;
  this.x = x;
  this.y = y; 
  this.speedX = 0;
  this.speedY = 0;
  this.right = false;
  this.left = false;
  this.up = false;
  this.down = false;
  this.rend = function(){
    ctx = game.context;
    ctx.fillStyle = color;
    ctx.fillRect(this.x, this.y, this.width, this.height);
  }
  this.movement = function() {
    this.x += this.speedX;
    this.y += this.speedY;
  }
}

edit max speed integration.

  var now = Date.now();
  var delta = now - lastUpdate;
  lastUpdate = now;
  this.width = width;
  this.height = height;
  this.x = x;
  this.y = y; 
  this.angle = 0;
  this.maxSpeed = 3;
  this.speedX = 0;
  this.speedY = 0;
  this.rend = function(){
    ctx = game.context;
    ctx.fillStyle = color;
    ctx.globalAlpha = 1;
    ctx.fillRect(this.x, this.y, this.width, this.height);
  }
  this.movement = function() {
    this.x += this.speedX;
    this.y += this.speedY;
}
}

editadded player making function.

\$\endgroup\$
1
\$\begingroup\$

I'm pretty sure I know what's wrong with your code. (Now I really hope I didn't make some stupid mistake myself).

You properly check whether the control buttons are pressed and you store that info. However! In the "movement" part of the code, you add speed in the same direction... plenty of times. (once each frame, which might be 60 or more times per second). You can imagine how quickly that scales up. You do the same thing in the later part of the code. You modify position by speed, but you do it every frame.

Imagine this: you want your player to move 10 meters per second. So you set up the speed to 10 - and then you move him, also by 10 in a method. But the code doesn't care about seconds that much, it will try to move whole 10 meters in one frame, which at 60fps is 600 meters per second!

What you would like to do is somehow check something called delta time. I don't know how to do it in javascript, but every game engine has something like that built in. You might look it up or experiment with checking the framerate?

deltaTime = 1 / framerate;

Then do this:

this.movement = function() {
    this.x += this.speedX * deltaTime;
    this.y += this.speedY * deltaTime;
  }

that should help with the biggest issue. I see a smaller problems that can emerge in your game.

 if(player.up == true){
    player.speedY += -1;
}

The way you add speed here is a good idea, but in the long run you might encounter some issues.

You are not checking for max speed. You are not using delta time, so again your acceleration might go crazy (also it will be too framerate dependant, so players with faster computers can have unfair advantage!).

And if you could add "decay". In other words, if the player isn't actively adding speed, you might want to slow down a bit. Otherwise, you will never really "stop". Your speed will go to some number like 15, so you press the opposite direction, but you will never hit exactly 15, so you will end up with speed of -2... you know what I mean?

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ How would I ensure when the max speed is reached that I cap the current speed? Also, I researched delta time and managed to come up with this var now = Date.now(); var delta = now - lastUpdate; lastUpdate = now; \$\endgroup\$ – Ameer Apr 7 '19 at 4:53
  • \$\begingroup\$ What you found about delta time sounds great. Definitely use that! And about max speed, there should be some kind of "clamp" method. If there's none, you can make one yourself: player.speedX += 1; if (player.speedX > maxSpeed){ player.speedX = maxSpeed; } \$\endgroup\$ – lilKriT Apr 7 '19 at 5:09
  • \$\begingroup\$ I tried that and it doesn't seem to work, I integrated it as seen in the new edit I just made. I'm not really sure if I integrated it properly. \$\endgroup\$ – Ameer Apr 7 '19 at 5:13
  • \$\begingroup\$ @Ameer Where did you set player.maxSpeed? \$\endgroup\$ – Bálint Apr 7 '19 at 7:32
  • \$\begingroup\$ I set it where I make my player I added it just now to the question. \$\endgroup\$ – Ameer Apr 7 '19 at 13:03
1
\$\begingroup\$

After a couple of hours of trying to solve this issue I came up with this

function moving() {
     if(game.keys && game.keys[87]){
        player.speedY = -2;
    }
    else if(game.keys && game.keys[83]){
        player.speedY = 2;
    }
    else if(game.keys && game.keys[65]){
        player.speedX = -2;
    }
    else if(game.keys && game.keys[68]){
        player.speedX = 2
    }else{
        player.stop();
    }
}

this.stop = function(){
    this.speedX = 0;
    this.speedY = 0;
  }

Basically, I check that none of those keys were pressed then say player speed X is 0 and speed Y is 0.

Thank you to all the commentators who helped!

| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ I'm glad we could help. If you like our answer, can you upvote us? ;) \$\endgroup\$ – lilKriT Apr 7 '19 at 20:39
  • 1
    \$\begingroup\$ you were very helpful so of course! \$\endgroup\$ – Ameer Apr 8 '19 at 2:34

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.