Working Multiplayer system

This commit is contained in:
A Bass 2022-04-20 14:53:36 -04:00
parent 962a376115
commit ef376178df
9 changed files with 254 additions and 95 deletions

Binary file not shown.

42
TODO.md Normal file
View file

@ -0,0 +1,42 @@
# Project To Do list
## Short Term
- [] Kill socket when browser closes/inactive.
- [] Make client get textures from single sprite sheet
## Mid Term
- [] Implement Rooms with different games on server
- [] Add room selection menu on client
- [] Implement Players
- [] Player Names
- [] Player Colors
- [] Prevent Duplicate player info
## Long Term
- [] Power and money system for players
- [] Add land ownership
- [] Land Claiming
- [] Difficulty to claim hills and seas
- [] Create bouy flag sprite
- [] Make differentiation between land owned by different players
- [] System to have animated widgets overtop of the canvas.
- [] Explosion
- [] Selection cursor
- [] Color for different land status (claimed/open/unclaimable)
- [] Create spites for classes of buildings for economy.
- [x] Factory
- [x] Farmland/town
- [] Fishing area
- [] Building selection menu
## Longer Term
- [] Add tests to ensure features act as they should
- [] Handle player death/leaving
- [] Dead player's resources go to killer with some tax.
- [] Leaving player's resources go to player
## Finishing Touches
- [] Sounds
- [] Graphics Redo
- [] Fancy webpage decorations
## Maybe
- [] Chat

134
index.js
View file

