Arrow Key implementation javascript - javascript

ive been trying to flip the arrows when the cars are in different side of the road. The image shows two multi-lane roads where forward on the left side goes up and i want forward on the right to go down, and the same for right and left. ive tried my method but it doesnt seem to work so i think im doing something stupid. please hep with a method that can work, heres the code
class Controls
{
constructor(type,laneIndex)
{
this.laneIndex = laneIndex;
this.forward =false;
this.left = false ;
this.foward = false ;
this.reverse =false;
switch (type)
{
case "KEYS":
this.#addKeyboardListeners();
break;
case "DUMMY":
this.forward =true;
break;
}
}
#addKeyboardListeners()
{
if (this.laneIndex <= 3)
{
document.onkeydown=(event)=>
{
switch(event.key)
{
case "ArrowLeft":
this.left =true;
break;
case "ArrowRight":
this.right =true;
break;
case "ArrowUp":
this.forward =true;
break;
case "ArrowDown":
this.reverse =true;
break;
}
}
document.onkeyup=(event)=>
{
switch(event.key)
{
case "ArrowLeft":
this.left = false;
break;
case "ArrowRight":
this.right = false;
break;
case "ArrowUp":
this.forward = false;
break;
case "ArrowDown":
this.reverse =false;
break;
}
}
}
if (this.laneIndex >= 4)
{
document.onkeydown=(event)=>
{
switch(event.key)
{
case "ArrowLeft":
this.right =true;
break;
case "ArrowRight":
this.left =true;
break;
case "ArrowUp":
this.reverse =true;
break;
case "ArrowDown":
this.forward =true;
break;
}
}
document.onkeyup=(event)=>
{
switch(event.key)
{
case "ArrowLeft":
this.right =false;
break;
case "ArrowRight":
this.left =false;
break;
case "ArrowUp":
this.reverse =false;
break;
case "ArrowDown":
this.forward =false;
break;
}
}
}
}
}

