Kali
Kali

Reputation: 135

Canvas.getContext : changing the colour of an object once an event happens

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>

Upvotes: 5

Views: 106

Answers (1)

Dacre Denny
Dacre Denny

Reputation: 30370

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!

Upvotes: 2

Related Questions