onlyforbopi
9/27/2018 - 7:19 AM

game with scoring

game with scoring

#myCanvas {
    border: 1px solid black;
    float: left;
}

#controls {
    float: left;
}

#panelRight {
    margin-left: 20px;
    float: left;
}
class Ball {
    constructor(x, y, radius, speedX, speedY, color) {
        this.x = x;
        this.y = y;
        this.radius = radius;
        this.speedX = speedX;
        this.speedY = speedY;
        this.color = color;
    }
    draw() {
        // GOOD practice: save the context, use 2D trasnformations
        ctx.save();

        // translate the coordinate system, draw relative to it
        ctx.translate(this.x, this.y);

        ctx.fillStyle = this.color;
        ctx.fillStyle = this.color;
        // (0, 0) is the top left corner of the monster.
        ctx.beginPath();
        ctx.arc(0, 0, this.radius, 0, 2 * Math.PI);
        ctx.fill();

        // GOOD practice: restore the context
        ctx.restore();
    }
    move(globalSpeedMutiplier) {
        this.x += (this.speedX * globalSpeedMutiplier);
        this.y += (this.speedY * globalSpeedMutiplier);

        this.testCollisionBallWithWalls();
    }
    testCollisionBallWithWalls() {
        // COLLISION WITH VERTICAL WALLS ?
        if ((this.x + this.radius) > w) {
            // the ball hit the right wall
            // change horizontal direction
            this.speedX = -this.speedX;

            // put the ball at the collision point
            this.x = w - this.radius;
        } else if ((this.x - this.radius) < 0) {
            // the ball hit the left wall
            // change horizontal direction
            this.speedX = -this.speedX;

            // put the ball at the collision point
            this.x = this.radius;
        }

        // COLLISIONS WTH HORIZONTAL WALLS ?
        // Not in the else as the ball can touch both
        // vertical and horizontal walls in corners
        if ((this.y + this.radius) > h) {
            // the ball hit the right wall
            // change horizontal direction
            this.speedY = -this.speedY;

            // put the ball at the collision point
            this.y = h - this.radius;
        } else if ((this.y - this.radius) < 0) {
            // the ball hit the left wall
            // change horizontal direction
            this.speedY = -this.speedY;

            // put the ball at the collision point
            this.Y = this.radius;
        }
    }
}

class Balls {
    constructor(n, globalSpeedMutiplier) {
        this.ballsArray = [];
        // create n balls
        for (var i = 0; i < n; i++) {
            var ball = new Ball(w / 2, h / 2, 5 + 20 * Math.random(), -2 + 4 * Math.random(), -2 + 4 * Math.random(), getARandomColor());
            this.ballsArray.push(ball);
        }
        this.globalSpeedMutiplier = globalSpeedMutiplier;
    }
    add(x, y, radius, speedX, speedY, color) {
        let ball = new Ball(x, y, radius, speedX, speedY, color);
        this.ballsArray.push(ball);
    }
    draw() {
        for (var i = 0; i < this.ballsArray.length; i++) {
            this.ballsArray[i].draw();
        };
    }
    drawBallNumbers() {
        ctx.save();
        ctx.font = "20px Arial";

        if (gameState === "displayGameOverMenu") {
            ctx.fillText("Game Over!", 20, 30);
            // Display Game Over Menu
            restartEl.style.display = "block";

            // keep game score on Local Store
            let ballGames = JSON.parse(localStorage.ballGames);
            var d = new Date();

            let ballGame = { 'date': d, 'level': gameLevel };
            ballGames.push(ballGame);
            ballGames.sort(function(a, b) {
                return b.level - a.level;
            });
            localStorage.ballGames = JSON.stringify(ballGames);

            let end = 10;
            if (ballGames.length < end) {
                end = ballGames.length;
            }
            for (var i = 0; i < end; i++) {
                let pEl = document.createElement('p');
                ballGames[i].date = new Date(ballGames[i].date);
                pEl.innerText = '' + (i + 1) + ' level: ' + ballGames[i].level + ' date: ' + ballGames[i].date.getFullYear() + '/' + ballGames[i].date.getMonth() + '/' + ballGames[i].date.getDate() + '  ' + ballGames[i].date.getHours() + ":" + ballGames[i].date.getMinutes() + ":" + ballGames[i].date.getSeconds();
                historyEl.append(pEl);
            }
            return;
        } else if (goodBallsEaten === numberOfGoodBalls) {
            /* ctx.fillText("You Win! Final score : " + (initialNumberOfBalls - wrongBallsEaten),
                20, 30); */
            gameLevel++;
            gameLevelEl.innerHTML = 'Game Level: ' + gameLevel;
            numberOfBalls++;
            startGame();
        } else {
            ctx.fillText("Balls still alive: " + this.ballsArray.length, 210, 30);
            ctx.fillText("Good Balls eaten: " + goodBallsEaten, 210, 50);
            ctx.fillText("Wrong Balls eaten: " + wrongBallsEaten, 210, 70);
        }
        ctx.restore();
    }
    move() {
        for (var i = 0; i < this.ballsArray.length; i++) {
            this.ballsArray[i].move(this.globalSpeedMutiplier);
            this.testCollisionWithPlayer(i);
        };
    }
    countNumberOfGoodBalls(colorToEat) {
        var nb = 0;

        for (var i = 0; i < this.ballsArray.length; i++) {
            if (this.ballsArray[i].color === colorToEat) {
                nb++;
            }
        };

        return nb;
    }
    testCollisionWithPlayer(index) {
        if (circRectsOverlap(player.x, player.y,
                player.width, player.height,
                this.ballsArray[index].x, this.ballsArray[index].y, this.ballsArray[index].radius)) {
            // we remove the element located at index
            // from the balls array
            // splice: first parameter = starting index
            //         second parameter = number of elements to remove
            if (this.ballsArray[index].color === colorToEat) {
                // Yes, we remove it and increment the score
                goodBallsEaten += 1;
            } else {
                wrongBallsEaten += 1;
                if (wrongBallsEaten >= numberOfWrongBalls) {
                    gameState = "displayGameOverMenu";
                }
            }


            balls.ballsArray.splice(index, 1);
        }
    }
}

