Javascript movement delay on initial keypress (3D) - javascript

I want the movement to be smooth upon pressing a key, the object does an initial movement and then starts moving completely when holding down the button.
//movement speed
var xSpeed = 0.5;
var zSpeed = 0.5;
document.addEventListener("keydown", onDocumentKeyDown, false);
function onDocumentKeyDown(event) {
var keyCode = event.which;
if (keyCode == 87) { //W KEY
car.position.z -= zSpeed;
} else if (keyCode == 83) { //S KEY
car.position.z += zSpeed;
} else if (keyCode == 65) { //A KEY
car.position.x -= xSpeed;
} else if (keyCode == 68) { //D KEY
car.position.x += xSpeed;
} else if (keyCode == 32) {
car.position.set(0, 0, 0);
}
};
Trying to get a GLTF imported model to be controlled on a plane with keyboard controls smoothly.
Tried wrapping the program in a loop and made the state of the keyboard available inside the scope of that loop but couldn't get it working

You could try an approach where the velocity is modified upon keyup/keydown, and the loop just modifies the car's position based on the velocity.
// initial movement speed
var xSpeed = 0;
var zSpeed = 0;
document.addEventListener("keydown", onDocumentKeyDown, false);
document.addEventListener("keydown", onDocumentKeyUp, false);
function onDocumentKeyDown(event) {
var keyCode = event.which;
if (keyCode == 87) { //W KEY
zSpeed = -0.5;
} ... // do so for the rest of the keys
};
function onDocumentKeyUp(event) {
var keyCode = event.which;
if (keyCode == 87) { //W KEY
zSpeed = 0;
} ... // do so for the rest of the keys
};
function loop() {
car.position.z += zSpeed;
car.position.x += xSpeed;
window.requestAnimationFrame(loop);
}
If you are interested in more eased movement, e.g. the car doesn't just start moving at constant velocity but ramps up and slows down, consider having the keyup/keydown modify an acceleration factor, and the loop modifies the velocity.
This is a good in-depth article by Daniel Shiffman about attempting to represent the real world with code:
https://natureofcode.com/book/chapter-1-vectors/

Related

Why and (&) in if statement is not working? [duplicate]

This question already has answers here:
How to detect if multiple keys are pressed at once using JavaScript?
(19 answers)
Closed 5 years ago.
So i am making a html5 game where i was working in movement. Player can move with w, a, s ,d in key. That is working well but i wanted to add a power ..like if player press a + space-bar or d + space-bar an ability will trigger.
i used and operator and it should have worked in my theory but it's not working.
I am new in html5 and any help will be appreciated. thanks in advance.
Here is my code... Just copy paste on html note.
<canvas id="canvas" width="800" height="500" style="border:1px solid #000000;"></canvas>
<script>
var c = document.getElementById("canvas").getContext("2d");
var WIDTH = 800;
var HEIGHT = 500;
var player = {
x: Math.random() * WIDTH,
y: Math.random() * HEIGHT,
width: 30,
height: 30,
color: 'black',
pressingDown: false,
pressingUp: false,
pressingLeft: false,
pressingRight: false,
pressinpowerRight: false,
pressinpowerLeft: false,
};
drawEntity = function(e) {
c.fillStyle = e.color;
c.fillRect(e.x - e.width / 2, e.y - e.height / 2, e.width, e.height);
}
document.onkeydown = function(event) {
if (event.keyCode === 68) //d
player.pressingRight = true;
else if (event.keyCode === 83) //s
player.pressingDown = true;
else if (event.keyCode === 65) //a
player.pressingLeft = true;
else if (event.keyCode === 87) // w
player.pressingUp = true;
else if (event.keyCode === 68 && event.keyCode === 32) // this statement is not working
player.pressinpowerRight = true;
else if (event.keyCode === 65 && event.keyCode === 32) // this statement is not working
player.pressinpowerLeft = true;
}
document.onkeyup = function(event) {
if (event.keyCode === 68) //d
player.pressingRight = false;
else if (event.keyCode === 83) //s
player.pressingDown = false;
else if (event.keyCode === 65) //a
player.pressingLeft = false;
else if (event.keyCode === 87) // w
player.pressingUp = false;
else if (event.keyCode === 68 && event.keyCode === 32) // not working
player.pressinpowerRight = false;
else if (event.keyCode === 65 && event.keyCode === 32) // not working
player.pressinpowerLeft = false;
}
updatePlayerPosition = function() {
if (player.pressingRight)
player.x += 5;
if (player.pressingLeft)
player.x -= 5;
if (player.pressingDown)
player.y += 5;
if (player.pressingUp)
player.y -= 5;
if (player.pressingpowerRight)
player.x += 50;
if (player.pressingpowerLeft)
player.x -= 50;
}
update = function() {
c.clearRect(0, 0, WIDTH, HEIGHT);
updatePlayerPosition();
drawEntity(player);
}
setInterval(update, 40);
</script>
Try creating a previousButtonKey global variable and always record the last key, then check the previousButtonKey with another key to combine two keys on your condition.
Ex. First key is to be pressed is 'Shift', store it to a variable, then once another key event happens, check the previous and the new key. If it is valid, then do the action that you want.

