Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions bouncing-balls-vim-motions/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
This is a simple game that is intended to help a user
become accoustomed to using vim motions to control a pointer.


The game consists of several balls generated at random that bounce across the screen.
When the pointer is collides with a ball the ball is destroyed.

H- moves LEFT
J- UP
K- DOWN
L- RIGHT
17 changes: 17 additions & 0 deletions bouncing-balls-vim-motions/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>Bouncing balls</title>
<link rel="stylesheet" href="style.css">
</head>

<body>
<h1>bouncing balls</h1>
<p></p>
<canvas></canvas>

<script src="main.js"></script>
</body>
</html>
199 changes: 199 additions & 0 deletions bouncing-balls-vim-motions/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
// setup canvas
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');

const width = canvas.width = window.innerWidth;
const height = canvas.height = window.innerHeight;

const para = document.querySelector('p');

// function to generate random number
function random(min, max) {
const num = Math.floor(Math.random() * (max - min + 1)) + min;
return num;
}

// function to generate random color
function randomRGB() {
return `rgb(${random(0, 255)},${random(0, 255)},${random(0, 255)})`;
}

class Shape {
constructor(x, y, velX, velY, exists) {
this.x = x;
this.y = y;
this.exists = true;
this.velX = velX;
this.velY = velY;
}
}

class EvilCircle extends Shape {
constructor(x, y) {
super(x, y, 20, 20);
this.color = "white";
this.size = 30;
window.addEventListener("keydown", (e) => {
switch (e.key) {
case "h":
this.x -= this.velX;
break;
case "l":
this.x += this.velX;
break;
case "k":
this.y -= this.velY;
break;
case "j":
this.y += this.velY;
break;
}
});
}
draw() {
ctx.beginPath();
ctx.lineWidth = 3;
ctx.strokeStyle = this.color;
ctx.arc(this.x, this.y, this.size, 0, 2 * Math.PI);
ctx.stroke();
}
checkBounds() {
if ((this.x + this.size) >= width) {
this.x = width - this.size;
}

if ((this.x - this.size) <= 0) {
this.x = this.size;
}

if ((this.y + this.size) >= height) {
this.y = height - this.size;
}

if ((this.y - this.size) <= 0) {
this.y = this.size;
}
}

collisionDetect() {
for (const ball of balls) {
if (ball.exists) {
const dx = this.x - ball.x;
const dy = this.y - ball.y;
const distance = Math.sqrt(dx * dx + dy * dy);

if (distance < this.size + ball.size) {
ball.exists = false;
}
}
}
}


}

class Ball extends Shape {
constructor(x, y, velX, velY, color, size) {
super(x, y, velX, velY);
this.color = color;
this.size = size;
}


draw() {
ctx.beginPath();
ctx.fillStyle = this.color;
ctx.arc(this.x, this.y, this.size, 0, 2 * Math.PI);
ctx.fill();
}

update() {
if ((this.x + this.size) >= width) {
this.velX = -(this.velX);
}

if ((this.x - this.size) <= 0) {
this.velX = -(this.velX);
}

if ((this.y + this.size) >= height) {
this.velY = -(this.velY);
}

if ((this.y - this.size) <= 0) {
this.velY = -(this.velY);
}

this.x += this.velX;
this.y += this.velY;
}

collisionDetect() {
for (const ball of balls) {
if (!(this === ball) && ball.exists) {
const dx = this.x - ball.x;
const dy = this.y - ball.y;
const distance = Math.sqrt(dx * dx + dy * dy);

if (distance < this.size + ball.size) {
ball.color = this.color = randomRGB();
this.velX = -(this.velX);
this.velY = -(this.velY);
}
}
}
}

}

const balls = [];

while (balls.length < 25) {
const size = random(10, 20);
const ball = new Ball(
// ball position always drawn at least one ball width
// away from the edge of the canvas, to avoid drawing errors
random(0 + size, width - size),
random(0 + size, height - size),
random(-7, 7),
random(-7, 7),
randomRGB(),
size
);

balls.push(ball);
}

const evilCircle = new EvilCircle(random(0, width), random(0, height));

let count = 0;

function loop() {
ctx.fillStyle = "rgba(0, 0, 0, 0.25)";
ctx.fillRect(0, 0, width, height);

for (const ball of balls) {
if (ball.exists) {
ball.draw();
ball.update();
ball.collisionDetect();
}
}
count = 0;
for (const ball of balls) {
if (ball.exists) {
count++;
}
}
para.textContent = `Ball count: ${count}`;
if (count > 0) {
evilCircle.draw();
evilCircle.checkBounds();
evilCircle.collisionDetect();
}

requestAnimationFrame(loop);
}


loop();
33 changes: 33 additions & 0 deletions bouncing-balls-vim-motions/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
html, body {
margin: 0;
}

html {
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
height: 100%;
}

body {
overflow: hidden;
height: inherit;
}

h1 {
font-size: 2rem;
letter-spacing: -1px;
position: absolute;
margin: 0;
top: -4px;
right: 5px;

color: transparent;
text-shadow: 0 0 4px white;
}

p {
position: absolute;
margin: 0;
top: 35px;
right: 5px;
color: #aaa;
}