resizing bouncing box at edges fails in canvas

37 views Asked by At

I saw this video, and tried to do the same in a canvas

Here's the code (without size increment)

canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");

canvas.width = parseInt(window.innerWidth, 10);
canvas.height = parseInt(window.innerHeight, 10);

let x = 0;
let y = 0;
let size = 50;
let dx = 5;
let dy = 5;
let hue = 0;

function animate()
{
    x += dx;
    y += dy;

    hue = (hue + 10) % 360;

    if(x <= 0 || x >= canvas.width - size)
    {
        dx = -dx;
    }

    if(y <= 0 || y >= canvas.height - size)
    {
        dy = -dy;
    }

    ctx.fillStyle = `hsl(${hue}, 100%, 50%)`;
    ctx.fillRect(x, y, size, size);
    ctx.strokeStyle = 'black';
    ctx.lineWidth = 1;
    ctx.strokeRect(x, y, size, size);

    window.requestAnimationFrame(animate);
}

animate();
<canvas id="canvas"></canvas>

It's working fine, but when I add the increase part then the square gets stuck on the edge and increases exponentially:

canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");

canvas.width = parseInt(window.innerWidth, 10);
canvas.height = parseInt(window.innerHeight, 10);

let x = 0;
let y = 0;
let size = 50;
let dx = 5;
let dy = 5;
let hue = 0;

function animate()
{
    x += dx;
    y += dy;

    hue = (hue + 10) % 360;

    if(x <= 0 || x >= canvas.width - size)
    {
        dx = -dx;
    size = Math.ceil(size * 1.10);
    }

    if(y <= 0 || y >= canvas.height - size)
    {
        dy = -dy;
    size = Math.ceil(size * 1.10);
    }

    ctx.fillStyle = `hsl(${hue}, 100%, 50%)`;
    ctx.fillRect(x, y, size, size);
    ctx.strokeStyle = 'black';
    ctx.lineWidth = 1;
    ctx.strokeRect(x, y, size, size);

    window.requestAnimationFrame(animate);
}

animate();
<canvas id="canvas"></canvas>

Depending on size increment, it get stuck at different edges and at different number of bounces.

I think I have to evaluate something more in the edge detection, but I can figure it out.

1

There are 1 answers

0
obscure On BEST ANSWER

This is a rather classical problem. The following part of your code

x += dx;
y += dy;

merely updates the square's position no matter what. That means it does neither take into account the future position of the square nor it's size - which increases over time.

The fix is quite simple: before updating the square's on-screen position, check if the square will move outside at it's current pace. If so, position it at the edge of the border and reverse the speed.

canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");

canvas.width = parseInt(window.innerWidth, 10);
canvas.height = parseInt(window.innerHeight, 10);

let x = 0;
let y = 0;
let size = 50;
let dx = 5;
let dy = 5;
let hue = 0;


function animate() {
  if (dx < 0) {
    if (x + dx < 0) {
      x = 0;
      dx = -dx;
      size = Math.ceil(size * 1.02);
    } else {
      x += dx;
    }
  } else {
    if (x + size + dx > canvas.width) {
      x = canvas.width - size;
      dx = -dx;
      size = Math.ceil(size * 1.02);
    } else {
      x += dx;
    }
  }
  if (dy < 0) {
    if (y + dy < 0) {
      y = 0;
      dy = -dy;
      size = Math.ceil(size * 1.02);
    } else {
      y += dy;
    }
  } else {
    if (y + size + dy > canvas.height) {
      y = canvas.height - size;
      dy = -dy;
      size = Math.ceil(size * 1.02);
    } else {
      y += dy;
    }
  }

  hue = (hue + 10) % 360;



  ctx.fillStyle = `hsl(${hue}, 100%, 50%)`;
  ctx.fillRect(x, y, size, size);
  ctx.strokeStyle = 'black';
  ctx.lineWidth = 1;
  ctx.strokeRect(x, y, size, size);

  window.requestAnimationFrame(animate);
}

animate();
<canvas id="canvas"></canvas>