JavaScript window.onkeydown

slight disclaimer, i'm relatively new to JavaScript and i'm not the best, although I guess that begs the question how do you define "best". Anyway I digress. My question is when I am moving an object around the canvas why is it slow (stuttery) and only one key press can be registered at one time. Is there a way to make it more smooth and so that you can register multiple keys at a time?
// player movement
window.onkeydown = function playermovement () {
var keypress = event.which || event.keyCode;
//up
if (keypress == 87 && player.y >0) {
player.y = player.y -20
}
//down
if (keypress == 83 && player.y < 400) {
player.y = player.y + 20
}
if (keypress == 38) {
player2.y = player2.y -20
}
if (keypress == 40) {
player2.y = player2.y +20
}
}
Thank you
James

Moving diagonally in 2d canvas JavaScript game

I've scoured the web for this answer. If it is buried in a StackOverflow answer somewhere I apologize.
I am working on a 2d canvas JavaScript game.
I am handling arrow key input with onkeydown and onkeyup events.
I store this input in an object called Keys.
var Keys = {
up: false,
down: false,
left: false,
right: false
};
This is what my event handlers look like:
window.onkeydown = function(e){
var kc = e.keyCode;
e.preventDefault();
if(kc === 37) Keys.left = true;
else if(kc === 38) Keys.up = true;
else if(kc === 39) Keys.right = true;
else if(kc === 40) Keys.down = true;
move();
};
window.onkeyup = function(e){
var kc = e.keyCode;
e.preventDefault();
if(kc === 37) Keys.left = false;
else if(kc === 38) Keys.up = false;
else if(kc === 39) Keys.right = false;
else if(kc === 40) Keys.down = false;
};
Then each time the keydown event occurs, I call my move() function:
var move = function(){
if(Keys.up){
hero.y -= 10;
}
else if(Keys.down){
hero.y += 10;
}
if(Keys.left){
hero.x -= 10;
}
else if(Keys.right){
hero.x += 10;
}
main();
}
The move() function calls my main() function which just draws the map again.
I'm trying to avoid looping the game, and instead update the map each time the player moves.
So my problem arises when I try to move diagonally. I am able to do it, however once I release the second key pressed, my character stops.
For example:
Right key pressed and then up key pressed, character moves northeast.
Up key released, player stops.
However, if I release the right key, the character continues moving up.
Another glitch is when I hold both left and right, the character will move left,
but I want it to stop moving.
Quickly sketched an example, jsfiddle: http://jsfiddle.net/ofnp4vj4/
HTML: <div id="log"></div>
JS:
var Keys = {
up: false,
down: false,
left: false,
right: false
};
var hero = {
x: 0,
y: 0
};
var log = document.getElementById("log");
window.onkeydown = function(e){
var kc = e.keyCode;
e.preventDefault();
if(kc === 37) Keys.left = true;
if(kc === 38) Keys.up = true;
if(kc === 39) Keys.right = true;
if(kc === 40) Keys.down = true;
};
window.onkeyup = function(e){
var kc = e.keyCode;
e.preventDefault();
if(kc === 37) Keys.left = false;
if(kc === 38) Keys.up = false;
if(kc === 39) Keys.right = false;
if(kc === 40) Keys.down = false;
};
function main() {
/* body */
move();
log.innerHTML = "x: "+hero.x+", y: "+hero.y;
};
function move(){
if(Keys.up){
hero.y -= 10;
}
if(Keys.down){
hero.y += 10;
}
if(Keys.left) {
hero.x -= 10;
}
if(Keys.right){
hero.x += 10;
}
}
setInterval(main, 100);
You mention that you want the player to stop moving when you press the left and right keys simultaneously. It appears you should be able to easily do this by replacing the else if statements in move with if statements, resulting in a move function similar to:
var move = function(){
if(Keys.up){
hero.y -= 10;
}
if(Keys.down){
hero.y += 10;
}
if(Keys.left){
hero.x -= 10;
}
if(Keys.right){
hero.x += 10;
}
main();
}

