So I am making an endless runner game, and I have made a function that should pause the game when the event runs, yet when I try to play the game, it crashes/doesn't load. Does anyone know why? I also tried an if function instead of a while loop, but when I pressed the P key, nothing happened. Essentially, I want it to freeze everything if the PP Boolean is set to false.
If you want to test it, I have it here: https://aakhilv.js.org/endless-runner/
Here is my code (only the relevant bits):
// Booleans
let UP = false;
let DOWN = false;
let HKD = true;
let PP = true;
// Controls
document.onkeydown = function(e) {
if (HKD && e.keyCode == 38) UP = true;
HKD = false;
if (e.keyCode == 40) DOWN = true;
};
document.onkeyup = function(e) {
if (!e.repeat && e.keyCode == 38) UP = false;
if (e.keyCode == 40) DOWN = false;
};
document.onkeypress = function(e) {
if (e.keyCode == 80 && PP) PP = false;
if (e.keyCode == 80 && !PP) PP = true;
};
// Frames
function update() {
// Clear
ctx.clearRect(0, 0, 512, 512);
// Environment
ctx.drawImage(bg, 0, 0);
ctx.drawImage(fl, 0, 384);
ctx.drawImage(fl, 128, 384);
ctx.drawImage(fl, 256, 384);
ctx.drawImage(fl, 384, 384);
ctx.drawImage(cb, 10, 10);
ctx.drawImage(c, 0.5, 0, c.width / 2, c.height / 2);
ctx.font = "40px Font";
ctx.textAlign = "left";
ctx.textBaseline = "top";
ctx.fillStyle = "#ae7640";
ctx.fillText(0, 55, 15);
// Enemies
if (mx >= -128) {
ctx.drawImage(m, mx -= speed, 256);
} else if (mx <= 0) {
mx = Math.floor(Math.random() * (1024 - 512) + 512);
};
if (bx >= -256) {
ctx.drawImage(b, bx -= speed, 215);
} else if (bx <= 0) {
bx = Math.floor(Math.random() * (1536 - 512) + 512);
};
if (cx >= -384) {
ctx.drawImage(c, cx -= speed, 280);
} else if (cx <= 0) {
cx = Math.floor(Math.random() * (4608 - 512) + 512);
};
while (Math.abs(mx - bx) < 192) {
mx = Math.floor(Math.random() * (1024 - 512) + 512);
bx = Math.floor(Math.random() * (1536 - 512) + 512);
};
// HKD
if (y == 256) {
HKD = true;
};
// UP
if (UP) {
if (y > 100) {
ctx.drawImage(pl, 0, y -= speed);
} else {
UP = false;
};
} else if (!UP) {
if (y < 256) {
ctx.drawImage(pl, 0, y += speed);
} else {
ctx.drawImage(pl, 0, y);
};
};
// DOWN
if (DOWN) {
pl.src = "./Assets/Duck.png";
} else if (!DOWN) {
pl.src = "./Assets/Idle.png";
};
};
while (PP) {
setInterval(update, 10);
};
The problem might be here -
document.onkeypress = function(e) {
if (e.keyCode == 80 && PP) PP = false;
if (e.keyCode == 80 && !PP) PP = true;
};
Initially PP = true
Now if user presses 'P'
1st if condition would be true and PP would be assigned false;
Now the 2nd condition would be checked, !PP would resolve to true, because of previous if code execution, so PP reverts back to true.
You might want to use if else above, i.e,
document.onkeypress = function(e) {
if (e.keyCode == 80 && PP) PP = false;
else if (e.keyCode == 80 && !PP) PP = true;
};
while (PP) {
setInterval(update, 10);
};
The code above infinitely calls setInterval, which will create infinitely many intervals. Instead, you want to setInterval only once, and then check within update if PP is true and skip the function body if it's false.
function update() {
if(PP){
// Clear
ctx.clearRect(0, 0, 512, 512);
// Environment
ctx.drawImage(bg, 0, 0);
// ...
}
};
setInterval(update, 10);
Other comments on the code: You should name your variables something understandable to others, and you don't need semicolons after the closing "}". Also, if is not a function.
Related
Good afternoon everyone. I was making my own snake game. And when I implemented the snake eating function, I ran into a problem (The function that should start while the snake is eating the apple doesn't work.)
I tried to equate the positions of the apple to the size of the block. And the function should return me an alert when the snake has eaten the apple.
var canvas = document.getElementById("game");
var ctx = canvas.getContext("2d");
var box = 10;
//Snake
var snake = [];
var px = canvas.width / 2;
var py = canvas.height / 2;
var dir = "right";
var maxCell = 10;
var can = canvas.getBoundingClientRect();
//Apple
var ax = Math.floor(Math.random() * ~~(canvas.width / box));
var ay = Math.floor(Math.random() * ~~(canvas.height / box));
document.addEventListener("keydown", function(e) {
if (e.keyCode === 37 && dir !== "right") {
dir = "left";
//console.log('left')
} else if (e.keyCode === 38 && dir !== "down") {
dir = "up";
//console.log('up')
} else if (e.keyCode === 39 && dir !== "left") {
dir = "right";
//console.log('right')
} else if (e.keyCode === 40 && dir !== "up") {
dir = "down";
//console.log('down')
}
});
function direction() {
if (dir == "right") {
px += box;
} else if (dir == "left") {
px -= box;
} else if (dir == "up") {
py -= box;
} else if (dir == "down") {
py += box;
}
}
//Closure )))
function Elems() {
//! Spawn apple
function Apple() {
ctx.fillStyle = "green";
ctx.fillRect(ax, ay, box, box);
}
//! Spawn snake
function Snake() {
direction();
var head = {
x: px,
y: py,
};
snake.unshift(head);
if (snake.length < maxCell) {
snake.push({
x: px,
y: py
});
}
if (px >= canvas.width) {
px = 0;
} else if (px < 0) {
px = canvas.width;
}
if (py >= canvas.height) {
py = 0;
} else if (py < 0) {
py = canvas.height;
}
snake.forEach(function(elem, index) {
ctx.fillStyle = `red`;
ctx.fillRect(elem.x, elem.y, box, box);
});
//BROKEN CODE
if (head.x == ax && head.y == ay) {
alert("HI");
}
snake.pop();
}
Snake();
Apple();
}
function loop() {
setInterval(() => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
Elems();
}, 2000 / 30);
}
loop();
canvas {
border: 1px solid #000;
background-color: #000;
}
<canvas id="game" width="450" height="450"></canvas>
You are checking for equality:
if (head.x == ax && head.y == ay) {
alert("HI");
}
You must check for overlap. Apple is not a point, it is an area. You need to check whether the two areas overlap or not.
(The area of apple and the area of the head of the snake)
The question is that you have two rectangles, and Do they overlap?
The second solution: you can set the position of apple in a way that your current code can work. Currently you are spawning apples on canvas randomly, if you can fix this, your current code might work.
Basically, you will ensure that the corner of the apple, and the corner of the head will be equal when the snake eats the apple. if you can fix the apple spawning code, it might work.
You need to calculate your grid if you box is 10x10 . In your case you have 450 x 450px canvas you divide that by 10 and the grid will be 45x45
Use grid.x and grid.y (those are your max values in you grid) to place the snake and generate an apple coords.
That way you need to check only top left coords and not if rectangles overlap
var canvas = document.getElementById("game");
var ctx = canvas.getContext("2d");
var box = 10;
//calculate your grid
var grid = {
x: Math.floor(canvas.width / box),
y: Math.floor(canvas.height / box)
};
var snake = [];
//use grid to center the snake
var px = Math.floor(grid.x / 2) * box;
var py = Math.floor(grid.y / 2) * box;
var dir = "right";
var maxCell = 10;
var can = canvas.getBoundingClientRect();
//Apple
//use your grid to spawn an apple
var ax = Math.floor(Math.random() * grid.x) * box;
var ay = Math.floor(Math.random() * grid.y) * box;
document.addEventListener("keydown", function(e) {
if (e.keyCode === 37 && dir !== "right") {
dir = "left";
//console.log('left')
} else if (e.keyCode === 38 && dir !== "down") {
dir = "up";
//console.log('up')
} else if (e.keyCode === 39 && dir !== "left") {
dir = "right";
//console.log('right')
} else if (e.keyCode === 40 && dir !== "up") {
dir = "down";
//console.log('down')
}
});
function direction() {
if (dir == "right") {
px += box;
} else if (dir == "left") {
px -= box;
} else if (dir == "up") {
py -= box;
} else if (dir == "down") {
py += box;
}
}
//Closure )))
function Elems() {
//! Spawn apple
function Apple() {
ctx.fillStyle = "green";
ctx.fillRect(ax, ay, box, box);
}
//! Spawn snake
function Snake() {
direction();
var head = {
x: px,
y: py,
};
snake.unshift(head);
if (snake.length < maxCell) {
snake.push({
x: px,
y: py
});
}
if (px >= canvas.width) {
px = 0;
} else if (px < 0) {
px = canvas.width;
}
if (py >= canvas.height) {
py = 0;
} else if (py < 0) {
py = canvas.height;
}
snake.forEach(function(elem, index) {
ctx.fillStyle = `red`;
ctx.fillRect(elem.x, elem.y, box, box);
});
//BROKEN CODE
if (head.x == ax && head.y == ay) {
alert("HI");
}
snake.pop();
}
Snake();
Apple();
}
function loop() {
setInterval(() => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
Elems();
}, 2000 / 30);
}
loop();
canvas {
border: 1px solid #000;
background-color: #000;
}
<canvas id="game" width="450" height="450"></canvas>
I am currently trying to make an endless runner game, and I've just finished making the jumping mechanics. However, if the player were to hold the up arrow key, or press it before they touched the ground, they are able to mimic the ability to "fly". I am not sure how to prevent them from "flying" if they have not touched the ground yet. If anyone has any ideas, please let me know. My code is below:
let ctx = document.querySelector("canvas").getContext("2d");
// Screen
ctx.canvas.height = 512;
ctx.canvas.width = 512;
// Images
let bg = new Image;
bg.src = "./Background.png";
let fl = new Image;
fl.src = "./Floor.png";
// Player
let y = 256;
let speed = 2.5;
let pl = new Image;
pl.src = "./Idle.png";
pl.onload = function() {
ctx.drawImage(pl, 0, y);
};
// Jumping
let UP = false;
// Ducking
let DOWN = false;
document.onkeydown = function(e) {
if (e.keyCode == 38) UP = true;
if (e.keyCode == 40) DOWN = true;
};
document.onkeyup = function(e) {
if (e.keyCode == 38) UP = false;
if (e.keyCode == 40) DOWN = false;
};
// Frames
function update() {
// Clear
ctx.clearRect(0, 0, 512, 512);
// Background
ctx.drawImage(bg, 0, 0);
// Floor
ctx.drawImage(fl, 0, 384);
ctx.drawImage(fl, 128, 384);
ctx.drawImage(fl, 256, 384);
ctx.drawImage(fl, 384, 384);
// UP
if (UP) {
if (y > 100) {
ctx.drawImage(pl, 0, y -= speed);
} else {
UP = false;
};
} else if (!UP) {
if (y < 256) {
ctx.drawImage(pl, 0, y += speed);
} else {
ctx.drawImage(pl, 0, y);
};
};
// DOWN
if (DOWN) {
pl.src = "./Duck.png";
} else if (!DOWN) {
pl.src = "./Idle.png";
};
};
setInterval(update, 10);
It's been few days that I've been learning JavaScript. So I'm completely new to this.
This is my code for snake game and it isn't complete yet but I've run into a problem. I'm not completely sure that if it's a logical error or not.
After eating the food several times, the game crashes with
TypeError: snakeBody[l] is undefined.
Screenshot of the error is here.
The entire code is given below:
<!DOCTYPE html>
<html lang="en">
<head>
<style>
canvas {
background: #080d16;
border: 5px solid green;
padding: 0;
}
</style>
</head>
<body>
<canvas id="mycan" class="mycan" width="1860" height="920"></canvas>
<script>
var canvas = document.getElementById('mycan');
var ctx = canvas.getContext('2d');
var snakeSize = 20;
var snakeX = 100;
var snakeY = 100;
var foodX = 310;
var foodY = 310;
var foodSize = 10;
var dx = 20;
var dy = 20;
var leftPressed = false;
var rightPressed = true;
var topPressed = false;
var bottomPressed = false;
var snakeBody = [{x:snakeX,y:snakeY},{x:snakeX-20,y:snakeY}];
var z = 0;
//keypress event listner
document.addEventListener('keypress', keyHandler, false);
//keypress event handler function
function keyHandler(e) {
if (e.keyCode == 37) {
leftPressed = true;
rightPressed = false;
topPressed = false;
bottomPressed = false;
} else if (e.keyCode == 38) {
leftPressed = false;
rightPressed = false;
topPressed = true;
bottomPressed = false;
} else if (e.keyCode == 39) {
leftPressed = false;
rightPressed = true;
topPressed = false;
bottomPressed = false;
} else if (e.keyCode == 40) {
leftPressed = false;
rightPressed = false;
topPressed = false;
bottomPressed = true;
}
}
//draw food
function food() {
ctx.beginPath();
ctx.arc(foodX, foodY, foodSize, 0, Math.PI * 2);
ctx.fillStyle = "pink";
ctx.fill();
ctx.closePath();
}
//draw snake
function snake() {
for (var l = 0; l < snakeBody.length; l++) {
ctx.beginPath();
ctx.rect(snakeBody[l].x, snakeBody[l].y, snakeSize, snakeSize);
if (l == 0) {
ctx.fillStyle = "lightblue";
} else {
ctx.fillStyle = 'grey';
}
ctx.fill();
ctx.closePath();
}
console.log(l);
var head = {
x: snakeX,
y: snakeY
};
snakeBody.pop();
snakeBody.unshift(head);
}
function tail() {
if ((snakeX + dx / 2 > foodX - foodSize && snakeX + dx / 2 < foodX + foodSize) && (snakeY + dy / 2 > foodY - foodSize && snakeY + dy / 2 < foodY + foodSize)) {
foodX = (Math.floor(Math.random() * 88) + 1) * 20 + 10;
foodY = (Math.floor(Math.random() * 45) + 1) * 20 + 10;
z++;
if (snakeBody[snakeBody.length - 1].x == snakeBody[snakeBody.length - 2].x && snakeBody[0].y < snakeBody[1].y) {
snakeBody[z] = {
x: snakeBody[snakeBody.length - 1].x,
y: snakeBody[snakeBody.length - 1].y + 20
};
} else if (snakeBody[snakeBody.length - 1].x == snakeBody[snakeBody.length - 2].x && snakeBody[0].y > snakeBody[1].y) {
snakeBody[z] = {
x: snakeBody[snakeBody.length - 1].x,
y: snakeBody[snakeBody.length - 1].y - 20
};
} else if (snakeBody[snakeBody.length - 1].y == snakeBody[snakeBody.length - 2].y && snakeBody[0].x > snakeBody[1].x) {
snakeBody[z] = {
x: snakeBody[snakeBody.length - 1].x - 20,
y: snakeBody[snakeBody.length - 1].y
};
} else if (snakeBody[snakeBody.length - 1].y == snakeBody[snakeBody.length - 2].y && snakeBody[0].x < snakeBody[1].x) {
snakeBody[z] = {
x: snakeBody[snakeBody.length - 1].x + 20,
y: snakeBody[snakeBody.length - 1].y
};
}
}
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
snake();
food();
tail();
if (rightPressed && snakeX + dx < canvas.width) {
snakeX += dx;
} else if (leftPressed && snakeX > 0) {
snakeX += -dx;
} else if (topPressed && snakeY > 0) {
snakeY += -dy;
} else if (bottomPressed && snakeY + dy < canvas.height) {
snakeY += dy;
}
}
setInterval(draw, 80);
</script>
</body>
</html>
You have error in algorithm - your snakeBody put/pops elements and you miss some "corner cases" when use indexes in this array - the problem is not with JS but with algorithm - debug it and also use "triangle" in chrome konsole on left side of error to see more details (stacktrace)
I check and run your code more than once. This error does not appear for me. It is good for you to check the values in snake function and then use them. Modify your snake function to this
function snake() {
for (var l = 0; l < snakeBody.length; l++) {
ctx.beginPath();
if(snakeBody && snakeBody[l] && snakeBody[l].hasOwnProperty('x') && snakeBody[l].hasOwnProperty('y')) {
ctx.rect(snakeBody[l].x, snakeBody[l].y, snakeSize, snakeSize);
}
if (l == 0) {
ctx.fillStyle = "lightblue";
} else {
ctx.fillStyle = 'grey';
}
ctx.fill();
ctx.closePath();
}
console.log(l);
var head = {
x: snakeX,
y: snakeY
};
snakeBody.pop();
snakeBody.unshift(head);
}
As you can see, snakeBody has no indexes 24 and 25. But this condition satisfy this.
I'm trying to write a variation of Snake where the snake "bounces" off the walls.
It works most of the time, but occasionally the snake "escapes" and I can't figure out why. Initially I had the inequalities in the collison detection function set to strictly < or > which I thought was the cause of the problem, but I've changed them to <= and >= and the problem persists.
Can anyone explain why this is happening please? (You usually have to play for a minute or so before the snake escapes...)
<canvas id="canvas" width=500 height=500 style="display: block; border: 1px solid green; margin: auto;"></canvas>
<script>
var ctx = document.getElementById('canvas').getContext('2d');
ctx.font = '30px Arial';
var HEIGHT = 500;
var WIDTH = 500;
var SEGMENT_WIDTH = 30;
var snakeVelocity = {
i: 1,
j: 0
};
var snakeArray = createSnake();
function createSnake() {
var snakeArray = [];
var length = 5; // Initial length of snake
for (var i = 0; i < length; i++) {
snakeArray.push({
x: i + 1,
y: 1
});
}
return snakeArray;
}
function moveSnake(arr) {
var head = arr.slice(-1)[0];
var tail = arr[0];
var newHead = arr.shift();
// check for wall collision, which also updates velocity if needed
snakeWallCollision(head);
newHead.x = head.x + snakeVelocity.i;
newHead.y = head.y + + snakeVelocity.j;
arr.push(newHead);
return arr;
}
function snakeWallCollision(obj) {
var collision = false;
if (obj.x >= WIDTH / SEGMENT_WIDTH || obj.x <= 0) {
snakeVelocity.i *= -1;
collision = true;
}
if (obj.y >= HEIGHT / SEGMENT_WIDTH || obj.y <= 0) {
snakeVelocity.j *= -1;
collision = true;
}
return collision;
}
function drawSnake() {
console.log(snakeArray[0]);
for (var i = 0; i < snakeArray.length; i++) {
var segment = snakeArray[i];
ctx.fillText('S', segment.x * SEGMENT_WIDTH, segment.y * SEGMENT_WIDTH + 30);
}
}
function update() {
ctx.clearRect(0, 0, WIDTH, HEIGHT);
moveSnake(snakeArray);
drawSnake();
}
function checkKey(e) {
e = e || window.event;
if ([38, 40, 37, 39].includes(e.keyCode)) {
e.preventDefault();
}
if (e.keyCode == '38') {
snakeVelocity = {
i: 0,
j: -1
};
} else if (e.keyCode == '40') {
snakeVelocity = {
i: 0,
j: 1
};
} else if (e.keyCode == '37') {
snakeVelocity = {
i: -1,
j: 0
};
} else if (e.keyCode == '39') {
snakeVelocity = {
i: 1,
j: 0
};
}
}
document.onkeydown = checkKey;
setInterval(update, 1000 / 20);
drawSnake();
</script>
The problem occurs if you change direction away from the wall just before you hit the wall.
Say for example the snake's head has just moved to x = 0 and moving left and the user keys right arrow just before the next update frame. Now the snakeVelocity.i is set to 1 away from the wall.
You then test the wall
if (obj.x >= WIDTH / SEGMENT_WIDTH || obj.x <= 0) {
snakeVelocity.i *= -1; // negate the direction
// but the direction is already away from the
// wall due to user input. This will turn it back
// onto the wall
}
Same happens for up and down.
You need to have the collision test know what direction the snake is heading and then based on that test if that move will result in a collision.
Change the test function to find the next position the snake's head will be if allowed to move as its current state dictates. Only if that move results in the head being outside the bounds of the game do you change the direction.
function snakeWallCollision(head) {
var x = head.x + snakeVelocity.i; // find out where the head will be
var y = head.y + snakeVelocity.j; // next frame
if (x > WIDTH / SEGMENT_WIDTH || x < 0) {
snakeVelocity.i *= -1;
return true;
}
if (y > HEIGHT / SEGMENT_WIDTH || y < 0) {
snakeVelocity.j *= -1;
return true;
}
return false;
}
What happens if you swap these lines around:
newHead.x = head.x + snakeVelocity.i;
newHead.y = head.y + + snakeVelocity.j;
// check for wall collision, which also updates velocity if needed
snakeWallCollision(head);
The problem seems to be that if the user presses a key synchronized with your collision check the directions changes twice and the snake goes beyond the wall.
Maybe this one helps you out (i added a test variable USER_ACTION to check if the user has pressed the key and if so, don't do the collision check):
var ctx = document.getElementById('canvas').getContext('2d');
ctx.font = '30px Arial';
var HEIGHT = 500;
var WIDTH = 500;
var SEGMENT_WIDTH = 30;
var USER_ACTION = false;
var snakeVelocity = {
i: 1,
j: 0
};
var snakeArray = createSnake();
function createSnake() {
var snakeArray = [];
var length = 5; // Initial length of snake
for (var i = 0; i < length; i++) {
snakeArray.push({
x: i + 1,
y: 1
});
}
return snakeArray;
}
function moveSnake(arr) {
var head = arr.slice(-1)[0];
var tail = arr[0];
var newHead = arr.shift();
// check for wall collision, which also updates velocity if needed
snakeWallCollision(head);
newHead.x = head.x + snakeVelocity.i;
newHead.y = head.y + +snakeVelocity.j;
arr.push(newHead);
return arr;
}
function snakeWallCollision(obj) {
if (!USER_ACTION) {
var collision = false;
if (obj.x >= WIDTH / SEGMENT_WIDTH || obj.x <= 0) {
snakeVelocity.i *= -1;
collision = true;
}
if (obj.y >= HEIGHT / SEGMENT_WIDTH || obj.y <= 0) {
snakeVelocity.j *= -1;
collision = true;
}
} else {
USER_ACTION = false;
}
return collision;
}
function drawSnake() {
console.log(snakeArray[0]);
for (var i = 0; i < snakeArray.length; i++) {
var segment = snakeArray[i];
ctx.fillText('S', segment.x * SEGMENT_WIDTH, segment.y * SEGMENT_WIDTH + 30);
}
}
function update() {
ctx.clearRect(0, 0, WIDTH, HEIGHT);
moveSnake(snakeArray);
drawSnake();
}
function checkKey(e) {
USER_ACTION = true;
e = e || window.event;
if ([38, 40, 37, 39].includes(e.keyCode)) {
e.preventDefault();
}
if (e.keyCode == '38') {
snakeVelocity = {
i: 0,
j: -1
};
} else if (e.keyCode == '40') {
snakeVelocity = {
i: 0,
j: 1
};
} else if (e.keyCode == '37') {
snakeVelocity = {
i: -1,
j: 0
};
} else if (e.keyCode == '39') {
snakeVelocity = {
i: 1,
j: 0
};
}
}
document.onkeydown = checkKey;
setInterval(update, 1000 / 20);
drawSnake();
so I've put some simple collision detection code on a canvas: if my obstacle car sprites touch my user car sprite, the obstacle car stops. For some reason, when the cars are close, the collision is only detected if I am pressing the keys that my user car uses to move (up, down, left, and right arrow keys). How can I get this function to work all the time, regardless of if I am pressing down the keys to move?
collision detection code:
//Collide test
function firstObstaclecollideTest () {
if (Math.abs(x1 - (usercar.width / 2) - x) < usercar.width && Math.abs(y1 - (usercar.height / 2) - y) < usercar.height) {
mod1 = 0;
speed1 = 0;
}
requestAnimationFrame(firstObstaclecollideTest);
}
requestAnimationFrame(firstObstaclecollideTest);
function secondObstaclecollideTest () {
if (Math.abs(x2 - (usercar.width / 2) - x) < usercar.width && Math.abs(y2 - (usercar.height / 2) - y) < usercar.height) {
mod2 = 0;
speed2 = 0;
}
requestAnimationFrame(secondObstaclecollideTest);
}
requestAnimationFrame(secondObstaclecollideTest);
Full Code: http://jsbin.com/dofihiwize/1/edit?output
Your code is a bit messy i fear :
- You are triggering 4 animation loops : have only one loop to avoid headaches.
- You are duplicating quite some code : go for a Car class to clean things up.
- There are several confusion of concern : for instance, the function drawing the car is clearing the canvas, and also drawing the time elapsed. The function names are also misleading (gameStart is a game loop, ... ).
updated fiddle is here :
http://jsbin.com/bafulazose/1/edit?js,output
//Setting the canvas and context
var canvas = document.getElementById('background');
var context = canvas.getContext('2d');
//================
// CAR Class
//================
//Uploading obstacle car
var carImage = new Image();
carImage.src = "http://www.i2clipart.com/cliparts/f/e/3/a/128135fe3a51f073730a8d561282d05b4f35ab.png";
function Car(x, y, speed, mod, angle) {
this.x = x; // x center of car
this.y = y; // y center of car
this.speed = speed;
this.mod = mod;
this.angle = angle;
this.move = function () {
this.x += (this.speed * this.mod) * Math.cos(Math.PI / 180 * this.angle);
this.y += (this.speed * this.mod) * Math.sin(Math.PI / 180 * this.angle);
if (this.y > context.canvas.height + 150) {
this.y = -carImage.height;
this.x = Math.floor(Math.random() * canvas.width);
}
};
this.draw = function () {
context.save();
context.translate(this.x, this.y);
context.rotate(this.angle* Math.PI / 180);
context.drawImage(carImage, -(carImage.width / 2), -(carImage.height / 2));
context.strokeRect(-(carImage.width / 2), -(carImage.height / 2), carImage.width , carImage.height);
context.restore();
};
this.testCollision = function(other) {
var dx = Math.abs(this.x - other.x );
var dy = Math.abs(this.y - other.y );
if ( dx < carImage.width && dy < carImage.height) {
this.mod = 0;
this.speed = 0;
}
};
}
//================
//ENTER: USER CAR
//================
var userCar = new Car(450, 550, 10, -1, -90);
setupKeys(userCar);
//=====================
//ENTER: OBSTACLE CAR 1
//=====================
var obstacleCar1 ;
//======================
//ENTER: OBSTACLE CAR 2
//======================
var obstacleCar2 ;
function setupGame () {
obstacleCar1 = new Car(200, 5, 5, 1, 90);
obstacleCar2 = new Car(340, 5, 5, 1, 90);
gameOver = false;
startTime = Date.now();
score = 0;
}
//=========================
//Properties for score keep
//=========================
var score;
var startTime;
var gameOver;
var spaceBarPressed = false;
//=========================
// Launch the game
//=========================
setupGame () ;
var gameLoopInterval = setInterval(gameLoop, 30);
//===========================
//Draw Final and Elasped Time
//===========================
function drawElapsedTime() {
context.save();
context.fillStyle = "black";
context.font = "30px Verdana";
context.fillText(parseInt((Date.now() - startTime) / 1000) + " secs", canvas.width - 120, 40);
context.restore();
}
function drawFinalScore() {
context.save();
context.fillStyle = "black";
context.font = "30px Verdana";
context.fillText("Game Over: " + score + " secs", 100, 100);
context.font = "12px Verdana";
context.fillText("Press space to restart", 190, 150);
context.restore();
}
//========================
// Game loop
//========================
function gameLoop() {
context.clearRect(0, 0, canvas.width, canvas.height);
if (gameOver) {
drawFinalScore();
if (spaceBarPressed) {
setupGame ();
}
return;
}
obstacleCar1.move();
obstacleCar2.move();
obstacleCar1.testCollision(userCar);
obstacleCar2.testCollision(userCar);
if (obstacleCar1.speed===0 && obstacleCar2.speed===0) {
score = parseInt((Date.now() - startTime) / 1000);
gameOver = true;
spaceBarPressed = false;
}
obstacleCar1.draw();
obstacleCar2.draw();
userCar.draw();
drawElapsedTime();
}
//========================
// Keys handling
//========================
function setupKeys(target) {
var cancelledKeys = [32, 37, 38, 39, 40];
function keyUpHandler(event) {
if (event.keyCode == 38 || event.keyCode == 40) {
mod = 0;
}
}
function keyDownHandler(event) {
var keyCode = event.keyCode;
if (keyCode == 37) {
target.x -= target.speed;
}
if (keyCode == 39) {
target.x += target.speed;
}
if (keyCode == 32) {
spaceBarPressed = true;
}
// space and arrow keys
if (cancelledKeys.indexOf(keyCode) > -1) {
event.preventDefault();
}
}
//Event listeners for keys
window.addEventListener("keydown", keyDownHandler, false);
window.addEventListener("keyup", keyUpHandler, false);
}
Edit :
Morning coffee improvements (:-)) :
- moves are smooth ( requestAnimationFrame + position += speed * time elapsed)
- keys are handled properly
- cars have a clean spawn function
- cars are now in a 'scene graph' (an array) so we can test intersection
- road !! (with roadPos, roadSpeed)
http://jsbin.com/zujecerehe/1/edit?js,output