I have reviewed the code and correct should be corrected.
About the controls, i use the Keyboard arrows instead of letters.
So:
-
Arrow Right to move the evil circle Forward
-
Arrow left to move the evil circle Backward
-
Arrow Up to move the evil circle Upward
-
Arrow down to move the evil circle DownWard
This is my reviewed Code:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title> BOUNCING BALLS </title>
<style>
body {
margin: 0;
padding: 0;
overflow: hidden;
}
.counter-container {
color: #fff;
position: absolute;
font-weight: bold;
top: 25px;
left: 25px;
}
</style>
</head>
<body>
<div class="counter-container">Remain balls: <span id="counter"></span></div>
<canvas id="black-board"></canvas>
<script>
// Get a reference to the canvas and store it into a variable
var blackBoard = document.querySelector('#black-board');
// Get a reference to the counter and store it into a variable
var counter = document.querySelector('#counter');
// Set a 2d context on the canvas
var blackBoardContext = blackBoard.getContext('2d');
// Set the scene width and height
var blackBoardWidth = blackBoard.width = window.innerWidth;
var blackBoardHeight = blackBoard.height = window.innerHeight;
// FDraw the sene and make it fit the window of the browser
blackBoardContext.fillStyle = 'rgba(0,0,0, .25)';
blackBoardContext.fillRect(0, 0, blackBoardWidth, blackBoardHeight);
// Define the random number generator function
function random(min, max) {
var num = Math.floor( Math.random() * (max - min + 1 ) ) + min;
return num;
}
// Define a shape Object constructor
function Shape(coordX, coordY, horizontalVelocity, verticalVelocity, size) {
// Coordinates of the shape
this.coordX = coordX;
this.coordY = coordY;
// Define a velocity for the shape movement
this.horizontalVelocity = horizontalVelocity;
this.verticalVelocity = verticalVelocity;
//Define the size of the shape
this.size = size;
}
/*
* Define the ball Object
* The Ball Object will inherit from the Shape Object
*/
function Ball(coordX, coordY, horizontalVelocity, verticalVelocity, size, ballColor) {
// Call the Shape constructor to inherit its properties from it
Shape.call(this, coordX, coordY, horizontalVelocity, verticalVelocity, size);
// Define a color for the ball
this.ballColor = ballColor;
/*
* Define an existance for our ball
* This will help us to make a ball disappear when it will be eaten by the evil circle
* By default, a ball exists at it creation
*/
this.exists = true;
}
// Define a method that will draw our balls on the game context
Ball.prototype.drawBall = function () {
// Create a new Path
blackBoardContext.beginPath();
// Set the Fill color of the ball with the ballColor of the current ball
blackBoardContext.fillStyle = this.ballColor;
// Design the abstract form of the circle with the current ball datas
blackBoardContext.arc(this.coordX, this.coordY, this.size, 0, 2 * Math.PI);
// Fill the cicrcle and make it solid ans visible with the current ball color
blackBoardContext.fill();
}
/*
* Define a function that will update ball position
* Though make a ball moves
*/
Ball.prototype.update = function () {
if ((this.coordX + this.size) >= blackBoardWidth) {
this.horizontalVelocity = - (this.horizontalVelocity);
}
if ((this.coordX + this.size) <= 0) {
this.horizontalVelocity = - (this.horizontalVelocity);
}
if ((this.coordY + this.size) >= blackBoardHeight) {
this.verticalVelocity = - (this.verticalVelocity);
}
if ((this.coordY + this.size) <= 0) {
this.verticalVelocity = - (this.verticalVelocity);
}
this.coordX += this.horizontalVelocity;
this.coordY += this.verticalVelocity;
}
/*
* var oneBall = new Ball(250, 250, -7, 7, 50, 'red');
* *oneBall.drawBall();
*/
// An array that will store all the balls we are playing with on the game scene
var balls = [];
/*
* Define a methodd to change color of the balls
* each time they collide of one another
*/
Ball.prototype.ballCollisionDetect = function () {
for (var i = 0; i < balls.length; i++) {
// Check if the ball is different from the current ball
if (!(this === balls[i])) {
// Determine the distance between the two balls
distanceX = this.coordX - balls[i].coordX;
distanceY = this.coordY - balls[i].coordY;
ballsDistance = Math.sqrt(distanceX * distanceX + distanceY * distanceY);
// Check if the two balls collides
// And have different colors
// Change the color of the second into the color of the current ball
if ((ballsDistance - this.size) <= balls[i].size) {
if (this.ballColor !== balls[i].ballColor) {
this.ballColor = balls[i].ballColor;
} else {
this.ballColor = 'rgb('+random(0, 255)+', '+random(0, 255)+', '+random(0, 255)+')';
}
}
}
}
}
/*
* Define the EvilCircle Object constructor
* This Object will inherit from Shape Object
*/
function EvilCircle(coordX, coordY, horizontalVelocity, verticalVelocity, size, evilStrokeColor) {
Shape.call(this, coordX, coordY, horizontalVelocity, verticalVelocity, size);
// Set the Sroke Color of our Evil Circle
this.evilStrokeColor = evilStrokeColor;
}
// Ddefine a method that draws the evil circle
EvilCircle.prototype.drawEvil = function() {
blackBoardContext.beginPath();
blackBoardContext.lineWidth = 2;
blackBoardContext.strokeStyle = "#fff";
blackBoardContext.arc(this.coordX, this.coordY, this.size, 0, 2*Math.PI );
blackBoardContext.stroke();
}
// Check the bounds to avoid the evil Circle to traverse the Window
EvilCircle.prototype.checkBounds = function() {
if( (this.coordX + this.size) >= blackBoardWidth ) {
this.coordX = blackBoardWidth + 2*this.horizontalVelocity;
}
if( (this.coordX + this.size ) <= 0 ) {
this.coordX = -2*this.horizontalVelocity;
}
if( (this.coordY + this.size ) >= blackBoardHeight ) {
this.coordY = blackBoardHeight - 2*this.verticalVelocity;
}
if( (this.coordY + this.size) <= 0) {
this.coordY = 2*this.verticalVelocity;
}
}
// Define a method that allows us control the movement of our evil circle
EvilCircle.prototype.setControls = function() {
console.log("I'am in");
var myEvilCircle = this;
// ArrowRight -> 39
// ArrowLeft -> 37
// ArrowUp -> 38
// ArrowDown -> 40
window.onkeydown = function(event) {
event.preventDefault();
// Move the Evil Cirlce Backward
if(event.keyCode === 37 ) {
myEvilCircle.checkBounds();
myEvilCircle.coordX += myEvilCircle.horizontalVelocity;
}
// Move the Evil Circle forward
if(event.keyCode === 39 ) {
myEvilCircle.checkBounds();
myEvilCircle.coordX -= myEvilCircle.horizontalVelocity;
}
// Move the Evil Circle UpWard
if(event.keyCode === 38 ) {
myEvilCircle.checkBounds();
myEvilCircle.coordY -= myEvilCircle.verticalVelocity;
}
// Move the Evil Circle downWard
if(event.keyCode === 40 ) {
myEvilCircle.checkBounds();
myEvilCircle.coordY += myEvilCircle.verticalVelocity;
}
}
}
// Make the Evil circle eats balls when they collide with it
EvilCircle.prototype.evilDetectCollision = function() {
for( var k = 0 ; k < balls.length ; k++ ) {
if( balls[k].exists ) {
let distanceEvilBallX = this.coordX - balls[k].coordX;
let distanceEvilBallY = this.coordY - balls[k].coordY;
let distanceEvilBall = Math.sqrt(distanceEvilBallX*distanceEvilBallX + distanceEvilBallY*distanceEvilBallY);
if((distanceEvilBall - this.size) <= balls[k].size ) {
balls[k].exists = false;
defaultNumber--;
}
}
}
}
// Create an evilCircle Object
var evilCircle = new EvilCircle(250, 250, -20, 20, 10, '#fff');
evilCircle.setControls();
// A default number of balls to draw
var defaultNumber = 25;
// Define a loop to create our balls bouncing in the game scene
function bouncingBallsLoop() {
blackBoardContext.fillStyle = 'rgba(0,0,0, .25)';
blackBoardContext.fillRect(0, 0, blackBoardWidth, blackBoardHeight);
while( balls.length <= defaultNumber - 1 ) {
// Create a New Ball with random parameters
var ball = new Ball(
random(0, blackBoardWidth),
random(0, blackBoardHeight),
random(-7, 7),
random(-7, 7),
random(5, 20),
'rgb('+random(0, 255)+', '+random(0, 255)+', '+random(0, 255)+')'
);
balls.push(ball);
}
// Draw the ball, update it, and detect if collides with another balls
for( var j = 0 ; j < balls.length ; j++ ) {
evilCircle.drawEvil();
evilCircle.evilDetectCollision();
if(balls[j].exists) {
balls[j].drawBall();
balls[j].update();
balls[j].ballCollisionDetect();
}
}
counter.textContent = defaultNumber;
// Recall the function by itself
requestAnimationFrame(bouncingBallsLoop);
}
bouncingBallsLoop();
</script>
</body>
</html>