Trouble with logical operators in JS

I'm trying to write a simple 2D platform game and I can't get my player object to double jump - or rather, I can't get him NOT to. When the up arrow or spacebar is pressed once, double jump is triggered no matter what. I am a JS newbie so I assume this has something to do with my use of logical operators, but I could be wrong. Here is the code:
(function() {
var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
window.requestAnimationFrame = requestAnimationFrame;
})();
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d"),
width = 500,
height = 200,
player = {
x : width/2,
y : height - 5,
width : 5,
height : 5,
speed : 3,
velX : 0,
velY : 0,
jumping : false,
jumping_twice : false
};
keys = [],
friction = 0.8,
gravity = 0.3;
canvas.width = width;
canvas.height = height;
function update(){
if (keys[38] || keys[32]) {
// up arrow or space
if (!player.jumping) {
player.jumping = true;
player.velY = -player.speed*2;
console.log("Player is jumping");
}
else if (!player.jumping_twice) {
player.jumping_twice = true;
player.velY = -player.speed;
console.log("Player is jumping twice");
}
}
if (keys[39]) {
// right arrow
if (player.velX < player.speed) {
player.velX++;
}
}
if (keys[37]) {
// left arrow
if (player.velX > -player.speed) {
player.velX--;
}
}
player.velX *= friction;
player.velY += gravity;
player.x += player.velX;
player.y += player.velY;
if (player.x >= width-player.width) {
player.x = width-player.width;
} else if (player.x <= 0) {
player.x = 0;
}
if (player.y >= height-player.height) {
player.y = height - player.height;
player.jumping = false;
player.jumping_twice = false;
}
ctx.clearRect(0,0,width,height);
ctx.fillStyle = "red";
ctx.fillRect(player.x, player.y, player.width, player.height);
requestAnimationFrame(update);
}
window.addEventListener("load", function(){
update();
})
document.body.addEventListener("keydown", function(e) {
keys[e.keyCode] = true;
});
document.body.addEventListener("keyup", function(e) {
keys[e.keyCode] = false;
});
#rhino is totally right about the explanation. I have another solution though. After the jump has been processed, reset the information about the jump key being pressed:
keys[32] = keys[38] = false;
requestAnimationFrame(update);
This happens because update() runs multiple times while the jump key is held down; both conditions are met, one after the other, before you release the key. You could do the check and make the character jump in the keydown handler to work around that, but it is a better idea to keep the changes of your character in the main loop (update() in your case). To do so, you need an extra variable which determines whether the player can actually jump, based on the changes of key state - when the key gets released, the player can jump again or perform a double jump. You could give player a new property called, for example, can_jump and initially set it to true. Then you can do as follows:
if (keys[38] || keys[32]) {
// up arrow or space
if (player.can_jump) {
if (!player.jumping) {
player.jumping = true;
player.velY = -player.speed*2;
player.can_jump = false; // the player can't jump anymore until the key is released
console.log("Player is jumping");
}
else if (!player.jumping_twice) {
player.jumping_twice = true;
player.velY = -player.speed;
console.log("Player is jumping twice");
}
}
And in the keyup handler:
if (e.keyCode == 32 || e.keyCode == 38) player.can_jump = true;
Working demo: http://jsfiddle.net/5JF69/
Also, be aware that the speed of your game depends on how fast the browser performs a redraw, as you are updating your game logic using requestAnimationFrame().
EDIT: In case the state of the spacebar and up keys doesn't need to remain "down" at all times the keys are actually held down (which doesn't in your current code), go for #lordvlad's solution. It's definitely better if you don't perform any other checks on those keys.
Hah I'm actually the author of the tutorial code you're using.
All the answers are good answers, this is how I would personally do it.
if (keys[38] || keys[32]) {
// up arrow or space
if (!player.jumping) {
player.jumping = true;
player.velY = -player.speed*2;
console.log("Player is jumping");
}
else if(player.jumping && !player.jumping_twice) {
player.jumping_twice = true;
player.velY = -player.speed;
console.log("Player is jumping twice");
}
keys[38] = keys[32] = false;
}
I would just set the keys to false if they are true in the check itself.
#lordvlad makes a good point, there should be an update cycle separate from the rendering, however for the purpose of the tutorial it was really just to get the user up and running to get something on the screen. At some point I'll make a part 3 to break the logic out a bit more. Anyway hope this helps.
Live Demo

