The main game and server connections are working

This commit is contained in:
Arne van Iterson 2020-11-08 13:23:38 +01:00
parent 4dc5ed358c
commit c19f2dbcc3
12 changed files with 6413 additions and 0 deletions

35
.eslintrc.js Normal file
View File

@ -0,0 +1,35 @@
module.exports = {
"env": {
"browser": true,
"commonjs": true,
"es6": true,
"node": true
},
"extends": "eslint:recommended",
"globals": {
"Atomics": "readonly",
"SharedArrayBuffer": "readonly"
},
"parserOptions": {
"ecmaVersion": 2018,
"sourceType": "module",
},
"rules": {
"indent": [
"error",
4
],
"linebreak-style": [
"error",
"unix"
],
"quotes": [
"error",
"double"
],
"semi": [
"error",
"always"
]
}
};

1
.gitignore vendored
View File

@ -106,4 +106,5 @@ dist
# Stores VSCode versions used for testing VSCode extensions
.vscode-test
*.code-workspace

27
html/index.html Normal file
View File

@ -0,0 +1,27 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Minesweeper 99</title>
</head>
<body>
<h1><i class="fas fa-bomb"></i>Minesweeper 99</h1>
<div id="main">
<div id="board">
<!-- Renderer will push content here -->
</div>
<div id="log">
<h2>Gamelog</h2>
<!-- Game log will be pushed here -->
</div>
</div>
<script src="/main.js"></script>
</body>
</html>

5970
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

31
package.json Normal file
View File

@ -0,0 +1,31 @@
{
"name": "minesweeper",
"version": "1.0.0",
"description": "Real actual competitive minesweeper in Node.JS. Flagging a mine correctly will send it to one of the other players.",
"main": "src/index.js",
"scripts": {
"start": "webpack serve",
"lint": "eslint .",
"build": "webpack"
},
"repository": {
"type": "git",
"url": "https://gitea.arnweb.nl/arne/minesweeper.git"
},
"author": "Arne van Iterson",
"license": "GPL-3.0-or-later",
"dependencies": {
"css-loader": "^5.0.1",
"eslint": "^7.12.1",
"file-loader": "^6.2.0",
"jquery": "^3.5.1",
"node-sass": "^5.0.0",
"sass": "^1.29.0",
"sass-loader": "^10.0.5",
"socket.io-client": "^3.0.0",
"style-loader": "^2.0.0",
"webpack": "^5.4.0",
"webpack-cli": "^4.2.0",
"webpack-dev-server": "^3.11.0"
}
}

69
scss/index.scss Normal file
View File

@ -0,0 +1,69 @@
body {
font-family: 'Courier New', Courier, monospace;
background: #121212;
color: lightgray;
// * {
// border: 1px solid white;
// }
h1 {
text-align: center;
}
div#main {
height: 100%;
width: max-content;
display: grid;
grid-template-columns: auto auto;
column-gap: 1em;
margin: 0 auto;
div {
padding: 1em;
border-radius: 0.75em;
background-color: #1E1E1E;
&#board {
text-align: center;
width: min-content;
display: grid;
grid-template-columns: auto auto auto auto auto auto auto auto auto auto auto auto auto auto auto;
column-gap: 0.25em;
row-gap: 0.25em;
span.cell {
border: 1px solid grey;
color: lightgray;
text-align: center;
width: 1em;
height: 1em;
padding: 0.5em;
border-radius: 0.25em;
&.discovered {
background-color: #5c5c5c;
}
&.bomb {
background-color: #5e3030;
}
}
}
&#log {
font-size: 12px;
width: 20vw;
h2 {
text-align: center;
}
span {
display: block;
width: 100%;
color: darkgray;
padding-bottom: 0.5em;
&.error {
color: red;
}
&.alert {
color: orange;
}
&.success {
color: cyan;
}
}
}
}
}
}

8
src/helpers/log.js Normal file
View File

@ -0,0 +1,8 @@
function log(message, type) {
var child = document.createElement("span");
child.innerHTML = "- " + message;
child.className = type;
document.getElementById("log").appendChild(child);
}
export default log;

View File

@ -0,0 +1,65 @@
/* eslint-disable no-unused-vars */
import io from "socket.io-client";
import log from "./log.js";
class Multiplayer {
constructor() {
// Keep local and external players
this.players = [];
this.connected = false;
this.game;
// Connect to TanksJS-Server instance
log("Connecting to server...");
this.socket = io("http://localhost:3000");
this.socket.on("identify", () => {
this.socket.emit("identification", {
name: "Arn",
playersMax: 2,
gameID: "ms99"
});
log(`Connected to server as ${this.socket.id}`, "success");
this.connected = true;
this.game.active = true;
});
// Handle player logins
this.socket.on("roomUpdate", (data) => {
console.log("roomUpdate");
// Add any player that is not the local player and is not already added
for (const id in data) {
if (id != this.socket.id && this.players.indexOf(id)) {
console.log(id);
this.players.push(id);
console.log(this.players);
}
}
// Remove any player that disconnects from the game
for (const id in this.players) {
if (data[id] == undefined) {
var index = this.players.indexOf(id);
this.players.splice(index, 1);
console.log(this.players);
}
}
});
// Handle player updates
this.socket.on("update", (data) => {
console.log("update");
});
// Start game
this.socket.on("gameStart", () => {
console.log("gameStart");
});
}
setInstance(game) {
this.game = game;
log("Game instance initialized");
}
}
export default Multiplayer;

