I am creating a Canvas game of 'Snake'. Using your arrow keys, you can move the snake around.
What I'm working on is clearing an interval when a different arrow key is pressed. I am trying to make use of both setInterval and clearInterval. Here is one of the four such functions I have.
https://jsfiddle.net/2q1svfod/2/
function moveUp() {
if (direction != "up") {
incrementScore();
}
direction = "up";
if (direction == "up") {
var goUp = setInterval(function() {
ctx.lineTo(headX, headY - 10);
ctx.stroke();
headY -= 10;
}, 1000);
}
else {
clearInterval(goUp);
}
}
The objective is to avoid crashing into the walls, which will result in losing the game, and your score will be reset. I'd like to prevent players from repeatedly tapping on a key to get extra points, so I only increase their score once per direction.
As long as the direction stays the same, I want the interval to keep running. That's why I declared the goUp interval inside this conditional.
If the direction has changed, I clear that interval. However, two intervals are now going on at the same time instead of 1.
Does anyone know where I'm going wrong here?
This is one implementation (out of many) you might consider.
var currentInput = {
left: false,
up: false,
right: false,
down: false
};
function getKey(keyCode) {
if (keyCode === 37) {
return 'left';
} else if (keyCode === 38) {
return 'up';
} else if (keyCode === 39) {
return 'right';
} else if (keyCode === 40) {
return 'down';
}
}
function onKeyDown(event) {
var key = getKey(event.keyCode);
currentInput[key] = true;
}
function onKeyUp(event) {
var key = getKey(event.keyCode);
currentInput[key] = false;
}
document.addEventListener('keydown', onKeyDown, false)
document.addEventListener('keyup', onKeyUp, false)
function update() {
requestAnimationFrame(update);
if (currentInput.left) {
// move snake left
} else if (currentInput.right) {
// etc.
}
}
// Kick off the event loop
requestAnimationFrame(update);
I managed to find a solution, but I'm not too thrilled I had to resort to using global variables.
It looks something like this
function moveUp() {
if (direction != "up") {
incrementScore();
}
direction = "up";
clearInterval(goRight);
upArrow();
}
function upArrow() {
if (direction == "up") {
goUp = setInterval(function() {
ctx.lineTo(headX, headY - 10);
ctx.stroke();
headY -= 10;
}, 1000);
}
}
It works and I'm able to change directions. But I don't like using globals.
Here's the updated fiddle
https://jsfiddle.net/2q1svfod/6/
Related
I'm building a 2D js pacman with a key/door for second level. The idea is to have an ability to get to next level after grabbing the key. The grid is updated once pacman gets to the door. Game data is an array with two grids in it. What is the best way to redraw the gird?
Also can anybody suggest good resources for creating ghosts? Thank you in advance.
level change logic
let level = 0;
let grid = gameData[0]
function levelChange() {
console.log(grid[pacman.y][pacman.x] === grid[door.y][door.x])
if (grid[pacman.y][pacman.x] === grid[door.y][door.x]) {
grid = gameData[1];
level += 1;
}
console.log(level)
console.log(grid)
}
let map;
let pacman = {
x: 6,
y: 4,
direction: 'right'
};
let door = {
x: 11,
y: 8,
}
drawing grid
function drawMap() {
map = document.createElement('div');
// console.log(grid)
let tiles = createTiles(grid);
tiles.forEach(tile => {
map.appendChild(tile);
});
document.getElementById('body').appendChild(map)
// document.body.appendChild(map);
}
calling the level change
function setupKeyboardControls() {
document.addEventListener('keydown', function (e) {
// console.log(e.keyCode);
if (e.keyCode === 37) {
moveLeft();
} else if (e.keyCode === 38) {
moveUp();
} else if (e.keyCode === 39) {
moveRight();
} else if (e.keyCode === 40) {
moveDown();
}
eraseMap();
drawMap();
screenScore();
doorUnlock();
levelChange();
});
}
function main() {
drawMap();
setupKeyboardControls();
}
main();
just had to move drawMap/eraseMap to the bottom of setupKeyboardControls()
I am working on a simple game, like Crossy Road, where the player is a spaceship, and they have to cross a lane which contains other ships moving from top to down. I've tried to use setInterval(), but that doesn't seem to. work, here is the link for the project in Code.org:
https://studio.code.org/projects/gamelab/mVC2Bqadlg-heWiFlPvrPX3D7AfH5Ty4EVbTAGLM3rE
I'll also include a snippet:
/*
function randomAnimation() {
var thing = createSprite(randomNumber(250,300),0);
thing.velocityY = randomNumber(5,10);
thing.velocityX = 0;
thing.scale = 0.5;
var randNumber = randomNumber(1,6);
if (randNumber === 1) {
thing.setAnimation("enemy1");
}
else if (randNumber === 2) {
thing.setAnimation("enemy2");
}
else if (randNumber === 3) {
thing.setAnimation("enemy3");
}
else if (randNumber === 4) {
thing.setAnimation("enemy4");
}
else if (randNumber === 5) {
thing.setAnimation("enemy5");
}
else if (randNumber === 6) {
thing.setAnimation("enemy6");
}
}
*/
function draw() {
background("white");
setInterval(function() {
var thing = createSprite(randomNumber(150, 300), 0);
/*thing.velocityY = randomNumber(5,10);
thing.velocityX = 0;
thing.scale = 0.5;
var randNumber = randomNumber(1,6);
if (randNumber === 1) {
thing.setAnimation("enemy1");
}
else if (randNumber === 2) {
thing.setAnimation("enemy2");
}
else if (randNumber === 3) {
thing.setAnimation("enemy3");
}
else if (randNumber === 4) {
thing.setAnimation("enemy4");
}
else if (randNumber === 5) {
thing.setAnimation("enemy5");
}
else if (randNumber === 6) {
thing.setAnimation("enemy6");
}*/
var enemies = createGroup();
}, 2000);
drawSprites();
}
As you can see, a lot of the code is commented, that is code that I tried using but didn't work as expected. The first bit of commented code is a function I created, I tried calling this function in a setInterval() outside of the draw() function, but that worked, creating a new ship every 2000ms, but they didn't have any velocity. I tried calling it in the. draw() function, but that caused one ship to appear every frame, which makes it impossible to cross said lane. I know that I need to use groups for this function, I just don't know how.
Also, there's an if statement which is used to randomly change the animation of the spawned sprites.
I'd try the following approach:
// Create a group outside of any functions, so it's available to all of them.
var enemies = createGroup();
// Create a function that just builds a single enemy
function createEnemy() {
// set velocity, scale, etc.
}
// In setInterval, create an enemy and add it to your group
setInterval(function() {
var enemy = createEnemy();
enemies.add(enemy);
}, 2000);
// A function to handle animation
function draw() {
drawSprites();
}
I'm not familiar with the studio.code.org platform, so I'm not sure whether each sprite's animation should be initialized in createEnemy() or draw(). If it's in draw(), I see you have access to group.setAnimationEach(), which might be the way to go.
I am having a problem when I move my key controls mainly the arrows on the keyboard. If the viewpoint is small enough it also moves the screen up and down because of the vertical side bar and the tetris piece at the same time. And I want the pieces to only move when I press the arrows. I am a novice at Js and I am not sure where to start to solve the problem, suggestions to where to start to look at?
Here is my Js script
document.addEventListener("keydown", CONTROL);
function CONTROL(event) {
if (event.keyCode == 37) {
p.moveLeft();
dropStart = Date.now();
}
else if (event.keyCode == 38) {
p.rotate();
}
else if (event.keyCode == 39) {
p.moveRight();
dropStart = Date.now();
}
else if (event.keyCode == 40) {
p.moveDown(0);
}
}
Arrow keys moving the browser window is a default browser behavior.
Use event.preventDefault()
To listen only to arrow keys use if (k >= 37 && k <= 40) {, or the opposite: if (k < 37 || k > 40) return;
const p = { // JUST FOR THIS DEMO. You use Piece.prototype
moveLeft() { console.log("LEFT"); },
rotate() { console.log("ROTATE"); },
moveRight() { console.log("RIGHT"); },
moveDown() { console.log("DOWN"); },
};
document.addEventListener("keydown", CONTROL);
function CONTROL(event) {
const k = event.keyCode;
if (k < 37 || k > 40) return; // Do nothing if was not an arrow key. Else Do:
event.preventDefault(); // Prevent browser scroll on arrows
if(k == 37 || k == 39) dropStart = Date.now(); // Only for left or right
return {
37: p.moveLeft,
38: p.rotate,
39: p.moveRight,
40: p.moveDown
}[k]();
}
html, body {min-height: 100%;}
so the problem here is that is that it's sensing each key individually (I've had the same problem so you need a keymap to keep track off ALL the keys pressed like so:
var keys = [];
function keysPressed(e) {
keys[e.keyCode] = true;
}
function keysReleased(e) {
keys[e.keyCode] = false;
}
if(keys[37] === true){
//do stuff here
}
if(keys[38] === true){
//do stuff here
}
You may also want to use the proper identifier "==="
I'm making a game in which a player character moves left and right.
Since simply using an onKeyDown eventListener had my character move in a choppy fashion, and with a slight delay, I tried using requestAnimationFrame to call the movement function as often as possible, as suggested by another answer(How can I move my JS objects smoothly using keyboard input?)
however, that has changed nothing.
Here is my Javascript Code
var NodoCampo = document.getElementById("campo");
var NodoGiocatore = null;
var Left = false;
var Right = false;
var FRAMERATE = 20;
//cache giocatore
var LARG_GIOCATORE = 30;
var ALT_GIOCATORE = 30;
var X_GIOCATORE = 300;
var Y_GIOCATORE = 1100;
var VEL_GIOCATORE = 10;
function mostra_giocatore() {
if (NodoGiocatore === null) {
NodoGiocatore = document.createElement('div');
NodoGiocatore.setAttribute ('id', 'player');
NodoCampo.appendChild (NodoGiocatore);
}
NodoGiocatore.style.marginLeft = (X_GIOCATORE - LARG_GIOCATORE) + 'px';
NodoGiocatore.style.marginTop = (Y_GIOCATORE - ALT_GIOCATORE) + 'px';
}
function muovi() {
if (Left) {
X_GIOCATORE = X_GIOCATORE - VEL_GIOCATORE;
//aggiorno immagine
mostra_giocatore();
}
else if (Right) {
X_GIOCATORE = X_GIOCATORE + VEL_GIOCATORE;
//aggiorno immagine
mostra_giocatore();
}
}
function stop() {
Left = false;
Right = false;
}
function interfaccia(e) {
//freccia sinstra
if (e.keyCode === 37) {
X_GIOCATORE = X_GIOCATORE - VEL_GIOCATORE;
//aggiorno immagine
mostra_giocatore();
}
//freccia destra
else if (e.keyCode === 39) {
X_GIOCATORE = X_GIOCATORE + VEL_GIOCATORE;
//aggiorno immagine
mostra_giocatore();
}
}
function inizia() {
mostra_giocatore();
requestAnimationFrame(muovi);
}
window.document.onkeypress = interfaccia;
window.document.onkeyup = stop;
Your choppy movement is likely a result of the amount you are moving the player on each frame with VEL_GIOCATORE. Try reducing this amount to observe smoother movement.
The delay you are experiencing is likely due to your operating system or browsers individual settings on how key presses should repeat. You can work around this by implementing your own key tracking -- it looks like you've started to experiment with this. Track the state of your left and right keys by updating a boolean value in onkeydown and onkeyup event listeners.
var keys = {
left: false,
right: false
};
window.document.onkeydown = function (e) {
if (e.keyCode === 37) {
keys.left = true;
} else if (e.keyCode === 39) {
keys.right = true;
}
window.document.onkeyup = function (e) {
if (e.keyCode === 37) {
keys.left = false;
} else if (e.keyCode === 39) {
keys.right = false;
}
Then, in your muovi function, check the state of these variables to determine if you should update the position of the player.
I feel like a complete klutz, I had this working and then I accidentally forgot to save it! I'm an idiot. I've spent the last day trying to recreate what I had but I can't do it. Basically (from my last save) I had this:
function canvasMove(e) {
if(!e) var e = window.event;
var downcheck;
var upcheck;
var leftcheck;
var rightcheck;
if(e.keyCode == '38') {
if(up + down == 0) downcheck = false;
else downcheck = true;
e.preventDefault();
}
if(e.keyCode == '40') {
if(up + down > HEIGHT - 110) upcheck = false;
else upcheck = true;
e.preventDefault();
}
if(e.keyCode == '37') {
if(left + right == 0) rightcheck = false;
else rightcheck = true;
e.preventDefault();
}
if(e.keyCode == "39") {
if(left + right > WIDTH - 110) leftcheck = false;
else leftcheck = true;
e.preventDefault();
}
if(leftcheck == true) { left += 10; counting() };
if(rightcheck == true) { right -= 10; counting() };
if(upcheck == true) { up += 10; counting(true) };
if(downcheck == true) { down -= 10; counting(true) };
}
The problem of course being that Javascrpt doesn't support the ability to check if two keys are being pressed at the same time. What I want to accomplish is when the user pressed up and left they'll move diagonally. Ignore the "counting" function, it's just to keep track of how much the user has moved.
I managed to accomplish this with just else and if statements, no less! So I was wondering if you guys could give it a shot. The first if statement in each key if statement is so the user can't leave the canvas box. Then I have a function that moves the user by redrawing the canvas.
function redraw() {
clear(draw);
draw.fillStyle = 'rgba(0,0,0,0.5)';
draw.fillRect(left + right, up + down, '100', '100');
}
The "clear" function is just a simple function that clears the entire canvas. This is all controlled by an init function that looks like this:
function init() {
canvas = document.getElementById('game');
HEIGHT = canvas.height;
WIDTH = canvas.width;
draw = canvas.getContext('2d');
setInterval(redraw, 30);
document.onkeydown = canvasMove;
}
Your -check flags need to be global variables rather than function-scoped variables, otherwise they will never stay set between keydown events (handling only one key at a time). You also need a keyup event handler that will unset the correct flag when a key is released.