function getARandomColor() {
    var colors = ['red', 'blue', 'cyan', 'purple', 'pink', 'green', 'yellow'];
    // a value between 0 and color.length-1
    // Math.round = rounded value
    // Math.random() a value between 0 and 1
    var colorIndex = Math.round((colors.length - 1) * Math.random());
    var c = colors[colorIndex];

    // return the random color
    return c;
}


function changeNbBalls(nb) {
    numberOfBalls = nb;
    startGame();
}

function changeNbWrongBalls(nb) {
    numberOfWrongBalls = nb;
    startGame();
}

function changeColorToEat(color) {
    colorToEat = color;
}

function changePlayerColor(color) {
    player.color = color;
}

function changeBallSpeed() {
    balls.globalSpeedMutiplier = speedEl.value * 1;
}

// useful to have them as global variables
var canvas, ctx, w, h;
var mousePos;

var historyEl;

// Game level
var gameLevel;
// Game State
var gameState;
// Number of Balls
var numberOfBalls;
var numberOfBallsEl;
// Number of Wrong Balls
var numberOfWrongBalls;
var numberOfWrongBallsEl;
var numberOfWrongBallsMax;
// Level Element
var gameLevelEl;
// Restart Element
var restartEl;
// Speed Element
var speedEl;

var player = {
    x: 10,
    y: 10,
    width: 20,
    height: 20,
    color: 'red'
}

let colorToEat = 'red';


window.onload = function init() {

    // called AFTER the page has been loaded
    canvas = document.querySelector("#myCanvas");

    // check local Storage
    if (localStorage.ballGames === undefined) {
        let ballGames = [];
        localStorage.ballGames = JSON.stringify(ballGames);
    }

    // Number of Balls
    numberOfBallsEl = document.querySelector("#nbBalls");
    numberOfBalls = numberOfBallsEl.value * 1; // make sure it's a number
    numberOfWrongBallsEl = document.querySelector("#nbWrongBalls");
    numberOfWrongBalls = numberOfWrongBallsEl.value * 1; // make sure it's a number

    // Sped
    speedEl = document.querySelector("#ballSpeed");
    speedEl.addEventListener("input", changeBallSpeed);

    // Game Level
    gameLevelEl = document.querySelector("#gameLevel");

    // Game Over Menu
    restartEl = document.querySelector("#restart");
    restartEl.addEventListener("click", init);

    // History
    historyEl = document.querySelector("#history");

    // often useful
    w = canvas.width;
    h = canvas.height;

    // important, we will draw with this object
    ctx = canvas.getContext('2d');

    // Game Level
    gameLevel = 1;
    // start game 
    startGame();

    // add a mousemove event listener to the canvas
    canvas.addEventListener('mousemove', mouseMoved);

    // ready to go !
    mainLoop();
};