11
src/index.js Normal file
View File

@ -0,0 +1,11 @@
/* eslint-disable no-unused-vars */
import "../scss/index.scss";
import log from "./helpers/log.js";
import Game from "./screens/game.js";
import Multiplayer from "./helpers/multiplayer.js";
var board = document.getElementById("board");
var mp = new Multiplayer();
var game = new Game(board);
mp.setInstance(game);

133
src/screens/game.js Normal file
View File

@ -0,0 +1,133 @@
import * as math from "../utilities/math.js";
import log from "../helpers/log.js";
class Game {
constructor(element) {
this.board = element;
this.children = element.children;
this.active = false;
this.sides = 15;
this.size = Math.pow(this.sides, 2);
this.bombAmount = 35;
this.bombs = [];
this.discovered = [];
for (let cell = 0; cell < this.size; cell++) {
this.bombs.push(0);
this.discovered.push(0);
var child = document.createElement("span");
child.className = "cell";
child.addEventListener("click", () => {
this.discover(cell);
});
this.board.appendChild(child);
}
for (let index = 0; index < this.bombAmount; index++) {
var rand = math.default.rand(0, this.size);
this.bombs[rand] = 1;
}
console.log(this.bombs);
console.log(this.discovered);
}
discover(cell) {
if (this.active && !this.discovered[cell]) {
this.discovered[cell] = 1;
this.children[cell].classList.add("discovered");
if (this.bombs[cell]) {
log("Game over", "error");
this.active = false;
for (let index = 0; index < this.size; index++) {
if (this.bombs[index]) {
this.children[index].innerHTML = "[]";
this.children[index].classList.add("bomb");
}
}
return;
}
var surrounds = [];
var limit = {
top: true,
bottom: true
};
if (!(cell - this.sides < 0)) {
// Cell is not on top of the map
limit.top = false;
surrounds.push(
cell - this.sides
);
}
if (!(cell + this.sides > this.size - 1)) {
// Cell is not on the bottom of the map
limit.bottom = false;
surrounds.push(
cell + this.sides
);
}
if (cell % this.sides === 0) {
// Cell is on the left side of the map
surrounds.push(cell + 1);
if (!limit.top) {
surrounds.push(cell - this.sides + 1);
}
if (!limit.bottom) {
surrounds.push(cell + this.sides + 1);
}
} else if ((cell + 1) % this.sides === 0 ) {
// Cell is on the right side of the map
surrounds.push(cell - 1);
if (!limit.top) {
surrounds.push(cell - this.sides - 1);
}
if (!limit.bottom) {
surrounds.push(cell + this.sides - 1);
}
} else {
// Cell is not on either sides of the map
surrounds.push(cell - 1);
surrounds.push(cell + 1);
if (!limit.top) {
surrounds.push(cell - this.sides - 1);
surrounds.push(cell - this.sides + 1);
}
if (!limit.bottom) {
surrounds.push(cell + this.sides - 1);
surrounds.push(cell + this.sides + 1);
}
}
var value = 0;
surrounds.forEach((number) => {
if (number != cell) {
if (this.bombs[number]) {
value++;
}
}
});
if (value == 0) {
surrounds.forEach((number) => {
if (number != cell) {
this.discover(number);
}
});
} else {
this.children[cell].innerHTML = String(value);
}
}
}
}
export default Game;

48
src/utilities/math.js Normal file
View File

@ -0,0 +1,48 @@
function angle(a, b) {
const dx = a.x - b.x;
const dy = a.y - b.y;
const angle = Math.atan2(dy, dx);
return angle;
}
function clamp(x, min, max) {
return Math.max(min, Math.min(x, max));
}
function distance(a, b) {
const dx = a.x - b.x;
const dy = a.y - b.y;
return Math.sqrt(dx * dx + dy * dy);
}
function rand(min, max) {
return Math.floor(randf(min, max));
}
function randf(min, max) {
if (max == null) {
max = min || 1;
min = 0;
}
return Math.random() * (max - min) + min;
}
function randOneFrom(items) {
return items[rand(items.length)];
}
function randOneIn(max = 2) {
return rand(0, max) === 0;
}
export default {
angle,
clamp,
distance,
rand,
randf,
randOneFrom,
randOneIn
};

15
webpack.config.js Normal file
View File

@ -0,0 +1,15 @@
module.exports = {
module: {
rules: [{
test: /\.s[ac]ss$/i,
use: [
// Creates `style` nodes from JS strings
"style-loader",
// Translates CSS into CommonJS
"css-loader",
// Compiles Sass to CSS
"sass-loader",
],
}, ]
}
};