window.addEventListener("keydown", keyDown, false);
window.addEventListener("keyup", keyUp, false);
var key = new Set();
function keyDown(k) {
key.add(k.keyCode);
if (key.has(83)) {
player.vy = 1;
};
if (key.has(87)) {
player.vy = -1;
};
if (key.has(65)) {
player.vx = -1;
if (key.has(68)) {
player.vx = -1;
};
};
if (key.has(68)) {
player.vx = 1;
if (key.has(65)) {
player.vx = 1;
};
};
};
function keyUp(k) {
key.delete(k.keyCode);
if (k.keyCode === 83) {
player.vy = 0;
};
if (k.keyCode === 87) {
player.vy = 0;
};
if (k.keyCode === 65) {
if (!key.has(68)) {
player.vx = 0;
};
};
if (k.keyCode === 68) {
if (!key.has(65)) {
player.vx = 0;
};
};
};
I am trying to create smooth movement when dialing around the W,A,S,D keys. I finally got something that works except one minor glitch. Whenever I am holding D to move right and I press A, the player's movement is not interrupted. That is how I want it to work but when I do the opposite, the movement is interrupted and reversed. If I switch the 2 blocks I pointed out in the code it will reverse the problem, fixing one and breaking the other. I assume its something to do with how its catching the if statements but I don't know. Can someone tell me what the ffffffff is going on?
Related
I'm trying to figure out how to make the keyboard get disabled after the score equals five. with everything else I'm fine. I got everything else done that I need to get done I'm just having issues with the keyboard, if I could get some help on this it would greatly be appreciated. this is just giving me a hard time so I thought I would get some help.
//Arrow key codes
var UP = 38;
var DOWN = 40;
var RIGHT = 39;
var LEFT = 37;
//Directions
var moveUp = false;
var moveDown = false;
var moveRight = false;
var moveLeft = false;
//Add keyboard listeners
window.addEventListener("keydown", function(event)
{
switch(event.keyCode)
{
case UP:
moveUp = true;
break;
case DOWN:
moveDown = true;
break;
case LEFT:
moveLeft = true;
break;
case RIGHT:
moveRight = true;
break;
}
}, false);
window.addEventListener("keyup", function(event)
{
switch(event.keyCode)
{
case UP:
moveUp = false;
break;
case DOWN:
moveDown = false;
break;
case LEFT:
moveLeft = false;
break;
case RIGHT:
moveRight = false;
break;
}
}, false);
function loadHandler()
{
update();
}
function update()
{
//The animation loop
requestAnimationFrame(update, canvas);
//Up
if(moveUp && !moveDown)
{
cat.vy = -5;
}
//Down
if(moveDown && !moveUp)
{
cat.vy = 5;
}
//Left
if(moveLeft && !moveRight)
{
cat.vx = -5;
}
//Right
if(moveRight && !moveLeft)
{
cat.vx = 5;
}
//Set the cat's velocity to zero if none of the keys are being pressed
if(!moveUp && !moveDown)
{
cat.vy = 0;
}
if(!moveLeft && !moveRight)
{
cat.vx = 0;
}
//Move the cat
cat.x += cat.vx;
cat.y += cat.vy;
//Check for a collision between the cat and the monster
//and change the monster's score when they collide
if(hitTestRectangle(cat, monster) && score < 5)
{
if(!collisionHasOccured)
{
score++;
collisionHasOccured = true;
}
}
else
{
collisionHasOccured = false;
}
if(score === 5)
{
message = " - Game Over!";
}
//Render the sprites
render();
}
function hitTestRectangle(r1, r2)
{
//A variable to determine whether there's a collision
var hit = false;
//Calculate the distance vector
var vx = r1.centerX() - r2.centerX();
var vy = r1.centerY() - r2.centerY();
//Figure out the combined half-widths and half-heights
var combinedHalfWidths = r1.halfWidth() + r2.halfWidth();
var combinedHalfHeights = r1.halfHeight() + r2.halfHeight();
//Check for a collision on the x axis
if(Math.abs(vx) < combinedHalfWidths)
{
//A collision might be occuring.
//Check for a collision on the y axis
if(Math.abs(vy) < combinedHalfHeights)
{
//There's definitely a collision happening
hit = true;
}
else
{
//There's no collision on the y axis
hit = false;
}
}
else
{
//There's no collision on the x axis
hit = false;
}
return hit;
}
function render(event)
{
drawingSurface.clearRect(0, 0, canvas.width, canvas.height);
if(sprites.length !== 0)
{
for(var i = 0; i < sprites.length; i++)
{
var sprite = sprites[i];
drawingSurface.drawImage
(
image,
sprite.sourceX, sprite.sourceY,
sprite.sourceWidth, sprite.sourceHeight,
Math.floor(sprite.x), Math.floor(sprite.y),
sprite.width, sprite.height
);
}
}
drawingSurface.fillText(score + message, monster.x, monster.y - 40);
}
</script>
You just need to add an if statement to your event listeners. ( IF score == 5 ) then don't do anything. You can place the code right above the switch statements.
EDIT
#JasonEnts:
window.addEventListener("keydown", function(event)
{ if (score < 5) {
switch(event.keyCode)
{
case UP:
moveUp = true;
break;
case DOWN:
moveDown = true;
break;
case LEFT:
moveLeft = true;
break;
case RIGHT:
moveRight = true;
break;
}
}
}, false);
I have this code which makes a square move, but when i for example press the right arrow key then the left arrow key and release the right arrow key, the square pauses for a while and then just moves the left.
is there a way to get rid of this pause?
this is the code i have now:
let velocity = 10
let x = 375
let y = 225
setInterval(function(){
document.getElementById("square").style.left = x + "px";
document.getElementById("square").style.top = y + "px";
}, 1)
var direction = ""
function currentDirection(movingToDirection){
if(movingToDirection != direction){
return true
}
else {
return false
}
}
function Sup() {
if(currentDirection("Sup")){
direction = "Sup";
var Sloopup = setInterval(function(){
y -= velocity/10
}, 1)
window.Sloopup = Sloopup
}
}
function Sdown() {
if(currentDirection("Sdown")){
direction = "Sdown";
var Sloopdown = setInterval(function(){
y += velocity/10
}, 1)
window.Sloopdown = Sloopdown
}
}
function Sleft() {
if(currentDirection("Sleft")){
direction = "Sleft";
var Sloopleft = setInterval(function(){
x -= velocity/10
}, 1)
window.Sloopleft = Sloopleft
}
}
function Sright() {
if(currentDirection("Sright")){
direction = "Sright";
var Sloopright = setInterval(function(){
x += velocity/10
}, 1)
window.Sloopright = Sloopright
}
}
function Break(Function) {
direction = ""
if (Function = "Sup") {
clearInterval(window.Sloopup)
} if (Function = "Sdown") {
clearInterval(window.Sloopdown)
} if (Function = "Sleft") {
clearInterval(window.Sloopleft)
} if (Function = "Sright") {
clearInterval(window.Sloopright)
}
}
document.addEventListener("keydown", event => {
if(event.key==="ArrowUp") {Sup()}
if(event.key==="ArrowDown") {Sdown()}
if(event.key==="ArrowLeft") {Sleft()}
if(event.key==="ArrowRight") {Sright()}
})
document.addEventListener("keyup", event => {
if(event.key==="ArrowUp") {Break("Sup")}
if(event.key==="ArrowDown") {Break("Sdown")}
if(event.key==="ArrowLeft") {Break("Sleft")}
if(event.key==="ArrowRight") {Break("Sright")}
})
and I also have a online example:
Online example
Any help is very appreciated!
Try this:
var Keys = {
up: false,
down: false,
left: false,
right: false
};
let y = 10;
let x = 10;
document.addEventListener("keydown", (event) => {
if (event.key === "ArrowLeft") Keys.left = true;
else if (event.key === "ArrowUp") Keys.up = true;
else if (event.key === "ArrowRight") Keys.right = true;
else if (event.key === "ArrowDown") Keys.down = true;
});
document.addEventListener("keyup", (event) => {
if (event.key === "ArrowLeft") Keys.left = false;
else if (event.key === "ArrowUp") Keys.up = false;
else if (event.key === "ArrowRight") Keys.right = false;
else if (event.key === "ArrowDown") Keys.down = false;
});
setInterval(() => {
if (Keys.up) {
y -= 1;
} else if (Keys.down) {
y += 1;
}
if (Keys.left) {
x -= 1;
} else if (Keys.right) {
x += 1;
}
}, 1);
setInterval(() => {
document.getElementById("app").style.left = x + "px";
document.getElementById("app").style.top = y + "px";
}, 1);
There might be some delay when you clear and set a new interval. Here I set 2 interval that keep listening to keydown, which you will need to clear later when the game ends
Here's the sandbox
so below my suggestion if I understand well your problem:
document.addEventListener("keydown", event => {
// the issue occurs here, you have to disable all current keydown event
Break("Sup");Break("Sdown");Break("Sleft");Break("Sright");
if(event.key==="ArrowUp") {Sup()}
if(event.key==="ArrowDown") {Sdown()}
if(event.key==="ArrowLeft") {Sleft()}
if(event.key==="ArrowRight") {Sright()}
})
BTW i tested it & it works, i hope that it helps you.
Good luck!
as well as we separate content from style same concept applies in different layers of the engine you need to separate the logic from the engine as well. The idea is separation so you can implement/debug much easier. Example code below:
const velocity = {x:0, y:0}
const position = {x:375, y:225}
const keys = { ArrowLeft:false, ArrowRight:false, ArrowUp:false, ArrowDown:false }
function UpdatePlayerInput()
{
velocity.x = ((+keys.ArrowRight) - (+keys.ArrowLeft)) * 10;
velocity.y = ((+keys.ArrowDown) - (+keys.ArrowUp)) * 10;
}
function PyhsicsUpdate(){
position.x += velocity.x / 10;
position.y += velocity.y / 10;
}
function RenderUpdate() {
if (document.getElementById("square").style.left !== position.x + "px")
document.getElementById("square").style.left = position.x + "px";
if (document.getElementById("square").style.top !== position.y + "px")
document.getElementById("square").style.top = position.y + "px";
}
setInterval(PyhsicsUpdate, 1)
setInterval(RenderUpdate, 10)
document.addEventListener("keydown", event => {
keys[event.key] = true;
UpdatePlayerInput();
})
document.addEventListener("keyup", event => {
keys[event.key] = false;
UpdatePlayerInput();
})
Javascript is a heavily event-driven, often asynchronous language.
window.setTimeout(() => console.log(1), 0);
console.log(2);
The above will log 2, then 1, despite the timeout having been set to 0 milliseconds. setTimeout and setTimeout delay execution of the passed function until the first tick of the event loop, after the specified interval / timeout having been exceeded. It is not expected to be immediately invoked, even with a zero-value time argument.
is there a way to get rid of this pause?
Several approaches exist.
Whichever you end up choosing, the key adjustments you have to make is to (a) separate application state from input state and (b) only update input state as a direct result from event handlers, derive position and velocity on the following (regularly scheduled) view state update. Have one data structure hold the current state of the key(s) pressed and another positional arguments.
Prior to writing code, formalize the expected outcome. What is supposed to happen, if for instance both left and right are pressed? No acceleration in either direction, because inputs cancel? Bail early and save yourself the superfluous zero-sum arithmetic.
First (last) pressed takes precedence? Don't use an object with boolean values to represent pressed keys, use a Set (or array if unavailable) and add / remove (push / prune) to it, encode order by time of insertion.
// wrap the pure string representations of keys in a common data structure
const Key = {
DOWN: 'ArrowDown',
LEFT: 'ArrowLeft',
RIGHT: 'ArrowRight',
UP: 'ArrowUp'
}
// holds currently pressed keys
const inputState = new Set([])
function handleKeyDown(event) {
inputState.add(event.key)
}
function handleKeyUp(event) {
inputState.delete(event.key)
}
document.addEventListener('keydown', handleKeyDown)
document.addEventListener('keyup', handleKeyUp)
const viewState = {
velocity: {
x: 10,
y: 10
},
position: {
x: 375,
y: 225
}
}
const targetDomNode = document.getElementById('square')
function updateTargetDomNode(x, y) {
targetDomNode.style.left = `${x}px`
targetDomNode.style.top = `${y}px`
}
function renderViewState() {
updateTargetDomNode(
viewState.position.x,
viewState.position.y
)
}
// you could abstract more, obviously
function accelerate() {
viewState.velocity.x += inputState.has(Key.LEFT) ? -1 : 0
viewState.velocity.x += inputState.has(Key.RIGHT) ? 1 : 0
viewState.velocity.y += inputState.has(Key.UP) ? -1 : 0
viewState.velocity.y += inputState.has(Key.DOWN) ? 1 : 0
}
function updatePosition(timeSinceLastUpdate) {
viewState.position.x += viewState.velocity.x * timeSinceLastUpdate
viewState.position.y += viewState.velocity.y * timeSinceLastUpdate
}
const UPDATE_INTERVAL = 50
setInterval(() => {
accelerate()
// note, this will be slightly more than 50ms,
// if you care for accuracy, use a measurement,
// rather than a static value
updatePosition(UPDATE_INTERVAL)
renderViewState()
}, UPDATE_INTERVAL)
We are using createJS and right now I am struggling with a hit test.
I get this error:
"ss.js:203 Uncaught TypeError: Cannot read property 'x' of undefined
at hitTest (ss.js:203)
at doCollisionChecking (ss.js:215)
at heartBeat (ss.js:238)
at Function.b._dispatchEvent (createjs-2015.11.26.min.js:12)
at Function.b.dispatchEvent (createjs-2015.11.26.min.js:12)
at Function.a._tick (createjs-2015.11.26.min.js:12)
at a._handleTimeout (createjs-2015.11.26.min.js:12)"
I think the problem has to the with the 2 objects x position, but one is a player controlled character and the other object have random x value.
All the hit test example i found always consist of a static object and a moving, but this time they are both moving and i have no idea what to do.
var stage, hero, queue, circle, coin;
var coins = [];
var Score, tekst1, tekst2;
var speed = 3;
var keys = {
u: false,
d: false,
l: false,
r: false
};
var settings = {
heroSpeed: 15
};
function preload() {
"use strict";
stage = new createjs.Stage("ss");
queue = new createjs.LoadQueue(true);
queue.installPlugin(createjs.Sound);
queue.loadManifest([
{
id: 'Vacuum',
src: "img/Vacuum.png"
},
{
id: 'Dust',
src: "img/dust.png"
},
{
id: 'Pickup',
src: "sounds/pickup.mp3"
},
{
id: 'Suger',
src: "sounds/suger.wav"
},
]);
queue.addEventListener('progress', function () {
console.log("hi mom, preloading");
});
queue.addEventListener('complete', setup);
}
function setup() {
"use strict";
window.addEventListener('keyup', fingerUp);
window.addEventListener('keydown', fingerDown);
circle = new createjs.Bitmap("img/Vacuum.png");
circle.width = 40;
circle.height = 90;
stage.addChild(circle);
circle.y = 570;
circle.x = 460;
Score = new createjs.Text("0", "25px Impact", "white");
Score.x = 900;
Score.y = 680;
Score.textBaseline = "alphabetic";
stage.addChild(Score);
tekst1 = new createjs.Text("Score", "25px Impact", "white");
tekst1.x = 740;
tekst1.y = 680;
tekst1.textBaseline = "alphabetic";
stage.addChild(tekst1);
tekst2 = new createjs.Text("Bombs fallin", "40px Impact", "white");
tekst2.x = 10;
tekst2.y = 50;
tekst2.textBaseline = "alphabetic";
stage.addChild(tekst2);
createjs.Ticker.setFPS(30);
createjs.Ticker.addEventListener('tick', heartBeat)
}
function addCoins() {
coin = new createjs.Bitmap("img/dust.png");
coin.x = Math.random() * 900;
coin.width = 36;
coin.height = 50;
coins.push(coin);
stage.addChild(coin);
}
function moveCoins() {
for (var i = 0; i < coins.length; i++) {
coins[i].y += speed;
}
for (var j = 0; j < coins.length; j++) {
if (coins[j].y > 650) {
console.log("hejsa");
stage.removeChild(coins[j]);
coins.splice(j, 1);
}
}
}
function maybeAddCoin() {
var rand = Math.random() * 500;
if (rand < 5) {
addCoins();
}
}
function fingerUp(e) {
"use strict";
//createjs.Sound.stop("Suger")
switch (e.keyCode) {
case 37:
keys.l = false;
break;
case 38:
keys.u = false;
break;
case 39:
keys.r = false;
break;
case 40:
keys.d = false;
break;
}
}
function fingerDown(e) {
"use strict";
switch (e.keyCode) {
case 37:
keys.l = true;
break;
case 38:
keys.u = true;
break;
case 39:
keys.r = true;
break;
case 40:
keys.d = true;
break;
}
}
function moveSlime() {
"use strict";
if (keys.l) {
circle.x -= settings.heroSpeed;
if (circle.x < 0) {
circle.x = 0;
}
if (circle.currentDirection != "left") {
circle.currentDirection = "left";
//createjs.Sound.play("Suger");
keys.u = false;
keys.r = false;
keys.d = false;
}
}
if (keys.r) {
circle.x += settings.heroSpeed;
if (circle.x > 960) {
circle.x = 960;
}
if (circle.currentDirection != "right") {
circle.currentDirection = "right";
//createjs.Sound.play("Suger")
keys.u = false;
keys.l = false;
keys.d = false;
}
}
}
function hitTest(rect1, rect2) {
if (rect1.x >= rect2.x + rect2.width || rect1.x + rect1.width <= rect2.x ||
rect1.y >= rect2.y + rect2.height || rect1.y + rect1.height <= rect2.y)
{
return false;
}
return true;
}
function doCollisionChecking() {
for (var k = coins.length - 1; k >= 0; k--) {
if (hitTest(circle, coin[k])) {
console.log("ramt");
}
}
}
function scoreTimer() {
//Score.text = parseInt(Score.text + 10);
}
function heartBeat(e) {
"use strict";
doCollisionChecking()
maybeAddCoin()
//addCoins()
moveCoins()
scoreTimer()
moveSlime()
stage.update(e);
}
window.addEventListener('load', preload);
Clearly one of your elements is undefined (either circle or coins[k]). I would start with figuring out which one.
Open your debugger.
Turn on "Pause on Exceptions" and re-run your code. When the error happens, your debugger will pause and you can inspect your code
Determine what is undefined. This should shed some light on what is causing the error
One important thing I noticed is that you are looking for rect.width when collision checking. EaselJS elements don't have a width property, so you should instead use getBounds(), which will work with Bitmaps once they are loaded.
// Example
var bounds = rect.getBounds();
var w = bounds.width, h = bounds.height;
Hope that helps!
Here's the problem:
function doCollisionChecking() {
for (var k = coins.length - 1; k >= 0; k--) {
if (hitTest(circle,
coin[k] // your array is coins, not coin
)) {
console.log("ramt");
}
}
}
It might help you in the future to pass arguments through the function instead of relying on global objects. They help you by keeping modifications to your data on tight track. With global variables, anything can modify coins from anywhere and you won't be able to tell what function it is if you have 50+ different functions editing that variable.
I am trying to move a sprite using arrow keys. Below is the logic that SHOULD cause the sprite to move diagonally if two keys are pressed. However, that is not the case. It will only move in one direction a a time. Since I am saving each keyCode as a Boolean within an object property whenever I press a button, I would think that this should not be an issue, but I can't get it to work. I have also tried using an array to store these Booleans, and checking those values instead. No luck.
I am at my wit's end and would greatly appreciate some help. I've scoured stackoverflow and many different blogs on building 2d games, but but nothing that I try works.
var keyState = {};
window.onkeydown = window.onkeyup = function(e) {
keyState[e.keyCode] = e.type == 'keydown';
// checks for up and left
if (keyState[38] && keyState[37]) {
player.pos.x -= 2;
player.pos.y -= 2;
}
// checks for up and right
else if (keyState[38] && keyState[39]) {
player.pos.x += 2;
player.pos.y += 2;
}
// checks for down and left
else if (keyState[40] && keyState [37]) {
player.pos.x -= 2;
player.pos.y -= 2;
}
// checks for down and right
else if(keyState[40] && keyState [39]) {
player.pos.x += 2;
player.pos.y -= 2;
}
// checks for up
else if (keyState[38]) {
player.animation.y = 64;
player.pos.y -= 2;
}
};
You should explicitly set the object key values as booleans and you should toggle them in separate keydown/keyup handlers:
let keysdown = {};
window.addEventListener('keydown', function(evt) {
keysdown[evt.which] = true;
if (keysdown["38"] === true && keysdown["37"] === true) {
console.log('up & left');
} else if (keysdown["38"] === true && keysdown["39"] === true) {
console.log('up & right');
} else if (keysdown["40"] === true && keysdown["37"] === true) {
console.log('down and left');
} else if (keysdown["40"] === true && keysdown["39"] === true) {
console.log('down and right');
} else if (keysdown["38"] === true) {
console.log('up');
}
}, false);
window.addEventListener('keyup', function(evt) {
keysdown[evt.which] = false;
}, false);
This logs all the correct key combinations for me.
You need to move the movement logic out of the event listener. Have the key event just log the current state of each key (up or down) then in the main loop check the state and move the play as needed.
As I am unsure if you want the movement to be constant or only on the press I have included the option to change the behaviour with the constant flag MOVE_ONLY_ON_PRESS if true movement only when a press is first detected. So that no key strokes are missed I clear the key flag in the main loop.
The following is an example of how to interface with the keyboard for a game.
// global key log;
var keyState = [];
const KEY_UP = 38;
const KEY_DOWN = 40;
const KEY_LEFT = 37;
const KEY_RIGHT = 39;
// Player
var player = {};
player.x = 100;
player.y = 100;
const MOVE_SPEED = 2;
const MOVE_ONLY_ON_PRESS = false; // This will toggle constant movement or only on press
// from your code
window.onkeydown = window.onkeyup = function (e) {
if (MOVE_ONLY_ON_PRESS) {
if (e.type === 'keydown') {
keyState[e.keyCode] = true;
}
} else {
keyState[e.keyCode] = e.type == 'keydown';
}
}
// in the main loop;
function update(timer) {
// you dont need to test for the combinations (ie up left) when its just simple movement
if (keyState[KEY_UP]) {
player.y -= MOVE_SPEED;
if (MOVE_ONLY_ON_PRESS) { keyState[KEY_UP] = false; }
}
if (keyState[KEY_DOWN]) {
player.y += MOVE_SPEED;
if (MOVE_ONLY_ON_PRESS) { keyState[KEY_DOWN] = false; }
}
if (keyState[KEY_LEFT]) {
player.x -= MOVE_SPEED;
if (MOVE_ONLY_ON_PRESS) { keyState[KEY_LEFT] = false; }
}
if (keyState[KEY_RIGHT]) {
player.x += MOVE_SPEED;
if (MOVE_ONLY_ON_PRESS) { keyState[KEY_RIGHT] = false; }
}
requestAnimationFrame(update);
}
requestAnimationFrame(update);
Bit fields.
Another way to simplify the arrow keys is to set the first 4 bits of a number to correspond to a key, one bit per key, then it is easy to test for combinations of keys as each of the 16 possible combinations has a unique number. You Could map many more keys this way but it becomes a little impractical when you go to far.
This is how to set them
var arrowBits = 0; // the value to hold the bits
const KEY_BITS = [4,1,8,2]; // left up right down
const KEY_MASKS = [0b1011,0b1110,0b0111,0b1101]; // left up right down
window.onkeydown = window.onkeyup = function (e) {
if(e.keyCode >= 37 && e.keyCode <41){
if(e.type === "keydown"){
arrowKeys |= KEY_BITS[e.keyCode - 37];
}else{
arrowKeys &= KEY_MASKS[e.keyCode - 37];
}
}
}
These are 8 of the 16 possible combinations
// postfix U,D,L,R for Up down left right
const KEY_U = 1;
const KEY_D = 2;
const KEY_L = 4;
const KEY_R = 8;
const KEY_UL = KEY_U + KEY_L; // up left
const KEY_UR = KEY_U + KEY_R; // up Right
const KEY_DL = KEY_D + KEY_L; //
const KEY_DR = KEY_D + KEY_R; //
This is how you test for then
if ((arrowBits & KEY_UL) === KEY_UL) { // is UP and LEFT only down
if (arrowBits & KEY_UL) { // is Up left down (down and right may also be down)
if ((arrowBits & KEY_U) === KEY_U) { // is Up only down
if (arrowBits & KEY_U) { // is Up down (any other key may be down)
if (!(arrowBits & KEY_U)) { // is Up up (any other key may be down)
if (!arrowBits) { // no keys are down
if (arrowBits) { // any one or more keys are down
I cannot tell you why your code doesn't work. If I replace the player-movements with console-logs, it works for me.
Although it's pretty primitive.
First separate the keystate-manager from the movement-logic.
var isKeyDown = (function(alias){
for(var i=0, a=Object.create(null); i<256;) a[i++]=false;
for(var k in alias) i=0|alias[k], i>0 && i<256 && Object.defineProperty(a,k,{get:Function("return this["+i+"]")});
function keyStateHandler(e){
a[e.which||e.keyCode] = e.type==="keydown"
}
addEventListener("keydown", keyStateHandler, false);
addEventListener("keyup", keyStateHandler, false);
return a;
})({
//add some aliases for more readable code
up: 38,
left: 37,
right: 39,
down: 40
});
once, because the update-interval of the keydown-event is not reliable, varies between browsers, and is not sync with the update-interval of the brwoser wich will cause flickering.
Now create a main loop for your game, and take account for the timing. Although requestAnimationFrame aims for a constant framerate you may have lags, and you don't want to see your player move at different speeds during these lags.
var lastCall = Date.now();
function tick(){
requestAnimationFrame(tick);
var now = Date.now(),
time = (now - lastCall) / 1000; //time in seconds
//because it's easier to think in terms like 2px/s
//than 0.002px/ms or 0.0333 px/frame
lastCall = now;
move(time);
}
tick();
now the actual movement:
//the speed of your player: it would be better if this would be
//a property of the player than hardcoded like you did, or global like this
var speed = 2; // 2px/second
function move( time ){
//accounts for varying framerates
//opposite directions cancel each other out
var dx = (isKeyDown.right - isKeyDown.left) * time,
dy = (isKeyDown.down - isKeyDown.up) * time;
//taking account for diagonals
if(dx && dy) dx /= Math.SQRT2, dy /= Math.SQRT2;
player.pos.x += dx * speed;
player.pos.y += dy * speed;
}
Based on skyline3000 answer I tried to make it work also in down, left and right. Appart from adding the other options I had to change window to document to make it work:
let keysdown = {};
document.addEventListener('keydown', function (evt) {
keysdown[evt.which] = true;
if (keysdown["38"] === true && keysdown["37"] === true) {
prota.moveUp();
prota.moveLeft();
// console.log('up & left');
} else if (keysdown["38"] === true && keysdown["39"] === true) {
prota.moveUp();
prota.moveRight();
// console.log('up & right');
} else if (keysdown["40"] === true && keysdown["37"] === true) {
prota.moveDown();
prota.moveLeft();
// console.log('down and left');
} else if (keysdown["40"] === true && keysdown["39"] === true) {
prota.moveDown();
prota.moveRight();
// console.log('down and right');
} else if (keysdown["38"] === true) {
prota.moveUp();
// console.log('up');
} else if (keysdown["40"] === true) {
prota.moveDown();
// console.log('down');
} else if (keysdown["39"] === true) {
prota.moveRight();
// console.log('right');
} else if (keysdown["37"] === true) {
prota.moveLeft();
// console.log('left');
}
}, false);
document.addEventListener('keyup', function (evt) {
keysdown[evt.which] = false;
}, false);
I'm trying to move a box in the canvas, all the functions work fine, but as soon as i press down on any of the 4 keys the box disappears, I can tell it is because i have a ctx.ClearRect after pressing any of the 4 keys, i managed to stop it from dispersing, the problem is now it does not move or disappear and the cosole does not show any errors so I am stuck again.
any help would be really really helpful, thank you.
function Player (row,col) {
this.isUpKey = false;
this.isRightKey = false;
this.isDownKey = false;
this.isLeftKey = false;
this.row = row;
this.col = col;
this.color = "#f00";
}
var players = new Array();
function drawPlayer() {
players[players.length] = new Player(2,2);
for (var p = 0; p < players.length; p++) {
ctxPlayer.fillStyle = players[p].color;
ctxPlayer.fillRect(players[p].row*25, players[p].col*25, 25, 25);
}
}
function doKeyDown(e){
if (e.keyCode == 87) {
ClearPlayer();
Player.isUpKey = true;
Player.col = Player.col - 1;
}
if (e.keyCode == 83) {
ClearPlayer();
Player.isDownKey = true;
Player.col = Player.col + 1;
}
if (e.keyCode == 65) {
ClearPlayer();
Player.isLeftKey = true;
Player.row = Player.row - 1;
}
if (e.keyCode == 68) {
ClearPlayer();
Player.isRightKey = true;
Player.row = Player.row + 1;
}
}
function ClearPlayer() {
ctxPlayer.clearRect(0,0,canvasWidth,canvasHeight);
}
I created a plnkr with an example of what I think you are trying to do:
// Code goes here
function Player(row, col) {
this.isUpKey = false;
this.isRightKey = false;
this.isDownKey = false;
this.isLeftKey = false;
this.row = row;
this.col = col;
this.color = "#f00";
}
var players = [];
var ctxPlayer;
var currentPlayer;
window.onload = function()
{
ctxPlayer = document.getElementById('c').getContext('2d');
currentPlayer = players[players.length] = new Player(2, 2);
setInterval(render, 25);
}
window.onkeypress = doKeyDown;
function render()
{
ClearPlayer();
drawPlayer();
}
function drawPlayer() {
for (var p = 0; p < players.length; p++) {
ctxPlayer.fillStyle = players[p].color;
ctxPlayer.fillRect(players[p].row * 25, players[p].col * 25, 25, 25);
}
}
function doKeyDown(e) {
console.log(e);
if (e.keyCode == 97) {
currentPlayer.isUpKey = true;
--currentPlayer.row;
}
if (e.keyCode == 100) {
currentPlayer.isDownKey = true;
++currentPlayer.row;
}
if (e.keyCode == 119) {
currentPlayer.isLeftKey = true;
--currentPlayer.col;
}
if (e.keyCode == 115) {
currentPlayer.isRightKey = true;
++currentPlayer.col;
}
}
function ClearPlayer() {
ctxPlayer.clearRect(0, 0, 600, 400);
}
http://plnkr.co/edit/XejZKCkshNiihdy8ui1u?p=preview
First I introduced a render function to call clear and draw. This render function will get called every 25 ms after the window has loaded.
Then you created a new Player every draw-call. I changed it so that one player is created onload. The key-events are respective to this player-object.
Last I changed the key-events for my testing purposes, but they should work with yours too.
Keep in mind that the plnkr is just a quick example on how it works. You probably need to adjust it to your needs.