Basic keyboard input
This answer shows a method for monitoring the ongoing keyboard state.
Keys of interest are flagged as true when down and false when up.
There is a demo (bottom) to show how this method can be used in an animated app interface.
Some pointers
Keep IO (mouse, keyboards, touch, joysticks etc..) and game logic separate as this help keeps the code simple.
Don't add events via the named event property. Eg document.onkeydown = function. As it can easily be overwritten by you or 3rd party code.
Use addEventListener to ensure the event will stay in place
Example of keyboard input
The example creates an object keys that has a property for each of the keys you want to keep track of. The keyboard event listener will set the state to true when a key is down and false if not.
You can add other keys by adding the KeyboardEvent.code name to keys object. Example I have added Space to listen for the space key (I will use it to switch tracks in next example.
const keys = (() => {
const keys = { // only names of keys you are interested in
ArrowUp: false,
ArrowRight: false,
ArrowDown: false,
ArrowLeft: false,
Space: false,
};
function listener(e) {
keys[e.code] !== undefined && (keys[e.code] = e.type === "keydown");
}
addEventListener("keyup", listener);
addEventListener("keydown", listener);
return keys;
})();
Using the input
Once you have the controlling input setup, your app logic need only monitor the state of the input and react as needed.
The example below uses the keys object to move the active car. W moves the car forward, and D moves it in reverse. The function that moves cars is Car.update
To switch cars press the space key. Switching cars can be found in renderLoop
Note Use WASD for control as arrow keys are not safe in stack overflow snippets
Note you need to focus the snippet for the keyboard events to be seen as stack overflow snippets can not automatically focus.
const keys = (() => {
const keys = { // only names of keys you are interested in
KeyW: false,
KeyS: false,
Space: false,
};
function listener(e) {
keys[e.code] !== undefined && (keys[e.code] = e.type === "keydown");
e.preventDefault(); // to stop stack overflow snippet problems
}
addEventListener("keyup", listener);
addEventListener("keydown", listener);
return keys;
})();
const P2 = (x, y) => ({x, y}); // creates 2D point
const Car = { // common properties for a car
on: false,
col: "#888",
/* Function that inspects keyboard state and moves car */
update() {
if (this.on) { // only if active
let mx = 0, my = 0;
if (keys.KeyW) { /* Check forward */
mx += this.dir.x * 3;
my += this.dir.y * 3;
}
if (keys.KeyS) { /* Check reverse */
mx -= this.dir.x;
my -= this.dir.y;
}
// Keep on canvas
if (this.pos.x + mx > W - 40 || this.pos.x + mx < 40) { mx = 0; }
if (this.pos.y + my > H - 40 || this.pos.y + my < 40) { my = 0; }
this.pos.x += mx;
this.pos.y += my;
}
},
draw() {
ctx.fillStyle = this.col;
const sx = this.size.x, sy = this.size.y;
ctx.setTransform(this.dir.y, this.dir.x, -this.dir.x, this.dir.y, this.pos.x, this.pos.y);
ctx.fillRect(sx * -0.5, sy * -0.5, sx, sy);
ctx.fillStyle = "#9AD";
ctx.fillRect(sx * -0.4, sy * -0.4, sx * 0.1, sy * 0.25);
ctx.fillRect(sx * -0.4, sy * -0.1, sx * 0.8, sy * 0.2);
ctx.fillRect(sx * 0.3, sy * -0.4, sx * 0.1, sy * 0.25);
ctx.strokeStyle = "#EA5";
ctx.lineWidth = 2;
ctx.beginPath();
if (this.on) {
ctx.moveTo(sx * -0.4 , sy * 1.5);
ctx.lineTo(sx * -0.25, sy * 0.5);
ctx.lineTo(sx * -0.1 , sy * 1.5);
ctx.moveTo(sx * 0.4 , sy * 1.5);
ctx.lineTo(sx * 0.25, sy * 0.5);
ctx.lineTo(sx * 0.1 , sy * 1.5);
}
ctx.moveTo(sx * -0.1 , sy * 0.5);
ctx.lineTo(sx * -0.4 , sy * 0.5);
ctx.moveTo(sx * 0.1 , sy * 0.5);
ctx.lineTo(sx * 0.4 , sy * 0.5);
ctx.stroke();
ctx.setTransform(1, 0, 0, 1, 0, 0); // restore default transform incase
// you draw stuff not using setTransform
}
}
const cars = [{
dir: P2(0, 1), // forward direction
size: P2(30, 50),
pos: P2(100, 100),
...Car
}, {
dir: P2(0, -1), // forward direction
size: P2(30, 50),
pos: P2(200, 100),
...Car
},
];
requestAnimationFrame(renderLoop);
const ctx = canvas.getContext("2d"), W = canvas.width, H = canvas.height;
var carOnIdx = 0;
cars[carOnIdx].on = true;
function renderLoop(time) {
ctx.setTransform(1,0,0,1,0,0);
ctx.clearRect(0, 0, W, H);
ctx.fillStyle = "#555";
ctx.fillRect(10, 10, W - 20, H - 20);
ctx.fillStyle = "#DDD";
ctx.fillRect(70, 10, 2, H - 20);
ctx.fillRect(130, 10, 2, H - 20);
ctx.fillRect(175, 10, 2, H - 20);
ctx.fillRect(225, 10, 2, H - 20);
// If space key press changed cars
if (keys.Space) {
cars[carOnIdx].on = false;
carOnIdx = (carOnIdx + 1) % cars.length;
cars[carOnIdx].on = true;
// Only want the key down for space to flag it as used
keys.Space = false;
}
for (const car of cars) { car.update(); }
for (const car of cars) { car.draw(); }
requestAnimationFrame(renderLoop);
}
* {
font-family: arial;
}
canvas {
background: #4A6;
}
.info {
position: absolute;
left: 340px;
top: 20px;
font-size: large;
}
ul {
position: absolute;
left: 320px;
top: 30px;
}
<canvas id="canvas" width="300" height="300"></canvas>
<div class="info">Using keyboard input</div>
<ul>
<li>To focus keyboard on snippet, click snippet</li>
<li>Uses WASD rather than arrow keys</li>
<li>Space to switch cars</li>
<li>W to drive forward</li>
<li>D to reverse</li>
<li><b>Note</b> cars can not go outside canvas</li>
</ul>

Related

Canvas JS game, Can't make the character jump only once after touching the ground

this is my code for a canvas game, my character is able to go left right and jump. The problem is that i want to make the character jump only once, then touch the ground again and now, to be able to jump again. In my code if i press w multiple times will jump forever.
const canvas = document.querySelector("canvas");
const c = canvas.getContext('2d')
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
const gravity = 0.5;
let isGrounded;
class Player {
constructor() {
this.position = {
x: 100,
y: 100
}
this.width = 100
this.height = 100
this.velocity = {
x: 0,
y: 1
}
}
draw() {
c.fillStyle = 'black'
c.fillRect(this.position.x, this.position.y,
this.width, this.height)
}
update() {
this.draw();
this.position.x += this.velocity.x;
this.position.y += this.velocity.y;
if (this.position.y + this.height + this.velocity.y >= canvas.height)
this.velocity.y = 0
else this.velocity.y += gravity;
}
}
class Platform {
constructor({
x,
y
}) {
this.position = {
x: x,
y: y
}
this.width = 400
this.height = 20
}
draw() {
c.fillStyle = 'black'
c.fillRect(this.position.x, this.position.y,
this.width, this.height)
}
}
const player = new Player()
const platforms = [
new Platform({
x: 150,
y: 800,
}),
new Platform({
x: 700,
y: 900
}),
];
const keys = {
right: {
pressed: false
},
left: {
pressed: false
},
up: {
pressed: false
}
}
let scrollOffset = 0
function animate() {
const JUMP_SPEED = 5
requestAnimationFrame(animate)
c.clearRect(0, 0, canvas.width, canvas.height)
player.update();
platforms.forEach(platform => {
platform.draw()
})
if (keys.right.pressed && player.position.x < 400) {
player.velocity.x = 5
} else if (keys.left.pressed && player.position.x > 100) {
player.velocity.x = -5
} else {
player.velocity.x = 0
if (keys.right.pressed) {
scrollOffset += 5;
platforms.forEach((platform) => {
platform.position.x -= 5;
});
} else if (keys.left.pressed) {
scrollOffset -= 5
platforms.forEach((platform) => {
platform.position.x += 5;
});
}
}
//platform collision detection
platforms.forEach(platform => {
if (player.position.y + player.height <= platform.position.y &&
player.position.y + player.height + player.velocity.y >= platform.position.y &&
player.position.x + player.width >= platform.position.x &&
player.position.x <= platform.position.x + platform.width) {
player.velocity.y = 0
}
})
if (scrollOffset > 300) {
console.log('u win')
}
}
animate()
window.addEventListener('keydown', ({keyCode}) => {
switch (keyCode) {
case 65:
keys.left.pressed = true;
break;
case 83:
break;
case 68:
keys.right.pressed = true;
break;
case 87:
keys.up.pressed = true;
player.velocity.y = -10
break;
}
})
window.addEventListener("keyup", ({keyCode}) => {
switch (keyCode) {
case 65:
keys.left.pressed = false;
break;
case 83:
break;
case 68:
keys.right.pressed = false;
break;
case 87:
keys.up.pressed = false;
break;
}
});
<canvas></canvas>
You could give the player a jumping flag, and check for that flag:
class Player {
constructor() {
this.position = {
x: 100,
y: 100
}
this.jumping = false;
...
}
...
jump() {
if (!this.jumping) {
this.jumping = true;
this.velocity.y -= 10; // you want relative velocity, not absolute.
}
}
}
Then you can use a simple if (!this.jumping) jump when the jump keydown happens:
const keyDownHandlers = {
"a": () => {
keys.left.pressed = true;
},
"d": () => {
keys.left.pressed = true;
},
"w": () => {
keys.up.pressed = true;
player.jump();
}
};
window.addEventListener('keydown', ({ key } => {
keyDownHandlers[key]?.();
})
But that will also allow the player to jump when they're falling (whenever you add that), so really what you want is a check to see if the player is currently in a collision state with a fixture or not. especially if those fixtures move (e.g. you want to be able to jump while standing on an elevator, despite your velocity vector already having a non-zero y value).
class Player {
constructor() {
this.position = {
x: 100,
y: 100
}
...
}
...
jump() {
if (this.isOnFixture()) {
this.velocity.y -= 10;
}
}
isOnFixture() {
// you get to implement this one
}
}
And since you already have collision detection code written, the onFixture() function for a player should mostly be a matter of moving the code that you're currently running in anime either into the player class, as into a dedicate function that you can then call inside isOnFixture().
addEventListener('keydown', ({ keyCode }) => {
// console.log(keyCode)
switch (keyCode) {
case 37:
console.log("left")
keys.left.pressed = true
break
case 38:
if(player.velocity.y == 0) {
player.velocity.y += -14
}
else {
console.log("not ready")
}
break
case 40:
console.log('down')
break
case 39:
console.log('right')
keys.right.pressed = true
break;
}
})
just check if the player y velocity is zero and if so they are able to jump again and also add this instead on the first actionlistener:
addEventListener('keyup', ({ keyCode }) => {
//console.log(keyCode)
switch (keyCode) {
case 37:
console.log("left")
keys.left.pressed = false
break
case 38:
console.log('up')
player.velocity.y += +15
if (event.repeat) { return }
player.velocity.y += -14
break
case 40:
console.log('down')
break
case 39:
console.log('right')
keys.right.pressed = false
}
});

If statement inside requestanimationframe continues even if parameters aren't met

I'm making a little video game, where the background (platform) moves down with my character (square) jumps. On line 113 I have tried different strategies to implement this thought, and that is the closest it has gotten to work. The issue is that even when the square velocity is 0, the platform velocity isn't. I have been stuck for a week now, and feels like javascript is the problem (even though I know it isn't).
canvasmain.width = window.innerWidth;
canvasmain.height = window.innerHeight;
//CHARACTER:
const square = {
height: 75,
jumping: true,
width: 75,
x: canvasmain.width / 2,
xVelocity: 0,
y: canvasmain.height / 2,
yVelocity: 0
};
//floor
const platform = {
height: 30,
width: 100,
x: square.x,
xVelocity: 0,
y: square.y + square.height,
yVelocity:0
}
//MOVEMENT:
const controller = {
left: false,
right: false,
up: false,
keyListener: function (event) {
let key_state = (event.type == "keydown") ? true : false;
switch (event.keyCode) {
case 37: // left arrow
controller.left = key_state;
break;
case 38: // up arrow
controller.up = key_state;
break;
case 39: // right arrow
controller.right = key_state;
break;
}
}
};
const loop = function () {
if (controller.up && square.jumping == false) {
square.yVelocity -= 30;
square.jumping = true;
}
if (controller.left) {
square.xVelocity -= 0.5;
}
if (controller.right) {
square.xVelocity += 0.5;
}
square.yVelocity += 1.5;// gravity
square.x += square.xVelocity;
square.y += square.yVelocity;
square.xVelocity *= 0.9;// friction
square.yVelocity *= 0.9;// friction
// if square is falling below floor line
if (square.y > canvasmain.height - 75) {
square.jumping = false;
square.y = canvasmain.height - 75;
square.yVelocity = 0;
}
// if square is going off the left of the screen
if (square.x < 0) {
square.x = 0;
} else if (square.x > canvasmain.width - 75) {// if square goes past right boundary
square.x = canvasmain.width - 75;
}
// Creates the backdrop for each frame
context.fillStyle = "#394129";
context.fillRect(0, 0, canvasmain.width, canvasmain.height); // x, y, width, height
// Creates and fills the cube for each frame
context.fillStyle = "#8DAA9D"; // hex for cube color
context.beginPath();
context.rect(square.x, square.y, square.width, square.height);
context.fill();
// Creates the "ground" for each frame
context.fillStyle = "#202020";
context.beginPath();
context.rect(platform.x, platform.y, platform.width, platform.height)
context.fill();
// call update when the browser is ready to draw again
window.requestAnimationFrame(loop);
//platform
platform.y += platform.yVelocity;
console.log(square.yVelocity)
if (square.yVelocity > 0.1 ) {
platform.yVelocity = 1.5
};
if (square.yVelocity < 0 ) {
platform.yVelocity = -1.5
};
}
window.addEventListener("keydown", controller.keyListener)
window.addEventListener("keyup", controller.keyListener);
window.requestAnimationFrame(loop);
You're not reseting the value of yVelocity.
Got it guys, thx #Teemu, I just needed to set it to 0 if it wasn't the if's. Dang, really took a while. if (square.yVelocity > 0 ) {platform.yVelocity = 1.5} else{ platform.yVelocity = 0}; if (square.yVelocity < 0 ) {platform.yVelocity = -1.5} else { platform.yVelocity = 0} }
edit: frick, it only moves the platform when the cube is going up, not down ;-;

How to make a 2d character run and jump in JavaScript

I'm trying to make a square using canvas and making it jump and run, and I have followed the toturial of PothOnProgramming on youtube. I have written the code in a html document and for some reason nothing shows up on the browser when i test it.
<body>
<script>
var context, controller, player, loop;
context=document.querySelector("canvas").getContext("2d");
context.canvas.height=180;
context.canvas.width=320;
player={
height=32,
jumping=true,
width=32,
x=144,
x_velocity=0,
y=0,
y_velocity:0
};
controller={
left=false,
right=false,
up=false,
keyListener:function(event){
var kay_state=(event.type=="keydown")?true:false;
switch(event.keyCode){
case 87:
controller.up=key_state;
break;
case 68:
controller.right=key_state;
break;
case 65:
controller.left=key_state;
break;
}
}
};
loop=function(){
if(controller.up && player.jumping==false){
player.y_velocity-=20;
player.jumping=true;
}
if(controller.left){
player.x_velocity-=0.5; //For at "player" akselererer smooth
}
if(controller.right){
player.x_velocity+=0.5; //For at "player" akselererer smooth
}
player.y_velocity+=1.5; //Gravity
player.x+=player.x_velocity;
player.y+=player-y_velocity;
player.x_velocity*=0.9; //Friksjon (må leggest til eller så synker ikke farten)
player.y_velocity*=0.9; //Friksjon
//dersom player faller til y verdien så koliderer den (bunn linjen)
if(player.y>180-16-32){
player.jumping=false;
player.y=180-16-32;
player.y_velocity=0;
}
context.fillStyle = "#202020";
context.fillRect(0, 0, 320, 180);
context.fillStyle="#ff0000";
context.beginPath();
context.rect(player.x, player.y, player.width, player.height);
context.fill();
context.strokeStyle="#ff0000";
context.lineWidth=4;
context.beginPath();
context.moveTo(0, 164);
context.lineTo(320, 164);
context.stroke();
window.requestAnimationFrame(loop);
};
window.addEventListener("keydown", controller.keyListener);
window.addEventListener("keyup", controller.keyListener);
window.requestAnimationFrame(loop);
</script>
</body>
I'm quite new to this so it may be a simple typo, but I would love to find out what I can do differently to make it work.
You have numerous issues with this code. First you need to fix the object declarations. Objects don't use = for assigning values. You also have several typos with your variable names that I have fixed. Here is a working version:
var context, controller, player, loop
context = document.querySelector('canvas').getContext('2d')
context.canvas.height = 180
context.canvas.width = 320
player = {
height: 32,
jumping: true,
width: 32,
x: 144,
x_velocity: 0,
y: 0,
y_velocity: 0,
}
controller = {
left: false,
right: false,
up: false,
keyListener: function(event) {
var key_state = event.type == 'keydown' ? true : false
switch (event.keyCode) {
case 87:
controller.up = key_state
break
case 68:
controller.right = key_state
break
case 65:
controller.left = key_state
break
}
},
}
loop = function() {
if (controller.up && player.jumping == false) {
player.y_velocity -= 20
player.jumping = true
}
if (controller.left) {
player.x_velocity -= 0.5 //For at "player" akselererer smooth
}
if (controller.right) {
player.x_velocity += 0.5 //For at "player" akselererer smooth
}
player.y_velocity += 1.5 //Gravity
player.x += player.x_velocity
player.y += player.y_velocity
player.x_velocity *= 0.9 //Friksjon (må leggest til eller så synker ikke farten)
player.y_velocity *= 0.9 //Friksjon
//dersom player faller til y verdien så koliderer den (bunn linjen)
if (player.y > 180 - 16 - 32) {
player.jumping = false
player.y = 180 - 16 - 32
player.y_velocity = 0
}
context.fillStyle = '#202020'
context.fillRect(0, 0, 320, 180)
context.fillStyle = '#ff0000'
context.beginPath()
context.rect(player.x, player.y, player.width, player.height)
context.fill()
context.strokeStyle = '#ff0000'
context.lineWidth = 4
context.beginPath()
context.moveTo(0, 164)
context.lineTo(320, 164)
context.stroke()
window.requestAnimationFrame(loop)
}
window.addEventListener('keydown', controller.keyListener)
window.addEventListener('keyup', controller.keyListener)
window.requestAnimationFrame(loop)
<canvas></canvas>
To assign values to properties of an object you should use : instead of =.
So for player object it should be:
player={
height:32,
jumping:true,
width:32,
x:144,
x_velocity:0,
y:0,
y_velocity:0
};

object movement has unwanted increase in speed using setTimeout inside setInterval

I'm testing movement for a practice game I'm working on, what I'm trying to get going with is a loop that will run twice (because the object is a rabbit) inside of an interval so that the object won't move in a continuous circle and it'll have uniqueness to it. How I'm executing it is the interval will run every 1500 miliseconds and the timeout (inside the interval) will run in half of that time to create the rabbit moving in one direction twice instead of once. The problem is after some time the bunny will take larger steps forword and do so faster. I'm not completely sure what the problem is, thank you for looking at this. Heres my code
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var wabbits = {
wabbit1: {
x: 200,
y: 200,
w: 10,
h: 10,
speed: 2,
moving: "",
dead: false,
updateInterval: 2000
}
};
//make it easier to type out the object
var bunny = wabbits.wabbit1;
var movement = ["up", "down", "left", "right"];
var left = "left";
var up = "up";
var down = "down";
var right = "right";
var update = setInterval(function(){
draw();
}, 1);
canvas.style.backgroundColor = "green";
function draw(){
context.clearRect(0, 0, canvas.width, canvas.height);
context.fillStyle = "grey";
context.fillRect(bunny.x, bunny.y, bunny.w, bunny.h);
context.fill();
border();
}
function border(){
if(bunny.x <= 0){
bunny.x += bunny.speed * 2;
}
if(bunny.x >= 490){
bunny.x -= bunny.speed * 2;
}
if(bunny.y <= 0){
bunny.y += bunny.speed * 2;
}
if(bunny.y >= 490){
bunny.y -= bunny.speed * 2;
}
}
function bunny1move(){
if(!wabbits.wabbit1.dead){
var randM = Math.floor(Math.random() * 3) + 0;
wabbits.wabbit1.moving = movement[randM];
function mv(){
switch(wabbits.wabbit1.moving){
case "up":
wabbits.wabbit1.y -= wabbits.wabbit1.speed;
break;
case "down":
wabbits.wabbit1.y += wabbits.wabbit1.speed;
break;
case "left":
wabbits.wabbit1.x -= wabbits.wabbit1.speed;
break;
case "right":
wabbits.wabbit1.x += wabbits.wabbit1.speed;
break;
default:
console.log("something in bunny1.mv() is not working properly, err: " + wabbits.wabbits1.moving);
break;
};
if(wabbits.wabbit1.y <= 0){
wabbits.wabbit1.y += wabbits.wabbit1.speed * 2;
wabbits.wabbit1.moving = down;
}
if(wabbits.wabbit1.y >= 758){
wabbits.wabbit1.y -= wabbits.wabbit1.speed * 2;
wabbits.wabbit1.moving = up;
}
if(wabbits.wabbit1.x <= 0){
wabbits.wabbit1.x += wabbits.wabbit1.speed * 2;
wabbits.wabbit1.moving = right;
}
if(wabbits.wabbit1.x >= 1356){
wabbits.wabbit1.x -= wabbits.wabbit1.speed * 2;
wabbits.wabbit1.moving = left;
}
//make mv repeat twice
this.setTimeout(mv, wabbits.wabbit1.updateInterval / 2);
}
mv();
}
}
//update the movement function
setInterval(bunny1move, wabbits.wabbit1.updateInterval);
<canvas id="canvas" height="500px" width="500px"></canvas>
You immediately invoke mv after creating it in bunny1move, but after each call to mv it sets a timeout to call itself again one second later. After it gets called again it sets a new timeout to call itself after the next second, and so on. This chain of calls extends ad infinitum.
This by itself wouldn't be too bad, actually it seems like it would be what you want, to have mv called every second. The problem happens when you call bunny1move every two seconds, each of these repeating calls to bunny1move creates a new chain of mv's and they all stack on top of the previous chains.
So it's not so much that the bunny is moving farther on each iteration, it's that more and more mv chains are being created, and they are all being called in sync, making it look like a longer jump when really it's just many more little jumps.
If you put a console.log statement at the end of mv you can see this increase in mv calls over time.
You should just be able to get rid of mv altogether, then call setInterval on bunny1move for every second:
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var wabbits = {
wabbit1: {
x: 200,
y: 200,
w: 10,
h: 10,
speed: 2,
moving: "",
dead: false,
updateInterval: 2000
}
};
//make it easier to type out the object
var bunny = wabbits.wabbit1;
var movement = ["up", "down", "left", "right"];
var left = "left";
var up = "up";
var down = "down";
var right = "right";
var update = setInterval(function(){
draw();
}, 1);
canvas.style.backgroundColor = "green";
function draw(){
context.clearRect(0, 0, canvas.width, canvas.height);
context.fillStyle = "grey";
context.fillRect(bunny.x, bunny.y, bunny.w, bunny.h);
context.fill();
border();
}
function border(){
if(bunny.x <= 0){
bunny.x += bunny.speed * 2;
}
if(bunny.x >= 490){
bunny.x -= bunny.speed * 2;
}
if(bunny.y <= 0){
bunny.y += bunny.speed * 2;
}
if(bunny.y >= 490){
bunny.y -= bunny.speed * 2;
}
}
function bunny1move(){
if(!wabbits.wabbit1.dead){
var randM = Math.floor(Math.random() * 3) + 0;
wabbits.wabbit1.moving = movement[randM];
switch(wabbits.wabbit1.moving){
case "up":
wabbits.wabbit1.y -= wabbits.wabbit1.speed;
break;
case "down":
wabbits.wabbit1.y += wabbits.wabbit1.speed;
break;
case "left":
wabbits.wabbit1.x -= wabbits.wabbit1.speed;
break;
case "right":
wabbits.wabbit1.x += wabbits.wabbit1.speed;
break;
default:
console.log("something in bunny1.mv() is not working properly, err: " + wabbits.wabbits1.moving);
break;
};
if(wabbits.wabbit1.y <= 0){
wabbits.wabbit1.y += wabbits.wabbit1.speed * 2;
wabbits.wabbit1.moving = down;
}
if(wabbits.wabbit1.y >= 758){
wabbits.wabbit1.y -= wabbits.wabbit1.speed * 2;
wabbits.wabbit1.moving = up;
}
if(wabbits.wabbit1.x <= 0){
wabbits.wabbit1.x += wabbits.wabbit1.speed * 2;
wabbits.wabbit1.moving = right;
}
if(wabbits.wabbit1.x >= 1356){
wabbits.wabbit1.x -= wabbits.wabbit1.speed * 2;
wabbits.wabbit1.moving = left;
}
}
}
//update the movement function
setInterval(bunny1move, wabbits.wabbit1.updateInterval / 2);
<canvas id="canvas" height="500px" width="500px"></canvas>
As an aside, you should consider posting this on https://codereview.stackexchange.com/ . They should have a few constructive comments on better ways to design your program for more flexibility, extendability, readability etc.

How can this code be factored out to reduce duplication (and should it)?

I'm making a basic browser-based game in javascript. This is my control method for the playable character:
obj.update = function(){
if (this.keyPressed === 'right'){
this.x += 100;
}
if (this.keyPressed === 'left'){
this.x += -100;
}
if (this.keyPressed === 'up'){
this.y -= 100;
}
if (this.keyPressed === 'down'){
this.y -= -100;
}
// reset key press
this.keyPressed = null;
};
I'm conscious that I'm repeating code here. Should I be factoring the repeated elements out? And if so what is the best way to do that?
Should is a matter of opinion. Answering the can part, I'd probably use a switch:
obj.update = function(){
switch (this.keyPressed) {
case 'right':
this.x += 100;
break;
case 'left':
this.x += -100;
break;
case 'up':
this.y -= 100;
break;
case 'down':
this.y -= -100;
break;
}
// reset key press
this.keyPressed = null;
};
...and probably make 100 a constant (in ES2015/ES6) or a variable I didn't change (in ES5 and earlier).
Although it's also tempting to use an object (or in ES2015/ES6 a Map) as a lookup table:
var table = {
right: {x: 100, y: 0},
left: {x: -100, y: 0},
up: {x: 0, y: -100},
down: {x: 0, y: 100}
};
obj.update = function(){
var entry = table[this.keyPressed];
if (entry) {
this.x += entry.x;
this.y += entry.y;
}
// reset key press
this.keyPressed = null;
};
You can probably make this more readable with a switch statement:
switch (this.keyPressed) {
case 'right': this.x += 100; break;
case 'left' : this.x += -100; break;
case 'up' : this.y -= 100; break;
case 'down' : this.y -= -100; break;
}
this.keyPressed = null;
You could make an object and call it with this.
The smart part of this solution, it is open for some more commands, like saving a state, or other.
var op = {
right: function (t) { t.x += 100; },
left: function (t) { t.x -= 100; },
up: function (t) { t.y -= 100; },
down: function (t) { t.y += 100; }
};
obj.update = function () {
var f = op[this.keyPressed];
f && f(this);
this.keyPressed = null;
};

Categories

Resources