<canvas id="canvas"></canvas>
body {
  margin: 0;
}

#canvas {
  display: block;
}
const canvas = document.querySelector("#canvas");
const ctx = canvas.getContext("2d");

let width = (canvas.width = window.innerWidth);
let height = (canvas.height = window.innerHeight);

const wall = {
  x: width,
  y: height / 2,
  w: 8,
  h: 100,
  px: 1,
  py: 0.5,
  speed: 3
};

const ballInitAngle = Math.random() * Math.PI * 2;

const ball = {
  x: width / 2,
  y: height / 2,
  r: 10,
  vx: Math.cos(ballInitAngle) * 4,
  vy: Math.sin(ballInitAngle) * 4
};

window.addEventListener("resize", (e) => {
  width = canvas.width = window.innerWidth;
  height = canvas.height = window.innerHeight;
});

let key = null;
window.addEventListener("keydown", (e) => key = e.key);
window.addEventListener("keyup", (e) => key = null);

let isFail = false;

function loop(now) {
  ctx.clearRect(0, 0, width, height);

  ctx.fillStyle = "red";
  ctx.fillRect(width - wall.w, 0, wall.w, height);

  if (key === "ArrowUp") {
    wall.y += -wall.speed;
  } else if (key === "ArrowDown") {
    wall.y += wall.speed;
  }

  const wallX = wall.x - wall.px * wall.w;
  const wallY = wall.y - wall.py * wall.h;

  ctx.fillStyle = "black";
  ctx.fillRect(wallX, wallY, wall.w, wall.h);

  ball.x += ball.vx;
  ball.y += ball.vy;

  if (ball.x < ball.r) {
    ball.x = ball.r;
    ball.vx = -ball.vx;
  } else if (ball.x > width - ball.r) {
    ball.x = width - ball.r;
    ball.vx = -ball.vx;
  }

  if (ball.y < ball.r) {
    ball.y = ball.r;
    ball.vy = -ball.vy;
  } else if (ball.y > height - ball.r) {
    ball.y = height - ball.r;
    ball.vy = -ball.vy;
  }

  if (ball.x > width - ball.r - wall.w) {
    ball.x = width - ball.r - wall.w;
    if (ball.y < wallY || ball.y > wallY + wall.h) {
      isFail = true;
    } else {
      ball.vx = -ball.vx;
    }
  }

  ctx.beginPath();
  ctx.arc(ball.x, ball.y, ball.r, 0, 2 * Math.PI);
  ctx.fill();

  ctx.font = "bold 48px sans-serif";
  ctx.textAlign = "center";

  if (!isFail) requestAnimationFrame(loop);
  else ctx.fillText("Game over", width / 2, height / 2);
}
requestAnimationFrame(loop);

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.