Get Alert when Balls turn red and how to change the canvas outline

Viewed 33

I am trying to get alert when any of the balls turn red. Every time when the balls turn red, alert should come. Anyone can you help me out to get this thing? And i want the canvas outline stroke as black color. How to do that? I tried adding > canvas.stokestyle also but it not showing anything.

function getBall(xVal, yVal, dxVal, dyVal, rVal, colorVal) {
  var ball = {
    x: xVal,
    y: yVal,
    dx: dxVal,
    dy: dyVal,
    r: rVal,
    color: colorVal
  };
  return ball;
}

var canvas = document.getElementById("Canvas");
var ctx = canvas.getContext("2d");
ctx.globalAlpha = 0.8
var containerR = 150;
canvas.width = canvas.height = containerR * 2;
canvas.style["border-radius"] = containerR + "px";


var balls = [
  getBall(canvas.width / 2, canvas.height - 30, 2, 2, 8, "#32CD32"),
  getBall(canvas.width / 3, canvas.height - 50, 2, 2, 8, "#32CD32"),
  getBall(canvas.width / 4, canvas.height - 60, 2, 2, 8, "#32CD32"),
  getBall(canvas.width / 2, canvas.height / 5, 2, 2, 8, "#32CD32")
];

function drawBall(curBall) {
  ctx.beginPath();
  ctx.arc(curBall.x, curBall.y, curBall.r, 0, Math.PI * 2, false);
  ctx.fillStyle = curBall.color;
  ctx.fill();
  ctx.closePath();
}

function updatePos(curBall) {
  curBall.x += curBall.dx;
  curBall.y += curBall.dy;
  var dx = curBall.x - containerR;
  var dy = curBall.y - containerR;

  if (Math.sqrt(dx * dx + dy * dy) >= containerR - curBall.r) {
    var v = Math.sqrt(curBall.dx * curBall.dx + curBall.dy * curBall.dy);

    var angleToCollisionPoint = Math.atan2(-dy, dx);
    var oldAngle = Math.atan2(-curBall.dy, curBall.dx);

    var newAngle = 2 * angleToCollisionPoint - oldAngle;
    curBall.dx = -v * Math.cos(newAngle);
    curBall.dy = v * Math.sin(newAngle);
  }
}

function ballsMeet(b1, b2) {
  return (Math.hypot(Math.abs(b1.x - b2.x), Math.abs(b1.y - b2.y)) < (b1.r + b2.r))
}

function draw() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);

  for (var i = 0; i < balls.length; i++) {
    drawBall(balls[i])
    updatePos(balls[i])

    meet = false
    for (var j = 0; j < balls.length; j++) {
      if (ballsMeet(balls[i], balls[j]) && i != j) {
        meet = true
        balls[j].color = "red"
        break
      }
    }
    balls[i].color = (meet) ? "red" : "green"

  }
  requestAnimationFrame(draw);
}

draw();
canvas {
  background: #eee;
  margin: 0 auto;
}
<html>
<canvas id="Canvas"></canvas>
<div id="x"></div>
<div id="y"></div>
<div id="dx"></div>
<div id="dy"></div>
</html>

Thanks in advance

1 Answers
  • Don't use alert() when working with RequestAnimationFrame
  • Don't color balls inside draw (BTW call it engine since it's a RAF recursion), use the drawBall instead.
  • Given the above, on collision, set the ball property collider to be the colliding ball - and paint accordingly inside drawBall - that way you can restore to the original color once the ball exits collision: ctx.fillStyle = ball.collider ? "red" : ball.color;
  • You could use CSS radius and box-shadow on the CANVAS element

const ctx = document.getElementById("Canvas").getContext("2d");
const containerR = 90;
const size = containerR * 2
ctx.canvas.width = ctx.canvas.height = size;
ctx.globalAlpha = 0.8

const getBall = (x, y, dx, dy, r, color) => ({x, y, dx, dy, r, color});

const balls = [
  getBall(size / 2, size - 30, 1, 1, 30, "Blue"),
  getBall(size / 3, size - 50, 1, 1, 20, "Yellow"),
  getBall(size / 4, size - 60, 1, 1, 10, "Fuchsia"),
  getBall(size / 2, size / 5,  1, 1, 8,  "Green"),
];

const drawBall = (ball) => {
  ctx.beginPath();
  ctx.arc(ball.x, ball.y, ball.r, 0, Math.PI * 2, false);
  ctx.fillStyle = ball.collider ? "red" : ball.color;
  ctx.fill();
  ctx.closePath();
}

const updatePos = (ball) => {

  ball.x += ball.dx;
  ball.y += ball.dy;
  const dx = ball.x - containerR;
  const dy = ball.y - containerR;

  if (Math.sqrt(dx * dx + dy * dy) >= containerR - ball.r) {
    const v = Math.sqrt(ball.dx * ball.dx + ball.dy * ball.dy);
    const angleToCollisionPoint = Math.atan2(-dy, dx);
    const oldAngle = Math.atan2(-ball.dy, ball.dx);
    const newAngle = 2 * angleToCollisionPoint - oldAngle;
    ball.dx = -v * Math.cos(newAngle);
    ball.dy = v * Math.sin(newAngle);
  }
}

const collides = (a, b) => (Math.hypot(Math.abs(a.x - b.x), Math.abs(a.y - b.y)) < (a.r + b.r));

function engine() {
  console.clear(); // Clear console test messages
  ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);

  balls.forEach((a, ai) => {
    a.collider = undefined;
    
    balls.forEach((b, bi) => {
      if (bi === ai) return; // Don't look at self
      if (collides(a, b)) a.collider = b; // Store the colliding B ball
    });
    
    if (a.collider) { // If ball has a collider:
      console.log(`${a.color[0]} → ← ${a.collider.color[0]}`);
    }
    
    updatePos(a);
    drawBall(a);
  });

  requestAnimationFrame(engine);
}

engine();
canvas {
  background: #eee;
  margin: 0 auto;
  border-radius: 50%;
  box-shadow: 0 0 0 4px #000;
}
<canvas id="Canvas"></canvas>

Related