@ -1,9 +1,61 @@
var noise = require('noisejs');
var express = require('express');
var express = require('express');
const worldgen = require("./worldgen.js")
const util = require("./util.js")
const gridSize = [18, 18]; const gridSize = [18, 18];
const perlinScale = 3; const perlinScale = 3;
var world = generateWorld();
class Player {
constructor(id, color) {
this.id = id;
this.color = color;
}
}
class Game {
constructor() {
this.players = [];
this.world = worldgen.generateWorld(gridSize, perlinScale);
}
addPlayer(id) {
var color
switch(util.randomNumber(1,4)) {
case 1:
color = "red";
break;
case 2:
color = "aquamarine";
break;
case 3:
color = "green";
break;
case 4:
color = "yellow";
break;
}
const player = new Player(id, color);
this.players.push(player);
}
removePlayer(id) {
this.players = this.players.filter(obj => obj.id != id);
console.log("removed player - " + id)
}
getPlayerByID(id) {
console.log(this.players)
console.log(id)
const player = this.players.filter(obj => obj.id == id)[0]
return player
}
}
var game = new Game();
var app = express() //Static resources server var app = express() //Static resources server
app.use(express.static(__dirname + '/www/'));var server = app.listen(8082, function () { app.use(express.static(__dirname + '/www/'));var server = app.listen(8082, function () {
@ -14,66 +66,36 @@ app.use(express.static(__dirname + '/www/'));var server = app.listen(8082, funct
var io = require('socket.io')(server);/* Connection events */ var io = require('socket.io')(server);/* Connection events */
io.on('connection', function(client) { io.on('connection', function(client) {
console.log('User connected'); console.log('User connected');
client.on('joinGame', function(tank){
console.log(client.id + ' joined the game');
// client.emit('addTank', { id: tank.id, type: tank.type, isLocal: true, x: initX, y: initY, hp: TANK_INIT_HP }); client.on('disconnect', function(){
// client.broadcast.emit('addTank', { id: tank.id, type: tank.type, isLocal: false, x: initX, y: initY, hp: TANK_INIT_HP} ); console.log(client.id + ' disconnected.')
// game.addTank({ id: tank.id, type: tank.type, hp: TANK_INIT_HP}); game.removePlayer(client.id)
client.emit('gameVars', {gridSize: gridSize, world: world}) client.broadcast.emit('playerList', game.players)
})
client.on('joinGame', function(tank){
game.addPlayer(client.id);
console.log(client.id + ' joined the game');
client.emit('gameVars', {gridSize: gridSize, world: game.world})
client.broadcast.emit('playerList', game.players)
client.emit('playerList', game.players)
})
client.on('leaveGame', function(tank){
console.log(client.id + ' disconnected.')
game.removePlayer(client.id)
client.broadcast.emit('playerList', game.players)
}) })
client.on('clickCanvas', function(data){ client.on('clickCanvas', function(data){
const xu = data.tilePosition[0] const xu = data.tilePosition[0]
const yu = data.tilePosition[1] const yu = data.tilePosition[1]
world[xu][yu].structure = data.structure game.world[xu][yu].structure = data.structure
client.broadcast.emit('sync',{world: world}) game.world[xu][yu].owner = game.getPlayerByID(client.id).color;
client.emit('sync',{world: world}) // console.log(world[xu][yu].owner = game.getPlayerbyID(client.id))
client.broadcast.emit('sync',{world: game.world})
client.emit('sync',{world: game.world})
}) })
}); });
function randomNumber(min, max) {
return Math.floor(Math.random() * (max - min) + min);
}
function generateWorld(){
let x, y = 0
let tempWorld = Array.from(Array(gridSize[0]), () => new Array(gridSize[1]));
for (x = 0; x < gridSize[0]; x++){
for (y = 0; y < gridSize[1]; y++){
tempWorld[x][y] = {type: 0, structure: 0}
}
}
noise.seed(Math.random())
for(x = 0; x < gridSize[0]; x++){
for(y = 0; y < gridSize[1]; y++){
var value = (noise.perlin2(x/perlinScale, y/perlinScale))*10;
if (value >= -3) {
tempWorld[x][y].type = 0
} else if (value < -3) {
tempWorld[x][y].type = 1
}
if (value > 1.4) {
tempWorld[x][y].type = 2
}
}
}
for (i = 0; i < gridSize[0]*gridSize[1]/15; i){
x = randomNumber(0,gridSize[0]);
y = randomNumber(0,gridSize[1]);
if (tempWorld[x][y].type != 1) {
i++;
tempWorld[x][y].structure = 1
}
}
return tempWorld;
}

5
util.js Normal file
View file

@ -0,0 +1,5 @@
function randomNumber(min, max) {
return Math.floor(Math.random() * (max - min) + min);
}
module.exports = {randomNumber}

40
worldgen.js Normal file
View file

@ -0,0 +1,40 @@
var noise = require('noisejs');
const util = require("./util.js")
function generateWorld(gridSize, perlinScale){
let x, y = 0
let tempWorld = Array.from(Array(gridSize[0]), () => new Array(gridSize[1]));
for (x = 0; x < gridSize[0]; x++){
for (y = 0; y < gridSize[1]; y++){
tempWorld[x][y] = {type: 0, structure: 0, owner: null}
}
}
noise.seed(Math.random())
for(x = 0; x < gridSize[0]; x++){
for(y = 0; y < gridSize[1]; y++){
var value = (noise.perlin2(x/perlinScale, y/perlinScale))*10;
if (value >= -3) {
tempWorld[x][y].type = 0
} else if (value < -3) {
tempWorld[x][y].type = 1
}
if (value > 1.4) {
tempWorld[x][y].type = 2
}
}
}
for (i = 0; i < gridSize[0]*gridSize[1]/15; i){
x = util.randomNumber(0,gridSize[0]);
y = util.randomNumber(0,gridSize[1]);
if (tempWorld[x][y].type != 1) {
i++;
tempWorld[x][y].structure = 1
}
}
return tempWorld;
}
module.exports = { generateWorld };

View file

@ -9,15 +9,21 @@
<body> <body>
<h1>Uber Secret Project</h1> <h1>Uber Secret Project</h1>
<div class="container"> <div class="container">
<canvas class="" id="spritejank" width=24 height=24></canvas>
<div class="wrapper"> <div class="wrapper">
<canvas id="canvas" width=0 height=0></canvas> <div class="canvasStack">
<canvas class="canvas1" id="canvas" width=0 height=0></canvas>
<canvas class="canvas2" id="hud" width="0" height="0"></canvas>
</div>
</div>
<div class="right"> <div class="right">
<p>Info</p><br> <p>Info</p><br>
<p id="cash">$0</p> <p id="cash">$0</p>
</div> </div>
</div> </div>
</div> </div>
</div>
</body> </body>
<script src='script.js'></script> <script src='script.js'></script>
</html> </html>

View file

@ -4,24 +4,35 @@ var gridSize;
var cash = 99; var cash = 99;
var world var world
var canvas = document.getElementById('canvas'); var canvas = document.getElementById('canvas');
var hud = document.getElementById('hud');
var ctx = canvas.getContext('2d'); var ctx = canvas.getContext('2d');
var hctx = hud.getContext('2d');
var socket = io.connect('http://127.0.0.1:8082/'); var socket = io.connect('http://127.0.0.1:8082/');
function joinGame(tankName, tankType, socket){ function joinGame(socket){
if(tankName != ''){ socket.emit('joinGame', {});
socket.emit('joinGame', {name: tankName, type: tankType});
} }
function leaveGame(socket){
socket.emit('leaveGame', {});
} }
joinGame("aaa", "blue", socket);
joinGame(socket);
window.onbeforeunload = function(){
socket.disconnect();
world = []
}
socket.on('gameVars', function(tank){ socket.on('gameVars', function(tank){
gridSize = tank.gridSize; gridSize = tank.gridSize;
world = tank.world; world = tank.world;
console.log(gridSize, world)
console.log(tank)
fill_canvas() fill_canvas()
}); });
socket.on('playerList', function(data){
console.log(data)
});
socket.on('sync', function (sync){ socket.on('sync', function (sync){
world = sync.world; world = sync.world;
render() render()
@ -49,13 +60,14 @@ window.onload = function () {
function fill_canvas() { function fill_canvas() {
// CREATE CANVAS CONTEXT. // CREATE CANVAS CONTEXT.
canvas.addEventListener("mousedown", function(e) hud.addEventListener("mousedown", function(e)
{ {
getMousePosition(canvas, e); getMousePosition(canvas, e);
}); });
canvas.width = tileSize*gridSize[0]; canvas.width = tileSize*gridSize[0];
canvas.height = tileSize*gridSize[1]; canvas.height = tileSize*gridSize[1];
hud.width = canvas.width
hud.height = canvas.height
render() render()
@ -74,20 +86,41 @@ function render() { // DRAW THE IMAGE TO THE CANVAS.
for(y = 0; y < gridSize[1]; y++){ for(y = 0; y < gridSize[1]; y++){
const xu = x*tileSize; const xu = x*tileSize;
const yu = y*tileSize; const yu = y*tileSize;
if (world[x][y].type == 0) {
// Draw buildings
switch (world[x][y].type) {
case (0):
ctx.drawImage(tiles[0], xu,yu) ctx.drawImage(tiles[0], xu,yu)
} else if (world[x][y].type == 1) { break;
case (1):
ctx.drawImage(tiles[2], xu,yu) ctx.drawImage(tiles[2], xu,yu)
} break;
if (world[x][y].type == 2) { case (2):
ctx.drawImage(tiles[1], xu,yu) ctx.drawImage(tiles[1], xu,yu)
break;
} }
if (world[x][y].structure == 1) {
// Draw Structures
switch (world[x][y].structure) {
case (1):
ctx.drawImage(tiles[3], xu,yu) ctx.drawImage(tiles[3], xu,yu)
} break;
if (world[x][y].structure == 2) {
case (2):
ctx.drawImage(tiles[4], xu,yu) ctx.drawImage(tiles[4], xu,yu)
break;
}
// Draw Property overlays
if (world[x][y].owner != null){
ctx.beginPath();
ctx.fillStyle = world[x][y].owner;
ctx.rect(xu, yu, tileSize, tileSize)
ctx.globalAlpha = 0.5;
ctx.fill()
ctx.globalAlpha = 1;
} }
} }
@ -109,7 +142,7 @@ function getMousePosition(canvas, event) {
console.log("Click!") console.log("Click!")
console.log(xu,yu)
socket.emit('clickCanvas', {tilePosition: [xu,yu], structure: 2}); socket.emit('clickCanvas', {tilePosition: [xu,yu], structure: 2});
// if (tile.type != 1 && tile.structure != 1 && cash > 10) { // if (tile.type != 1 && tile.structure != 1 && cash > 10) {
// tile.structure = 2 // tile.structure = 2

BIN
www/sheet.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

View file

@ -5,18 +5,30 @@ canvas {
image-rendering: crisp-edges; image-rendering: crisp-edges;
border: solid white; border: solid white;
border-radius: 6px; border-radius: 6px;
background-color: #ccc; /* display: inline-block; */
display: inline-block; /* margin: auto; */
float: left;
} }
.right { .canvas1{
background: red; z-index: 0;
display: inline-block; position: fixed;
float: left; left: 50%;
width: 60px; transform: translate(-50%, 0);
}
.canvas2 {
z-index: 1;
position: fixed;
left: 50%;
transform: translate(-50%, 0);
}
.canvasStack {
position: fixed;
top: 150px;
} }
body { body {
text-align: center; text-align: center;
background-color: #2c2f33; background-color: #2c2f33;
@ -25,13 +37,12 @@ font-variant: normal;
font-family: verdana; font-family: verdana;
} }
.wrapper { /* .wrapper {
position: fixed; position: fixed;
left: 50%; left: 50%;
transform: translate(-50%, 0); transform: translate(-50%, 0);
margin: auto;
background-color: #ff00ff; background-color: #ff00ff;
} } */
.container{ .container{
margin: 0px; margin: 0px;
} }