function startGame() {
    do {
        balls = new Balls(numberOfBalls, speedEl.value * 1);
        initialNumberOfBalls = numberOfBalls;
        numberOfGoodBalls = balls.countNumberOfGoodBalls(colorToEat);
    } while (numberOfGoodBalls === 0);

    wrongBallsEaten = goodBallsEaten = 0;

    gameState = "gameRunning";

    // Game Level
    gameLevelEl.innerHTML = 'Game Level: ' + gameLevel;

    // Hide Game Over Menu
    restartEl.style.display = "none";

    // Delete Score Standings
    historyEl.innerHTML = '';

}

function mouseMoved(evt) {
    mousePos = getMousePos(canvas, evt);
}

function getMousePos(canvas, evt) {
    // necessary work in the canvas coordinate system
    var rect = canvas.getBoundingClientRect();
    return {
        x: evt.clientX - rect.left,
        y: evt.clientY - rect.top
    };
}

function movePlayerWithMouse() {
    if (mousePos !== undefined) {
        player.x = mousePos.x;
        player.y = mousePos.y;
    }
}

function mainLoop() {
    // 1 - clear the canvas
    ctx.clearRect(0, 0, w, h);

    // draw the ball and the player
    drawFilledRectangle(player);
    balls.draw();
    balls.drawBallNumbers();
    if (gameState === "displayGameOverMenu") {
        return;
    }

    // animate the ball that is bouncing all over the walls
    balls.move();

    movePlayerWithMouse();

    // ask for a new animation frame
    requestAnimationFrame(mainLoop);
}

// Collisions between rectangle and circle
function circRectsOverlap(x0, y0, w0, h0, cx, cy, r) {
    var testX = cx;
    var testY = cy;
    if (testX < x0) testX = x0;
    if (testX > (x0 + w0)) testX = (x0 + w0);
    if (testY < y0) testY = y0;
    if (testY > (y0 + h0)) testY = (y0 + h0);
    return (((cx - testX) * (cx - testX) + (cy - testY) * (cy - testY)) < r * r);
}




function drawFilledRectangle(r) {
    // GOOD practice: save the context, use 2D trasnformations
    ctx.save();

    // translate the coordinate system, draw relative to it
    ctx.translate(r.x, r.y);

    ctx.fillStyle = r.color;
    // (0, 0) is the top left corner of the monster.
    ctx.fillRect(0, 0, r.width, r.height);

    // GOOD practice: restore the context
    ctx.restore();
}
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Animating a ball</title>



    <link rel="stylesheet" href="css/style.css">


</head>

<body>

    <!DOCTYPE html>
    <html lang="en">

    <head>
        <meta charset="utf-8">
        <title>Draw a monster in a canvas</title>
    </head>

    <body>
        <div id="controls">
            <label for="nbBalls">Number of balls: </label>
            <input type="number" min=1 max=30 value=10 id="nbBalls" oninput="changeNbBalls(this.value);">
            <p></p>
            <label for="nbWrongBalls">Number of Wrong balls: </label>
            <input type="number" min=1 max=5 value=3 id="nbWrongBalls" oninput="changeNbWrongBalls(this.value);">
            <p></p>
            <label for="colorChooser">Player color: </label>
            <input type="color" value='#FF0000' oninput="changePlayerColor(this.value);" id="colorChooser">
            <p></p>
            <label for="selectColorOfBallToEat">Color of ball to eat: </label>
            <select onchange="changeColorToEat(this.value);" id="selectColorOfBallToEat">
        <option value='red'>red</option>
        <option value='blue'>blue</option>
        <option value='green'>green</option>
    </select>
            <p></p>

            <label for="ballSpeed">Change ball speed: </label> - <input type="range" value='1' min=0.1 max=3 step=0.1 id="ballSpeed"> +
            <p></p>

        </div>
        <canvas id="myCanvas" width="400" height="400"></canvas>
        <section id="panelRight">
            <p id="gameLevel"></p>
            <button id="restart">Restart</button>
            <div id="history"></div>
        </section>
    </body>

    </html>


    <script src="js/balls.js"></script>
    <script src="js/index.js"></script>




</body>

</html>