Working Multiplayer system
This commit is contained in:
parent
962a376115
commit
ef376178df
BIN
Assets/Sheet.xcf
BIN
Assets/Sheet.xcf
Binary file not shown.
42
TODO.md
Normal file
42
TODO.md
Normal 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
134
index.js
|
@ -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
5
util.js
Normal 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
40
worldgen.js
Normal 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 };
|
|
@ -9,12 +9,18 @@
|
||||||
<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">
|
||||||
<div class="right">
|
<canvas class="canvas1" id="canvas" width=0 height=0></canvas>
|
||||||
<p>Info</p><br>
|
<canvas class="canvas2" id="hud" width="0" height="0"></canvas>
|
||||||
<p id="cash">$0</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="right">
|
||||||
|
<p>Info</p><br>
|
||||||
|
<p id="cash">$0</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -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,21 +86,42 @@ 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) {
|
|
||||||
|
|
||||||
ctx.drawImage(tiles[0], xu,yu)
|
// Draw buildings
|
||||||
} else if (world[x][y].type == 1) {
|
switch (world[x][y].type) {
|
||||||
ctx.drawImage(tiles[2], xu,yu)
|
case (0):
|
||||||
}
|
ctx.drawImage(tiles[0], xu,yu)
|
||||||
if (world[x][y].type == 2) {
|
break;
|
||||||
ctx.drawImage(tiles[1], xu,yu)
|
case (1):
|
||||||
}
|
ctx.drawImage(tiles[2], xu,yu)
|
||||||
if (world[x][y].structure == 1) {
|
break;
|
||||||
ctx.drawImage(tiles[3], xu,yu)
|
case (2):
|
||||||
}
|
ctx.drawImage(tiles[1], xu,yu)
|
||||||
if (world[x][y].structure == 2) {
|
break;
|
||||||
ctx.drawImage(tiles[4], xu,yu)
|
}
|
||||||
}
|
|
||||||
|
// Draw Structures
|
||||||
|
switch (world[x][y].structure) {
|
||||||
|
case (1):
|
||||||
|
ctx.drawImage(tiles[3], xu,yu)
|
||||||
|
break;
|
||||||
|
|
||||||
|
case (2):
|
||||||
|
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
BIN
www/sheet.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.2 KiB |
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue