Graphics overhaul as well as many other things
This commit is contained in:
@@ -25,10 +25,13 @@ if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(naviga
|
|||||||
fps = 29;
|
fps = 29;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let play = true;
|
||||||
|
|
||||||
// Draw
|
// Draw
|
||||||
function draw() {
|
function draw() {
|
||||||
// Loop
|
// Loop
|
||||||
requestAnimationFrame(draw);
|
if(play)
|
||||||
|
requestAnimationFrame(draw);
|
||||||
|
|
||||||
// Set NOW and DELTA
|
// Set NOW and DELTA
|
||||||
now = Date.now();
|
now = Date.now();
|
||||||
|
@@ -10,13 +10,10 @@ overlay2Canvas.height = H;
|
|||||||
|
|
||||||
//Random Circles creator
|
//Random Circles creator
|
||||||
function create() {
|
function create() {
|
||||||
|
|
||||||
//Place the circles at the center
|
//Place the circles at the center
|
||||||
|
|
||||||
this.x = W/2;
|
this.x = W/2;
|
||||||
this.y = H/2;
|
this.y = H/2;
|
||||||
|
|
||||||
|
|
||||||
//Random radius between 2 and 6
|
//Random radius between 2 and 6
|
||||||
this.radius = 2 + Math.random()*3;
|
this.radius = 2 + Math.random()*3;
|
||||||
|
|
||||||
@@ -30,26 +27,27 @@ function create() {
|
|||||||
this.b = Math.round(Math.random())*255;
|
this.b = Math.round(Math.random())*255;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0; i < 500; i++) {
|
function initBalls() {
|
||||||
circles.push(new create());
|
for (let i = 0; i < 500; i++) {
|
||||||
|
circles.push(new create());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawVictory() {
|
function drawVictory() {
|
||||||
|
|
||||||
//Fill overlay2Canvas with black color
|
//Fill overlay2Canvas with black color
|
||||||
overlay2Ctx.globalCompositeOperation = "source-over";
|
overlayCtx.globalCompositeOperation = "source-over";
|
||||||
overlay2Ctx.fillStyle = "rgba(0,0,0,0.15)";
|
overlayCtx.fillStyle = "rgba(0,0,0,0.15)";
|
||||||
overlay2Ctx.fillRect(0, 0, W, H);
|
overlayCtx.fillRect(0, 0, W, H);
|
||||||
|
|
||||||
//Fill the overlay2Canvas with circles
|
//Fill the overlay2Canvas with circles
|
||||||
for(var j = 0; j < circles.length; j++){
|
for(let j = 0; j < circles.length; j++){
|
||||||
var c = circles[j];
|
const c = circles[j];
|
||||||
|
|
||||||
//Create the circles
|
//Create the circles
|
||||||
overlay2Ctx.beginPath();
|
overlayCtx.beginPath();
|
||||||
overlay2Ctx.arc(c.x, c.y, c.radius, 0, Math.PI*2, false);
|
overlayCtx.arc(c.x, c.y, c.radius, 0, Math.PI*2, false);
|
||||||
overlay2Ctx.fillStyle = "rgba("+c.r+", "+c.g+", "+c.b+", 0.5)";
|
overlayCtx.fillStyle = "rgba("+c.r+", "+c.g+", "+c.b+", 0.5)";
|
||||||
overlay2Ctx.fill();
|
overlayCtx.fill();
|
||||||
|
|
||||||
c.x += c.vx;
|
c.x += c.vx;
|
||||||
c.y += c.vy;
|
c.y += c.vy;
|
||||||
|
@@ -23,5 +23,6 @@
|
|||||||
<script type="text/javascript" src="animations/click.js"></script>
|
<script type="text/javascript" src="animations/click.js"></script>
|
||||||
<script type="text/javascript" src="animations/victory.js"></script>
|
<script type="text/javascript" src="animations/victory.js"></script>
|
||||||
<script type="text/javascript" src="minesweeper.js"></script>
|
<script type="text/javascript" src="minesweeper.js"></script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
579
minesweeper.js
579
minesweeper.js
@@ -1,7 +1,7 @@
|
|||||||
const canvas = document.getElementById('minesweeper-game');
|
const canvas = document.getElementById('minesweeper-game');
|
||||||
const ctx = canvas.getContext('2d');
|
const ctx = canvas.getContext('2d');
|
||||||
|
|
||||||
const fieldSize = {x: 21, y: 13};
|
const fieldSize = {x: 15, y: 10};
|
||||||
let tileSize;
|
let tileSize;
|
||||||
const bombCount = 30;
|
const bombCount = 30;
|
||||||
const field = [];
|
const field = [];
|
||||||
@@ -10,78 +10,120 @@ let victory = false;
|
|||||||
const scaleFactor = .5;
|
const scaleFactor = .5;
|
||||||
let isFirstClick = true;
|
let isFirstClick = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines all possible colors for the tile numbers
|
||||||
|
* @type {{ 1: string, 2: string, 3: string, 4: string, 6: string }}
|
||||||
|
*/
|
||||||
|
const colors = {
|
||||||
|
1: "blue",
|
||||||
|
2: "green",
|
||||||
|
3: "red",
|
||||||
|
4: "purple",
|
||||||
|
5: "yellow",
|
||||||
|
6: "pink"
|
||||||
|
};
|
||||||
|
|
||||||
ctx.scale(canvas.width / fieldSize.x * scaleFactor, canvas.height / fieldSize.y * scaleFactor);
|
ctx.scale(canvas.width / fieldSize.x * scaleFactor, canvas.height / fieldSize.y * scaleFactor);
|
||||||
|
|
||||||
/**
|
function animateBackground(x, y, width, height, curOpacity, finalOpacity, startTime, duration, color) {
|
||||||
* Initializes game by creating the game field and setting bombs
|
const time = (new Date()).getTime() - startTime;
|
||||||
*/
|
|
||||||
function initGame() {
|
|
||||||
for(let x = 0; x < fieldSize.x; x++) {
|
|
||||||
field.push([]);
|
|
||||||
for(let y = 0; y < fieldSize.y; y++) {
|
|
||||||
field[x].push({tileValue: 0, clicked: false, flagged: false});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
scaleCanvas();
|
if (curOpacity >= finalOpacity)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const newOpacity = easeInOutCubic(time, 0, finalOpacity, duration);
|
||||||
|
|
||||||
|
console.log(newOpacity, finalOpacity, color);
|
||||||
|
|
||||||
|
if (newOpacity <= finalOpacity)
|
||||||
|
curOpacity = newOpacity;
|
||||||
|
else
|
||||||
|
curOpacity = finalOpacity;
|
||||||
|
|
||||||
|
color.a = curOpacity;
|
||||||
|
|
||||||
|
overlay2Ctx.clearRect(x, y, width, height);
|
||||||
|
overlay2Ctx.fillStyle = "rgba(" + color.r + "," + color.g + "," + color.b + "," + color.a + ")";
|
||||||
|
overlay2Ctx.fillRect(x, y, width, height);
|
||||||
|
|
||||||
|
requestAnimFrame(function () {
|
||||||
|
animateBackground(x, y, width, height, curOpacity, finalOpacity, startTime, duration, color);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function initBombs(startX, startY) {
|
function animateTile(x, y, curWidth, curHeight, finalWidth, finalHeight, curRadius, finalRadius, startTime, duration, color) {
|
||||||
for(let i = 0; i < bombCount; i++) {
|
const time = (new Date()).getTime() - startTime;
|
||||||
const ranX = Math.floor(Math.random() * fieldSize.x);
|
|
||||||
const ranY = Math.floor(Math.random() * fieldSize.y);
|
|
||||||
|
|
||||||
if (ranX === startX || ranX === startX - 1 || ranX === startX + 1 || ranY === startY || ranY === startY - 1 || ranY === startY + 1 || field[ranX][ranY].tileValue === true) {
|
if (curWidth === finalWidth && curHeight === finalHeight && curRadius === finalRadius)
|
||||||
i--;
|
return;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
field[ranX][ranY].tileValue = true;
|
const newWidth = easeInOutCubic(time, 0, finalWidth, duration);
|
||||||
|
const newHeight = easeInOutCubic(time, 0, finalHeight, duration);
|
||||||
|
const newRadius = easeInOutCubic(time, 0, finalRadius, duration);
|
||||||
|
|
||||||
|
if (newWidth < finalWidth)
|
||||||
|
curWidth = newWidth;
|
||||||
|
else
|
||||||
|
curWidth = finalWidth;
|
||||||
|
|
||||||
|
if (newHeight < finalHeight)
|
||||||
|
curHeight = newHeight;
|
||||||
|
else
|
||||||
|
curHeight = finalHeight;
|
||||||
|
|
||||||
|
if (newRadius < finalRadius)
|
||||||
|
curRadius = newRadius;
|
||||||
|
else
|
||||||
|
curRadius = finalRadius;
|
||||||
|
|
||||||
|
drawRoundedRect(ctx, x + 1, y + 1, finalWidth - 2, finalHeight - 2, finalRadius, "#2e8cdd");
|
||||||
|
|
||||||
|
drawRoundedRect(ctx, x + (finalWidth - curWidth) / 2, y + (finalHeight - curHeight) / 2, curWidth, curHeight, curRadius, color);
|
||||||
|
|
||||||
|
requestAnimFrame(() => {
|
||||||
|
animateTile(x, y, curWidth, curHeight, finalWidth, finalHeight, curRadius, finalRadius, startTime, duration, color);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function animateText(text, x, y, curFontSize, finalFontSize, startTime, duration, color, font, context) {
|
||||||
|
const time = (new Date()).getTime() - startTime;
|
||||||
|
|
||||||
|
if(context === undefined)
|
||||||
|
context = ctx;
|
||||||
|
|
||||||
|
if (curFontSize === finalFontSize)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const newFontSize = easeInOutCubic(time, 0, finalFontSize, duration);
|
||||||
|
|
||||||
|
if (newFontSize < finalFontSize) {
|
||||||
|
curFontSize = newFontSize;
|
||||||
|
} else {
|
||||||
|
curFontSize = finalFontSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(let x = 0; x < fieldSize.x; x++) {
|
if (font === undefined)
|
||||||
|
font = "Roboto";
|
||||||
|
|
||||||
|
context.fillStyle = color;
|
||||||
|
context.font = "bold " + curFontSize + "px " + font;
|
||||||
|
context.textAlign = "center";
|
||||||
|
context.fillText(text, x, y + tileSize.y * .5 + curFontSize * .33);
|
||||||
|
|
||||||
|
requestAnimFrame(function () {
|
||||||
|
animateText(text, x, y, curFontSize, finalFontSize, startTime, duration, color, font, context);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function countClickedTiles() {
|
||||||
|
let count = 0;
|
||||||
|
for (let x = 0; x < fieldSize.x; x++) {
|
||||||
for (let y = 0; y < fieldSize.y; y++) {
|
for (let y = 0; y < fieldSize.y; y++) {
|
||||||
if (field[x][y].tileValue !== true) {
|
if (field[x][y].clicked && !field[x][y].flagged)
|
||||||
field[x][y].tileValue = countBombs(x, y);
|
count++;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
return count;
|
||||||
|
|
||||||
function drawGrid() {
|
|
||||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
||||||
for(let x = 0; x < fieldSize.x; x++) {
|
|
||||||
for (let y = 0; y < fieldSize.y; y++) {
|
|
||||||
ctx.strokeRect(x * tileSize.x, y * tileSize.y, tileSize.x, tileSize.y);
|
|
||||||
if(field[x][y].clicked)
|
|
||||||
drawText(x, y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getSurroundingTiles(x, y) {
|
|
||||||
const tiles = {};
|
|
||||||
if(x > 0) {
|
|
||||||
tiles["left"] = { tileValue: field[x - 1][y], x: x - 1, y: y };
|
|
||||||
if(y > 0) {
|
|
||||||
tiles["left-top"] = { tileValue: field[x - 1][y - 1], x: x - 1, y: y - 1 };
|
|
||||||
}
|
|
||||||
if(y < fieldSize.y - 1) {
|
|
||||||
tiles["left-bottom"] = { tileValue: field[x - 1][y + 1], x: x - 1, y: y + 1 };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(x < fieldSize.x - 1) {
|
|
||||||
tiles["right"] = { tileValue: field[x + 1][y], x: x + 1, y: y};
|
|
||||||
if(y > 0)
|
|
||||||
tiles["right-top"] = { tileValue: field[x + 1][y - 1], x: x + 1, y: y - 1 };
|
|
||||||
if(y < fieldSize.y - 1)
|
|
||||||
tiles["right-bottom"] = { tileValue: field[x + 1][y + 1], x: x + 1, y: y + 1 };
|
|
||||||
}
|
|
||||||
if(y > 0)
|
|
||||||
tiles["top"] = { tileValue: field[x][y - 1], x: x, y: y - 1 };
|
|
||||||
if(y < fieldSize.y - 1)
|
|
||||||
tiles["bottom"] = { tileValue: field[x][y + 1], x: x, y: y + 1 };
|
|
||||||
return tiles;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function countBombs(x, y) {
|
function countBombs(x, y) {
|
||||||
@@ -94,10 +136,236 @@ function countFlaggedBombs(x, y) {
|
|||||||
return tiles.countFlagged(true);
|
return tiles.countFlagged(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function drawGrid() {
|
||||||
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||||
|
for (let x = 0; x < fieldSize.x; x++) {
|
||||||
|
for (let y = 0; y < fieldSize.y; y++) {
|
||||||
|
drawTile(x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawRoundedRect(context, x, y, w, h, r, color) {
|
||||||
|
context.fillStyle = color;
|
||||||
|
context.beginPath();
|
||||||
|
context.moveTo(x + r, y);
|
||||||
|
|
||||||
|
context.arcTo(x + w, y, x + w, y + h, r);
|
||||||
|
context.arcTo(x + w, y + h, x, y + h, r);
|
||||||
|
context.arcTo(x, y + h, x, y, r);
|
||||||
|
context.arcTo(x, y, x + w, y, r);
|
||||||
|
|
||||||
|
context.closePath();
|
||||||
|
context.fill();
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawTile(x, y) {
|
||||||
|
const fontSize = tileSize.y * scaleFactor;
|
||||||
|
ctx.textAlign = "center";
|
||||||
|
if (!field[x][y].flagged && field[x][y].clicked) {
|
||||||
|
animateTile(x * tileSize.x + .1 * tileSize.x, y * tileSize.y + .1 * tileSize.y,
|
||||||
|
0, 0,
|
||||||
|
tileSize.x - (.2 * tileSize.x), tileSize.y - (.2 * tileSize.y),
|
||||||
|
0, tileSize.x * .1,
|
||||||
|
new Date().getTime(), 150, "#ddd");
|
||||||
|
setTimeout(() => {
|
||||||
|
|
||||||
|
}, 151);
|
||||||
|
if (field[x][y].tileValue !== 0) {
|
||||||
|
animateText(field[x][y].tileValue, (x + .5) * tileSize.x, y * tileSize.y, 0, fontSize, new Date().getTime(), 150, colors[field[x][y].tileValue]);
|
||||||
|
setTimeout(() => {
|
||||||
|
animateText(field[x][y].tileValue, (x + .5) * tileSize.x, y * tileSize.y, fontSize, fontSize, new Date().getTime(), 1, colors[field[x][y].tileValue]);
|
||||||
|
}, 151);
|
||||||
|
}
|
||||||
|
} else if (field[x][y].flagged) {
|
||||||
|
animateTile(x * tileSize.x + .1 * tileSize.x, y * tileSize.y + .1 * tileSize.y,
|
||||||
|
0, 0,
|
||||||
|
tileSize.x - (.2 * tileSize.x), tileSize.y - (.2 * tileSize.y),
|
||||||
|
0, tileSize.x * .1,
|
||||||
|
new Date().getTime(), 150, "#ff0000");
|
||||||
|
|
||||||
|
animateText("", (x + .5) * tileSize.x, y * tileSize.y, 0, fontSize, new Date().getTime(), 150, "white", "FontAwesome");
|
||||||
|
} else {
|
||||||
|
drawRoundedRect(ctx, x * tileSize.x + (.1 * tileSize.x), y * tileSize.y + (.1 * tileSize.y), tileSize.x - (.2 * tileSize.x), tileSize.y - (.2 * tileSize.y), tileSize.x * .1, "#2e8cdd");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function easeInOutCubic(t, b, c, d) {
|
||||||
|
t /= d;
|
||||||
|
t--;
|
||||||
|
return c * (Math.pow(t, 3) + 1) + b;
|
||||||
|
}
|
||||||
|
|
||||||
|
function gameOverEvent() {
|
||||||
|
console.log("Game Over");
|
||||||
|
animateBackground(0, 0, canvas.width, canvas.height, 0, .75, new Date().getTime(), 200, {r: 0, g: 0, b: 0, a: 0});
|
||||||
|
animateText("Game Over", canvas.width / 2, canvas.height / 2, 0, tileSize.y * 1.33, new Date().getTime(), 200, "orange", "Roboto", overlay2Ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPositon(e) {
|
||||||
|
const x = e.x - canvas.offsetLeft;
|
||||||
|
const y = e.y - canvas.offsetTop;
|
||||||
|
const fieldX = Math.floor(x / tileSize.x);
|
||||||
|
const fieldY = Math.floor(y / tileSize.y);
|
||||||
|
|
||||||
|
return {x: fieldX, y: fieldY};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSurroundingTiles(x, y) {
|
||||||
|
const tiles = {};
|
||||||
|
if (x > 0) {
|
||||||
|
tiles["left"] = {tileValue: field[x - 1][y], x: x - 1, y: y};
|
||||||
|
if (y > 0) {
|
||||||
|
tiles["left-top"] = {tileValue: field[x - 1][y - 1], x: x - 1, y: y - 1};
|
||||||
|
}
|
||||||
|
if (y < fieldSize.y - 1) {
|
||||||
|
tiles["left-bottom"] = {tileValue: field[x - 1][y + 1], x: x - 1, y: y + 1};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (x < fieldSize.x - 1) {
|
||||||
|
tiles["right"] = {tileValue: field[x + 1][y], x: x + 1, y: y};
|
||||||
|
if (y > 0)
|
||||||
|
tiles["right-top"] = {tileValue: field[x + 1][y - 1], x: x + 1, y: y - 1};
|
||||||
|
if (y < fieldSize.y - 1)
|
||||||
|
tiles["right-bottom"] = {tileValue: field[x + 1][y + 1], x: x + 1, y: y + 1};
|
||||||
|
}
|
||||||
|
if (y > 0)
|
||||||
|
tiles["top"] = {tileValue: field[x][y - 1], x: x, y: y - 1};
|
||||||
|
if (y < fieldSize.y - 1)
|
||||||
|
tiles["bottom"] = {tileValue: field[x][y + 1], x: x, y: y + 1};
|
||||||
|
return tiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes game by creating the game field and setting bombs
|
||||||
|
*/
|
||||||
|
function initGame() {
|
||||||
|
for (let x = 0; x < fieldSize.x; x++) {
|
||||||
|
field.push([]);
|
||||||
|
for (let y = 0; y < fieldSize.y; y++) {
|
||||||
|
field[x].push({tileValue: 0, clicked: false, flagged: false});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
scaleCanvas();
|
||||||
|
initBalls();
|
||||||
|
}
|
||||||
|
|
||||||
|
function initBombs(startX, startY) {
|
||||||
|
for (let i = 0; i < bombCount; i++) {
|
||||||
|
const ranX = Math.floor(Math.random() * fieldSize.x);
|
||||||
|
const ranY = Math.floor(Math.random() * fieldSize.y);
|
||||||
|
|
||||||
|
if (ranX === startX || ranX === startX - 1 || ranX === startX + 1 || ranY === startY || ranY === startY - 1 || ranY === startY + 1 || field[ranX][ranY].tileValue === true) {
|
||||||
|
i--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
field[ranX][ranY].tileValue = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let x = 0; x < fieldSize.x; x++) {
|
||||||
|
for (let y = 0; y < fieldSize.y; y++) {
|
||||||
|
if (field[x][y].tileValue !== true) {
|
||||||
|
field[x][y].tileValue = countBombs(x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function scaleCanvas() {
|
||||||
|
tileSize = {x: window.innerWidth / fieldSize.x * .9, y: window.innerWidth / fieldSize.x * .9};
|
||||||
|
|
||||||
|
W = fieldSize.x * tileSize.x;
|
||||||
|
H = fieldSize.y * tileSize.y;
|
||||||
|
|
||||||
|
canvas.width = W;
|
||||||
|
canvas.height = H;
|
||||||
|
overlayCanvas.width = W;
|
||||||
|
overlayCanvas.height = H;
|
||||||
|
overlay2Canvas.width = W;
|
||||||
|
overlay2Canvas.height = H;
|
||||||
|
|
||||||
|
drawGrid();
|
||||||
|
if (gameOver) {
|
||||||
|
gameOverEvent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function tileClickEvent(x, y) {
|
||||||
|
if (gameOver)
|
||||||
|
return;
|
||||||
|
uncoverTile(x, y);
|
||||||
|
if (!field[x][y].flagged && field[x][y].tileValue === true) {
|
||||||
|
gameOver = true;
|
||||||
|
gameOverEvent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function tileDoubleClick(x, y) {
|
||||||
|
if (gameOver)
|
||||||
|
return;
|
||||||
|
if (field[x][y].clicked && !field[x][y].flagged && countFlaggedBombs(x, y) === field[x][y].tileValue) {
|
||||||
|
uncoverSurroundings(x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function tileFlag(x, y) {
|
||||||
|
if (gameOver)
|
||||||
|
return;
|
||||||
|
if (field[x][y].clicked && !field[x][y].flagged)
|
||||||
|
return;
|
||||||
|
field[x][y].flagged = !field[x][y].flagged;
|
||||||
|
field[x][y].clicked = field[x][y].flagged;
|
||||||
|
ctx.clearRect(x * tileSize.x + (1 / scaleFactor), y * tileSize.y + (1 / scaleFactor), tileSize.x - (2 / scaleFactor), tileSize.y - (2 / scaleFactor));
|
||||||
|
drawTile(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
function uncoverSurroundings(x, y) {
|
||||||
|
const surrounding = getSurroundingTiles(x, y);
|
||||||
|
for (let tile in surrounding) {
|
||||||
|
if (surrounding.hasOwnProperty(tile)) {
|
||||||
|
uncoverTile(surrounding[tile].x, surrounding[tile].y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function uncoverTile(x, y) {
|
||||||
|
if (field[x][y].clicked || field[x][y].flagged) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
field[x][y].clicked = true;
|
||||||
|
drawTile(x, y);
|
||||||
|
if (field[x][y].tileValue === true) {
|
||||||
|
gameOverEvent();
|
||||||
|
}
|
||||||
|
if (field[x][y].tileValue === 0) {
|
||||||
|
setTimeout(() => {
|
||||||
|
uncoverSurroundings(x, y);
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function victoryCheck() {
|
||||||
|
if (!victory && countClickedTiles() === fieldSize.x * fieldSize.y - bombCount) {
|
||||||
|
victory = true;
|
||||||
|
victoryEvent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function victoryEvent() {
|
||||||
|
console.log("Win!");
|
||||||
|
animate();
|
||||||
|
play = false;
|
||||||
|
const fontSize = tileSize.y * 1.33;
|
||||||
|
animateBackground(0, 0, canvas.width, canvas.height, 0, .01, new Date().getTime(), 200, {r: 0, g: 0, b: 0, a: 0});
|
||||||
|
animateText("Victory!", canvas.width / 2, canvas.height / 2 - fontSize / 2, 0, fontSize, new Date().getTime(), 200, "green", "Roboto", overlay2Ctx);
|
||||||
|
}
|
||||||
|
|
||||||
Object.prototype.count = function (val) {
|
Object.prototype.count = function (val) {
|
||||||
let counter = 0;
|
let counter = 0;
|
||||||
for(let el in this) {
|
for (let el in this) {
|
||||||
if(this.hasOwnProperty(el)) {
|
if (this.hasOwnProperty(el)) {
|
||||||
if (val === this[el].tileValue.tileValue) {
|
if (val === this[el].tileValue.tileValue) {
|
||||||
counter++;
|
counter++;
|
||||||
}
|
}
|
||||||
@@ -108,9 +376,9 @@ Object.prototype.count = function (val) {
|
|||||||
|
|
||||||
Object.prototype.countFlagged = function (val) {
|
Object.prototype.countFlagged = function (val) {
|
||||||
let counter = 0;
|
let counter = 0;
|
||||||
for(let el in this) {
|
for (let el in this) {
|
||||||
if(this.hasOwnProperty(el)) {
|
if (this.hasOwnProperty(el)) {
|
||||||
if(this[el].tileValue.flagged === val) {
|
if (this[el].tileValue.flagged === val) {
|
||||||
counter++;
|
counter++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -118,40 +386,10 @@ Object.prototype.countFlagged = function (val) {
|
|||||||
return counter;
|
return counter;
|
||||||
};
|
};
|
||||||
|
|
||||||
function tileClickEvent(x, y) {
|
|
||||||
if(gameOver)
|
|
||||||
return;
|
|
||||||
uncoverTile(x, y);
|
|
||||||
if(!field[x][y].flagged && field[x][y].tileValue === true) {
|
|
||||||
gameOver = true;
|
|
||||||
gameOverEvent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function tileDoubleClick(x, y) {
|
|
||||||
if(gameOver)
|
|
||||||
return;
|
|
||||||
if(field[x][y].clicked && !field[x][y].flagged && countFlaggedBombs(x, y) === field[x][y].tileValue) {
|
|
||||||
uncoverSurroundings(x, y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function tileFlag(x, y) {
|
|
||||||
if(gameOver)
|
|
||||||
return;
|
|
||||||
if(field[x][y].clicked && !field[x][y].flagged)
|
|
||||||
return;
|
|
||||||
field[x][y].flagged = !field[x][y].flagged;
|
|
||||||
field[x][y].clicked = field[x][y].flagged;
|
|
||||||
ctx.clearRect(x * tileSize.x + (1 / scaleFactor), y * tileSize.y + (1 / scaleFactor), tileSize.x - (2 / scaleFactor), tileSize.y - (2 / scaleFactor));
|
|
||||||
drawText(x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
overlay2Canvas.addEventListener("click", (e) => {
|
overlay2Canvas.addEventListener("click", (e) => {
|
||||||
const pos = getPositon(e);
|
const pos = getPositon(e);
|
||||||
|
|
||||||
if(isFirstClick) {
|
if (isFirstClick) {
|
||||||
initBombs(pos.x, pos.y);
|
initBombs(pos.x, pos.y);
|
||||||
isFirstClick = false;
|
isFirstClick = false;
|
||||||
}
|
}
|
||||||
@@ -173,161 +411,14 @@ overlay2Canvas.addEventListener("dblclick", (e) => {
|
|||||||
|
|
||||||
overlay2Canvas.addEventListener("contextmenu", (e) => {
|
overlay2Canvas.addEventListener("contextmenu", (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
console.log(e);
|
|
||||||
|
|
||||||
const pos = getPositon(e);
|
const pos = getPositon(e);
|
||||||
|
|
||||||
tileFlag(pos.x, pos.y);
|
tileFlag(pos.x, pos.y);
|
||||||
});
|
});
|
||||||
|
|
||||||
function getPositon(e) {
|
|
||||||
const x = e.x - canvas.offsetLeft;
|
|
||||||
const y = e.y - canvas.offsetTop;
|
|
||||||
const fieldX = Math.floor(x / tileSize.x);
|
|
||||||
const fieldY = Math.floor(y / tileSize.y);
|
|
||||||
|
|
||||||
return {x: fieldX, y: fieldY};
|
|
||||||
}
|
|
||||||
|
|
||||||
function scaleCanvas() {
|
|
||||||
canvas.width = window.innerWidth;
|
|
||||||
canvas.height = window.innerHeight;
|
|
||||||
overlayCanvas.width = window.innerWidth;
|
|
||||||
overlayCanvas.height = window.innerHeight;
|
|
||||||
|
|
||||||
W = window.innerWidth;
|
|
||||||
H = window.innerHeight;
|
|
||||||
|
|
||||||
// tileSize = {x: canvas.width / fieldSize.x, y: canvas.height / fieldSize.y};
|
|
||||||
tileSize = {x: 100, y: 100};
|
|
||||||
drawGrid();
|
|
||||||
if(gameOver) {
|
|
||||||
gameOverEvent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function uncoverTile(x, y) {
|
|
||||||
if(field[x][y].clicked || field[x][y].flagged) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
field[x][y].clicked = true;
|
|
||||||
drawText(x, y);
|
|
||||||
if(field[x][y].tileValue === true) {
|
|
||||||
gameOverEvent();
|
|
||||||
}
|
|
||||||
if(field[x][y].tileValue === 0) {
|
|
||||||
uncoverSurroundings(x, y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function uncoverSurroundings(x, y) {
|
|
||||||
const surrounding = getSurroundingTiles(x, y);
|
|
||||||
for(let tile in surrounding) {
|
|
||||||
if(surrounding.hasOwnProperty(tile)) {
|
|
||||||
uncoverTile(surrounding[tile].x, surrounding[tile].y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const colors = {
|
|
||||||
1: "blue",
|
|
||||||
2: "green",
|
|
||||||
3: "red",
|
|
||||||
4: "purple",
|
|
||||||
5: "yellow",
|
|
||||||
6: "pink"
|
|
||||||
};
|
|
||||||
|
|
||||||
function drawText(x, y) {
|
|
||||||
ctx.font = "bold 50px Roboto";
|
|
||||||
ctx.textAlign = "center";
|
|
||||||
if(!field[x][y].flagged && field[x][y].clicked) {
|
|
||||||
ctx.fillStyle = "#ddd";
|
|
||||||
ctx.fillRect(x * tileSize.x + 1, y * tileSize.y + 1, tileSize.x - 2, tileSize.y - 2);
|
|
||||||
if (field[x][y].tileValue !== 0) {
|
|
||||||
ctx.fillStyle = colors[field[x][y].tileValue];
|
|
||||||
ctx.fillText(field[x][y].tileValue, (x + .5) * tileSize.x, (y + .5) * tileSize.y + 15);
|
|
||||||
}
|
|
||||||
} else if(field[x][y].flagged) {
|
|
||||||
ctx.fillStyle = "red";
|
|
||||||
ctx.fillRect(x * tileSize.x + 5 / scaleFactor, y * tileSize.y + 5 / scaleFactor, tileSize.x - 10 / scaleFactor, tileSize.y - 10 / scaleFactor);
|
|
||||||
|
|
||||||
ctx.font = "bold 50px FontAwesome";
|
|
||||||
ctx.fillStyle = "white";
|
|
||||||
ctx.fillText("", (x + .5) * tileSize.x, (y + .5) * tileSize.y + 15);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
window.addEventListener("resize", () => {
|
window.addEventListener("resize", () => {
|
||||||
scaleCanvas();
|
scaleCanvas();
|
||||||
});
|
});
|
||||||
|
|
||||||
function gameOverEvent() {
|
|
||||||
console.log("Game Over");
|
|
||||||
ctx.fillStyle = "orange";
|
|
||||||
ctx.fillText("Game Over", canvas.width / 2, canvas.height / 2);
|
|
||||||
animateBackground({r: 0, g: 0, b: 0, a: 0}, 0, 0, canvas.width, canvas.height, .75, new Date().getTime(), 2);
|
|
||||||
animateText("Game Over", canvas.width / 2, canvas.height / 2, 0, 100, new Date().getTime(), 200);
|
|
||||||
}
|
|
||||||
|
|
||||||
function animateText(text, x, y, curFontSize, finalFontSize, startTime, speed) {
|
|
||||||
const time = (new Date()).getTime() - startTime;
|
|
||||||
|
|
||||||
const newFontSize = speed * time / 1000;
|
|
||||||
|
|
||||||
if(newFontSize < finalFontSize) {
|
|
||||||
curFontSize = newFontSize;
|
|
||||||
} else {
|
|
||||||
curFontSize = finalFontSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
// drawGrid();
|
|
||||||
ctx.fillStyle = "orange";
|
|
||||||
ctx.font = "bold " + curFontSize + "px Roboto";
|
|
||||||
ctx.fillText(text, x, y);
|
|
||||||
|
|
||||||
requestAnimFrame(function () {
|
|
||||||
animateText(text, x, y, curFontSize, finalFontSize, startTime, speed);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function animateBackground(color, x, y, width, height, maxOpacity, startTime, speed) {
|
|
||||||
const time = (new Date()).getTime() - startTime;
|
|
||||||
|
|
||||||
const newOpacity = speed * time / 1000;
|
|
||||||
|
|
||||||
if(newOpacity <= maxOpacity) color.a = newOpacity;
|
|
||||||
|
|
||||||
drawGrid();
|
|
||||||
ctx.fillStyle = "rgba(" + color.r + "," + color.g + "," + color.b + "," + color.a + ")";
|
|
||||||
ctx.fillRect(x, y, width, height);
|
|
||||||
|
|
||||||
requestAnimFrame(function () {
|
|
||||||
animateBackground(color, x, y, width, height, maxOpacity, startTime, speed);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function countClickedTiles() {
|
|
||||||
let count = 0;
|
|
||||||
for(let x = 0; x < fieldSize.x; x++) {
|
|
||||||
for(let y = 0; y < fieldSize.y; y++) {
|
|
||||||
if(field[x][y].clicked && !field[x][y].flagged)
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
function victoryCheck() {
|
|
||||||
if(!victory && countClickedTiles() === fieldSize.x * fieldSize.y - bombCount) {
|
|
||||||
victory = true;
|
|
||||||
victoryEvent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function victoryEvent() {
|
|
||||||
console.log("Win!");
|
|
||||||
animate();
|
|
||||||
}
|
|
||||||
|
|
||||||
initGame();
|
initGame();
|
Reference in New Issue
Block a user