Published
Edited
Jan 15, 2021
Insert cell
Insert cell
Insert cell
gameOverEnabled = true
Insert cell
objectColors = ({
paddleFill: "lime",
ballStroke: "green",
ballFill: "lime"
})
Insert cell
ballStartingVelocity = ({vx: 0, vy: -speed}) // when you click mouse
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function initBricks() {
const rows = 6;
const columns = Math.floor(w / targetBrickWidth);
const padding = 3;
const top = 70;
const brickWidth = (w - (padding * (columns + 1)) - scale * 2) / columns;
let bricks = new Array(rows).fill(1).map(() => new Array(columns).fill(1));
eachBrick(bricks, (b, row, col) => {
bricks[row][col] = {
w: brickWidth,
h: scale,
x: col * (brickWidth + padding) + padding + scale,
y: row * (scale + padding) + top,
color: colors[row],
points: brickPoints[row]
}
});
return bricks;
}
Insert cell
Insert cell
function renderScene(c) {
// Draw background.
c.fillStyle = "black";
c.fillRect(0, 0, w, h);
drawBricks(c);
drawWalls(c);
drawBall(c, ball);
drawPaddle(c, paddle);
}
Insert cell
function eachBrick(bricks, callback) {
for (let row = 0; row < bricks.length; ++row) {
for (let col = 0; col < bricks[row].length; ++col) {
let brick = bricks[row][col];
if (brick === undefined) continue;
if (callback(brick, row, col)) return;
}
}
}
Insert cell
function collideWithBrick(brick, ball) {
let {x, y, vx, vy, r} = ball;
let hit = x + r > brick.x && x - r < brick.x + brick.w &&
y + r > brick.y && y - r < brick.y + brick.h;
if (!hit) return direction.none;
if (x - vx + r <= brick.x || x - vx - r >= brick.x + brick.w) return direction.horizontal;
if (y - vy + r <= brick.y || y - vy - r >= brick.y + brick.h) return direction.vertical;
throw new Error("this line of code is unreachable");
}
Insert cell
function bounceOffBricks() {
let {x, y, vx, vy, r} = mutable ball;
eachBrick(mutable bricks, (brick, row, col) => {
const hit = collideWithBrick(brick, mutable ball);
// if (bricks === undefined) throw new Error("brick === undefined");
// if (bricks[row][col] === undefined) throw new Error("brick === undefined");
if (hit === direction.none) return false; // if false => keep looping because collided brick not found yet
mutable score += brick.points;
// hit === direction.vertical ? : vy = -vy : vx = -vx;
if (hit === direction.vertical) {
if (vy > 0) {
// ball moving from up to down
let highBoundary = brick.y - r;
y = -y + 2 * highBoundary;
} else {
// ball moving from down to up
// y - lowBoundary = - (y - lowBoundary)
let lowBoundary = brick.y + brick.h + r;
y = -y + 2 * lowBoundary;
}
vy = -vy;
} else { // hit === direction.horizontal
if (vx > 0) {
let leftBoundary = brick.x - r;
x = -x + 2 * leftBoundary;
} else {
let rightBoundary = brick.x + brick.w + r;
x = -x + 2 * rightBoundary;
}
vx = -vx;
}
bricks[row][col] = undefined; // make brick invisible and untouchable by ball
return hit !== direction.none; // if true => end loop
});
mutable ball = {x, y, vx, vy, r};
}
Insert cell
direction = ({
vertical: 0,
horizontal: 1,
none: 2
})
Insert cell
Insert cell
Insert cell
gameloop = {
while(!mutable gameOver) {
// Update paddle
paddle.x = Math.min(Math.max(scale, mousePos.x - paddle.width / 2), w - paddle.width - scale);
mutable ball = updateBall(mutable ball);
mutable ball = collideWalls(mutable ball);
mutable ball = bounceOffPaddle(mutable paddle, mutable ball);
bounceOffBricks();
// mutable ball = bounceOffBricks(mutable ball);

renderScene(c);
yield true;
}
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
c.canvas.onmouseup = e => {
if (!gameStarted) {
mutable ball.vx = ballStartingVelocity.vx;
mutable ball.vy = ballStartingVelocity.vy;
mutable gameStarted = true;
} else if (gameOver) {
initGame();
}
}
Insert cell
mutable mousePos = ({x: 0, y: 0})
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
md`### Changelog:
Jan 14
* Make gameloop and basic drawing stuff
* Setup deadline timer! (I don't know why i use it)
* Add mousemove
* Add collideWalls
* hitBlock: (rigorously physics for paddle, ball and blocks)
+ writing Theorem1
+ writing collide zones

Jan 15
* Add Simple paddle bounce off method (not rigorous)
* Add gameStarted variable
* Observe strange behavior of marquee tag: When I push newgame button some blinking stuff happened
* Observe freezes when created array of bricks, tried fix: move it to inside of function method \`initBricks()\`
* Remove arguments from \`function bounceOffBricks()\` to increase speed of rendering
* Observe some freezes removing arguments not helps: maybe we have memory leak?
* Fixing \`bounceOffBricks()\`: the ball goes through the blocks.

Instead of changing only velocity:

\`hit === direction.vertical ? : vy = -vy : vx = -vx;\`

we will change position of the ball.
* When ball collides paddle predicted x position not calibrated: bouncing point must be intersection of the velocity vector of the ball and the upper edge of the paddle.
y position fixed by this: \`y = -y + 2 * highBoundary;\` but angle of bouncing ball is slightly wrong

\`TODO: Fix x position => then angle be fixed.\`
* Observe that freezes are independent of the method \`bounceOffBricks()\`
`
Insert cell
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more