I'm making a pacman game. If you've ever played it you'll know that when pacman is moving a certain direction through a maze, if he moves towards a wall nothing happens. He just keeps going. What would be a a good way of doing this given my current code?
So here's the code.
this.move = function(key){
var Rblocked = false;
var Bblocked = false;
clearInterval(timer);
timer = window.setInterval(function(){
//key is event switch
switch (key) {
case 39:
for (var butt39 in blockArrayLeft){
if ($('#pacMan').position().left == blockArrayLeft[butt39].position().left && $('#pacMan').position().top == blockArrayLeft[butt39].position().top){
Rblocked = true;
pacMan.move(this.direction);
}
}
if (!Rblocked){
this.direction = 39;
pacMan.rightMove();
}
break;
case 40:
for (var butt40 in blockArrayTop){
if ($('#pacMan').position().left == blockArrayTop[butt40].position().left && $('#pacMan').position().top == blockArrayTop[butt40].position().top){
Bblocked = true;
pacMan.move(this.direction);
}
}
if (!Bblocked){
this.direction = 40;
pacMan.bottomMove();
}
break;
default:
clearInterval(timer);
break;
}
}
};
}
Pressing a key causes pacMan to move one direction continuously. I have a setInterval that makes him move his length's space, every 100 seconds.
If he bumps into a wall and he moves towards it he is blocked. The setInterval only goes when the blocked variable is false.
But what would be a way to make him keep moving a direction if he goes right suddenly?
Related
I'm trying to create a simple animation effect of a pendulum swinging back and forth. I'm only using a single image sprite for it, and I've got the code below, but the animation only tilts to a 45 angle then stops completely. What might I be doing wrong?
var title = new Phaser.Scene("GameTitle");
var pendulum;
var direction;
title.create = function(){
pendulum = this.add.sprite(200, 0, 'titlePendulum').setOrigin(0.5, 0).setScale(1.8).setRotation(79);
direction = "left";
};
title.update = function(){
console.log(pendulum.angle.toFixed(0));
swing(direction);
if(pendulum.angle.toFixed(0) == 71){
swing ("right");
}
if(pendulum.angle.toFixed(0) == -76){
swing("left");
}
};
function swing(dir){
if(dir == "left"){
if(pendulum.angle.toFixed(0) == 71){
swing("right");
}else{
pendulum.angle +=1.5;
}
}else{
if(pendulum.angle.toFixed(0) > -80){
pendulum.angle -= 1.5;
}
if(pendulum.angle.toFixed(0) == -76){
swing("left");
}
}
}
I noticed that you check if the pendulum.angle is larger than or exactly equal to 80 in two separate if statements. However 80 is not divisible by 1.5, and the value of the angle could be .. 76, 77.5, 79, 80.5 .. and the condition pendulum.angle.toFixed(0) == 80 will never be true.
Also, the name of the function parameter is dir but you check for a direction.
I'm pretty sure that is causing the problem. Even if that's not it, it's still better (more elegant and "cleaner") to use if-else when you are checking for a condition that can either be one thing or the other, instead of using two separate if statements.
So change your code to something like this:
function swing(dir) {
if (dir == "left") { // check parameter, not the direction global var
if (pendulum.angle.toFixed(0) < 80) {
pendulum.angle +=1.5;
} else {
swing("right");
}
} else { // dir == "right"
if (pendulum.angle.toFixed(0) > -80) {
pendulum.angle -= 1.5;
} else {
swing("left");
}
}
}
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);
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?
Space Invader game: I want to control the 'base gun' (move it left and right and fire missiles at the invaders. So I need a keypress or (keydown?) event to change a variable (x coordinate) and a key press event to fire a missile.
Can anyone show me how the keypress event is detected and the variable is changed?
document.onkeydown = function(e) {
var key = e.keyCode;
if (key===37) {//left arrow pressed
} else if (key===39) {//right arrow pressed
}
}
Like this?
document.onkeydown = checkKey;
var xCoord = 100;
function checkKey(e) {
e = e || window.event;
switch (e.keyCode) {
case 37 : // left
xCoord -= 5;
break;
case 39 : // right
xCoord += 5;
break;
}
}
Exciting fiddle: http://jsfiddle.net/u5eJp/
Couple things I would like to add to the other answers:
1) Use constants to make it easier on yourself
2) There is no way to check if a key is currently pressed in javascript, so you should keep track of what is currently pressed as well
var pressed = {
up: false,
down: false,
left: false,
right: false
};
var LEFT_ARROW = 37;
var UP_ARROW = 38;
var RIGHT_ARROW = 39;
var DOWN_ARROW = 40;
document.onkeydown = function (e) {
e = e || window.event;
switch (e.keyCode) {
case LEFT_ARROW:
pressed.left = true;
break;
case UP_ARROW:
pressed.up = true;
break;
case RIGHT_ARROW:
pressed.right = true;
break;
case DOWN_ARROW:
pressed.down = true;
break;
default:
break;
}
}
//update position separately
function updatePos() {
if (pressed.up) { //change y up }
if (pressed.down) { //change y down }
if (pressed.left) { //change x left }
if (pressed.right) { //change x right }
}
Hope this helps, and good luck!
I have to make a game for school with html5 canvas Javascript.
I am new to javascript and still learning but i really need some help with this issue that i have and would appreciate it if someone could help me out. I tried several things but nothing seems to work and im at a loss.
So this is the code for the player object. It can move from left to right.
Now the problem is that it leaves the canvas. I want it to stay in the canvas on the x axes.
// Things to do when keys are down
function onKeyDown(event) {
// prevent arrow keys from scrolling the page
if (event.keyCode >= 37 && event.keyCode <= 39) event.preventDefault();
switch (event.keyCode) {
case 37:
player.vx = -1;
player.image = player.imgLeft;
break; // left key
// case 38: player.vy = -1; break; // up key
case 39:
player.vx = 1;
player.image = player.imgRight;
break; // right key
}
}
// Things to do when keys are up
function onKeyUp(event) {
switch (event.keyCode) {
case 37:
case 39:
player.vx = 0;
player.image = player.original;
break; // left or right key released
// case 38: player.vy = 0; break; // up or down key released
}
}
This is what i got so far....
if ((player.x >= 800) && (player.x <= 0)) {
} else {
}
You could consider adding two functions to check that you're within bounds.
(Essentially the same as your code, albeit with my true condition returned in what would be your else statement.)
// returns true if param is in range [0..799]
function isInXrange(intPos)
{
if ((intPos>=0) && (intPos<800))
return true;
else
return false;
}
// returns true if param is in range [0..599]
function isInYrange(intPos)
{
if ((intPos>=0) && (intPos<600))
return true;
else
return false;
}
You could then add a function to move the player and another to handle colliding with the walls/wandering out of bounds
function movePlayer()
{
if (isInXRange(player.x))
player.x += player.vx;
if (isInXRange(player.y))
player.y += player.vy;
}
function handleOutOfBounds()
{
if (isInXRange(player.x) == false)
{
// do something;
}
if (isInYRange(player.y) == false)
{
// do something else
}
}
Basically just test to see if x + width (optional: + velocity) > canvas.width and the same for height.