There is a tank(group), I need to control (move), panzer must go in the direction where its muzzle is looking
window.addEventListener('keydown', function (event) {
if (event.code === 'KeyW') {
model.position.z += -0.1
} else if (event.code === 'KeyA') {
model.rotation.y += 0.01
} else if (event.code === 'KeyD') {
model.rotation.y += -0.01
} else if (event.code === 'KeyS') {
model.position.z += 0.1
}
})
the tank always moves in z, when I change its rotation it still moves in the direction of z, but it should move diagonally - where the muzzle is looking
Related
I'm working on a project for school and I'm writing a calculator.
I got to the point where I'm programming the keydown event, the numbers aren't causing any problems, but I got stuck at the %, * and +.
The output I receive in the console.log is correct - I'm getting the asterisk * each time I press shift + 8, not when I press shift or 8 individually. But what I'm getting in the #output.innerHTML is " *8 ", since I also have an event listener for number 8, as seen above.
function forDisplay(value) {
document.getElementById("output").innerHTML += value;
}
document.addEventListener('keydown', (event)=>{
if(event.keyCode === 56 || event.keyCode === 104){
document.getElementById("output").innerHTML += 8
}
if(event.shiftKey && event.keyCode === 56){
console.log('*')
forDisplay('*')
}
})
Is there any way I can make the code work in the output too, since it's working correctly in the console.log?
Thanks!
I see your problem - the first if is firing, and so is the second if when you press Shift and 8. Simply check for the Shift and 8 first, then add an else if statement, in case the condition is not true.
document.addEventListener('keydown', (event) => {
if (event.shiftKey && event.keyCode === 56) {
console.log('*')
document.getElementById("output").innerHTML += "*";
} else if (event.keyCode === 56 || event.keyCode === 104) {
document.getElementById("output").innerHTML += 8
}
})
<div id="output"></div>
Also, here's my attempt at a calculator, complete with regular numbers, addition, subtraction, multiplication, division, exponent, Num Pad, designated symbols for multiplication and division, prevention for operands next to each other (things like 132+*837), backspace, clearing options, and evaluation for Enter key, equal to, or Evaluate button:
var outputEl = document.getElementById("output")
function CheckLastChar() {
if (["×", "+", "-", "÷", "^"].includes(outputEl.innerText.slice(-1))) {
outputEl.innerText = outputEl.innerText.slice(0, -1)
}
}
document.addEventListener('keydown', (event) => {
key = String.fromCharCode(event.keyCode);
if (event.shiftKey) {
if (key == "8") {
CheckLastChar();
outputEl.innerText += "×";
} else if (key == "6") {
CheckLastChar();
outputEl.innerText += "^";
} else if (event.keyCode == 187) {
CheckLastChar();
outputEl.innerText += "+";
}
} else {
if ([...Array(10).keys()].map(el => el.toString()).includes(key)) {
outputEl.innerText += key;
} else if (event.keyCode == 106) {
CheckLastChar();
outputEl.innerText += "×";
} else if (event.keyCode == 107) {
CheckLastChar();
outputEl.innerText += "+";
} else if (event.keyCode == 189 || event.keyCode == 109) {
CheckLastChar();
outputEl.innerText += "-";
} else if (event.keyCode == 191 || event.keyCode == 111) {
CheckLastChar();
outputEl.innerText += "÷";
} else if (event.keyCode == 8) {
outputEl.innerText = outputEl.innerText.slice(0, -1);
} else if (event.keyCode == 13) {
document.querySelectorAll("button")[0].click();
} else if (event.keyCode == 187) {
document.querySelectorAll("button")[0].click();
}
}
})
document.querySelectorAll("button")[0].addEventListener("click", () => {
stringToEvaluate = document.getElementById("output").innerText.replace("×", "*").replace("÷", "/").replace("^", "**");
console.clear();
try {
console.log(eval(stringToEvaluate));
} catch {
console.log("Unexpected error or invalid expression.");
}
})
document.querySelectorAll("button")[1].addEventListener("click", () => {
outputEl.innerText = "";
})
<div id="output"></div>
<button>Evaluate!</button>
<button>Clear!</button>
I have an SVG
<svg id='mainSvg' viewBox='0 0 1920 1080'>
<rect id='rectangle' x='800' y='800'/>
</svg>
and I am moving the rectangle inside the SVG with javascript with left and right arrow keys and A and D keys.
that is working perfectly but I have a problem that the rectangle can go outside of the view-box of the SVG and I want the rectangle to stop when it touches the left or right corner. this is my code.
function keyDown(event) {
if (event.key === 'ArrowLeft' || event.key === 'a') {
leftKey = true;
aKey = true;
} else if (event.key === 'ArrowRight' || event.key === 'd') {
rightKey = true;
dKey = true;
}
}
function keyUp(event) {
if (event.key === 'ArrowLeft' || event.key === 'a') {
leftKey = false;
aKey = false;
} else if (event.key === 'ArrowRight' || event.key === 'd') {
rightKey = false;
dKey = false;
}
}
function move() {
let xPosition = parseInt(rectangle.getAttribute('x'));
const movmentSpeed = 10;
//if right arrow key,d is pressed
if (rightKey) {
rectangle.setAttribute('x', xPosition + movmentSpeed);
//if right arrow key,a is pressed
} else if (leftKey) {
rectangle.setAttribute('x', xPosition - movmentSpeed)
if(xPosition === 0){
leftKey = false;
}
}
setTimeout(move, 10);
}
on the last function move() I tried saying if(Xposition ===0){leftKey = false} that works briefly but if the user keeps pressing the left arrow then the rectangle will start moving again and go out of the viewBox.
Also, the arrow keys have a value of false by default
Any ideas on how to fix this?
I have coded this game inspired by The Coding Train's Snake Game and I can't figure a problem out. If the player presses both the right button and the down button, for example, they would just turn to the opposite direction, which would just kill them. I wonder how I would set a cooldown on the keys opposite of eachother. I'm using the p5js library.
I appreciate any help!
this.dir = function(x, y) {
this.xspeed = x;
this.yspeed = y;
}
if (keyCode === UP_ARROW && s.yspeed != 1) {
s.dir(0, -1);
} else if (keyCode === DOWN_ARROW && s.yspeed != -1) {
s.dir(0, 1);
} else if (keyCode === RIGHT_ARROW && s.xspeed != -1) {
s.dir(1, 0);
} else if (keyCode === LEFT_ARROW && s.xspeed != 1) {
s.dir(-1, 0);
}
I want to use arrow function syntax with a few code snippets I've been working with. I was successful until I reached one in particular with multiple if statements. I know this might come up as a duplicate question, but after looking through some of the previous answers, I still can't find a working syntax.
I looked at a few of the duplicate answers on stack overflow and tried the formats suggested but nothing works. I also get no errors.
function keydownHandler(event) {
"use strict"
// handle user keyboard input
if (event.keyCode == UP) {
rocket.y -= velocity;
}
if (event.keyCode == LEFT) {
rocket.x -= velocity;
}
if (event.keyCode === DOWN) {
rocket.y += velocity;
}
if (event.keyCode == RIGHT) {
rocket.x += velocity;
}
render( );
}
//===========One of many formats i've tried=============================
var keydownHandler = event => {
if (event.keyCode == UP) {
rocket.y -= velocity;
}
if (event.keyCode == LEFT) {
rocket.x -= velocity;
}
if (event.keyCode === DOWN) {
rocket.y += velocity;
}
if (event.keyCode == RIGHT) {
rocket.x += velocity;
}
render( );
}
You could take an object with a default function for unknown keyCode.
const
directions = {
UP: () => rocket.y -= velocity,
LEFT: () => rocket.x -= velocity,
DOWN: () => rocket.y += velocity,
RIGHT: () => rocket.x += velocity,
default: () => {}
};
Call with
(directions[event.keyCode] || directions.default)();
You could use the Conditional (ternary) operator if you want to turn it into a 1 liner. This will only allow 1 key press at a time though
const keydownHandler = (event) => {event.keyCode === UP ? rocket.y -= velocity : event.keyCode === LEFT ? rocket.x -= velocity : event.keyCode === DOWN ? rocket.y += velocity : event.keyCode === RIGHT ? rocket.x += velocity : 0; render();}
This code is untested.
But for readablity I'd recommend using a switch statement or partial ternary operation
const keydownHandler = (event) => {
// this prevents the rocket from going up and down at the same time
rocket.y += event.keyCode === UP ? velocity : event.keyCode === DOWN ? -velocity : 0;
// this prevents the rocket from going left and right at the same time. if both keys are pressed the rocket will turn right
rocket.x += event.keyCode === RIGHT ? velocity : event.keyCode === LEFT ? -velocity : 0;
render();
};
This section of code will prevent the rocket from going up and down at the same time. If both keys are pressed it will go up. The same goes for the left and right.
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);