Good progress on UI and making this thing actually work.
|
@ -4,10 +4,10 @@ import {roomManager} from "./roomManager.mjs"
|
|||
import { World} from "./world/world.mjs"
|
||||
|
||||
export class Game {
|
||||
constructor(name) {
|
||||
this.name = name;
|
||||
constructor(id, options) {
|
||||
this.id = id;
|
||||
this.players = [];
|
||||
this.world = new World([16,16])
|
||||
this.world = new World(options)
|
||||
}
|
||||
|
||||
addPlayer(id, name) {
|
||||
|
@ -22,7 +22,7 @@ export class Game {
|
|||
this.players = this.players.filter(obj => obj.id != id);
|
||||
log.log("removed player - " + id)
|
||||
if (this.players.length < 1) {
|
||||
roomManager.removeGame(this.name);
|
||||
roomManager.removeGameByID(this.id);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,15 +40,4 @@ export class Game {
|
|||
}
|
||||
return names
|
||||
}
|
||||
|
||||
getSettings() {
|
||||
const settings =
|
||||
{
|
||||
mines: this.world.mines,
|
||||
dimensions: this.world.dimensions,
|
||||
name: this.name
|
||||
}
|
||||
return settings
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,33 +1,31 @@
|
|||
import {Game} from "./game.mjs"
|
||||
import * as log from "./log.mjs"
|
||||
import * as util from "./util.mjs"
|
||||
import {IllegalAction} from "./server/illegalAction.mjs"
|
||||
class RoomManager {
|
||||
constructor(){
|
||||
this.games = [];
|
||||
}
|
||||
getGameByName(name, create) {
|
||||
const game = this.games.filter(obj => obj.name == name)[0]
|
||||
if (game === undefined && create) {
|
||||
this.addGame(name);
|
||||
// Oh no.... This cant be good code.
|
||||
// Coming back to it two months later. Horrible, but I don't know how to fix it. Maybe I'll leave it as an ancient artifact.
|
||||
return this.getGameByName(name);
|
||||
getGameByID(id) {
|
||||
const game = this.games.filter(obj => obj.id == id)[0]
|
||||
if (game === undefined) {
|
||||
return false
|
||||
}
|
||||
return game
|
||||
}
|
||||
|
||||
addGame(name, settings) {
|
||||
const game = new Game(name, settings);
|
||||
addGame(id, options) {
|
||||
const game = new Game(id, options);
|
||||
this.games.push(game);
|
||||
return game
|
||||
}
|
||||
removeGame(name) {
|
||||
this.games = this.games.filter(obj => obj.name != name);
|
||||
log.log("removed game - " + name)
|
||||
// Broken?
|
||||
removeGameByID(id) {
|
||||
this.games = this.games.filter(obj => obj.id != id);
|
||||
log.log("removed game - " + id)
|
||||
|
||||
}
|
||||
|
||||
getAllIDs() {
|
||||
getAllPlayerIDs() {
|
||||
let ids = []
|
||||
for (let i = 0; i < this.games.length; i++) {
|
||||
for (let j = 0; j < this.games[i].players.length; j++) {
|
||||
|
@ -37,26 +35,44 @@ class RoomManager {
|
|||
return ids
|
||||
}
|
||||
|
||||
joinClientToGame(room, nick, id, client) {
|
||||
if (this.getAllIDs().includes(id)) {
|
||||
getAllGameIDs() {
|
||||
let ids = []
|
||||
for (let i = 0; i < this.games.length; i++) {
|
||||
ids.push(this.games[i].id)
|
||||
}
|
||||
return ids
|
||||
}
|
||||
|
||||
playerJoinGame(roomCode, playerName, playerID) {
|
||||
// See if the client is already in a game
|
||||
console.log(roomCode, playerName)
|
||||
if (this.getAllPlayerIDs().includes(playerID)) {
|
||||
return new IllegalAction(id, 22)
|
||||
}
|
||||
if (nick.length > 9) {
|
||||
return new IllegalAction(id, 21)
|
||||
if (!this.getAllGameIDs().includes(roomCode)) {
|
||||
return new IllegalAction(id, 30)
|
||||
}
|
||||
const game = this.getGameByName(room, true);
|
||||
const player = game.addPlayer(id, nick);
|
||||
const game = this.getGameByID(roomCode);
|
||||
const player = game.addPlayer(playerID, playerName);
|
||||
// See if player name is taken already
|
||||
if (player === false) {
|
||||
this.removeGame(game)
|
||||
return new IllegalAction(id, 20)
|
||||
}
|
||||
|
||||
client.join(game.name)
|
||||
client.game = game;
|
||||
client.player = player
|
||||
return true
|
||||
return [game, player]
|
||||
}
|
||||
|
||||
playerCreateGame(options, playerName, playerID) {
|
||||
if (this.getAllPlayerIDs().includes(playerID)) {
|
||||
return new IllegalAction(id, 22)
|
||||
}
|
||||
console.log(options)
|
||||
const id = util.createCode()
|
||||
const game = this.addGame(id, options)
|
||||
const player = game.addPlayer(playerID, playerName);
|
||||
return [game, player]
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@ import {IllegalAction} from "./illegalAction.mjs"
|
|||
import * as log from "../log.mjs"
|
||||
import {roomManager} from "../roomManager.mjs"
|
||||
import {io} from "./io.mjs"
|
||||
var oldWorld = 0
|
||||
|
||||
io.on('connection', function(client){
|
||||
connected(client)
|
||||
|
@ -12,34 +11,54 @@ io.on('connection', function(client){
|
|||
function connected(client) {
|
||||
client.sync = function() {
|
||||
const tempWorld = client.game.world.obfuscate();
|
||||
io.to(client.game.name).emit('sync',{world: tempWorld})
|
||||
io.to(client.game.id).emit('sync',{world: tempWorld})
|
||||
}
|
||||
|
||||
client.sendMeta = function() {
|
||||
const roomSettings = client.game.getSettings();
|
||||
const roomID = client.game.id
|
||||
const roomPlayers = client.game.players; // Dont send client id's to everyone, TODO
|
||||
const metadata = {players: roomPlayers, settings: roomSettings}
|
||||
io.to(client.game.name).emit('metadata', metadata)
|
||||
const metadata = {players: roomPlayers, roomID: roomID}
|
||||
io.to(client.game.id).emit('metadata', metadata)
|
||||
|
||||
|
||||
|
||||
const id = client.game.id
|
||||
client.emit('message', id)
|
||||
}
|
||||
|
||||
client.game = "";
|
||||
client.player = "";
|
||||
|
||||
client.on('disconnect', function(){
|
||||
if (!roomManager.getAllIDs().includes(client.id)) return new IllegalAction(client.id, 22)
|
||||
if (!roomManager.getAllPlayerIDs().includes(client.id)) return new IllegalAction(client.id, 22)
|
||||
log.log(client.id + ' disconnected.', 'FgCyan')
|
||||
client.game.removePlayerByID(client.id)
|
||||
client.sendMeta();
|
||||
})
|
||||
|
||||
client.on('joinGame', function(data){
|
||||
if(!roomManager.joinClientToGame(data.room, data.name, client.id, client)) return
|
||||
const info = roomManager.playerJoinGame(data.room, data.name, client.id)
|
||||
client.join(info[0].id)
|
||||
client.game = info[0];
|
||||
client.player = info[1]
|
||||
client.sync()
|
||||
log.log(`${client.id} joined the game as ${data.name} requesting to join room: ${data.room}`, 'FgMagenta');
|
||||
client.emit('inGame', true)
|
||||
client.sendMeta()
|
||||
})
|
||||
|
||||
client.on('createGame', function(data){
|
||||
const info = roomManager.playerCreateGame(data.options, data.name, client.id)
|
||||
client.join(info[0].id)
|
||||
client.game = info[0];
|
||||
client.player = info[1]
|
||||
|
||||
log.log(`${client.id} joined the game as ${data.name} `, 'FgMagenta');
|
||||
client.emit('inGame', true)
|
||||
client.sync()
|
||||
client.sendMeta()
|
||||
})
|
||||
|
||||
|
||||
client.on('leaveGame', function(data){
|
||||
log.log(client.id + ' disconnected.')
|
||||
|
@ -49,8 +68,8 @@ function connected(client) {
|
|||
|
||||
|
||||
client.on('clickCanvas', function(data){
|
||||
if (!roomManager.getAllIDs().includes(client.id)) return new IllegalAction(client.id, 1)
|
||||
client.game.world.click([data.tilePosition[0],data.tilePosition[1]], data.mode, client.player)
|
||||
if (!roomManager.getAllPlayerIDs().includes(client.id)) return new IllegalAction(client.id, 1)
|
||||
client.game.world.click(data.tilePosition[0],data.tilePosition[1], data.mode, client.player)
|
||||
|
||||
client.sync()
|
||||
})
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
import crypto from "crypto";
|
||||
export function randomNumber(min, max) {
|
||||
return Math.floor(Math.random() * (max - min) + min);
|
||||
}
|
||||
export function clamp(number, min, max) {
|
||||
return Math.max(min, Math.min(number, max));
|
||||
}
|
||||
|
||||
export function createCode() {
|
||||
const randomString = crypto.randomBytes(3).toString("hex").toUpperCase()
|
||||
return randomString
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
|
||||
export function flag(data, location, player) {
|
||||
let tile = data[location[0]][location[1]]
|
||||
export function flag(x, y, data, player) {
|
||||
let tile = data[x][y]
|
||||
|
||||
if (!tile.mask || tile.color === 0) return data
|
||||
const color = player.color * 1
|
||||
|
@ -17,6 +17,6 @@ export function flag(data, location, player) {
|
|||
tile.flag = 0;
|
||||
}
|
||||
console.log(tile.flag)
|
||||
data[location[0]][location[1]] = tile
|
||||
data[x][y] = tile
|
||||
return data;
|
||||
}
|
||||
|
|
|
@ -14,22 +14,22 @@ const searchLoc =
|
|||
[-1,-1],[0,-1],[1,-1]
|
||||
]
|
||||
|
||||
export function generate(world, avoidLocation){
|
||||
export function generate(avoidX, avoidY, world){
|
||||
var minesPlanted = 0;
|
||||
while (minesPlanted < world.mines || !(minesPlanted <= world.dimensions[0]*world.dimensions[1]-15)) {
|
||||
const x = util.randomNumber(0,world.dimensions[0])
|
||||
const y = util.randomNumber(0,world.dimensions[1])
|
||||
while (minesPlanted < world.mines || !(minesPlanted <= world.width*world.height-15)) {
|
||||
const x = util.randomNumber(0,world.width)
|
||||
const y = util.randomNumber(0,world.height)
|
||||
var suitable = true;
|
||||
searchLoc.forEach(loc => {
|
||||
const tempx = x + loc[0]
|
||||
const tempy = y + loc[1]
|
||||
if (tempx === avoidLocation[0] && tempy === avoidLocation[1]) {
|
||||
if (tempx === avoidX && tempy === avoidX) {
|
||||
suitable = false;
|
||||
}
|
||||
})
|
||||
// console.log([x,y] + ":----:" + avoidLocation)
|
||||
if (x == avoidLocation[0] && y == avoidLocation[1]) { suitable = false }
|
||||
if (world.data[x][y].type == 5) { suitable = false }
|
||||
|
||||
if (x == avoidX && y == avoidY) { suitable = false }
|
||||
if (world.data[x][y].type == 5) { suitable = false }
|
||||
|
||||
if (suitable) {
|
||||
world.data[x][y].type = 5
|
||||
|
|
|
@ -7,14 +7,14 @@ const searchLoc =
|
|||
// Place Numbers
|
||||
export function mark(world) {
|
||||
|
||||
for(let x = 0; x < world.dimensions[0]; x++){
|
||||
for(let y = 0; y < world.dimensions[1]; y++){
|
||||
for(let x = 0; x < world.width; x++){
|
||||
for(let y = 0; y < world.height; y++){
|
||||
if (world.data[x][y].type === 1) {
|
||||
var counter = 0;
|
||||
searchLoc.forEach(location => {
|
||||
const tempx = x + location[0]
|
||||
const tempy = y + location[1]
|
||||
if (tempx >= 0 && tempy >= 0 && tempx < world.dimensions[0] && tempy < world.dimensions[1]) {
|
||||
if (tempx >= 0 && tempy >= 0 && tempx < world.width && tempy < world.height) {
|
||||
if (world.data[tempx][tempy].type === 5) {
|
||||
counter++;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
|
||||
export function obfuscate(world) {
|
||||
let tempWorld = world;
|
||||
for(let x = 0; x < tempWorld.dimensions[0]; x++){
|
||||
for(let y = 0; y < tempWorld.dimensions[1]; y++){
|
||||
for(let x = 0; x < tempWorld.width; x++){
|
||||
for(let y = 0; y < tempWorld.height; y++){
|
||||
|
||||
if (tempWorld.data[x][y].mask === true) {
|
||||
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
import * as log from "../log.mjs"
|
||||
import * as revealer from "./revealer.mjs"
|
||||
export function place(data, location, id) {
|
||||
let tile = data[location[0]][location[1]];
|
||||
export function place(x, y, data) {
|
||||
let tile = data[x][y];
|
||||
if (tile.mask === true) {
|
||||
if (tile.mask && tile.flag === 0) {
|
||||
tile.mask = false;
|
||||
}
|
||||
|
||||
data[location[0]][location[1]] = tile;
|
||||
revealer.reveal(data, location)
|
||||
data[x][y] = tile;
|
||||
revealer.reveal(x, y, data)
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
|
|
@ -6,15 +6,16 @@ const searchLoc =
|
|||
[-1,-1],[0,-1],[1,-1]
|
||||
]
|
||||
|
||||
export function reveal(data, location) {
|
||||
if (data[location[0]][location[1]].type !== 5) {
|
||||
export function reveal(x, y, data) {
|
||||
if (data[x][y].type !== 5) {
|
||||
|
||||
var toSearch = [];
|
||||
var searchedLocations = [];
|
||||
toSearch.push(location)
|
||||
toSearch.push([x, y])
|
||||
|
||||
if (data[location[0]][location[1]].type === 1) {
|
||||
if (data[x][y].type === 1) {
|
||||
while (toSearch.length > 0) {
|
||||
console.log("LoopReveal")
|
||||
const x = toSearch[0][0]
|
||||
const y = toSearch[0][1]
|
||||
searchedLocations.push(toSearch[0])
|
||||
|
|
|
@ -6,39 +6,40 @@ import * as flagger from "./flagger.mjs"
|
|||
import * as placer from "./placer.mjs"
|
||||
|
||||
export class World {
|
||||
constructor(dimensions = [32,32], mines = 30) {
|
||||
this.mines = 200
|
||||
this.dimensions = dimensions;
|
||||
constructor(options) {
|
||||
this.mines = options.mines
|
||||
this.width = options.width*1
|
||||
this.height = options.height*1
|
||||
this.isGenerated = false;
|
||||
this.isObfuscated = false;
|
||||
this.isMarked = false;
|
||||
this.data = Array.from(Array(this.dimensions[0]), () => new Array(this.dimensions[1]));
|
||||
for (let x = 0; x < this.dimensions[0]; x++){
|
||||
for (let y = 0; y < this.dimensions[1]; y++){
|
||||
this.data = Array.from(Array(this.width), () => new Array(this.height));
|
||||
for (let x = 0; x < this.width; x++){
|
||||
for (let y = 0; y < this.height; y++){
|
||||
this.data[x][y] = {type: 1, flag: 0, mask: true}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
click (location, mode, player) {
|
||||
click (x, y, mode, player) {
|
||||
if (this.isGenerated) {
|
||||
if (mode === 2) {
|
||||
this.data = flagger.flag(this.data, location, player)
|
||||
this.data = flagger.flag(x, y, this.data, player)
|
||||
}
|
||||
|
||||
if (mode === 0) {
|
||||
this.data = placer.place(this.data, location, player)
|
||||
this.data = placer.place(x, y, this.data, player)
|
||||
}
|
||||
} else {
|
||||
this.generate(location).mark();
|
||||
this.data = placer.place(this.data, location, player)
|
||||
this.generate(x, y).mark();
|
||||
this.data = placer.place(x, y, this.data, player)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
generate(location) {
|
||||
generate(x, y) {
|
||||
if (this.isGenerated) return log.log("Already Generated");
|
||||
return generator.generate(this, location);
|
||||
return generator.generate(x, y, this);
|
||||
}
|
||||
|
||||
mark() {
|
||||
|
|
3
test.mjs
Normal file
|
@ -0,0 +1,3 @@
|
|||
import * as util from "./scripts/util.mjs"
|
||||
|
||||
console.log(util.createCode())
|
BIN
www/fonts/moderndos.ttf
Normal file
BIN
www/fonts/moderndos.woff2
Normal file
87
www/game.html
Normal file
|
@ -0,0 +1,87 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
<script src="http://localhost:35729/livereload.js" charset="utf-8"></script>
|
||||
<script type="text/javascript" src="socket.io.min.js"></script>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<script src='scripts/script.js' type="module"></script>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Canvas used to generate individual sprites off one sprite atlas -->
|
||||
|
||||
<canvas class="hidden" id="spriteJank" width=24 height=24></canvas>
|
||||
<main>
|
||||
<p id="message"></p>
|
||||
<div id="game" style="display: none;">
|
||||
<span id="leftBar">
|
||||
<p id="status">Connection Status</p>
|
||||
</span>
|
||||
<span id="rightBar">
|
||||
<div class="canvasContainer">
|
||||
<canvas oncontextmenu="return false;" id="canvas" width=0 height=0></canvas>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="menu" id="menu">
|
||||
<div id="joinType">
|
||||
<h2>Create Room Or Join with code?</h2>
|
||||
<button type="button" id="gotoCreate">create game</button>
|
||||
<button type="button" id="gotoJoin">Join game</button>
|
||||
|
||||
</div>
|
||||
<div id="joinGame" style="display: none;">
|
||||
<input type="text" id="joinGameCode" value="">
|
||||
<input type="text" id="joinGameUsername" value="bob">
|
||||
<button type="button" id="joinGameButton">Join</button>
|
||||
</div>
|
||||
<div id="createGame" >
|
||||
<h2>Create Room</h2>
|
||||
<hr>
|
||||
<div class="leftRight">
|
||||
<div class="left">
|
||||
<h3>Settings</h3>
|
||||
<div class="row">
|
||||
<span>Username</span>
|
||||
<input type="text" id="createGameUsername" value="">
|
||||
</div>
|
||||
<u>Color</u>
|
||||
<div id="createGameSelectColorBar"></div>
|
||||
<u>Mode</u>
|
||||
<div id="createGameSelectModeBar"></div>
|
||||
</div>
|
||||
<span class="centerBar"></span>
|
||||
<div class="right">
|
||||
<h3>Game Settings</h3>
|
||||
<div class="row">
|
||||
<span>Percentage mines</span>
|
||||
<input type="range" min="0" max="1000" value="50" class="slider">
|
||||
</div>
|
||||
<div class="row">
|
||||
<span>Number of mines</span>
|
||||
<input type="number" id="createGameOptionsMines" value="100">
|
||||
</div>
|
||||
<div class="row">
|
||||
<span>Minefield Width</span>
|
||||
<input type="number" id="createGameOptionsWidth" value="32">
|
||||
</div>
|
||||
<div class="row">
|
||||
<span>Minefield Height</span>
|
||||
<input type="number" id="createGameOptionsHeight" value="32">
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<button type="button" id="createRoomButton">Start Game</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
|
||||
</html>
|
BIN
www/img/city.png
Before Width: | Height: | Size: 296 B |
Before Width: | Height: | Size: 264 B |
Before Width: | Height: | Size: 358 B |
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 64 KiB |
BIN
www/img/modes.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
www/img/rock.png
Before Width: | Height: | Size: 292 B |
BIN
www/img/sea.png
Before Width: | Height: | Size: 285 B |
|
@ -3,51 +3,14 @@
|
|||
<head>
|
||||
<title></title>
|
||||
<script src="http://localhost:35729/livereload.js" charset="utf-8"></script>
|
||||
<script type="text/javascript" src="socket.io.min.js"></script>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<script src='scripts/script.js' type="module"></script>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Canvas used to generate individual sprites off one sprite atlas -->
|
||||
|
||||
<canvas class="hidden" id="spriteJank" width=24 height=24></canvas>
|
||||
<main>
|
||||
<p id="message"></p>
|
||||
<div id="game" style="display: none;">
|
||||
<span id="leftBar">
|
||||
<p id="status">Connection Status</p>
|
||||
</span>
|
||||
<span id="rightBar">
|
||||
<div class="canvasContainer">
|
||||
<canvas oncontextmenu="return false;" id="canvas" width=0 height=0></canvas>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="menu" id="menu">
|
||||
<div id="joinType">
|
||||
<h2>Create Room Or Join with code?</h2>
|
||||
<button type="button" id="gotoCreate">create game</button>
|
||||
<button type="button" id="gotoJoin">Join game</button>
|
||||
|
||||
</div>
|
||||
<div id="joinGame" style="display: none;">
|
||||
<input type="text" id="joinGameCode" value="">
|
||||
<input type="text" id="joinGameUsername" value="bob">
|
||||
<button type="button" id="joinGameButton">Join</button>
|
||||
</div>
|
||||
<div id="createGame" style="display: none;">
|
||||
<input type="text" id="createGameUsername" value="bob">
|
||||
<button type="button" id="createRoomButton">create Room</button>
|
||||
<div id="createGameOptions">
|
||||
<h3>Options:</h3>
|
||||
<input type="number" id="createGameOptionsMines" value="100">
|
||||
<input type="number" id="createGameOptionsWidth" value="32">
|
||||
<input type="number" id="createGameOptionsHeight" value="32">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
<h1>Multiplayer Minesweeper!</h1>
|
||||
<h2>Up to 8 Players</h2>
|
||||
<a href="./game.html" class="buttonLink">Play Now!</a>
|
||||
</main>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import * as main from '../script.js';
|
||||
import {tileArray} from './tileRenderer.js';
|
||||
import { cursor } from '../interface/game/mouse.js'
|
||||
import { ctx} from './html.js';
|
||||
|
@ -9,23 +8,22 @@ renderTiles()
|
|||
}
|
||||
|
||||
export function renderTiles() { // DRAW THE IMAGE TO THE CANVAS.
|
||||
const width = game.world.width;
|
||||
const height = game.world.height;
|
||||
canvas.width = game.tileSize*width;
|
||||
canvas.height = game.tileSize*height;
|
||||
let x, y = 0
|
||||
const gridSize = game.gridSize;
|
||||
const tileSize = game.tileSize;
|
||||
for(x = 0; x < gridSize[0]; x++){
|
||||
for(y = 0; y < gridSize[1]; y++){
|
||||
for(x = 0; x < width; x++){
|
||||
for(y = 0; y < height; y++){
|
||||
const xu = x*tileSize;
|
||||
const yu = y*tileSize;
|
||||
const tempWorld = game.world.data;
|
||||
// Draw buildings
|
||||
|
||||
ctx.drawImage(tileArray[tempWorld[x][y].type], xu,yu)
|
||||
|
||||
// Draw Structures
|
||||
const flag = tempWorld[x][y].flag
|
||||
// console.log(flag)
|
||||
if (flag !== 0) {
|
||||
// console.log("FALAG")
|
||||
ctx.drawImage(tileArray[flag + 7], xu,yu)
|
||||
}
|
||||
|
||||
|
|
|
@ -3,8 +3,7 @@ import {game} from "../game/game.js"
|
|||
export var canvas = document.getElementById('canvas');
|
||||
export var ctx = canvas.getContext('2d');
|
||||
export var wrapper = document.getElementById('game');
|
||||
canvas.width = game.tileSize*game.gridSize[0];
|
||||
canvas.height = game.tileSize*game.gridSize[1];
|
||||
|
||||
scaleEverythingGood()
|
||||
|
||||
window.addEventListener('resize', scaleEverythingGood);
|
||||
|
|
|
@ -1,20 +1,26 @@
|
|||
import {game} from "/scripts/game/game.js"
|
||||
|
||||
export var tileArray = loadSprites();
|
||||
export function loadSprites() {
|
||||
var tiles = [];
|
||||
var spriteJank = document.getElementById('spriteJank');
|
||||
spriteJank.width = game.tileSize;
|
||||
spriteJank.height = game.tileSize;
|
||||
var ctxj = spriteJank.getContext('2d');
|
||||
var spriteSheet = new Image();
|
||||
export const tileArray = loadSprites('/img/mine.png', game.tileSize);
|
||||
var counter = 0;
|
||||
|
||||
spriteSheet.src = '/mine.png'
|
||||
export function loadSprites(path, tileSize) {
|
||||
|
||||
let tiles = [];
|
||||
let spriteJank = document.createElement("canvas");
|
||||
spriteJank.id = `spriteJank${counter}`
|
||||
spriteJank.style = "display: none;"
|
||||
spriteJank.width = tileSize;
|
||||
spriteJank.height = tileSize;
|
||||
document.body.appendChild(spriteJank);
|
||||
let ctxj = spriteJank.getContext('2d');
|
||||
let spriteSheet = new Image();
|
||||
|
||||
spriteSheet.src = path
|
||||
spriteSheet.onload = function() {
|
||||
|
||||
const tileSize = game.tileSize;
|
||||
for (let y = 0; y < 8; y++) {
|
||||
for (let x = 0; x < 8; x++) {
|
||||
|
||||
for (let y = 0; y < spriteSheet.height/tileSize; y++) {
|
||||
for (let x = 0; x < spriteSheet.width/tileSize; x++) {
|
||||
ctxj.drawImage(spriteSheet, -x*tileSize,-y*tileSize)
|
||||
var tmp = new Image();
|
||||
tmp.src = spriteJank.toDataURL();
|
||||
|
@ -24,5 +30,7 @@ export function loadSprites() {
|
|||
}
|
||||
}
|
||||
spriteJank.remove();
|
||||
|
||||
return tiles;
|
||||
}
|
||||
export const menuArray = loadSprites('/img/modes.png', 32)
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
class Game {
|
||||
constructor(tileSize, gridSize, world, status) {
|
||||
this.tileSize = tileSize;
|
||||
this.gridSize = gridSize;
|
||||
this.world = world;
|
||||
this.status = status;
|
||||
}
|
||||
reset() {
|
||||
game = new Game(16, [16, 16], null, false);
|
||||
game = new Game(16, null, false);
|
||||
}
|
||||
}
|
||||
|
||||
export var game = new Game(16, [16, 16])
|
||||
export var game = new Game(16, null, false)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import {statusElement} from "/scripts/interface/game/html.js"
|
||||
const statusElement = document.getElementById("status")
|
||||
|
||||
export function updateConnectionStatus(connection) {
|
||||
statusElement.textContent = `Server Connection: ${connection}`
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
export let statusElement = document.getElementById("status")
|
||||
export let buttonBar = document.getElementById("buttonBar")
|
|
@ -1,6 +1,5 @@
|
|||
import {game} from "../../game/game.js";
|
||||
import { clickCanvas } from "/scripts/net/netcode.js";
|
||||
import { getButton } from "/scripts/interface/game/picker.js";
|
||||
import { canvas } from "../../display/html.js"
|
||||
|
||||
class Cursor {
|
||||
|
|
|
@ -1,52 +0,0 @@
|
|||
import {tileArray} from "/scripts/display/tileRenderer.js"
|
||||
import {buttonBar} from "/scripts/interface/game/html.js"
|
||||
var button = 0;
|
||||
|
||||
function clickSelector(e) {
|
||||
document.querySelectorAll('.button').forEach(item => {
|
||||
item.style ="";
|
||||
})
|
||||
event.target.style = "background: lightslategray;"
|
||||
button = event.target.no
|
||||
|
||||
}
|
||||
|
||||
export function create() {
|
||||
for(let i=0;i < 5;i++) {
|
||||
let span = document.createElement('span')
|
||||
span.className = "button"
|
||||
let n;
|
||||
switch (i) {
|
||||
case (1):
|
||||
n = 1
|
||||
break;
|
||||
case (2):
|
||||
n = 2
|
||||
break;
|
||||
case (3):
|
||||
n = 3
|
||||
break;
|
||||
case (4):
|
||||
n = 4
|
||||
break;
|
||||
default:
|
||||
n = 5
|
||||
};
|
||||
span.appendChild(tileArray[n]);
|
||||
buttonBar.appendChild(span);
|
||||
span.no = i;
|
||||
span.addEventListener('click', e => {
|
||||
clickSelector(e);
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
export function getButton() {
|
||||
return button;
|
||||
}
|
||||
|
||||
export function destroy() {
|
||||
while (buttonBar.lastChild) {
|
||||
buttonBar.removeChild(buttonBar.lastChild)
|
||||
}
|
||||
}
|
|
@ -1,6 +1,10 @@
|
|||
import * as status from "../../net/status.js"
|
||||
import {joinGame, createGame} from "/scripts/net/netcode.js"
|
||||
import { changeScene } from "/scripts/interface/scene.js"
|
||||
import * as picker from "./picker.js"
|
||||
import {tileArray, menuArray} from "/scripts/display/tileRenderer.js"
|
||||
|
||||
|
||||
|
||||
function ID(id) {
|
||||
return document.getElementById(id)
|
||||
|
@ -13,6 +17,8 @@ const createGameMenu = ID("createGame")
|
|||
ID("gotoCreate").addEventListener("click", e => {
|
||||
joinType.style.display = "none"
|
||||
createGameMenu.style.display = ""
|
||||
picker.create("createGameSelectColorBar", tileArray, [8, 16])
|
||||
picker.create("createGameSelectModeBar", menuArray, [0,4], "wide")
|
||||
})
|
||||
|
||||
ID("gotoJoin").addEventListener("click", e => {
|
||||
|
@ -29,7 +35,7 @@ ID("joinGameButton").addEventListener("click", e => {
|
|||
function join(event) {
|
||||
const roomCode = ID("joinGameCode").value
|
||||
const name = ID("joinGameUsername").value
|
||||
if (room == '' || name == '' || status.get() == 'disconnected') return
|
||||
if (roomCode == '' || name == '' || status.get() == 'disconnected') return
|
||||
joinGame({room: roomCode, name: name})
|
||||
|
||||
}
|
||||
|
@ -37,6 +43,7 @@ function join(event) {
|
|||
|
||||
ID("createRoomButton").addEventListener("click", e => {
|
||||
create(e)
|
||||
picker.destroy("createGameSelectColorBar")
|
||||
});
|
||||
|
||||
function create(event) {
|
||||
|
@ -45,14 +52,17 @@ function create(event) {
|
|||
const width = ID("createGameOptionsWidth").value
|
||||
const height = ID("createGameOptionsHeight").value
|
||||
if (name == '' || mines == '' || width == '' || height == '' || status.get() == 'disconnected') return
|
||||
|
||||
const data =
|
||||
{
|
||||
name: name,
|
||||
const options = {
|
||||
mines: mines,
|
||||
width: width,
|
||||
height: height
|
||||
}
|
||||
const data =
|
||||
{
|
||||
name: name,
|
||||
options: options
|
||||
}
|
||||
console.log(data)
|
||||
createGame(data)
|
||||
|
||||
}
|
||||
|
|
40
www/scripts/interface/mainmenu/picker.js
Normal file
|
@ -0,0 +1,40 @@
|
|||
function clickSelector(e, parentID) {
|
||||
document.getElementById(parentID).querySelectorAll('.button').forEach(item => {
|
||||
item.style ="";
|
||||
item.active ="false";
|
||||
})
|
||||
event.target.style = "background: #4CAF50;"
|
||||
event.target.active = "true"
|
||||
|
||||
}
|
||||
|
||||
export function getButton(parentID) {
|
||||
document.getElementById(parentID).querySelectorAll('.button').forEach(item => {
|
||||
if (item.active === "true") {
|
||||
return item.no
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function create(parentID, spriteSheet, ranges, style = "") {
|
||||
const buttonBar = document.getElementById(parentID);
|
||||
|
||||
for(let i=0;i < ranges[1]-ranges[0];i++) {
|
||||
let span = document.createElement('span')
|
||||
span.className = `button ${style}`
|
||||
const n = i + ranges[0]
|
||||
span.appendChild(spriteSheet[n]);
|
||||
buttonBar.appendChild(span);
|
||||
span.no = i;
|
||||
span.addEventListener('click', e => {
|
||||
clickSelector(e, parentID);
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
export function destroy(parentID) {
|
||||
const buttonBar = document.getElementById(parentID);
|
||||
while (buttonBar.lastChild) {
|
||||
buttonBar.removeChild(buttonBar.lastChild)
|
||||
}
|
||||
}
|
|
@ -1,4 +1,3 @@
|
|||
import * as picker from "/scripts/interface/game/picker.js"
|
||||
|
||||
export function changeScene(scene) {
|
||||
if (scene == "game") {
|
||||
|
|
|
@ -32,7 +32,7 @@ socket.on('disconnect', function(data){
|
|||
|
||||
socket.on('message', function(data) {
|
||||
const mess = document.getElementById("message")
|
||||
mess.textContent = `Server Connection: ${connection}`
|
||||
mess.textContent = `${data}`
|
||||
|
||||
})
|
||||
|
||||
|
@ -63,5 +63,6 @@ socket.on('inGame', function(data){
|
|||
|
||||
socket.on('sync', function (sync){
|
||||
game.world = sync.world;
|
||||
console.log(game.world)
|
||||
render()
|
||||
})
|
||||
|
|
165
www/style.css
|
@ -1,16 +1,124 @@
|
|||
* {
|
||||
font-family: pixserif;
|
||||
}
|
||||
|
||||
/* #mydiv {
|
||||
position: absolute;
|
||||
cursor: move;
|
||||
z-index: 10;
|
||||
background: coral;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border: 1px solid #d3d3d3;
|
||||
} */
|
||||
|
||||
h1, h2 {
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 3em;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 2.5em;
|
||||
}
|
||||
h3 {
|
||||
font-size: 2em;
|
||||
}
|
||||
|
||||
p, span, input, button, u {
|
||||
font-size: 1.7em;
|
||||
}
|
||||
|
||||
hr {
|
||||
border-color: white;
|
||||
/* height: 3px; */
|
||||
border: none;
|
||||
height: 3px;
|
||||
background: white;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
.row {
|
||||
padding: 20px;
|
||||
display: flex;
|
||||
justify-content:space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.row > span {
|
||||
margin-left: 20px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.leftRight {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.centerBar {
|
||||
width: 3px;
|
||||
height: inherit;
|
||||
background: white
|
||||
}
|
||||
|
||||
.right {
|
||||
display: inline;
|
||||
margin: 40px;
|
||||
/* background: red; */
|
||||
|
||||
}
|
||||
|
||||
.left {
|
||||
display: inline;
|
||||
margin: 40px;
|
||||
/* background: red; */
|
||||
}
|
||||
|
||||
.slider {
|
||||
display: inline-block;
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
height: 55px;
|
||||
width: 300px;
|
||||
background-color: lightgray;
|
||||
}
|
||||
|
||||
.slider::-webkit-slider-thumb {
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
width: 20px;
|
||||
height: 60px;
|
||||
background: #f1f8t6;
|
||||
cursor: pointer;
|
||||
}
|
||||
.slider::-moz-range-thumb {
|
||||
width: 20px;
|
||||
height: 60px;
|
||||
border-radius: 0px;
|
||||
background: #f1f8t6;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
input[type=button], button, .buttonLink {
|
||||
width: 100%;
|
||||
background-color: #4CAF50;
|
||||
color: white;
|
||||
padding: 14px 20px;
|
||||
margin: 8px 0;
|
||||
border: none;
|
||||
cursor: pointer; }
|
||||
|
||||
input[type=number], input[type=text] {
|
||||
/* width: 100%; */
|
||||
width: 300px;
|
||||
display: inline-block;
|
||||
padding: 12px 20px;
|
||||
margin: 3px 0;
|
||||
border: none;
|
||||
box-sizing: border-box;
|
||||
background-color: lightgray; }
|
||||
|
||||
|
||||
@font-face {
|
||||
/* font-weight: 500; */
|
||||
font-family: "pixserif";
|
||||
src: url('fonts/moderndos.woff2') format('woff2'),
|
||||
url('fonts/moderndos.ttf') format('truetype');
|
||||
}
|
||||
span.button > img {
|
||||
pointer-events: none;
|
||||
image-rendering: optimizeSpeed; /* STOP SMOOTHING, GIVE ME SPEED */
|
||||
|
@ -18,22 +126,29 @@ span.button > img {
|
|||
image-rendering: -o-crisp-edges; /* Opera */
|
||||
image-rendering: -webkit-optimize-contrast; /* Chrome (and eventually Safari) */
|
||||
image-rendering: pixelated; /* Chrome */
|
||||
-ms-interpolation-mode: nearest-neighbor; /* IE8+ */
|
||||
width: 70px;
|
||||
height: 70px;
|
||||
transform: translate(0, 8px);
|
||||
border: 2px solid darkgray;
|
||||
border-radius: 4px;
|
||||
transform: translate(0, 10px);
|
||||
background: lightgray;
|
||||
}
|
||||
|
||||
span.button.wide {
|
||||
width: 128px;
|
||||
height: 128px;
|
||||
}
|
||||
|
||||
span.button.wide > img {
|
||||
width: 108px;
|
||||
height: 108px;
|
||||
}
|
||||
|
||||
span.button {
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
display: inline-block;
|
||||
background: tan;
|
||||
background: lightgray;
|
||||
width:90px;
|
||||
height:90px;
|
||||
margin: 5px 5px 5px 5px;
|
||||
|
@ -111,25 +226,5 @@ body {
|
|||
text-align: center;
|
||||
background-color: #2c2f33;
|
||||
color: white;
|
||||
font-variant: normal;
|
||||
font-family: verdana;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 25pt;
|
||||
|
||||
}
|
||||
h2 {
|
||||
font-size: 20pt;
|
||||
}
|
||||
p{
|
||||
/* font-size: 12pt; */
|
||||
/* text-align: left; */
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 12pt;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
|