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
Related
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/
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.
I have element
<div id="square"></div>
He has a property to move on document
var square = document.getElementById("square");
document.body.onkeydown = function(e) {
if (e.keyCode == 37) {left()}
if (e.keyCode == 38) {up()}
if (e.keyCode == 39) {right()}
if (e.keyCode == 40) {down()}
}
How I make a function, which not allowed movement, if square element is closest to document border?
JSFiddle: https://jsfiddle.net/zutxyLsq/
You need to check if left is outside of boundaries like this:
function left() {
console.log('Left');
var left = parseInt(square.style.left || getComputedStyle(square)['left'], 10);
if (left >= 50) {
square.style.left = (left - 50) + 'px';
}
}
function right() {
console.log('Right');
var left = parseInt(square.style.left || getComputedStyle(square)['left'], 10);
if (left+50+square.offsetWidth < window.innerWidth) {
square.style.left = (left + 50) + 'px';
}
}
https://jsfiddle.net/zutxyLsq/3/
and the same for up and down.
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();
}
http://jsfiddle.net/xknbn/
http://jsfiddle.net/xknbn/embedded/result/
Hey guys. I'm having issues getting my collision system to function without problems. At the moment, if I'm going too fast, I get embedded in the object and my collision resolution fails. I'm fairly certain that the problem happens because of how I have velocity set up, but I don't know how I can go about fixing the issue. Any help would be greatly appreciated.
friction = 0.9,
gravity = 0.3;
function keycheck() {
if (keys[32]) {
if (!player.jumping) {
player.jumping = true;
player.vely = -player.speed;
}
}
if (keys[68]) {
if (player.velx < player.speed) {
player.velx++;
}
}
if (keys[65]) {
if (player.velx > -player.speed) {
player.velx--;
}
}
}
ctx.startx = player.x;
ctx.starty = player.y;
function playerupdate() {
player.Intersects = function(object) {
return player.x < object.x + object.width + 1 &&
player.x + player.width + 1 > object.x &&
player.y < object.y + object.height + 1 &&
player.y + player.height + 1 > object.y;
}
solidcount = 0;
for (i = 0; i < tgen.length; i++) {
for (ii = 0; ii < tgen[i].length; ii++) {
if ( player.Intersects(tgen[i][ii]) && tgen[i][ii].solid ) {
var pright = player.x + player.width,
pleft = player.x,
ptop = player.y,
pbottom = player.y + player.height,
oright = tgen[i][ii].x + tgen[i][ii].width,
oleft = tgen[i][ii].x,
otop = tgen[i][ii].y,
obottom = tgen[i][ii].y + tgen[i][ii].height;
//if player is to the right of his previous position, and his right side has collided with objects left
if (player.x >= ctx.startx && pright > oleft - 1) {
player.x--;
}
//if player is to the left of his previous position, and his left side has collided with objects right
if (player.x <= ctx.startx && pleft < oright + 1) {
player.x++;
}
//if player is above his previous position, and his top side has collided with objects bottom
if (player.y <= ctx.starty && ptop < obottom + 1) {
player.y++;
}
//if player is below his previous position, and his bottom side has collided with objects top
if (player.y >= ctx.starty && pbottom > otop - 1) {
player.y--;
player.vely = 0;
player.jumping = false;
}
solidcount++;
}
}
if ( i == tgen.length - 1 && solidcount == 0 ) {
player.jumping = true;
}
}
ctx.diffx = player.x - ctx.startx;
ctx.diffy = player.y - ctx.starty;
if (player.x <= bgimg.width - width/2 && player.x >= width/2) {
ctx.translate(-ctx.diffx,0);
}
if (player.y <= bgimg.height - 360 - player.height) {
ctx.translate(0,-ctx.diffy);
}
ctx.startx = player.x;
ctx.starty = player.y;
ctx.clearRect(player.x-width/2,player.y-height/2,width,height);
ctx.fillStyle = 'red';
ctx.fillRect(player.x,player.y,player.width,player.height);
keycheck();
player.velx *= friction;
if (player.jumping) {player.vely += gravity;}
player.x += player.velx;
player.x = Math.round(player.x);
player.y += player.vely;
player.y = Math.round(player.y);
if (player.y >= bgimg.height - player.height - 1) {
player.y = bgimg.height - player.height - 1;
player.vely = 0;
player.jumping = false;
}
if (player.x > bgimg.width - player.width) {
player.x = bgimg.width - player.width;
player.velx = 0;
};
if (player.x < 0) {
player.x = 0;
player.velx = 0;
}
if (!keys[65] && !keys[68] && (player.velx < 0.2 && player.velx > -0.2)) {player.velx = 0};
console.log(player.x,player.y)
requestAnimationFrame(playerupdate);
}
So this is a common platform engine problem. If your player was moving too fast, it would go straight though the obstacles, because no collision testing occurs between the current position and the next position. Your aim is to test collisions as few times as possible but so that all possible collisions between the start position and the target are tested. Also when you detect a collision in the path, you have to handle it properly.
Moving objects safely
To move any objects safely you need to move them in steps, and test for collisions at each step. The simplest choice is to move the player by 1 pixel at a time, and then test for a collision. This does mean doing a lot of collision tests though.
To improve this, if you are only doing box collision testing, you can move the player by a maximum of the width of the player each time.
Dealing with collisions
So in your example, you move the player back 1 pixel depending on the direction of the player. If the player were to sink 5 pixels into the obstacle, then your collision handling mechanism only moves the player back to 4 pixels into the obstacle. It appears as if the player slowly moves through the obstacle.
If you move the player 1 pixel at a time, the approach you have taken works. If you move the player more than 1 pixel at a time then you have to move the player back until it no longer overlaps an obstacle. Something like while (overlapping) -> move back one pixel