I have been trying to make my first game in javascript, its a pong like game where two players move their rectangles around to bump the ball in the other direction. I want it so that when player one hits the "a" key, their character moves left, when they hit the d key they move right.
Right now, nothing happens when I click the desired keys.
This is my current code:
$(document).ready(function() {
// things needed
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
//positions of elements at start
var ballposx = 400;
var ballposy = 50;
var balldx = 1;
var balldy = 2;
var balld2x = 0;
var balld2y = 0;
var p1posx = 80;
var p1posy = 225;
var p1dx = 0;
var p1dy = 0;
var p2posx = 620;
var p2posy = 225;
var p2dx = 0;
var p2dy = 0;
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
//goal1
ctx.fillStyle = "#0F3F0F";
var goal1 = ctx.fillRect(0, 150, 50, 150);
//goal2
ctx.fillStyle = "#204050";
var goal2 = ctx.fillRect(750, 150, 50, 150);
ctx.beginPath();
//ball
var ball = ctx.arc(ballposx, ballposy, 60, 0, 2 * Math.PI);
ctx.stroke();
//p1
ctx.fillStyle = "#FF0000";
var p1 = ctx.fillRect(p1posx, p1posy, 40, 75);
//p2
ctx.fillStyle = "#0000FF";
var p1 = ctx.fillRect(p2posx, p2posy, 40, 75);
p1posx += p1dx;
p2posx += p2dx;
balldx += balld2x;
balldy += balld2y;
ballposx += balldx;
ballposy += balldy;
$(window).keypress(function(e) {
var code = e.which;
switch (code) {
case 65:
p1dx = 1;
case 68:
p1dx = -1;
case 37:
p2dx = -1;
case 39:
p2dx = 1;
default:
break;
}
});
if (ballposy === 240) {
balldy = -1;
} else if (ballposy === 60) {
balldy = 1;
} else if (ballposx === 60) {
balldx = 1;
} else if (ballposx === 740) {
balldx = -1;
} else if (ballposx === p1posx && ballposy < p1posy) {
balldx = 1;
} else if (ballposx === p2posx && ballposy < p2posy) {
balldx = -1;
}
}
setInterval(draw, 10);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<center>
<canvas id="myCanvas" width="800px" height="300px" style="border:1px solid #000000;"> Sorry your browser doesnt support this!</canvas></center>
You're adding another keypress handler every 10 ms. So after a few seconds there are thousands of handlers running every time you press a key, and this is probably bogging down the browser. You should just bind the handler once, outside the draw function.
And in the function, you need break statements in each case.
Your code tests are also wrong. Lowercase a is 97, not 65. And the values of p1dx are backwards -- if you want to go left, it should be -1, not 1.
$(document).ready(function() {
// things needed
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
//positions of elements at start
var ballposx = 400;
var ballposy = 50;
var balldx = 1;
var balldy = 2;
var balld2x = 0;
var balld2y = 0;
var p1posx = 80;
var p1posy = 225;
var p1dx = 0;
var p1dy = 0;
var p2posx = 620;
var p2posy = 225;
var p2dx = 0;
var p2dy = 0;
$(window).keypress(function(e) {
var code = e.which;
switch (code) {
case 97:
p1dx = -1;
break;
case 100:
p1dx = 1;
break;
case 37:
p2dx = -1;
break;
case 39:
p2dx = 1;
break;
default:
break;
}
});
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
//goal1
ctx.fillStyle = "#0F3F0F";
var goal1 = ctx.fillRect(0, 150, 50, 150);
//goal2
ctx.fillStyle = "#204050";
var goal2 = ctx.fillRect(750, 150, 50, 150);
ctx.beginPath();
//ball
var ball = ctx.arc(ballposx, ballposy, 60, 0, 2 * Math.PI);
ctx.stroke();
//p1
ctx.fillStyle = "#FF0000";
var p1 = ctx.fillRect(p1posx, p1posy, 40, 75);
//p2
ctx.fillStyle = "#0000FF";
var p1 = ctx.fillRect(p2posx, p2posy, 40, 75);
p1posx += p1dx;
p2posx += p2dx;
balldx += balld2x;
balldy += balld2y;
ballposx += balldx;
ballposy += balldy;
if (ballposy === 240) {
balldy = -1;
} else if (ballposy === 60) {
balldy = 1;
} else if (ballposx === 60) {
balldx = 1;
} else if (ballposx === 740) {
balldx = -1;
} else if (ballposx === p1posx && ballposy < p1posy) {
balldx = 1;
} else if (ballposx === p2posx && ballposy < p2posy) {
balldx = -1;
}
}
setInterval(draw, 10);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<center>
<canvas id="myCanvas" width="800px" height="300px" style="border:1px solid #000000;"> Sorry your browser doesnt support this!</canvas></center>
I didn't check the whole code, but ou should add the break; statement in every case, not just the default.
For example, your code should be something like:
$(window).keypress(function(e){
var code = e.which;
switch (code)
{
case 65:
p1dx = 1;
break;
case 68:
p1dx = -1;
break;
case 37:
p2dx = -1;
break;
case 39:
p2dx = 1;
break;
default:
break;
}
});
Related
I'm developing a snake game using canvas but am having trouble with displaying the player's score in the upper right corner. This should be handled in the drawScore function but the text doesn't appear. I'm not getting any errors in the console, nor can I find any problem with the code itself.
Any advice would be appreciated!
class SnakePart {
constructor(x,y) {
this.x = x;
this.y = y;
}
}
const body = document.body;
const canvas = document.querySelector('#canvas');
const ctx = canvas.getContext('2d');
let speed = 7; // base speed variable of snake
const snakeParts = [];
let tailLength = 2;
let tileCount = 20;//number of tiles on screen
let headX = 10;//snake width
let headY = 10;//snake height
let tileSize = canvas.width / tileCount - 2;//size of tiles where apple spawns
let xv = 0;// x axis velocity
let yv = 0;//y axis velocity
let ax = 5;//apple position x axis
let ay = 5;//apple position y axis
let score = 0;
//draws game loop
function drawGame(){
//game loop
clearScreen();
changeSnakePosition();
checkAppleCollision();
drawApple();
drawSnake();
drawScore();
setTimeout(drawGame, 1000/speed);
}
function drawScore(){
ctx.fillStyle = 'white';
ctx.font = '12px Helvetica';
ctx.fillText = ("Score: " + score, canvas.width-50, 10);
}
function clearScreen(){
ctx.fillStyle = 'black';
ctx.fillRect(0,0,canvas.width,canvas.height);
}
function drawSnake(){
ctx.fillStyle = 'orange';
ctx.fillRect(headX * tileCount, headY * tileCount, tileSize,tileSize);
ctx.fillStyle = 'green'
for(let i = 0; i<snakeParts.length; i++){
let part = snakeParts[i];
ctx.fillRect(part.x *tileCount,part.y*tileCount,tileSize,tileSize)
}
snakeParts.push(new SnakePart(headX,headY)); //put a segment at the end of the snake next to the head
while(snakeParts.length > tailLength){
snakeParts.shift(); //remove the furthest item from the snake parts if we have more than our tailSize.
}
}
body.addEventListener('keydown', keyDown);
function keyDown(event){
switch(event.keyCode) {
case 37:
if(xv == 1)
return;
yv = 0;
xv = -1
break;
case 38:
if(yv == 1)
return;
yv= -1;
xv = 0;
break;
case 39:
if(xv == -1)
return;
yv = 0;
xv = 1
break;
case 40:
if(yv == -1)
return;
yv = 1;
xv = 0;
}
}
function changeSnakePosition(){
headX = headX + xv;
headY = headY + yv;
}
function drawApple(){
ctx.fillStyle = 'red';
ctx.fillRect(ax*tileCount,ay*tileCount,tileSize,tileSize)
}
function checkAppleCollision(){
if(ax === headX && ay == headY){
ax = Math.floor(Math.random()*tileCount);
ay = Math.floor(Math.random()*tileCount);
tailLength++;
score++;
speed++;
}
}
drawGame();
<canvas id="canvas"></canvas>
The problem is this line :
ctx.fillText = ("Score: " + score, canvas.width-50, 10);
Which should be :
ctx.fillText("Score: " + score, canvas.width-50, 10);
Here's a stripped down example :
const body = document.body;
const canvas = document.querySelector('#canvas');
const ctx = canvas.getContext('2d');
let score = 0;
function drawGame() {
clearScreen();
drawScore();
}
function drawScore() {
ctx.fillStyle = 'white';
ctx.font = '12px Helvetica';
ctx.fillText("Score: " + score, canvas.width-50, 10);
}
function clearScreen() {
ctx.fillStyle = 'black';
ctx.fillRect(0,0,canvas.width,canvas.height);
}
drawGame();
<canvas id="canvas"></canvas>
I am making a javascript game, and the animated sprite blinks when he moves i think it has to do with the speed of the animation because I also need to slow it down. here is my code for updateign the animation
var playerani = setInterval(function(){
if(animate == true){
if(aniframe == maxframes){
aniframe = 1
}else{
aniframe += 1;
}
}
if(controller.left == true){
animate = true;
window.aniimgY = 576;
}else if(controller.up == true){
animate = true;
window.aniimgY = 512;
}else if(controller.down == true){
animate = true;
window.aniimgY = 640;
}else if(controller.right == true){
animate = true;
window.aniimgY = 704;
}else{
animate = false;
aniframe = 0;
}
},10)
Here is The spritesheet
, And a Gif of the animation
You can test the game here
As #HanYolo suggested, set var maxframes = 8; :
var aniframe = 0;
var maxframes = 8;
var animate = false;
window.aniimg = document.getElementById("aniimg1")
var timer = null;
var aniTimer = null;
var levelnum = 0;
var img = document.getElementById("img")
var img2 = document.getElementById("img2")
var c = document.getElementById("c");
var ctx = c.getContext('2d')
var props = document.getElementById("props");
var prps = c.getContext('2d')
var tilesize = 32;
var tiles = 10;
player = {
size: 10,
x: 150,
y: 150,
v: 2,
}
controller = {
up: false,
right: false,
left: false,
down: false,
keyParse: function(key) {
switch (key) {
//keydowns
case 38:
this.up = true;
break;
case 37:
this.left = true;
break;
case 39:
this.right = true;
break;
case 40:
this.down = true;
break;
}
},
keyStop: function(key) {
switch (key) {
//keydowns
case 38:
this.up = false;
break;
case 37:
this.left = false;
break;
case 39:
this.right = false;
break;
case 40:
this.down = false;
break;
}
}
}
function drawlvl() {
for (y = 0; y < lvl[levelnum].length; y++) {
for (x = 0; x < lvl[levelnum][y].length; x++) {
switch (lvl[levelnum][y][x]) {
case 0:
//nw grass
var imgvar = img
var sx = 32;
var sy = 192;
break;
case 1:
//w dirt
var imgvar = img
var sx = 224;
var sy = 160;
break;
case 2:
//nw top dirt
var imgvar = img
var sx = 128;
var sy = 96;
break;
case 3:
//nw bottom dirt
var imgvar = img2
var sx = 95;
var sy = 320;
break;
case 4:
//lvl up dirt
var imgvar = img
var sx = 224;
var sy = 160;
break;
case 5:
//lvl down dirt
var imgvar = img
var sx = 224;
var sy = 160;
break;
case 6:
//w water
var imgvar = img
var sx = 0;
var sy = 416;
break;
case 7:
//w water side left
var imgvar = img
var sx = 0;
var sy = 288;
break;
case 8:
//w water side right
var imgvar = img2
var sx = 223;
var sy = 128;
break;
}
ctx.drawImage(imgvar, sx, sy, 32, 32, x * tilesize, y * tilesize, tilesize, tilesize)
}
}
}
walkable_blocks = [1, 6, 7, 8]
walkable_props = [0, 8, 9, 10, 11, 12]
lvlup_blocks = [4]
lvldown_blocks = [5]
function gameLoop() {
if (controller.up == true) {
player.newY = player.y - player.v
} else if (controller.left == true) {
player.newX = player.x - player.v
} else if (controller.right == true) {
player.newX = player.x + player.v
} else if (controller.down == true) {
player.newY = player.y + player.v
} else {
player.newY = player.y;
player.newX = player.x;
}
function playerani() {
if (animate == true) {
if (aniframe == maxframes) {
aniframe = 1
} else {
aniframe += 1;
}
}
if (window.aniimgY == null) {
window.aniimgY = 640;
}
if (controller.left == true) {
animate = true;
window.aniimgY = 576;
} else if (controller.up == true) {
animate = true;
window.aniimgY = 512;
} else if (controller.down == true) {
animate = true;
window.aniimgY = 640;
} else if (controller.right == true) {
animate = true;
window.aniimgY = 704;
} else {
animate = false;
aniframe = 0;
}
}
player.col = Math.floor((player.newX + 5) / tilesize)
player.row = Math.floor((player.newY + 5) / tilesize)
tileval = lvl[levelnum][player.row][player.col]
propval = propsArr[levelnum][player.row][player.col]
ctx.fillStyle = "black"
if (walkable_blocks.includes(tileval) && walkable_props.includes(propval)) {
player.y = player.newY;
player.x = player.newX;
if (player.x <= 0) {
player.x = 0
}
if (player.y <= 0) {
player.y = 0
}
if (player.x + player.size >= c.width) {
player.x = c.width - player.size;
}
if (player.y + player.size >= c.height) {
player.y = c.height - player.size;
}
} else if (lvlup_blocks.includes(tileval)) {
document.getElementById("body").style.ainmation = "fadeInAnimation";
document.getElementById('body').style.animationPlayState = "running";
if (timer == null) {
timer = setTimeout(function() {
levelnum++;
player.x = 280;
player.y = 150;
timer = null;
}, 2500)
if (aniTimer == null) {
aniTimer = setTimeout(function() {
document.getElementById("body").style.animationPlayState = "paused";
clearTimeout(aniTimer)
aniTimer = null;
}, 5000)
}
} else {
}
} else if (lvldown_blocks.includes(tileval)) {
document.getElementById("body").style.ainmation = "fadeInAnimation";
document.getElementById('body').style.animationPlayState = "running";
if (timer == null) {
timer = setTimeout(function() {
levelnum--;
player.x = 33;
player.y = 150;
timer = null;
}, 2500)
}
if (aniTimer == null) {
aniTimer = setTimeout(function() {
document.getElementById("body").style.animationPlayState = "paused";
clearTimeout(aniTimer);
aniTimer = null;
}, 5000)
}
} else {
player.y = player.y;
player.x = player.x;
if (player.x <= 0) {
player.x = 0
}
if (player.y <= 0) {
player.y = 0
}
if (player.x + player.size >= c.width) {
player.x = c.width - player.size;
}
if (player.y + player.size >= c.height) {
player.y = c.height - player.size;
}
}
ctx.fillRect(0, 0, c.width, c.height)
drawlvl()
drawprops()
drawEnemy()
playerani()
ctx.drawImage(window.aniimg, 64 * (Math.floor(aniframe)), window.aniimgY, 64, 64, player.x - 16, player.y - 16, 48, 48)
}
var gameintertval = setInterval(function() {
gameLoop()
}, 10)
document.addEventListener('keydown', function(event) {
controller.keyParse(event.keyCode)
})
document.addEventListener('keyup', function(event) {
controller.keyStop(event.keyCode)
})
body {
zoom: 100%;
animation: fadeInAnimation ease 5s;
animation-play-state: paused;
animation-iteration-count: infinite;
}
#keyframes fadeInAnimation {
0% {
opacity: 1;
}
50% {
opacity: 0;
}
100% {
opacity: 1;
}
}
canvas{
position: absolute;
}
#props{
z-index: 1000;
}
#c{
z-index: -1000;
}
<html>
<head>
<title>TileGame</title>
<base href="http://ryangrube.com/projects/tilegame/">
</head>
<body id="body">
<img id="img" style="display: none;" src="TileSet_V1.png">
<img id="img2" style="display: none;" src="TileSet_V2.png">
<img id="img3" style="display: none;" src="TileSet_V3.png">
<img id="aniimg1" style="display: none;" src="no_dagger.png">
<img id="aniimg2" style="display: none;" src="dagger.png">
<canvas id="c" width="320" height="320" style="background-color: black;border:3px solid black;"></canvas>
<canvas id="props" width="320" height="320" style="border:3px solid black;"></canvas>
<script src="map.js"></script>
<script src="props.js"></script>
<script src="drawprops.js"></script>
<script src="enemy.js"></script>
<script src="drawenemy.js"></script>
</body>
</html>
I'm writing simple "snake" game and I'm facing this issue:
every tame my snake hits the red circle (apple) , apple should be moved to a new location on the canvas. Right now new apple appears, but the old one does not disappear ( it should) , and also when there are more than 2 apples on the canvas they create a filled figure... it looks like this: ibb.co/nrYdLQ (also shouldn't happen).
The code responsible for moving an apple is this:
if (!this.objectCollide(myApple)) {
this.segments.pop();
} else {
myApple = new block(Math.floor(Math.random() * gameField.width),Math.floor(Math.random() * gameField.height))
};
and I have no idea why It's working like I described above, instead just moving an apple to a new location and removing old one.
Please help.
JSFiddle: https://jsfiddle.net/e1ga0fpm/
full JavaScript code:
var gameField = document.getElementById('gameField');
var ctx = gameField.getContext("2d");
var blockSize = 10;
columnCt = gameField.width / blockSize;
rowsCt = gameField.height / blockSize;
var block = function(x, y) {
this.x = x;
this.y = y;
}
block.prototype.drawBlock = function() {
ctx.fillStyle = "blue";
ctx.fillRect(this.x * blockSize, this.y * blockSize, blockSize,
blockSize);
};
block.prototype.drawApple = function() {
ctx.fillStyle = "red";
ctx.textBaseline = "bottom";
ctx.arc(this.x, this.y, 6, 2 * Math.PI, false);
ctx.fill();
}
var Snake = function() {
this.segments = [new block(20, 20), new block(19, 20), new block(18, 20), new block(17, 20),
new block(16, 20), new block(15, 20), new block(14, 20), new block(13, 20), new block(12, 20),
new block(11, 20), new block(10, 20)
];
this.direction = "right";
}
Snake.prototype.drawSnake = function() {
for (i = 0; i < this.segments.length; i++) {
this.segments[i].drawBlock();
}
}
Snake.prototype.setDirection = function(dir) {
if (this.direction == "left" && dir == "right" || this.direction == "right" && dir == "left" || this.direction == "up" && dir == "down" ||
this.direction == "down" && dir == "up") {
return
} else {
this.direction = dir;
};
};
Snake.prototype.objectCollide = function(obj) {
if (this.segments[0].x == Math.round(obj.x / blockSize) && this.segments[0].y == Math.round(obj.y / blockSize)) {
return true
} else {
return false
}
};
Snake.prototype.move = function() {
var head = this.segments[0];
var newHead;
switch (this.direction) {
case "right":
newHead = new block(head.x + 1, head.y);
break;
case "left":
newHead = new block(head.x - 1, head.y)
break;
case "down":
newHead = new block(head.x, head.y + 1)
break;
case "up":
newHead = new block(head.x, head.y - 1)
break;
}
this.segments.unshift(newHead);
if (!this.objectCollide(myApple)) {
this.segments.pop();
} else {
myApple = new block(Math.floor(Math.random() * gameField.width),Math.floor(Math.random() * gameField.height))
};
var collision = newHead.x >= columnCt || newHead.x <= -1 ||
newHead.y >= rowsCt || newHead.y <= -1;
for (i = 1; i < this.segments.length; i++) {
if (this.segments[i].x == newHead.x && this.segments[i].y == newHead.y) {
collision = true;
break;
};
};
if (collision) {
clearInterval(myFun);
};
};
var mySnake = new Snake()
mySnake.drawSnake();
var myApple = new block(Math.floor(Math.random() * gameField.width),
Math.floor(Math.random() * gameField.height));
var myFun = setInterval(function() {
ctx.clearRect(0, 0, gameField.width, gameField.height);
mySnake.move();
mySnake.drawSnake();
myApple.drawApple();
}, 100)
var directions = {
37: "left",
38: "up",
39: "right",
40: "down"
};
document.onkeydown = function(event) {
var newDirection = directions[event.keyCode]
if (newDirection != undefined) {
mySnake.setDirection(newDirection);
};
Im quite unshure why the apple is not "eaten" however, i might know why it looks so weird:
If you draw to a canvas it looks like a pen. So whenever you draw a new apple, the pen moves to that position, and draws a line. After a few apples, if you call .fill(), this (yet invisible) line, gets filled. So you need to move the pen before you draw:
block.prototype.drawApple = function() {
ctx.fillStyle = "red";
ctx.textBaseline = "bottom";
ctx.moveTo(this.x,this.y);
ctx.arc(this.x, this.y, 6, 2 * Math.PI, false);
ctx.fill();
}
You forgot to beginpath while you draw apple. Also when apple eaten, you have to add new block to snake. Check edited code below.
Here is updated fiddle
block.prototype.drawApple = function() {
ctx.fillStyle = "red";
ctx.textBaseline = "bottom";
ctx.beginPath();
ctx.arc(this.x, this.y, 6, 2 * Math.PI, false);
ctx.fill();
}
var gameField = document.getElementById('gameField');
var ctx = gameField.getContext("2d");
var blockSize = 10;
columnCt = gameField.width / blockSize;
rowsCt = gameField.height / blockSize;
var block = function(x, y) {
this.x = x;
this.y = y;
}
block.prototype.drawBlock = function() {
ctx.fillStyle = "blue";
ctx.fillRect(this.x * blockSize, this.y * blockSize, blockSize,
blockSize);
};
block.prototype.drawApple = function() {
ctx.fillStyle = "red";
ctx.textBaseline = "bottom";
ctx.beginPath();
ctx.arc(this.x, this.y, 6, 2 * Math.PI, false);
ctx.fill();
}
var Snake = function() {
this.segments = [new block(20, 20), new block(19, 20), new block(18, 20), new block(17, 20),
new block(16, 20), new block(15, 20)
];
this.direction = "right";
}
Snake.prototype.drawSnake = function() {
for (i = 0; i < this.segments.length; i++) {
this.segments[i].drawBlock();
}
}
Snake.prototype.setDirection = function(dir) {
if (this.direction == "left" && dir == "right" || this.direction == "right" && dir == "left" || this.direction == "up" && dir == "down" ||
this.direction == "down" && dir == "up") {
return
} else {
this.direction = dir;
};
};
Snake.prototype.objectCollide = function(obj) {
if (this.segments[0].x == Math.round(obj.x / blockSize) && this.segments[0].y == Math.round(obj.y / blockSize)) {
return true
} else {
return false
}
};
Snake.prototype.move = function() {
var head = this.segments[0];
var newHead;
switch (this.direction) {
case "right":
newHead = new block(head.x + 1, head.y);
break;
case "left":
newHead = new block(head.x - 1, head.y)
break;
case "down":
newHead = new block(head.x, head.y + 1)
break;
case "up":
newHead = new block(head.x, head.y - 1)
break;
}
this.segments.unshift(newHead);
if (!this.objectCollide(myApple)) {
this.segments.pop();
} else {
myApple = new block(Math.floor(Math.random() * gameField.width), Math.floor(Math.random() * gameField.height));
this.segments.push(new block(this.segments[0][0], 20))
};
var collision = newHead.x >= columnCt || newHead.x <= -1 ||
newHead.y >= rowsCt || newHead.y <= -1;
for (i = 1; i < this.segments.length; i++) {
if (this.segments[i].x == newHead.x && this.segments[i].y == newHead.y) {
collision = true;
break;
};
};
if (collision) {
clearInterval(myFun);
};
};
var mySnake = new Snake()
mySnake.drawSnake();
var myApple = new block(Math.floor(Math.random() * gameField.width),
Math.floor(Math.random() * gameField.height));
var myFun = setInterval(function() {
ctx.clearRect(0, 0, gameField.width, gameField.height);
mySnake.move();
mySnake.drawSnake();
myApple.drawApple();
}, 100)
var directions = {
37: "left",
38: "up",
39: "right",
40: "down"
};
document.onkeydown = function(event) {
var newDirection = directions[event.keyCode]
if (newDirection != undefined) {
mySnake.setDirection(newDirection);
};
};
canvas {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
border: 5px solid grey;
}
<canvas id="gameField" height="500" width="500">
</canvas>
OK, so I'm new to JS, so am trying to make the basic 'breakout' game. What I'm trying to do is arrange the bricks into a triangle shape (or more accurately, forming a triangle out of the absence of bricks). But when I choose which items in the 2D array I want to equal 0 (no brick), it only allows me choose one. after that, the game simply won't load.
Weirdest thing is, it will only accept the first line in this part. No matter what I change, the second line onwards will cause the game to not load:
bricks[0][10]=0;
bricks[7][16]=0;
bricks[7][15]=0;
bricks[7][14]=0;
bricks[7][13]=0;
bricks[7][12]=0;
bricks[7][11]=0;
bricks[7][10]=0;
bricks[7][9]=0;
bricks[7][8]=0;
bricks[7][7]=0;
bricks[7][6]=0;
bricks[7][5]=0;
bricks[7][4]=0;
bricks[7][3]=0;
bricks[7][17]=0;
bricks[6][4]=0;
bricks[6][16]=0;
bricks[5][15]=0;
bricks[5][5]=0;
bricks[4][14]=0;
bricks[4][6]=0;
bricks[3][13]=0;
bricks[3][7]=0;
bricks[2][8]=0;
bricks[2][12]=0;
bricks[1][11]=0;
bricks[1][9]=0;
Also, i know the code is incomplete and flawed as it is. It's not finished and still need a lot of polishing up.
Here's my entire code
canvasApp();
function canvasApp(){
var canvas=document.getElementById("canvas")
if (!canvas || !canvas.getContext){
return;
}
var ctx = canvas.getContext("2d");
if (!ctx) {
return
}
//Application States
const GAME_STATE_TITLE = 0;
const GAME_STATE_NEW_LEVEL = 1;
const GAME_STATE_GAME_OVER = 2;
var currentGameState = 0;
var currentGameStateFunction = null;
var brickcount;
var bouncecount = 0;
//Initialise Start Screen State
var titleStarted = false;
var gameStarted = false;
var gameOver = false;
var keyPressList = [];
var keys = false //mouse or keys. false = mouse control, vice versa
var difficulty = 0;
// Declarations for the game
var dx = 6;
var dy = 6;
var x = 150;
var y = 100;
var r = 10;
var WIDTH = 500;
var HEIGHT = 400;
var ballx = 200;
var bally = 200;
var paddlex = WIDTH/1.2;
var paddleh = 10;
var paddlew = 75;
var paddledx = 30
var mouseX;
var bricks;
var NROWS;
var NCOLS;
var BRICKWIDTH;
var BRICKHEIGHT;
var PADDING;
var rowcolours = ["#FF1C0A", "#FFFD0A", "#00A308", "#0008DB", "#EB0093"];
var paddlecolour = "#FF00FF";
var ballcolour = "#00FFFF";
var backcolour = "#0000FF";
function initbricks() {
NROWS = 9
NCOLS = 21
brickcount = NROWS*NCOLS;
BRICKWIDTH = (WIDTH/NCOLS) - 1;
BRICKHEIGHT = 10;
PADDING = 1;
bricks = new Array(NROWS);
for (i=0; i < NROWS; i++) {
bricks[i] = new Array(NCOLS);
for (j=0; j < NCOLS; j++) {
bricks[i][j] = 1;
}
bricks[0][10]=0;
bricks[7][16]=0;
bricks[7][15]=0;
bricks[7][14]=0;
bricks[7][13]=0;
bricks[7][12]=0;
bricks[7][11]=0;
bricks[7][10]=0;
bricks[7][9]=0;
bricks[7][8]=0;
bricks[7][7]=0;
bricks[7][6]=0;
bricks[7][5]=0;
bricks[7][4]=0;
bricks[7][3]=0;
bricks[7][17]=0;
bricks[6][4]=0;
bricks[6][16]=0;
bricks[5][15]=0;
bricks[5][5]=0;
bricks[4][14]=0;
bricks[4][6]=0;
bricks[3][13]=0;
bricks[3][7]=0;
bricks[2][8]=0;
bricks[2][12]=0;
bricks[1][11]=0;
bricks[1][9]=0;
}
}
initbricks();
function switchGameState(newState) {
currentGameState = newState;
switch (currentGameState) {
case GAME_STATE_TITLE:
currentGameStateFunction = gameStateTitle;
break;
case GAME_STATE_NEW_LEVEL:
currentGameStateFunction = gameStatePlayLevel;
break;
case GAME_STATE_GAME_OVER:
currentGameStateFunction = gameStateGameOver;
break;
}
}
function gameStateTitle(){
if (titleStarted != true){
ctx.fillStyle = '#000000';
ctx.fillRect(0,0,500,400);
ctx.fillStyle = '#ffffff';
ctx.font = '20px _sans';
ctx.textBaseline = 'top';
ctx.fillText ("Breakout!", 200,150);
ctx.fillText ("Press Space to Play", 170,200);
if (keys == 0 ) {
ctx.fillText ("Mouse selected", 180,250);
ctx.fillText ("Press k to switch to keys", 140,300);
} else {
ctx.fillText ("Keys selected", 190,250);
ctx.fillText ("Press m to switch to mouse", 140,300);
}
titleStarted = true;
}else{
if (keyPressList[75] == true){
keys = 1;
titleStarted = false;
gameStateTitle(); // Redraw the title page
}
if (keyPressList[77] == true){
keys = 0;
titleStarted = false;
gameStateTitle();
}
if (keyPressList[32] == true){
switchGameState(GAME_STATE_NEW_LEVEL);
titleStarted = false;
}
}
}
function gameStatePlayLevel(){
ctx.fillStyle = '#000000';
ctx.fillRect(0,0,500,400);
ctx.fillStyle = '#ffffff';
// Update the game state and check for game over
function update() {
x+=dx
y+=dy
if (keys == 0) {
paddlex = mouseX;
}else{
if (keyPressList[37]==true){
paddlex-=paddledx;
}
if (keyPressList[39]==true){
paddlex+=paddledx;
}
}
//have we hit a brick?
rowheight = BRICKHEIGHT + PADDING;
colwidth = BRICKWIDTH + PADDING;
row = Math.floor(y/rowheight);
col = Math.floor(x/colwidth);
//if so, reverse the ball and mark the brick as broken
if (y < NROWS * rowheight && row >= 0 && col >= 0 && bricks[row][col] == 1) {
dy = -dy;
bricks[row][col] = 0;
brickcount--;
if (brickcount == 0) {
switchGameState(GAME_STATE_NEW_LEVEL);
difficulty+=1;
initbricks();
x=250;
y=200 + (difficulty*20);
brickcount=NROWS*NCOLS;
bouncecount=0;
}
}
if( x<0 || x>WIDTH) dx=-dx;
if( y<0 || y>HEIGHT) dy=-dy;
else if (y + dy > HEIGHT) {
if (x > paddlex && x < paddlex + paddlew) {
dx = 8 * ((x-(paddlex+paddlew/2))/paddlew);
dy = -dy;
bouncecount++;
}
else {
//game over, so stop the animation
switchGameState(GAME_STATE_GAME_OVER);
initbricks();
}
}
}
function render() {
ctx.save();
function circle(x,y,r) {
ctx.beginPath();
ctx.arc(x, y, r, 0, Math.PI*2, true);
ctx.fill();
}
function rect(x,y,w,h) {
ctx.beginPath();
ctx.rect(x,y,w,h);
ctx.closePath();
ctx.fill();
ctx.stroke();
}
//draw bricks
for (i=0; i < NROWS; i++) {
ctx.fillStyle = rowcolours [i];
for (j=0; j < NCOLS; j++) {
if (bricks[i][j] == 1) {
rect((j * (BRICKWIDTH + PADDING)) + PADDING,
(i * (BRICKHEIGHT + PADDING)) + PADDING, BRICKWIDTH, BRICKHEIGHT);
}
}
}
circle(x, y, 10);
// init_paddle();
ctx.fillStyle = paddlecolour;
rect (paddlex, HEIGHT-paddleh, paddlew, paddleh);
ctx.restore();
show_result()
}
update();
render();
}
function gameStateGameOver(){
if (gameOver != true){
bouncecount=0;
ctx.fillStyle = '#000000';
ctx.fillRect(0,0,500,400);
ctx.fillStyle = '#ffffff';
ctx.font = '20px _sans';
ctx.textBaseline = 'top';
ctx.fillText ("Game over", 200,150);
ctx.fillText ("Press Space to Restart", 160,200);
ctx.fillText ("You completed " + difficulty + " levels", 160,240);
difficulty=0;
gameOver = true;
}else{
if (keyPressList[32] == true){
switchGameState(GAME_STATE_TITLE);
gameOver = false;
}
}
}
function runGame(){
currentGameStateFunction();
}
// Key handler
document.onkeydown = function(e){
e= e?e:window.event;
keyPressList[e.keyCode] = true;
}
document.onkeyup = function(e){
e= e?e:window.event;
keyPressList[e.keyCode] = false;
}
function onMouseMove(evt) {
// Event data passes to this function
mouseX = evt.clientX-canvas.offsetLeft - paddlew/2;
// Assign the relative position of the mouse in the canvas to mouseX
mouseY = evt.clientY-canvas.offsetTop;
//Do the same for mouseY
document.title="("+mouseX+","+mouseY+")";
//Put the mouse X and Y in the title for info
paddlex = mouseX;
// Position the paddle
}
canvas.addEventListener("mousemove",onMouseMove, false);
//Application start
switchGameState(GAME_STATE_TITLE);
const FRAME_RATE = 40;
var intervalTime = 1000/FRAME_RATE;
setInterval(runGame, intervalTime);
function show_result(){
ctx.fillText ("There are " + brickcount + " bricks", 160,200);
ctx.fillText ("Paddle bounces are " + bouncecount , 160,220);
}
}
With proper indenting, your code looks like this:
bricks = new Array(NROWS);
for (i=0; i < NROWS; i++) {
bricks[i] = new Array(NCOLS);
for (j=0; j < NCOLS; j++) {
bricks[i][j] = 1;
}
bricks[0][10]=0;
bricks[7][16]=0;
In other words, you're attempting to access bricks[7] in the very first iteration when only bricks[0] has been created. Properly close the first for loop with a } before running your list of overrides.
I have been reading/searching for an answer to detect collisions of sprites in two arrays. I am not understanding how to pass two arrays into the detection function and have it check all contents of each array against each other. Any input would be greatly appreciated.
<script type="text/javascript">
var FIRE = 0;
var NORTH = 38;
var SOUTH = 40;
var EAST = 39;
var WEST = 37;
var destX = 350;
var destY = 500;
var canvas = null;
var context = null;
var sprites = null;
var player = null;
var island = null;
var enemies = [];
var fires = [];
var gameLoopInterval = null;
var offScreenFire = null;
var isShooting = false;
var intersect = null;
var Fire = function() {
this.spriteX = 278;
this.spriteY = 110;
this.spriteWidth = 13;
this.spriteHeight = 16;
this.destX = player.destX + 25;
this.destY = player.destY;
this.speed = 5;
}
var Player = function(name) {
this.name = name;
this.spriteX = 5;
this.spriteY = 400;
this.spriteWidth = 64;
this.spriteHeight = 64;
this.destX = 350;
this.destY = 500;
this.speed = 5;
this.level = 1;
}
var Enemy = function() {
this.spriteX = 4;
this.spriteY = 4;
this.spriteWidth = 32;
this.spriteHeight = 32;
this.destX = Math.ceil(Math.random() * (800 - this.spriteWidth));
this.destY = this.spriteWidth;
this.speed = Math.ceil(Math.random() * 5);
}
var Island = function() {
this.spriteX = 168;
this.spriteY = 500;
this.spriteWidth = 64;
this.spriteHeight = 64;
this.destX = Math.ceil(Math.random() * (800 - this.spriteWidth));
this.destY = this.spriteWidth - 64;
this.speed = 2;
}
Fire.prototype.takeTurn = function() {
var intersect;
var projdestX = this.destX;
var projdestY = this.destY;
var projspriteWidth = this.spriteWidth;
var projspriteHeight = this.spriteHeight;
for (enemy in enemies) {
intersect = intersect || intersects(enemy.destX, enemy.destY, enemy.spriteWidth, enemy.spriteHeight, projdestX, projdestY, projspriteWidth, projspriteHeight);
}
if(intersect == true) { alert("colliding"); }
else{drawImage(this);}
// if (intersect != true){
// drawImage(this);
// }
// else {
// alert("boom");
// }
if(this.destY <= 0){
offScreenFire = fires.indexOf(this);
fires.splice(offScreenFire, 1);
}
else
this.destY -= this.speed;
}
Player.prototype.takeTurn = function() {
drawImage(this);
}
Enemy.prototype.takeTurn = function() {
drawImage(this);
if (this.destY < canvas.height)
this.destY += this.speed;
else
this.destY = -32;
}
Island.prototype.takeTurn = function() {
drawImage(this);
this.destY += this.speed;
}
function fireAction() {
var fire = new Fire();
drawImage(fire);
fires.push(fire);
}
function drawImage(sprite) {
context.drawImage(sprites, sprite.spriteX, sprite.spriteY, sprite.spriteWidth, sprite.spriteHeight, sprite.destX, sprite.destY, sprite.spriteWidth, sprite.spriteHeight );
}
function gameLoop () {
context.clearRect(0, 0, canvas.width, canvas.height);
island.takeTurn();
player.takeTurn();
//console.log(fires); //debug
for (fire in fires) {
fires[fire].takeTurn();
}
for (enemy in enemies) {
enemies[enemy].takeTurn();
}
}
function intersects(x1, y1, w1, h1, x2, y2, w2, h2) {
if (w2 !== Infinity && w1 !== Infinity) {
w2 += x2;
w1 += x1;
if (isNaN(w1) || isNaN(w2) || x2 > w1 || x1 > w2)
return false;
}
if (y2 !== Infinity && h1 !== Infinity) {
h2 += y2;
h1 += y1;
if (isNaN(h1) || isNaN(y2) || y2 > h1 || y1 > h2)
return false;
}
return true;
}
window.onload = function() {
//alert('here');
canvas = document.getElementById('gameWorld');
context = canvas.getContext("2d");
sprites = new Image();
player = new Player('Brad');
island = new Island();
sprites.onload = function() {
drawImage(player);
for (i = 0; i < 3; i++) {
var enemy = new Enemy();
drawImage(enemy);
enemies.push(enemy);
}
}
sprites.src = "Sprites/1945.png";
gameLoopInterval = setInterval('gameLoop()', 100)
}
window.onkeypress = function(e){
var evt = window.event ? event : e;
//alert(evt.keyCode);
switch(evt.keyCode) {
case NORTH:
if (player.destY > 0)
player.destY -= player.speed;
else
player.destY == player.destY;
break;
case SOUTH:
if (player.destY < canvas.height - player.spriteWidth)
player.destY += player.speed;
else
player.destY == player.destY;
break;
case EAST:
if (player.destX < canvas.width - player.spriteWidth)
player.destX += player.speed;
else
player.destX == player.destY;
break;
case WEST:
if (player.destX > 0)
player.destX -= player.speed;
else
player.destX == player.destX;
break;
case FIRE:
fireAction();
break;
}
}
</script>
Your problems seems to be in:
for (enemy in enemies) {
intersect = intersects(enemy.destX, enemy.destY, enemy.spriteWidth, enemy.spriteHeight, projdestX, projdestY, projspriteWidth, projspriteHeight);
}
intersect will always have the last value saved. (Meaning you are really only checking if it intersects with the last enemy.)
A quick solution would be to change the inner line to:
intersect = intersect || intersects(enemy.destX, enemy.destY, enemy.spriteWidth, enemy.spriteHeight, projdestX, projdestY, projspriteWidth, projspriteHeight);
This will make intersect stay as true if the fire doesn't intersect with the next enemy.
Edit:
Your second problem is in the same for(). In javascript, when you do a for in, the first variable does not have a reference to the instance, but rather is only the key.
Your final for should look like:
for (enemy in enemies) {
intersect = intersect || intersects(enemies[enemy].destX, enemies[enemy].destY, enemies[enemy].spriteWidth, enemies[enemy].spriteHeight, projdestX, projdestY, projspriteWidth, projspriteHeight);
}
You also seem to not be spawning any enemies. In my fiddle of your code (http://jsfiddle.net/path411/umjnQ/) I added the following snippet into your gameLoop():
if(enemies.length < 1) {
enemies.push(new Enemy());
}
This simply creates a new enemy if you don't already have one. (You will probably want to change later).