How to get input from javascript without stutters between changing keys pressed

I am currently doing this for input handling:
var upKey = false;
var downKey = false;
var leftKey = false;
var rightKey = false;
var sqrt2over2 = 0.707106781;
var MoveSpeed = 20.0;
var Horizontal = false;
var Vertical = false;
document.onkeyup=function(e){
if(e.which == 87)
{
Vertical = false;
upKey = false;
}
if(e.which == 83)
{
Vertical = false;
downKey = false;
}
if(e.which == 65)
{
Horizontal = false;
leftKey = false;
}
if(e.which == 68)
{
Horizontal = false;
rightKey = false;
}
}
document.onkeydown=function(e){
//Up arrow key
if(e.which == 87) upKey = true;
//Down arrow key
if(e.which == 83) downKey = true;
//Left arrow key
if(e.which == 65) leftKey = true;
//Right arrow key
if(e.which == 68) rightKey = true;
var diagonals = Vertical && Horizontal;
if(downKey)
{
Vertical = true;
moveY -= diagonals ? MoveSpeed * sqrt2over2: MoveSpeed;
}
if(upKey)
{
Vertical = true;
moveY += diagonals ? MoveSpeed * sqrt2over2: MoveSpeed;
}
if(rightKey)
{
Horizontal = true;
moveX -= diagonals ? MoveSpeed * sqrt2over2: MoveSpeed;
}
if(leftKey)
{
Horizontal = true;
moveX += diagonals ? MoveSpeed * sqrt2over2: MoveSpeed;
}
}
I need to have this work so that the screen doesn't pause at all when you press another direction or multiple directions. Currently there is a bit of a pause. Is there a setting to turn off this pause or is there another approach to pooling and responding to input which circumvents this dilemma?
I think the pause is due to key repeat rate. Take a look at this question / answers: remove key press delay in javascript
The problem is that you're using the operating system's key repeat as the 'tick' for moving. Instead of this you should use setInterval to create your own tick for moving, and then monitor keydown / keyup to change the direction of movement.

Categories