I'm trying to get my head around using javascript in the html < canvas >, and I started with the MDN Breakout game tutorial. Here is how the complete game looks like. I'm stuck with one of the exercises and I really could not find any solution to my issue after an hour of googling!! :((. The following code generates a ball on the canvas.
ctx.beginPath();
ctx.arc(x, y, radius, 0, Math.PI * 2);
ctx.fillStyle = '#FFFFF';
ctx.fill();
ctx.closePath();
I needed the ball to change its colour after it collides with one of the bricks. In order to achieve that, I created a variable to store the colour value: let colour = '#FFFFF';, and later in a function which detects collisions, changed the value of this variable. It worked fine, however, whenever the ball changed its colour, so did the bricks and the paddle. As I tried to fix this, I found out that whenever I manually change the colour of either a ball, a brick or a paddle (all of which are set in different functions), all of the objects change the colour as well.
This is very strange, because if in an emply .js file I make just two shapes and colour them differently it works fine:
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.rect(0, 0, 20, 40);
ctx.fillStyle = 'cyan';
ctx.fill();
ctx.closePath();
ctx.beginPath();
ctx.arc(50, 50, 20, 0, Math.PI*2);
ctx.fillStyle = 'black';
ctx.fill();
ctx.closePath();
But with all the game code I have right now, I can not assign different colour to different objects, they all change colour instead! I have no idea how to fix this and change just the colour of the ball! Anyone knows what might be causing the issue? Please help, thank you so much in advance 🙏
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
//Ball variables
const radius = 10;
let colour = '#FFFFF';
let x = canvas.width / 2;
let y = canvas.height - 30;
let dx = 2;
let dy = -2;
//Paddle
const paddleHeight = 10;
let paddleWidth = 100;
let paddleX = (canvas.width - paddleWidth) / 2;
//Paddle movement
var rightPressed = false;
var leftPressed = false;
//Bricks
var brickRowCount = 3;
var brickColumnCount = 5;
var brickWidth = 75;
var brickHeight = 20;
var brickPadding = 10;
var brickOffsetTop = 30;
var brickOffsetLeft = 30;
var bricks = [];
for (var c = 0; c < brickColumnCount; c++) {
bricks[c] = [];
for (var r = 0; r < brickRowCount; r++) {
bricks[c][r] = {
x: 0,
y: 0,
status: 1
};;
}
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawBall();
drawPaddle();
drawBricks();
collisionDetection();
x += dx;
y += dy;
if (rightPressed && paddleX < canvas.width - paddleWidth) {
paddleX += 7;
} else if (leftPressed && paddleX > 0) {
paddleX -= 7;
}
}
function drawBall() {
ctx.beginPath();
ctx.arc(x, y, radius, 0, Math.PI * 2);
ctx.fillStyle = colour;
ctx.fill();
ctx.closePath();
//Bounce off the walls
if (x + dx > canvas.width - radius || x + dx < radius) {
dx = -dx;
}
if (y + dy < radius) {
dy = -dy;
} else if (y + dy > canvas.height - radius) {
//Collision detection (ball + paddle)
if (x > paddleX && x < paddleX + paddleWidth) {
dy = -dy;
} else {
//alert("GAME OVER");
document.location.reload();
}
}
}
function drawPaddle() {
ctx.beginPath();
ctx.rect(paddleX, canvas.height - paddleHeight, paddleWidth, paddleHeight);
ctx.fillStyle = '#FFFFF';
ctx.fill();
ctx.closePath();
}
function drawBricks() {
for (var c = 0; c < brickColumnCount; c++) {
for (var r = 0; r < brickRowCount; r++) {
if (bricks[c][r].status == 1) {
var brickX = (c * (brickWidth + brickPadding)) + brickOffsetLeft;
var brickY = (r * (brickHeight + brickPadding)) + brickOffsetTop;
bricks[c][r].x = brickX;
bricks[c][r].y = brickY;
ctx.beginPath();
ctx.rect(brickX, brickY, brickWidth, brickHeight);
ctx.fillStyle = "#FFFFF";
ctx.fill();
ctx.closePath();
}
}
}
}
document.addEventListener("keydown", keyDownHandler, false);
document.addEventListener("keyup", keyUpHandler, false);
function keyDownHandler(e) {
if (e.key == "Right" || e.key == "ArrowRight") {
rightPressed = true;
} else if (e.key == "Left" || e.key == "ArrowLeft") {
leftPressed = true;
}
}
function keyUpHandler(e) {
if (e.key == "Right" || e.key == "ArrowRight") {
rightPressed = false;
} else if (e.key == "Left" || e.key == "ArrowLeft") {
leftPressed = false;
}
}
function collisionDetection() {
for (var c = 0; c < brickColumnCount; c++) {
for (var r = 0; r < brickRowCount; r++) {
var b = bricks[c][r];
if (b.status == 1) {
if (x > b.x && x < b.x + brickWidth && y > b.y && y < b.y + brickHeight) {
dy = -dy;
b.status = 0;
colour = '#ff9ecb';
}
}
}
}
}
var interval = setInterval(draw, 10);
<!DOCTYPE html>
<html>
<head>
<title>Breakout Game</title>
</head>
<body>
<canvas id='canvas' height='320' width='480'></canvas>
<script src="app.js"></script>
</body>
</html>
Looks like a minor error with the colour hex codes you're using for your fillStyle, which are invalid. See the corrections in the snippet below from:
let colour = '#FFFFF'; // Six characters invalid
To:
let colour = '#FF0000'; // Seven characters valid
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
//Ball variables
const radius = 10;
// Fix colour
let colour = '#FF0000';
let x = canvas.width / 2;
let y = canvas.height - 30;
let dx = 2;
let dy = -2;
//Paddle
const paddleHeight = 10;
let paddleWidth = 100;
let paddleX = (canvas.width - paddleWidth) / 2;
//Paddle movement
var rightPressed = false;
var leftPressed = false;
//Bricks
var brickRowCount = 3;
var brickColumnCount = 5;
var brickWidth = 75;
var brickHeight = 20;
var brickPadding = 10;
var brickOffsetTop = 30;
var brickOffsetLeft = 30;
var bricks = [];
for (var c = 0; c < brickColumnCount; c++) {
bricks[c] = [];
for (var r = 0; r < brickRowCount; r++) {
bricks[c][r] = {
x: 0,
y: 0,
status: 1
};;
}
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawBall();
drawPaddle();
drawBricks();
collisionDetection();
x += dx;
y += dy;
if (rightPressed && paddleX < canvas.width - paddleWidth) {
paddleX += 7;
} else if (leftPressed && paddleX > 0) {
paddleX -= 7;
}
}
function drawBall() {
// Update to valid colour
ctx.fillStyle = colour;
ctx.beginPath();
ctx.arc(x, y, radius, 0, Math.PI * 2);
ctx.fill();
ctx.closePath();
//Bounce off the walls
if (x + dx > canvas.width - radius || x + dx < radius) {
dx = -dx;
}
if (y + dy < radius) {
dy = -dy;
} else if (y + dy > canvas.height - radius) {
//Collision detection (ball + paddle)
if (x > paddleX && x < paddleX + paddleWidth) {
dy = -dy;
} else {
//alert("GAME OVER");
document.location.reload();
}
}
}
function drawPaddle() {
// Update to valid colour
ctx.fillStyle = '#00FF00';
// Consider using fillRect
ctx.fillRect(paddleX, canvas.height - paddleHeight, paddleWidth, paddleHeight);
}
function drawBricks() {
for (var c = 0; c < brickColumnCount; c++) {
for (var r = 0; r < brickRowCount; r++) {
if (bricks[c][r].status == 1) {
var brickX = (c * (brickWidth + brickPadding)) + brickOffsetLeft;
var brickY = (r * (brickHeight + brickPadding)) + brickOffsetTop;
bricks[c][r].x = brickX;
bricks[c][r].y = brickY;
// Update to valid colour
ctx.fillStyle = "#FFFFaa";
// Consider using fillRect
ctx.fillRect(brickX, brickY, brickWidth, brickHeight);
}
}
}
}
document.addEventListener("keydown", keyDownHandler, false);
document.addEventListener("keyup", keyUpHandler, false);
function keyDownHandler(e) {
if (e.key == "Right" || e.key == "ArrowRight") {
rightPressed = true;
} else if (e.key == "Left" || e.key == "ArrowLeft") {
leftPressed = true;
}
}
function keyUpHandler(e) {
if (e.key == "Right" || e.key == "ArrowRight") {
rightPressed = false;
} else if (e.key == "Left" || e.key == "ArrowLeft") {
leftPressed = false;
}
}
function collisionDetection() {
for (var c = 0; c < brickColumnCount; c++) {
for (var r = 0; r < brickRowCount; r++) {
var b = bricks[c][r];
if (b.status == 1) {
if (x > b.x && x < b.x + brickWidth && y > b.y && y < b.y + brickHeight) {
dy = -dy;
b.status = 0;
colour = '#ff9ecb';
}
}
}
}
}
var interval = setInterval(draw, 10);
<!DOCTYPE html>
<html>
<head>
<title>Breakout Game</title>
</head>
<body>
<canvas id='canvas' height='320' width='480'></canvas>
<script src="app.js"></script>
</body>
</html>
Also, consider using fillRect() as shown above, for a slightly simpler implementation. Hope that helps!
Related
I made a game of atari breakout of where i want the bricks to be multi coloured. I want it so that each individual brick has its own random colour that is randomly generated. I also dont want the other attributes such as the ball and the paddle to be targeted with this random colour change.
Here are the lines of code:
'use strict';
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var ballRadius = 20;
var x = canvas.width/2;
var y = canvas.height-30;
var dx = 3;
var dy = -3;
var paddleHeight = 10;
var paddleWidth = 175;
var paddleX = (canvas.width-paddleWidth)/2;
var rightPressed = false;
var leftPressed = false;
var brickRowCount = 11;
var brickColumnCount = 5;
var brickWidth = 73;
var brickHeight = 20;
var brickPadding = 10;
var brickOffsetTop = 30;
var brickOffsetLeft = 30;
var score = 0;
var lives = 3;
var bricks = [];
for(var c=0; c<brickColumnCount; c++) {
bricks[c] = [];
for(var r=0; r<brickRowCount; r++) {
bricks[c][r] = { x: 0, y: 0, status: 1 };
}
}
document.addEventListener("keydown", keyDownHandler, false);
document.addEventListener("keyup", keyUpHandler, false);
document.addEventListener("mousemove", mouseMoveHandler, false);
function keyDownHandler(e) {
if(e.key == "Right" || e.key == "ArrowRight") {
rightPressed = true;
}
else if(e.key == "Left" || e.key == "ArrowLeft") {
leftPressed = true;
}
}
function keyUpHandler(e) {
if(e.key == "Right" || e.key == "ArrowRight") {
rightPressed = false;
}
else if(e.key == "Left" || e.key == "ArrowLeft") {
leftPressed = false;
}
}
function mouseMoveHandler(e) {
var relativeX = e.clientX - canvas.offsetLeft;
if(relativeX > 0 && relativeX < canvas.width) {
paddleX = relativeX - paddleWidth/2;
}
}
function collisionDetection() {
for(var c=0; c<brickColumnCount; c++) {
for(var r=0; r<brickRowCount; r++) {
var b = bricks[c][r];
if(b.status == 1) {
if(x > b.x && x < b.x+brickWidth && y > b.y && y < b.y+brickHeight) {
dy = -dy;
b.status = 0;
score++;
if(score == brickRowCount*brickColumnCount) {
alert("YOU WIN, CONGRATS!");
document.location.reload();
}
}
}
}
}
}
function drawBall() {
ctx.beginPath();
ctx.arc(x, y, ballRadius, 0, Math.PI*2);
ctx.fill();
ctx.closePath();
}
function drawPaddle() {
ctx.beginPath();
ctx.rect(paddleX, canvas.height-paddleHeight, paddleWidth, paddleHeight);
ctx.fill();
ctx.closePath();
}
function drawBricks() {
for(var c=0; c<brickColumnCount; c++) {
for(var r=0; r<brickRowCount; r++) {
if(bricks[c][r].status == 1) {
var brickX = (r*(brickWidth+brickPadding))+brickOffsetLeft;
var brickY = (c * (brickHeight + brickPadding)) + brickOffsetTop;
bricks[c][r].x = brickX;
bricks[c][r].y = brickY;
ctx.beginPath();
ctx.rect(brickX, brickY, brickWidth, brickHeight);
ctx.fill();
ctx.closePath();
}
}
}
}
function drawScore() {
ctx.font = "16px Arial";
ctx.fillText("Score: "+score, 8, 20);
}
function drawLives() {
ctx.font = "16px Arial";
ctx.fillText("Lives: "+lives, canvas.width-65, 20);
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawBricks();
drawBall();
drawPaddle();
drawScore();
drawLives();
collisionDetection();
if(x + dx > canvas.width-ballRadius || x + dx < ballRadius) {
dx = -dx;
}
if(y + dy < ballRadius) {
dy = -dy;
}
else if(y + dy > canvas.height-ballRadius) {
if(x > paddleX && x < paddleX + paddleWidth) {
dy = -dy;
}
else {
lives--;
if(!lives) {
alert("GAME OVER");
document.location.reload();
}
else {
x = canvas.width/2;
y = canvas.height-30;
dx = 3;
dy = -3;
paddleX = (canvas.width-paddleWidth)/2;
}
}
}
if(rightPressed && paddleX < canvas.width-paddleWidth) {
paddleX += 7;
}
else if(leftPressed && paddleX > 0) {
paddleX -= 7;
}
x += dx;
y += dy;
requestAnimationFrame(draw);
}
function hardFunction(){
ballRadius = 8;
paddleWidth = 80;
lives = 1;
dx = 5;
dy = -5;
};
function mediumFunction(){
ballRadius = 15;
paddleWidth = 120;
lives = 2;
dx = 4;
dy = -4;
};
function easyFunction(){
ballRadius = 20;
paddleWidth = 175;
lives = 3;
dx = 3;
dy = -3;
};
draw();
console.log(ctx.fillStyle);
* {
padding: 0;
margin: 0;
}
canvas {
background: #eee;
display: block;
margin: 0 auto;
}
button {
border: none;
color: gray;
padding: 16px 32px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
margin: 4px 2px 0px 16.67%;
transition-duration: 0.4s;
cursor: pointer
}
.buttonHard:hover {
background-color: red;
color: black;
}
.buttonMedium:hover {
background-color: yellow;
color: black;
}
.buttonEasy:hover {
background-color: green;
color: black;
}
<canvas id="myCanvas" width="960" height="640"></canvas>
<button id="button" class="buttonHard" onclick="hardFunction();">Hard Mode</button>
<button id="button" class="buttonMedium" onclick="mediumFunction();">Medium Mode</button>
<button id="button" class="buttonEasy" onclick="easyFunction();">Easy Mode</button>
<script src="script.js"></script>
After the bricks are drawn reset the ctx.fillStyle back to black to not affect the paddle and ball color.
You can try it like this:
'use strict';
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var ballRadius = 20;
var x = canvas.width/2;
var y = canvas.height-30;
var dx = 3;
var dy = -3;
var paddleHeight = 10;
var paddleWidth = 175;
var paddleX = (canvas.width-paddleWidth)/2;
var rightPressed = false;
var leftPressed = false;
var brickRowCount = 11;
var brickColumnCount = 5;
var brickWidth = 73;
var brickHeight = 20;
var brickPadding = 10;
var brickOffsetTop = 30;
var brickOffsetLeft = 30;
var score = 0;
var lives = 3;
// colors picked from here: https://hightekk.com/tools/swatch
const colors = [
"#d1c4e9",
"#b39ddb",
"#9575cd",
"#7e57c2",
"#673ab7",
"#5e35b1",
"#512da8",
"#4527a0",
"#311b92",
"#b388ff",
"#7c4dff",
"#651fff",
"#6200ea",
];
function getRandomColor(){
return colors[Math.floor(Math.random() * colors.length)];
}
var bricks = [];
for(var c=0; c<brickColumnCount; c++) {
bricks[c] = [];
for(var r=0; r<brickRowCount; r++) {
bricks[c][r] = { x: 0, y: 0, status: 1, color: getRandomColor() };
}
}
document.addEventListener("keydown", keyDownHandler, false);
document.addEventListener("keyup", keyUpHandler, false);
document.addEventListener("mousemove", mouseMoveHandler, false);
function keyDownHandler(e) {
if(e.key == "Right" || e.key == "ArrowRight") {
rightPressed = true;
}
else if(e.key == "Left" || e.key == "ArrowLeft") {
leftPressed = true;
}
}
function keyUpHandler(e) {
if(e.key == "Right" || e.key == "ArrowRight") {
rightPressed = false;
}
else if(e.key == "Left" || e.key == "ArrowLeft") {
leftPressed = false;
}
}
function mouseMoveHandler(e) {
var relativeX = e.clientX - canvas.offsetLeft;
if(relativeX > 0 && relativeX < canvas.width) {
paddleX = relativeX - paddleWidth/2;
}
}
function collisionDetection() {
for(var c=0; c<brickColumnCount; c++) {
for(var r=0; r<brickRowCount; r++) {
var b = bricks[c][r];
if(b.status == 1) {
if(x > b.x && x < b.x+brickWidth && y > b.y && y < b.y+brickHeight) {
dy = -dy;
b.status = 0;
score++;
if(score == brickRowCount*brickColumnCount) {
alert("YOU WIN, CONGRATS!");
document.location.reload();
}
}
}
}
}
}
function drawBall() {
ctx.beginPath();
ctx.arc(x, y, ballRadius, 0, Math.PI*2);
ctx.fill();
ctx.closePath();
}
function drawPaddle() {
ctx.beginPath();
ctx.rect(paddleX, canvas.height-paddleHeight, paddleWidth, paddleHeight);
ctx.fill();
ctx.closePath();
}
function drawBricks() {
for(var c=0; c<brickColumnCount; c++) {
for(var r=0; r<brickRowCount; r++) {
if(bricks[c][r].status == 1) {
var brickX = (r*(brickWidth+brickPadding))+brickOffsetLeft;
var brickY = (c * (brickHeight + brickPadding)) + brickOffsetTop;
bricks[c][r].x = brickX;
bricks[c][r].y = brickY;
ctx.beginPath();
ctx.rect(brickX, brickY, brickWidth, brickHeight);
ctx.fillStyle = bricks[c][r].color;
ctx.fill();
ctx.closePath();
}
}
}
ctx.fillStyle = "#000000";
}
function drawScore() {
ctx.font = "16px Arial";
ctx.fillText("Score: "+score, 8, 20);
}
function drawLives() {
ctx.font = "16px Arial";
ctx.fillText("Lives: "+lives, canvas.width-65, 20);
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawBricks();
drawBall();
drawPaddle();
drawScore();
drawLives();
collisionDetection();
if(x + dx > canvas.width-ballRadius || x + dx < ballRadius) {
dx = -dx;
}
if(y + dy < ballRadius) {
dy = -dy;
}
else if(y + dy > canvas.height-ballRadius) {
if(x > paddleX && x < paddleX + paddleWidth) {
dy = -dy;
}
else {
lives--;
if(!lives) {
alert("GAME OVER");
document.location.reload();
}
else {
x = canvas.width/2;
y = canvas.height-30;
dx = 3;
dy = -3;
paddleX = (canvas.width-paddleWidth)/2;
}
}
}
if(rightPressed && paddleX < canvas.width-paddleWidth) {
paddleX += 7;
}
else if(leftPressed && paddleX > 0) {
paddleX -= 7;
}
x += dx;
y += dy;
requestAnimationFrame(draw);
}
function hardFunction(){
ballRadius = 8;
paddleWidth = 80;
lives = 1;
dx = 5;
dy = -5;
};
function mediumFunction(){
ballRadius = 15;
paddleWidth = 120;
lives = 2;
dx = 4;
dy = -4;
};
function easyFunction(){
ballRadius = 20;
paddleWidth = 175;
lives = 3;
dx = 3;
dy = -3;
};
draw();
console.log(ctx.fillStyle);
* {
padding: 0;
margin: 0;
}
canvas {
background: #eee;
display: block;
margin: 0 auto;
}
button {
border: none;
color: gray;
padding: 16px 32px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
margin: 4px 2px 0px 16.67%;
transition-duration: 0.4s;
cursor: pointer
}
.buttonHard:hover {
background-color: red;
color: black;
}
.buttonMedium:hover {
background-color: yellow;
color: black;
}
.buttonEasy:hover {
background-color: green;
color: black;
}
<canvas id="myCanvas" width="960" height="640"></canvas>
<button id="button" class="buttonHard" onclick="hardFunction();">Hard Mode</button>
<button id="button" class="buttonMedium" onclick="mediumFunction();">Medium Mode</button>
<button id="button" class="buttonEasy" onclick="easyFunction();">Easy Mode</button>
<script src="script.js"></script>
Perhaps the desired result would also want to have some control over the randomized colors.
This basic example generate a random color in hsl with a randomized hue, but keep saturation and lightness the same at a set number.
If needed, further calculation based saturation and lightness can be added for coloring each brick with some patterns. The example includes a basic use of this by generating a gradient in lightness based on rows, but it is totally optional.
Example:
"use strict";
// 👇 Set a range for random color hue,
const minHue = 0;
const maxHue = 360;
// 👇 Set custom saturation and lightness
const saturation = 100;
const lightness = 50;
// 👇 Optional: set lightness as an array for a row gradient
const lightnessList = [30, 40, 50, 60, 70];
const randColor = (minHue, maxHue, saturation, lightness) =>
`hsl(${
minHue + Math.floor(Math.random() * (maxHue - minHue))
} ${saturation}% ${lightness}%)`;
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var ballRadius = 20;
var x = canvas.width / 2;
var y = canvas.height - 30;
var dx = 3;
var dy = -3;
var paddleHeight = 10;
var paddleWidth = 175;
var paddleX = (canvas.width - paddleWidth) / 2;
var rightPressed = false;
var leftPressed = false;
var brickRowCount = 11;
var brickColumnCount = 5;
var brickWidth = 73;
var brickHeight = 20;
var brickPadding = 10;
var brickOffsetTop = 30;
var brickOffsetLeft = 30;
var score = 0;
var lives = 3;
var bricks = [];
for (var c = 0; c < brickColumnCount; c++) {
bricks[c] = [];
// 👇 Optional: for using lightnessList
const lit = lightnessList?.[c] || lightness;
for (var r = 0; r < brickRowCount; r++) {
bricks[c][r] = {
x: 0,
y: 0,
status: 1,
color: randColor(minHue, maxHue, saturation, lit),
};
}
}
document.addEventListener("keydown", keyDownHandler, false);
document.addEventListener("keyup", keyUpHandler, false);
document.addEventListener("mousemove", mouseMoveHandler, false);
function keyDownHandler(e) {
if (e.key == "Right" || e.key == "ArrowRight") {
rightPressed = true;
} else if (e.key == "Left" || e.key == "ArrowLeft") {
leftPressed = true;
}
}
function keyUpHandler(e) {
if (e.key == "Right" || e.key == "ArrowRight") {
rightPressed = false;
} else if (e.key == "Left" || e.key == "ArrowLeft") {
leftPressed = false;
}
}
function mouseMoveHandler(e) {
var relativeX = e.clientX - canvas.offsetLeft;
if (relativeX > 0 && relativeX < canvas.width) {
paddleX = relativeX - paddleWidth / 2;
}
}
function collisionDetection() {
for (var c = 0; c < brickColumnCount; c++) {
for (var r = 0; r < brickRowCount; r++) {
var b = bricks[c][r];
if (b.status == 1) {
if (
x > b.x &&
x < b.x + brickWidth &&
y > b.y &&
y < b.y + brickHeight
) {
dy = -dy;
b.status = 0;
score++;
if (score == brickRowCount * brickColumnCount) {
alert("YOU WIN, CONGRATS!");
document.location.reload();
}
}
}
}
}
}
function drawBall() {
ctx.beginPath();
ctx.arc(x, y, ballRadius, 0, Math.PI * 2);
ctx.fill();
ctx.closePath();
}
function drawPaddle() {
ctx.beginPath();
ctx.rect(paddleX, canvas.height - paddleHeight, paddleWidth, paddleHeight);
ctx.fill();
ctx.closePath();
}
function drawBricks() {
for (var c = 0; c < brickColumnCount; c++) {
for (var r = 0; r < brickRowCount; r++) {
if (bricks[c][r].status == 1) {
var brickX = r * (brickWidth + brickPadding) + brickOffsetLeft;
var brickY = c * (brickHeight + brickPadding) + brickOffsetTop;
bricks[c][r].x = brickX;
bricks[c][r].y = brickY;
ctx.fillStyle = bricks[c][r]?.color || "#000";
ctx.beginPath();
ctx.rect(brickX, brickY, brickWidth, brickHeight);
ctx.fill();
ctx.closePath();
ctx.fillStyle = "#000";
}
}
}
}
function drawScore() {
ctx.font = "16px Arial";
ctx.fillText("Score: " + score, 8, 20);
}
function drawLives() {
ctx.font = "16px Arial";
ctx.fillText("Lives: " + lives, canvas.width - 65, 20);
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawBricks();
drawBall();
drawPaddle();
drawScore();
drawLives();
collisionDetection();
if (x + dx > canvas.width - ballRadius || x + dx < ballRadius) {
dx = -dx;
}
if (y + dy < ballRadius) {
dy = -dy;
} else if (y + dy > canvas.height - ballRadius) {
if (x > paddleX && x < paddleX + paddleWidth) {
dy = -dy;
} else {
lives--;
if (!lives) {
alert("GAME OVER");
document.location.reload();
} else {
x = canvas.width / 2;
y = canvas.height - 30;
dx = 3;
dy = -3;
paddleX = (canvas.width - paddleWidth) / 2;
}
}
}
if (rightPressed && paddleX < canvas.width - paddleWidth) {
paddleX += 7;
} else if (leftPressed && paddleX > 0) {
paddleX -= 7;
}
x += dx;
y += dy;
requestAnimationFrame(draw);
}
function hardFunction() {
ballRadius = 8;
paddleWidth = 80;
lives = 1;
dx = 5;
dy = -5;
}
function mediumFunction() {
ballRadius = 15;
paddleWidth = 120;
lives = 2;
dx = 4;
dy = -4;
}
function easyFunction() {
ballRadius = 20;
paddleWidth = 175;
lives = 3;
dx = 3;
dy = -3;
}
draw();
console.log(ctx.fillStyle);
* {
padding: 0;
margin: 0;
}
canvas {
background: #eee;
display: block;
margin: 0 auto;
}
button {
border: none;
color: gray;
padding: 16px 32px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
margin: 4px 2px 0px 16.67%;
transition-duration: 0.4s;
cursor: pointer;
}
.buttonHard:hover {
background-color: red;
color: black;
}
.buttonMedium:hover {
background-color: yellow;
color: black;
}
.buttonEasy:hover {
background-color: green;
color: black;
}
<canvas id="myCanvas" width="960" height="640"></canvas>
<button id="button" class="buttonHard" onclick="hardFunction();">Hard Mode</button>
<button id="button" class="buttonMedium" onclick="mediumFunction();">Medium Mode</button>
<button id="button" class="buttonEasy" onclick="easyFunction();">Easy Mode</button>
<script src="script.js"></script>
Hope this will help.
So I was making a breakout game for class and finished it, so for fun, my teacher asked before I went off for Christmas break that I make the bricks change color, and yea I did that but it's WAY too fast. He says it's fine how it is- if it was slower, or if the colors changed every time a brick was hit. Can I get some help?
canvas = document.getElementById("myCanvas");
ctx = canvas.getContext("2d");
ballRadius = 10;
x = canvas.width/2;
y = canvas.height-30;
dx = 2;
dy = -2;
const ballColor1 = "#0095DD";
const ballColor2 = "#ff0000";
var ballColor = ballColor1;
paddleHeight = 10;
paddleWidth = 75;
paddleX = (canvas.width-paddleWidth)/2;
rightPressed = false;
leftPressed = false;
const brickRowCount = 5;
const brickColumnCount = 3;
const brickWidth = 75;
const brickHeight = 20;
const brickPadding = 10;
const brickOffsetTop = 30;
const brickOffsetLeft = 30;
let score = 0;
let lives = 3;
const bricks = [];
for(let c=0; c<brickColumnCount; c++) {
bricks[c] = [];
for(let r=0; r<brickRowCount; r++) {
bricks[c][r] = { x: 0, y: 0, status: 1 };
}
}
function randBrick() {
return "#" + ((1 << 24) * Math.random() | 0).toString(16).padStart(6, "0")
}
console.log(randBrick());
document.addEventListener("keydown", keyDownHandler, false);
document.addEventListener("keyup", keyUpHandler, false);
document.addEventListener("mousemove", mouseMoveHandler, false);
document.getElementById("startAgain").addEventListener("click", function() {
document.location.reload();
clearInterval(interval);
});
document.getElementById("playAgain").addEventListener("click", function() {
document.location.reload();
clearInterval(interval);
});
function keyDownHandler(e) {
if(e.key == "Right" || e.key == "ArrowRight") {
rightPressed = true;
}
else if(e.key == "Left" || e.key == "ArrowLeft") {
leftPressed = true;
}
}
function keyUpHandler(e) {
if(e.key == "Right" || e.key == "ArrowRight") {
rightPressed = false;
}
else if(e.key == "Left" || e.key == "ArrowLeft") {
leftPressed = false;
}
}
function mouseMoveHandler(e) {
const relativeX = e.clientX - canvas.offsetLeft;
if(relativeX > 0 && relativeX < canvas.width) {
paddleX = relativeX - paddleWidth/2;
}
}
function collisionDetection() {
for(let c=0; c<brickColumnCount; c++) {
for(let r=0; r<brickRowCount; r++) {
const b = bricks[c][r];
if(b.status == 1) {
if(x > b.x && x < b.x+brickWidth && y > b.y && y < b.y+brickHeight) {
dy = -dy;
b.status = 0;
score++;
if(score == brickRowCount*brickColumnCount) {
document.getElementById('gameWin').style.display = 'block';
clearInterval(interval);
randBrick();
}
}
}
}
}
}
function drawBall() {
ctx.beginPath();
ctx.arc(x, y, ballRadius, 0, Math.PI*2);
ctx.fillStyle = ballColor;
ctx.fill();
ctx.closePath();
}
function drawPaddle() {
ctx.beginPath();
ctx.rect(paddleX, canvas.height-paddleHeight, paddleWidth, paddleHeight);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
}
function drawBricks() {
for(let c=0; c<brickColumnCount; c++) {
for(let r=0; r<brickRowCount; r++) {
if(bricks[c][r].status == 1) {
const brickX = (r*(brickWidth+brickPadding))+brickOffsetLeft;
const brickY = (c*(brickHeight+brickPadding))+brickOffsetTop;
bricks[c][r].x = brickX;
bricks[c][r].y = brickY;
ctx.beginPath();
ctx.rect(brickX, brickY, brickWidth, brickHeight);
ctx.fillStyle = "#" + ((1 << 24) * Math.random() | 0).toString(16).padStart(6, "0");
ctx.fill();
ctx.closePath();
}
}
}
}
function drawScore() {
ctx.font = "16px Arial";
ctx.fillStyle = "#0095DD";
ctx.fillText("Score: "+score, 8, 20);
}
function drawLives() {
ctx.font = "16px Arial";
ctx.fillStyle = "#0095DD";
ctx.fillText("Lives: "+lives, canvas.width-65, 20);
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawBall();
drawBricks();
drawPaddle();
drawScore();
drawLives();
collisionDetection();
if(x + dx > canvas.width-ballRadius || x + dx < ballRadius) {
dx = -dx;
if (ballColor == ballColor1) {
ballColor = ballColor2;
} else {
ballColor = ballColor1;
}
}
if(y + dy < ballRadius) {
dy = -dy;
if (ballColor == ballColor1) {
ballColor = ballColor2;
} else {
ballColor = ballColor1;
}
}
else if(y + dy > canvas.height-ballRadius) {
if(x > paddleX && x < paddleX + paddleWidth) {
dy = -dy;
}
else {
lives--;
if(!lives) {
document.getElementById('gameOver').style.display = 'block';
clearInterval(interval);
}
else {
x = canvas.width/2;
y = canvas.height-30;
dx = 3;
dy = -3;
paddleX = (canvas.width-paddleWidth)/2;
}
}
}
if(rightPressed && paddleX < canvas.width-paddleWidth) {
paddleX += 7;
}
else if(leftPressed && paddleX > 0) {
paddleX -= 7;
}
x += dx;
y += dy;
requestAnimationFrame(draw);
}
draw();
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Breakout</title>
<style>
* {
padding: 0;
margin: 0;
}
canvas {
background: #eee;
display: block;
margin: 0 auto;
border: 5px solid red;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="480" height="320"></canvas>
<div id="gameOver" style="display: none; position: absolute; top: 50px; left: 50px; width: 200px;">
<h1>Game Over!</h1>
<button id="startAgain">Try Again?</button>
</div>
<div id="gameWin" style="display: none; position: absolute; top: 50px; left: 50px; width: 200px;">
<h1>You Win!</h1>
<button id="playAgain">Play Again?</button>
</div>
<script src=breakoutCode.js></script>
</body>
</html>
You're changing the color on every block draw. The Math.random() is getting called on every draw to the canvas thus that means it's changing every block's color on each draw.
Possible solutions:
Save the colors in an array + a the time you want to change them
Save the colors in an array and change them randomly
Don't re-draw the blocks on every re-draw (better for performance)
Here's one possible solution that stores the colors in an array and changes them randomly:
let blkColors = []
function drawBricks() {
for(let c=0; c<brickColumnCount; c++) {
for(let r=0; r<brickRowCount; r++) {
if(bricks[c][r].status == 1) {
const brickX = (r*(brickWidth+brickPadding))+brickOffsetLeft;
const brickY = (c*(brickHeight+brickPadding))+brickOffsetTop;
bricks[c][r].x = brickX;
bricks[c][r].y = brickY;
ctx.beginPath();
ctx.rect(brickX, brickY, brickWidth, brickHeight);
if (!blkColors[c] || !blkColors[c][r] || Math.random() > 0.97) { // new color
if (!blkColors[c])
blkColors[c] = [];
ctx.fillStyle = blkColors[c][r] = "#" + ((1 << 24) * Math.random() | 0).toString(16).padStart(6, "0");
} else {
ctx.fillStyle = blkColors[c][r];
}
ctx.fill();
ctx.closePath();
}
}
}
}
On JSFiddle
I am fairly new to using html canvas. I'm creating a breakout game. I want to implement a fall text when a brick is hit that the paddle at the bottom can catch to increase points.
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var ballRadius = 10;
var x = canvas.width / 2;
var y = canvas.height - 30;
var dx = 2;
var dy = -2;
var paddleHeight = 10;
var paddleWidth = 75;
var paddleX = (canvas.width - paddleWidth) / 2;
var rightPressed = false;
var leftPressed = false;
var brickRowCount = 4;
var brickColumnCount = 4;
var brickWidth = 50;
var brickHeight = 10;
var brickPadding = 15;
var brickOffsetTop = 30;
var brickOffsetLeft = 30;
var score = 0;
var lives = 3;
var reward = { value: 1, x: canvas.width / 2 - 5, y: 20 };
var bricks = [];
for (var c = 0; c < brickColumnCount; c++) {
bricks[c] = [];
for (var r = 0; r < brickRowCount; r++) {
bricks[c][r] = { x: 0, y: 0, status: 1 };
}
}
document.addEventListener("keydown", keyDownHandler, false);
document.addEventListener("keyup", keyUpHandler, false);
document.addEventListener("mousemove", mouseMoveHandler, false);
function keyDownHandler(e) {
if (e.keyCode == 39) {
rightPressed = true;
} else if (e.keyCode == 37) {
leftPressed = true;
}
}
function keyUpHandler(e) {
if (e.keyCode == 39) {
rightPressed = false;
} else if (e.keyCode == 37) {
leftPressed = false;
}
}
function mouseMoveHandler(e) {
var relativeX = e.clientX - canvas.offsetLeft;
if (relativeX > 0 && relativeX < canvas.width) {
paddleX = relativeX - paddleWidth / 2;
}
}
function collisionDetection() {
for (var c = 0; c < brickColumnCount; c++) {
for (var r = 0; r < brickRowCount; r++) {
var b = bricks[c][r];
if (b.status == 1) {
if (
x + 5 > b.x &&
x - 5 < b.x + brickWidth &&
y > b.y &&
y < b.y + brickHeight
) {
reward.value++;
reward.x = b.x;
reward.y = b.y;
// drawReward();
// drawReward(x, y);
ctx.font = "16px Arial";
ctx.fillStyle = "#50b848";
ctx.fillText("1GB", 8, 10);
dy = -dy;
b.status = 0;
score++;
if (score == brickRowCount * brickColumnCount) {
alert("YOU WIN, CONGRATS!");
document.location.reload();
}
}
}
}
}
}
function drawBall() {
// var img = document.getElementById("icon");
// var img = new Image();
// img.src = "/images/glo_icon.png";
// ctx.drawImage(img, x, y, 25, 25);
ctx.beginPath();
ctx.arc(x, y, ballRadius, 0, Math.PI * 2);
ctx.fillStyle = "#50b848";
ctx.fill();
ctx.closePath();
}
function drawPaddle() {
ctx.beginPath();
ctx.rect(paddleX, canvas.height - paddleHeight, paddleWidth, paddleHeight);
ctx.fillStyle = "#50b848";
ctx.fill();
ctx.closePath();
}
function drawBricks() {
for (var c = 0; c < brickColumnCount; c++) {
for (var r = 0; r < brickRowCount; r++) {
if (bricks[c][r].status == 1) {
var brickX = r * (brickWidth + brickPadding) + brickOffsetLeft;
var brickY = c * (brickHeight + brickPadding) + brickOffsetTop;
bricks[c][r].x = brickX;
bricks[c][r].y = brickY;
ctx.beginPath();
ctx.rect(brickX, brickY, brickWidth, brickHeight);
ctx.fillStyle = `#50b848`;
ctx.fill();
ctx.closePath();
}
}
}
}
// function drawReward() {
// // ctx.clearRect(reward.x, reward.y, 30, 30);
// ctx.font = "25px Arial";
// ctx.fillStyle = "#ffffff";
// ctx.fillText(reward.value + "GB", canvas.width / 2 - 5, 20);
// if (y >= 300) {
// y = 290; // Set the ball's Y position to the bottom of the canvas
// dy = 0; //And finally this set the falling is zero
// }
// }
function drawScore() {
ctx.font = "16px Arial";
ctx.fillStyle = "purple";
ctx.fillText("Score: " + score, 8, 20);
}
function drawLives() {
ctx.font = "16px Arial";
ctx.fillStyle = "red";
ctx.fillText("Lives: " + lives, canvas.width - 65, 20);
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawBricks();
drawBall();
drawPaddle();
drawScore();
drawLives();
// drawReward();
collisionDetection();
if (x + dx > canvas.width - ballRadius || x + dx < -5) {
dx = -dx;
}
if (y + dy < -5) {
dy = -dy;
}
if (y + dy > canvas.height - ballRadius) {
if (x > paddleX - 10 && x < paddleX + paddleWidth + 10) {
dy = -dy;
} else {
dy = -dy;
lives--;
if (!lives) {
// alert("GAME OVER");
// document.location.reload();
} else {
x = canvas.width / 2;
y = canvas.height - 30;
dx = 3;
dy = -3;
paddleX = (canvas.width - paddleWidth) / 2;
}
}
}
if (rightPressed && paddleX < canvas.width - paddleWidth) {
paddleX += 7;
} else if (leftPressed && paddleX > 0) {
paddleX -= 7;
}
x += dx;
y += dy;
requestAnimationFrame(draw);
}
draw();
<canvas id="myCanvas"></canvas>
when a brick is hit, at text like "2X" should be drawn from that point and drop down to the bottom so the paddle can pick it up.
thanks for the assistance in advance
You need to be able to render multiple rewards; this is because several blocks may be hit within a short period of time, leading to several falling text items at once.
The only real trick here is to create an array of rewards, create another top-level rendering function named drawRewards (in the plural), and within that function, loop through all rewards in our rewards array, and render them. (Oh, and don't forget to actually add new rewards into the array whenever a block is hit!) I've modified your code to do all these things; let me know if this is what you were looking for:
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var ballRadius = 10;
var x = canvas.width / 2;
var y = canvas.height - 30;
var dx = 2;
var dy = -2;
var paddleHeight = 10;
var paddleWidth = 75;
var paddleX = (canvas.width - paddleWidth) / 2;
var rightPressed = false;
var leftPressed = false;
var brickRowCount = 4;
var brickColumnCount = 4;
var brickWidth = 50;
var brickHeight = 10;
var brickPadding = 15;
var brickOffsetTop = 30;
var brickOffsetLeft = 30;
var score = 0;
var lives = 3;
var reward = { value: 1, x: canvas.width / 2 - 5, y: 20 };
let rewards = [];
var bricks = [];
for (var c = 0; c < brickColumnCount; c++) {
bricks[c] = [];
for (var r = 0; r < brickRowCount; r++) {
bricks[c][r] = { x: 0, y: 0, status: 1 };
}
}
document.addEventListener("keydown", keyDownHandler, false);
document.addEventListener("keyup", keyUpHandler, false);
document.addEventListener("mousemove", mouseMoveHandler, false);
function keyDownHandler(e) {
if (e.keyCode == 39) {
rightPressed = true;
} else if (e.keyCode == 37) {
leftPressed = true;
}
}
function keyUpHandler(e) {
if (e.keyCode == 39) {
rightPressed = false;
} else if (e.keyCode == 37) {
leftPressed = false;
}
}
function mouseMoveHandler(e) {
var relativeX = e.clientX - canvas.offsetLeft;
if (relativeX > 0 && relativeX < canvas.width) {
paddleX = relativeX - paddleWidth / 2;
}
}
function collisionDetection() {
for (var c = 0; c < brickColumnCount; c++) {
for (var r = 0; r < brickRowCount; r++) {
var b = bricks[c][r];
if (b.status == 1) {
if (
x + 5 > b.x &&
x - 5 < b.x + brickWidth &&
y > b.y &&
y < b.y + brickHeight
) {
reward.value++;
reward.x = b.x;
reward.y = b.y;
rewards.push({ x: b.x, y: b.y, text: '1GB' });
dy = -dy;
b.status = 0;
score++;
if (score == brickRowCount * brickColumnCount) {
document.location.reload();
}
}
}
}
}
}
function drawBall() {
// var img = document.getElementById("icon");
// var img = new Image();
// img.src = "/images/glo_icon.png";
// ctx.drawImage(img, x, y, 25, 25);
ctx.beginPath();
ctx.arc(x, y, ballRadius, 0, Math.PI * 2);
ctx.fillStyle = "#50b848";
ctx.fill();
ctx.closePath();
}
function drawPaddle() {
ctx.beginPath();
ctx.rect(paddleX, canvas.height - paddleHeight, paddleWidth, paddleHeight);
ctx.fillStyle = "#50b848";
ctx.fill();
ctx.closePath();
}
function drawBricks() {
for (var c = 0; c < brickColumnCount; c++) {
for (var r = 0; r < brickRowCount; r++) {
if (bricks[c][r].status == 1) {
var brickX = r * (brickWidth + brickPadding) + brickOffsetLeft;
var brickY = c * (brickHeight + brickPadding) + brickOffsetTop;
bricks[c][r].x = brickX;
bricks[c][r].y = brickY;
ctx.beginPath();
ctx.rect(brickX, brickY, brickWidth, brickHeight);
ctx.fillStyle = `#50b848`;
ctx.fill();
ctx.closePath();
}
}
}
}
function drawRewards() {
for (let reward of rewards) {
reward.y = reward.y + 1;
ctx.font = "12px Arial";
ctx.fillStyle = "#000";
ctx.fillText(reward.text, reward.x, reward.y);
}
// Remove any rewards which fall out of view
rewards = rewards.filter(reward => reward.y < canvas.height);
}
function drawScore() {
ctx.font = "16px Arial";
ctx.fillStyle = "purple";
ctx.fillText("Score: " + score, 8, 20);
}
function drawLives() {
ctx.font = "16px Arial";
ctx.fillStyle = "red";
ctx.fillText("Lives: " + lives, canvas.width - 65, 20);
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawBricks();
drawBall();
drawPaddle();
drawScore();
drawRewards();
drawLives();
// drawReward();
collisionDetection();
if (x + dx > canvas.width - ballRadius || x + dx < -5) {
dx = -dx;
}
if (y + dy < -5) {
dy = -dy;
}
if (y + dy > canvas.height - ballRadius) {
if (x > paddleX - 10 && x < paddleX + paddleWidth + 10) {
dy = -dy;
} else {
dy = -dy;
lives--;
if (!lives) {
// alert("GAME OVER");
// document.location.reload();
} else {
x = canvas.width / 2;
y = canvas.height - 30;
dx = 3;
dy = -3;
paddleX = (canvas.width - paddleWidth) / 2;
}
}
}
if (rightPressed && paddleX < canvas.width - paddleWidth) {
paddleX += 7;
} else if (leftPressed && paddleX > 0) {
paddleX -= 7;
}
x += dx;
y += dy;
requestAnimationFrame(draw);
}
draw();
<canvas id="myCanvas"></canvas>
I am trying to code a Pause/Play button for my breakout-clone because I have some text and links planned for the site on which the game will be, so you can pause the game while reading the text or interacting with links. My code is written in JS and mostly consists of "function" and "var". If the CSS or the HTML file is needed for an answer then please contact me. This is my first time asking anything on stackoverflow and I would be glad for any help.
var canvas = document.getElementById("TheCanvas");
var ctx = canvas.getContext("2d");
var x = canvas.width/2;
var y = canvas.height-50;
var dx = 2
var dy = -2;
var ballRadius = 10;
var paddleHeight = 15;
var paddleWidth = 80;
var paddleX = (canvas.width-paddleWidth) / 2;
var rightPressed = false;
var leftPressed = false;
var brickRowCount = 6;
var brickColumnCount = 4;
var brickWidth = 90;
var brickHeight = 20;
var brickPadding = 10;
var brickOffsetTop = 30;
var brickOffsetLeft = 15;
var score = 0;
var lives = 99;
var bricks = [];
for(var c=0; c<brickColumnCount; c++) {
bricks[c] = [];
for(var r=0; r<brickRowCount; r++) {
bricks[c][r] = { x: 0, y: 0,status: 1 };
}
}
document.addEventListener("keydown", keyDownHandler, false);
document.addEventListener("keyup", keyUpHandler, false);
document.addEventListener("mousemove", mouseMoveHandler, false);
function mouseMoveHandler(e) {
var relativeX = e.clientX - canvas.offsetLeft;
if(relativeX > 0 && relativeX < canvas.width) {
paddleX = relativeX - paddleWidth/2;
}
}
function keyDownHandler(e) {
if(e.key == "Right" || e.key == "ArrowRight") {
rightPressed = true;
}
else if(e.key === "Left" || e.key == "ArrowLeft") {
leftPressed = true;
}
}
function keyUpHandler(e) {
if(e.key === "Right" || e.key === "ArrowRight") {
rightPressed = false;
}
else if(e.key === "Left" || e.key === "ArrowLeft") {
leftPressed = false;
}
}
function collisionDetection() {
for(var c=0; c<brickColumnCount; c++) {
for(var r=0; r<brickRowCount; r++) {
var b = bricks[c][r];
if(b.status == 1) {
if(x > b.x && x < b.x+brickWidth && y > b.y && y < b.y+brickHeight) {
dy = -dy;
b.status = 0;
score++;
if(score == brickRowCount*brickColumnCount) {
alert("YOU WIN, WELL DONE!");
document.location.reload();
clearInterval(interval); // <- This is needed for the browser to end the game \\
}
}
}
}
}
}
function drawScore() {
ctx.font = "16px OCR A";
ctx.fillStyle = "#00ffd9"
ctx.fillText("Score: "+score, 8, 20);
}
function drawLives() {
ctx.font = "16px OCR A"
ctx.fillStyle = "00ffd9"
ctx.fillText("Lives: "+lives, canvas.width-85, 20);
}
function drawBall() {
// drawing code \\
ctx.beginPath();
ctx.arc(x, y, ballRadius, 0, Math.PI*2);
ctx.lineWidth=3
ctx.strokeStyle = "#00ff00";
ctx.stroke();
ctx.closePath();
}
function drawPaddle() {
ctx.beginPath();
ctx.rect(paddleX, canvas.height-15, paddleWidth, paddleHeight);
ctx.lineWidth=2
ctx.fillStyle = "#ff0000";
ctx.fill();
ctx.closePath();
}
function drawBricks() {
for(var c=0; c<brickColumnCount; c++) {
for(var r=0; r<brickRowCount; r++) {
if(bricks[c][r].status == 1) {
var brickX = (c*(brickWidth+brickPadding))+brickOffsetLeft;
var brickY = (r*(brickHeight+brickPadding))+brickOffsetTop;
bricks[c][r].x = brickX;
bricks[c][r].y = brickY;
ctx.beginPath();
ctx.rect(brickX, brickY, brickWidth, brickHeight);
ctx.strokeStyle = "#33FFFF";
ctx.stroke();
ctx.closePath();
}
}
}
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawBricks();
drawBall();
drawPaddle();
drawScore();
drawLives();
collisionDetection();
if (x + dx > canvas.width - ballRadius || x + dx < ballRadius) {
dx = -dx;
}
if (y + dy < ballRadius) {
dy = -dy;
}
else if (y + dy > canvas.height - ballRadius) {
if (x > paddleX && x < paddleX + paddleWidth) {
dy = -dy;
}
else {
lives--;
if(!lives) {
alert("Game Over! Press 'Ok' to reload!");
document.location.reload();
clearInterval(interval); // Is needed for Browser to end the game \\
}
else {
x = canvas.width/2;
y = canvas.height-30
dx = 2;
dy = -2;
paddleX = (canvas.width-paddleWidth)/2;
}
}
}
if (rightPressed && paddleX < canvas.width - paddleWidth) {
paddleX += 3;
} else if (leftPressed && paddleX > 0) {
paddleX -= 3;
}
x += dx;
y += dy;
}
var interval = setInterval(draw, 9);
var checkbox = document.getElementById('darkmode');
function darkmode() {
if (checkbox.checked == true){
document.documentElement.style.setProperty('--primary-background', 'black');
document.documentElement.style.setProperty('--primary-color', 'white');
} else {
document.documentElement.style.setProperty('--primary-background', 'white');
document.documentElement.style.setProperty('--primary-color', 'black');
}
}
checkbox.addEventListener('click', darkmode);
darkmode();
I am following a Mozilla 2D game tutorial. This is not my original code nor my original idea. Link below.
Mozilla Game
I have gotten stuck on a particular aspect of the game: collision detection of the ball with the bricks. Everything worked fine with the program until I called the collisionDetection() function.
Here is the function:
function collisionDetection() {
for(c=0; c<brickColumnCount; c++) {
for(r=0; r<brickRowCount; r++) {
var b = bricks[c][r];
if(x > b.x && x < b.x+brickWidth && y > b.y && y < b.y+brickHeight) {
dy = -dy;
}
}
}
}
Below calling this function, the ball flew around the canvas and the game mechanics worked perfectly. However, upon adding this call to my code, the ball stayed motionless at its starting point with no movement at all.
Obviously there is a problem with the collisionDetection() function but it all looks correct to me!
I also searched for a problem with the ball-to-wall and ball-to-paddle collision detection 'if statements' but everything seemed correct.
The entire code is below.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Gamedev Canvas Workshop</title>
<style>
* { padding: 0; margin: 0; }
canvas { background: #eee; display: block; margin: 0 auto; }
</style>
</head>
<body>
<canvas id="myCanvas" width="480" height="320"> </canvas>
<script>
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
// Circle variables
var radiusCircle = 10;
var xCircle = canvas.width/2;
var yCircle = canvas.height - radiusCircle;
var dx = 2;
var dy = -2;
// Keyboard movement variables
var keyLeft = false;
var keyRight = false;
// Paddle variables
var paddleHeight = 10;
var paddleWidth = 75;
var xPaddle = (canvas.width - paddleWidth)/2;
// Brick variables
var brickRowCount = 3;
var brickColumnCount = 5;
var brickWidth = 75;
var brickHeight = 20;
var brickPadding = 10;
var brickOffsetTop = 30;
var brickOffsetLeft = 30;
var bricks = [];
for(c=0; c<brickColumnCount; c++) {
bricks[c] = [];
for(r=0; r<brickRowCount; r++) {
bricks[c][r] = { x: 0, y: 0 };
}
}
document.addEventListener("keydown", keyDownHandler, false);
document.addEventListener("keyup", keyUpHandler, false);
function keyDownHandler(e) {
if(e.keyCode == 39) {
keyRight = true;
}
else if(e.keyCode == 37) {
keyLeft = true;
}
}
function keyUpHandler(e) {
if(e.keyCode == 39) {
keyRight = false;
}
else if(e.keyCode == 37) {
keyLeft = false;
}
}
function collisionDetection() {
for(c=0; c<brickColumnCount; c++) {
for(r=0; r<brickRowCount; r++) {
var b = bricks[c][r];
if(x > b.x && x < b.x+brickWidth && y > b.y && y < b.y+brickHeight) {
dy = -dy;
}
}
}
}
function drawBall() {
ctx.beginPath();
ctx.arc(xCircle, yCircle, radiusCircle, 0, Math.PI * 2, false);
ctx.fillStyle = "green";
ctx.fill();
ctx.closePath;
}
function drawPaddle() {
ctx.beginPath();
ctx.rect(xPaddle, canvas.height - paddleHeight, paddleWidth, paddleHeight);
ctx.fillStyle = "green";
ctx.fill();
ctx.closePath();
}
function drawBricks() {
for(c=0; c<brickColumnCount; c++) {
for(r=0; r<brickRowCount; r++) {
var brickX = (c*(brickWidth+brickPadding))+brickOffsetLeft;
var brickY = (r*(brickHeight+brickPadding))+brickOffsetTop;
bricks[c][r].x = brickX;
bricks[c][r].y = brickY;
ctx.beginPath();
ctx.rect(brickX, brickY, brickWidth, brickHeight);
ctx.fillStyle = "green";
ctx.fill();
ctx.closePath();
}
}
}
// Renders game
var draw = function() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawBricks();
drawBall();
drawPaddle();
collisionDetection();
// Collision detection for ball and paddle and game over mechanic
if (xCircle + dx > canvas.width - radiusCircle || xCircle < radiusCircle) {
dx = -dx;
}
if (yCircle + dy < radiusCircle) {
dy = -dy;
}
else if (yCircle + dy > canvas.height - radiusCircle) {
if (xCircle > xPaddle && xCircle < xPaddle + paddleWidth) {
if (yCircle = yCircle - paddleHeight) {
dy = -dy;
}
}
else {
alert("GAME OVER!");
document.location.reload();
}
}
// Paddle movement mechanics
if (keyRight && xPaddle < canvas.width - paddleWidth) {
xPaddle += 5;
}
else if (keyLeft && xPaddle > 0) {
xPaddle += -5;
}
// Makes the ball move
xCircle += dx;
yCircle += dy;
}
setInterval(draw, 10);
</script>
</body>
</html>
Can someone please help me by pointing out an error in my code or or how the collisionDetection() function isn't working with another piece of code for the game mechanics? i.e. the ball movement or paddle movement.
I have also attached a photo of the game in its current, nonfunctional, state.
Thank you
Photo of game
In your code variables x and y does not defined. I suppose you mean xCircle and yCircle. Your collisionDetection function must looks like this:
function collisionDetection() {
for (c=0; c<brickColumnCount; c++) {
for (r=0; r<brickRowCount; r++) {
var b = bricks[c][r];
if (xCircle > b.x && xCircle < b.x+brickWidth && yCircle > b.y && yCircle < b.y+brickHeight) {
dy = -dy;
}
}
}
}