Idk Linux now
This commit is contained in:
parent
165366c2b7
commit
80a21f626a
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1 +1 @@
|
|||
*node_modules/*
|
||||
*node_modules/*
|
||||
|
|
84
TODO.md
84
TODO.md
|
@ -1,42 +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
|
||||
# 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
|
||||
|
|
287
index.js
287
index.js
|
@ -1,121 +1,166 @@
|
|||
const worldgen = require("./worldgen.js")
|
||||
const util = require("./util.js")
|
||||
const log = require("./log.js")
|
||||
const gridSize = [18, 18];
|
||||
const perlinScale = 3;
|
||||
|
||||
var express = require('express');
|
||||
|
||||
process.title = "Server"
|
||||
setInterval(function(){ updateInfo()},5000)
|
||||
|
||||
function updateInfo() {
|
||||
const players = game.players;
|
||||
|
||||
log.setInfo(players)
|
||||
}
|
||||
|
||||
class Player {
|
||||
constructor(id, name, color) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.color = color;
|
||||
}
|
||||
}
|
||||
|
||||
class Game {
|
||||
constructor() {
|
||||
this.players = [{id: "adfhad", name: "bobbert"}];
|
||||
this.world = worldgen.generateWorld(gridSize, perlinScale);
|
||||
}
|
||||
|
||||
addPlayer(id, name) {
|
||||
if (this.getAllNames().includes(name)) return false
|
||||
var color = "blue"
|
||||
const player = new Player(id, name, color);
|
||||
this.players.push(player);
|
||||
return true
|
||||
}
|
||||
|
||||
removePlayer(id) {
|
||||
this.players = this.players.filter(obj => obj.id != id);
|
||||
log.log("removed player - " + id)
|
||||
}
|
||||
|
||||
getPlayerByID(id) {
|
||||
const player = this.players.filter(obj => obj.id == id)[0]
|
||||
return player
|
||||
}
|
||||
|
||||
getAllIDs() {
|
||||
let ids = []
|
||||
for (i = 0; i < this.players.length; i++) {
|
||||
ids.push(this.players[i].id)
|
||||
}
|
||||
return ids
|
||||
}
|
||||
getAllNames() {
|
||||
let names = []
|
||||
for (i = 0; i < this.players.length; i++) {
|
||||
names.push(this.players[i].name)
|
||||
}
|
||||
return names
|
||||
}
|
||||
}
|
||||
var game = new Game();
|
||||
|
||||
|
||||
var app = express() //Static resources server
|
||||
app.use(express.static(__dirname + '/www/'));var server = app.listen(8082, function () {
|
||||
var port = server.address().port;
|
||||
log.log(`Server running at port ${port}`, "bright");
|
||||
});
|
||||
|
||||
var io = require('socket.io')(server);/* Connection events */
|
||||
io.on('connection', function(client) {
|
||||
|
||||
client.illegalAction = function(action) {
|
||||
client.emit('illegalAction', action)
|
||||
}
|
||||
|
||||
log.log('User connected', 'FgGreen');
|
||||
|
||||
client.on('disconnect', function(){
|
||||
log.log(client.id + ' disconnected.', 'FgCyan')
|
||||
game.removePlayer(client.id)
|
||||
client.broadcast.emit('playerList', game.players)
|
||||
})
|
||||
|
||||
client.on('joinGame', function(data){
|
||||
if (game.addPlayer(client.id, data.name) == false) return client.illegalAction(20)
|
||||
sendMap(client)
|
||||
log.log(`${client.id} joined the game as ${data.name} requesting to join room: ${data.room}`, 'FgMagenta');
|
||||
client.broadcast.emit('playerList', game.players)
|
||||
client.emit('playerList', game.players)
|
||||
})
|
||||
client.on('leaveGame', function(tank){
|
||||
log.log(client.id + ' disconnected.')
|
||||
game.removePlayer(client.id)
|
||||
client.broadcast.emit('playerList', game.players)
|
||||
})
|
||||
|
||||
|
||||
client.on('clickCanvas', function(data){
|
||||
if (!game.getAllIDs().includes(client.id)) return client.illegalAction(1)
|
||||
const xu = data.tilePosition[0]
|
||||
const yu = data.tilePosition[1]
|
||||
game.world[xu][yu].structure = data.structure
|
||||
game.world[xu][yu].owner = game.getPlayerByID(client.id).color;
|
||||
// log.log(world[xu][yu].owner = game.getPlayerbyID(client.id))
|
||||
|
||||
client.broadcast.emit('sync',{world: game.world})
|
||||
client.emit('sync',{world: game.world})
|
||||
})
|
||||
|
||||
|
||||
});
|
||||
|
||||
function sendMap(client) {
|
||||
client.broadcast.emit('sync',{world: game.world.map})
|
||||
client.emit('sync',{world: game.world.map})
|
||||
}
|
||||
const worldgen = require("./worldgen.js")
|
||||
const util = require("./util.js")
|
||||
const log = require("./log.js")
|
||||
const gridSize = [18, 18];
|
||||
const perlinScale = 3;
|
||||
var express = require('express');
|
||||
log.setMode(0)
|
||||
process.title = "Server"
|
||||
setInterval(function(){ updateInfo()},5000)
|
||||
|
||||
function updateInfo() {
|
||||
log.setInfo(server.games)
|
||||
}
|
||||
|
||||
class Player {
|
||||
constructor(id, name, color) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.color = color;
|
||||
}
|
||||
}
|
||||
|
||||
class Server {
|
||||
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.
|
||||
return this.getGameByName(name);
|
||||
}
|
||||
return game
|
||||
}
|
||||
|
||||
addGame(name) {
|
||||
const game = new Game(name);
|
||||
this.games.push(game);
|
||||
return game
|
||||
}
|
||||
removeGame(name) {
|
||||
this.games = this.games.filter(obj => obj.name != name);
|
||||
log.log("removed game - " + name)
|
||||
}
|
||||
|
||||
getAllIDs() {
|
||||
let ids = []
|
||||
for (let i = 0; i < this.games.length; i++) {
|
||||
for (let j = 0; j < this.games[i].players.length; j++) {
|
||||
ids.push(this.games[i].players[j].id)
|
||||
}
|
||||
}
|
||||
return ids
|
||||
}
|
||||
|
||||
joinClientToGame(room, nick, id, client) {
|
||||
const game = this.getGameByName(room, true);
|
||||
if (game.addPlayer(id, nick) == false) {
|
||||
this.removeGame(game)
|
||||
return client.illegalAction(20)
|
||||
}
|
||||
client.join(game.name)
|
||||
client.game = game;
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
class Game {
|
||||
constructor(name) {
|
||||
this.name = name;
|
||||
this.players = [];
|
||||
this.world = worldgen.generateWorld(gridSize, perlinScale);
|
||||
}
|
||||
|
||||
addPlayer(id, name) {
|
||||
if (this.getAllNames().includes(name)) return false
|
||||
var color = "blue"
|
||||
const player = new Player(id, name, color);
|
||||
this.players.push(player);
|
||||
return true
|
||||
}
|
||||
|
||||
removePlayer(id) {
|
||||
this.players = this.players.filter(obj => obj.id != id);
|
||||
log.log("removed player - " + id)
|
||||
if (this.players.length < 1) {
|
||||
server.removeGame(this.name);
|
||||
}
|
||||
}
|
||||
|
||||
getPlayerByID(id) {
|
||||
const player = this.players.filter(obj => obj.id == id)[0]
|
||||
return player
|
||||
}
|
||||
|
||||
getAllIDs() {
|
||||
let ids = []
|
||||
for (i = 0; i < this.players.length; i++) {
|
||||
ids.push(this.players[i].id)
|
||||
}
|
||||
return ids
|
||||
}
|
||||
getAllNames() {
|
||||
let names = []
|
||||
for (i = 0; i < this.players.length; i++) {
|
||||
names.push(this.players[i].name)
|
||||
}
|
||||
return names
|
||||
}
|
||||
}
|
||||
var server = new Server();
|
||||
|
||||
|
||||
var app = express() //Static resources server
|
||||
app.use(express.static(__dirname + '/www/'));
|
||||
var webServer = app.listen(8082, function () {
|
||||
var port = webServer.address().port;
|
||||
log.log(`Server running at port ${port}`, "bright");
|
||||
});
|
||||
|
||||
var io = require('socket.io')(webServer);/* Connection events */
|
||||
io.on('connection', function(client) {
|
||||
|
||||
client.illegalAction = function(action) {
|
||||
client.emit('illegalAction', action)
|
||||
}
|
||||
|
||||
log.log('User connected', 'FgGreen');
|
||||
|
||||
client.on('disconnect', function(){
|
||||
if (!server.getAllIDs().includes(client.id)) return client.illegalAction(22)
|
||||
log.log(client.id + ' disconnected.', 'FgCyan')
|
||||
client.game.removePlayer(client.id)
|
||||
})
|
||||
|
||||
client.on('joinGame', function(data){
|
||||
if(!server.joinClientToGame(data.room, data.name, client.id, client)) return
|
||||
io.to(client.game.name).emit('sync',{world: client.game.world})
|
||||
log.log(`${client.id} joined the game as ${data.name} requesting to join room: ${data.room}`, 'FgMagenta');
|
||||
client.emit('inGame', true)
|
||||
})
|
||||
client.on('leaveGame', function(tank){
|
||||
log.log(celient.id + ' disconnected.')
|
||||
client.game.removePlayer(client.id)
|
||||
io.to(client.game.name).emit('playerList', client.game.players)
|
||||
})
|
||||
|
||||
|
||||
client.on('clickCanvas', function(data){
|
||||
if (!server.getAllIDs().includes(client.id)) return client.illegalAction(1)
|
||||
const room = client.game.name
|
||||
const xu = util.clamp(data.tilePosition[0], 0, gridSize[0])
|
||||
const yu = util.clamp(data.tilePosition[1], 0, gridSize[1])
|
||||
if (!Number.isInteger(xu) || !Number.isInteger(yu)) return client.illegalAction(23)
|
||||
|
||||
client.game.world[xu][yu].structure = data.structure
|
||||
client.game.world[xu][yu].owner = client.game.getPlayerByID(client.id).color;
|
||||
io.to(client.game.name).emit('sync',{world: client.game.world})
|
||||
// client.emit('sync',{world: client.game.world})
|
||||
})
|
||||
|
||||
|
||||
});
|
||||
|
|
224
log.js
224
log.js
|
@ -1,101 +1,123 @@
|
|||
const os = require("os")
|
||||
|
||||
var logs = []
|
||||
var info = [[],[]]
|
||||
|
||||
function updateLog() {
|
||||
console.clear()
|
||||
const columns = process.stdout.columns;
|
||||
const rows = process.stdout.rows;
|
||||
const vertSplit = Math.round(rows/4)
|
||||
|
||||
for (var i = 0; i < vertSplit; i++) {
|
||||
process.stdout.cursorTo(Math.round(columns/2),i);
|
||||
process.stdout.clearLine();
|
||||
process.stdout.write(`|`)
|
||||
}
|
||||
for (var i = 0; i < columns; i++) {
|
||||
process.stdout.cursorTo(i, vertSplit)
|
||||
process.stdout.write(`=`)
|
||||
}
|
||||
|
||||
process.stdout.cursorTo(0,0)
|
||||
process.stdout.write("Players:")
|
||||
const players = info[0]
|
||||
for (var i = 0; i < players.length; i++) {
|
||||
process.stdout.cursorTo(0,i+1)
|
||||
process.stdout.write(`Name: \x1b[1m${players[i].name}\x1b[0m -\x1b[1m ID:${players[i].id}\x1b[0m`)
|
||||
}
|
||||
for (var i = 0; i < logs.length; i++ ) {
|
||||
process.stdout.cursorTo(0,vertSplit+1+i)
|
||||
process.stdout.write(`${logs[i]}${os.EOL}` )
|
||||
}
|
||||
|
||||
}
|
||||
function log(string, color) {
|
||||
if (string == undefined) return;
|
||||
var prefix = '';
|
||||
switch (color) {
|
||||
case "reset":
|
||||
prefix = "\x1b[0m"
|
||||
break;
|
||||
case "bright":
|
||||
prefix = "\x1b[1m"
|
||||
break;
|
||||
case "dim":
|
||||
prefix = "\x1b[2m"
|
||||
break;
|
||||
case "underscore":
|
||||
prefix = "\x1b[4m"
|
||||
break;
|
||||
case "reverse":
|
||||
prefix = "\x1b[7m"
|
||||
break;
|
||||
case "FgBlack":
|
||||
prefix = "\x1b[30m"
|
||||
break;
|
||||
case "FgRed":
|
||||
prefix = "\x1b[31m"
|
||||
break;
|
||||
case "FgGreen":
|
||||
prefix = "\x1b[32m"
|
||||
break;
|
||||
case "FgYellow":
|
||||
prefix = "\x1b[33m"
|
||||
break;
|
||||
case "FgBlue":
|
||||
prefix = "\x1b[34m"
|
||||
break;
|
||||
case "FgMagenta":
|
||||
prefix = "\x1b[35m"
|
||||
break;
|
||||
case "FgCyan":
|
||||
prefix = "\x1b[36m"
|
||||
break;
|
||||
case "FgWhite":
|
||||
prefix = "\x1b[37m"
|
||||
break;
|
||||
}
|
||||
|
||||
// BgBlack = "\x1b[40m"
|
||||
// BgRed = "\x1b[41m"
|
||||
// BgGreen = "\x1b[42m"
|
||||
// BgYellow = "\x1b[43m"
|
||||
// BgBlue = "\x1b[44m"
|
||||
// BgMagenta = "\x1b[45m"
|
||||
// BgCyan = "\x1b[46m"
|
||||
// BgWhite = "\x1b[47m"
|
||||
const newString = prefix + string + "\x1b[0m"
|
||||
logs.push(newString)
|
||||
updateLog();
|
||||
}
|
||||
|
||||
function setInfo (players){
|
||||
if (players != undefined) {
|
||||
info[0] = players;
|
||||
updateLog()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = {log, updateLog, setInfo}
|
||||
const os = require("os")
|
||||
var mode = 0
|
||||
var logs = []
|
||||
var info = [[],[]]
|
||||
|
||||
function setMode(type) {
|
||||
mode = type
|
||||
}
|
||||
|
||||
function updateLog() {
|
||||
if (mode) return
|
||||
let templogs = logs;
|
||||
|
||||
console.clear()
|
||||
const columns = process.stdout.columns;
|
||||
const rows = process.stdout.rows;
|
||||
const vertSplit = Math.round(rows/4)
|
||||
|
||||
for (var i = 0; i < vertSplit; i++) {
|
||||
process.stdout.cursorTo(Math.round(columns/2),i);
|
||||
process.stdout.clearLine();
|
||||
process.stdout.write(`|`)
|
||||
}
|
||||
for (var i = 0; i < columns; i++) {
|
||||
process.stdout.cursorTo(i, vertSplit)
|
||||
process.stdout.write(`=`)
|
||||
}
|
||||
|
||||
process.stdout.cursorTo(0,0)
|
||||
process.stdout.write("Players:")
|
||||
const games = info[0]
|
||||
var pointer = 0
|
||||
for (i = 0; i < games.length; i++) {
|
||||
process.stdout.cursorTo(0,pointer+1)
|
||||
|
||||
process.stdout.write(`\x1b[46mGameName: \x1b[1m${games[i].name}\x1b[0m`)
|
||||
const players = games[i].players;
|
||||
for (var j = 0; j < players.length; j++) {
|
||||
process.stdout.cursorTo(0,pointer+2)
|
||||
process.stdout.write(`--Name: \x1b[1m${players[j].name}\x1b[0m -\x1b[1m ID:${players[j].id}\x1b[0m`)
|
||||
pointer++;
|
||||
}
|
||||
pointer++;
|
||||
}
|
||||
if (templogs.length > Math.round(3*rows/4)-3) {
|
||||
templogs.splice(0, logs.length-Math.round(3*rows/4)+2);
|
||||
}
|
||||
for (var i = 0; i < templogs.length; i++ ) {
|
||||
process.stdout.cursorTo(0,vertSplit+1+i)
|
||||
process.stdout.write(`${templogs[i]}${os.EOL}` )
|
||||
}
|
||||
|
||||
}
|
||||
function log(string, color) {
|
||||
if (mode) return console.log(string)
|
||||
if (string == undefined) return;
|
||||
var prefix = '';
|
||||
switch (color) {
|
||||
case "reset":
|
||||
prefix = "\x1b[0m"
|
||||
break;
|
||||
case "bright":
|
||||
prefix = "\x1b[1m"
|
||||
break;
|
||||
case "dim":
|
||||
prefix = "\x1b[2m"
|
||||
break;
|
||||
case "underscore":
|
||||
prefix = "\x1b[4m"
|
||||
break;
|
||||
case "reverse":
|
||||
prefix = "\x1b[7m"
|
||||
break;
|
||||
case "FgBlack":
|
||||
prefix = "\x1b[30m"
|
||||
break;
|
||||
case "FgRed":
|
||||
prefix = "\x1b[31m"
|
||||
break;
|
||||
case "FgGreen":
|
||||
prefix = "\x1b[32m"
|
||||
break;
|
||||
case "FgYellow":
|
||||
prefix = "\x1b[33m"
|
||||
break;
|
||||
case "FgBlue":
|
||||
prefix = "\x1b[34m"
|
||||
break;
|
||||
case "FgMagenta":
|
||||
prefix = "\x1b[35m"
|
||||
break;
|
||||
case "FgCyan":
|
||||
prefix = "\x1b[36m"
|
||||
break;
|
||||
case "FgWhite":
|
||||
prefix = "\x1b[37m"
|
||||
break;
|
||||
}
|
||||
|
||||
// BgBlack = "\x1b[40m"
|
||||
// BgRed = "\x1b[41m"
|
||||
// BgGreen = "\x1b[42m"
|
||||
// BgYellow = "\x1b[43m"
|
||||
// BgBlue = "\x1b[44m"
|
||||
// BgMagenta = "\x1b[45m"
|
||||
// BgCyan = "\x1b[46m"
|
||||
// BgWhite = "\x1b[47m"
|
||||
const newString = prefix + string + "\x1b[0m"
|
||||
logs.push(newString)
|
||||
|
||||
updateLog();
|
||||
}
|
||||
|
||||
function setInfo (players){
|
||||
if (mode) return false
|
||||
if (players != undefined) {
|
||||
info[0] = players;
|
||||
updateLog()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = {log, updateLog, setInfo, setMode}
|
||||
|
|
622
perlin.js
622
perlin.js
|
@ -1,311 +1,311 @@
|
|||
/*
|
||||
* A speed-improved perlin and simplex noise algorithms for 2D.
|
||||
*
|
||||
* Based on example code by Stefan Gustavson (stegu@itn.liu.se).
|
||||
* Optimisations by Peter Eastman (peastman@drizzle.stanford.edu).
|
||||
* Better rank ordering method by Stefan Gustavson in 2012.
|
||||
* Converted to Javascript by Joseph Gentle.
|
||||
* Converted to NPM Package by Jacob Schneider
|
||||
*
|
||||
* Version 2012-03-09
|
||||
*
|
||||
* This code was placed in the public domain by its original author,
|
||||
* Stefan Gustavson. You may use it as you see fit, but
|
||||
* attribution is appreciated.
|
||||
*
|
||||
*/
|
||||
|
||||
module.exports = (function(global){
|
||||
var functions = global.noise = {};
|
||||
|
||||
function Grad(x, y, z) {
|
||||
this.x = x; this.y = y; this.z = z;
|
||||
}
|
||||
|
||||
Grad.prototype.dot2 = function(x, y) {
|
||||
return this.x*x + this.y*y;
|
||||
};
|
||||
|
||||
Grad.prototype.dot3 = function(x, y, z) {
|
||||
return this.x*x + this.y*y + this.z*z;
|
||||
};
|
||||
|
||||
var grad3 = [new Grad(1,1,0),new Grad(-1,1,0),new Grad(1,-1,0),new Grad(-1,-1,0),
|
||||
new Grad(1,0,1),new Grad(-1,0,1),new Grad(1,0,-1),new Grad(-1,0,-1),
|
||||
new Grad(0,1,1),new Grad(0,-1,1),new Grad(0,1,-1),new Grad(0,-1,-1)];
|
||||
|
||||
var p = [151,160,137,91,90,15,
|
||||
131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
|
||||
190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
|
||||
88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
|
||||
77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
|
||||
102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
|
||||
135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
|
||||
5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
|
||||
223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
|
||||
129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
|
||||
251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
|
||||
49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
|
||||
138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180];
|
||||
// To remove the need for index wrapping, double the permutation table length
|
||||
var perm = new Array(512);
|
||||
var gradP = new Array(512);
|
||||
|
||||
// This isn't a very good seeding function, but it works ok. It supports 2^16
|
||||
// different seed values. Write something better if you need more seeds.
|
||||
functions.seed = function(seed) {
|
||||
if(seed > 0 && seed < 1) {
|
||||
// Scale the seed out
|
||||
seed *= 65536;
|
||||
}
|
||||
|
||||
seed = Math.floor(seed);
|
||||
if(seed < 256) {
|
||||
seed |= seed << 8;
|
||||
}
|
||||
|
||||
for(var i = 0; i < 256; i++) {
|
||||
var v;
|
||||
if (i & 1) {
|
||||
v = p[i] ^ (seed & 255);
|
||||
} else {
|
||||
v = p[i] ^ ((seed>>8) & 255);
|
||||
}
|
||||
|
||||
perm[i] = perm[i + 256] = v;
|
||||
gradP[i] = gradP[i + 256] = grad3[v % 12];
|
||||
}
|
||||
};
|
||||
|
||||
functions.seed(0);
|
||||
|
||||
/*
|
||||
for(var i=0; i<256; i++) {
|
||||
perm[i] = perm[i + 256] = p[i];
|
||||
gradP[i] = gradP[i + 256] = grad3[perm[i] % 12];
|
||||
}*/
|
||||
|
||||
// Skewing and unskewing factors for 2, 3, and 4 dimensions
|
||||
var F2 = 0.5*(Math.sqrt(3)-1);
|
||||
var G2 = (3-Math.sqrt(3))/6;
|
||||
|
||||
var F3 = 1/3;
|
||||
var G3 = 1/6;
|
||||
|
||||
// 2D simplex noise
|
||||
functions.simplex2 = function(xin, yin) {
|
||||
var n0, n1, n2; // Noise contributions from the three corners
|
||||
// Skew the input space to determine which simplex cell we're in
|
||||
var s = (xin+yin)*F2; // Hairy factor for 2D
|
||||
var i = Math.floor(xin+s);
|
||||
var j = Math.floor(yin+s);
|
||||
var t = (i+j)*G2;
|
||||
var x0 = xin-i+t; // The x,y distances from the cell origin, unskewed.
|
||||
var y0 = yin-j+t;
|
||||
// For the 2D case, the simplex shape is an equilateral triangle.
|
||||
// Determine which simplex we are in.
|
||||
var i1, j1; // Offsets for second (middle) corner of simplex in (i,j) coords
|
||||
if(x0>y0) { // lower triangle, XY order: (0,0)->(1,0)->(1,1)
|
||||
i1=1; j1=0;
|
||||
} else { // upper triangle, YX order: (0,0)->(0,1)->(1,1)
|
||||
i1=0; j1=1;
|
||||
}
|
||||
// A step of (1,0) in (i,j) means a step of (1-c,-c) in (x,y), and
|
||||
// a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y), where
|
||||
// c = (3-sqrt(3))/6
|
||||
var x1 = x0 - i1 + G2; // Offsets for middle corner in (x,y) unskewed coords
|
||||
var y1 = y0 - j1 + G2;
|
||||
var x2 = x0 - 1 + 2 * G2; // Offsets for last corner in (x,y) unskewed coords
|
||||
var y2 = y0 - 1 + 2 * G2;
|
||||
// Work out the hashed gradient indices of the three simplex corners
|
||||
i &= 255;
|
||||
j &= 255;
|
||||
var gi0 = gradP[i+perm[j]];
|
||||
var gi1 = gradP[i+i1+perm[j+j1]];
|
||||
var gi2 = gradP[i+1+perm[j+1]];
|
||||
// Calculate the contribution from the three corners
|
||||
var t0 = 0.5 - x0*x0-y0*y0;
|
||||
if(t0<0) {
|
||||
n0 = 0;
|
||||
} else {
|
||||
t0 *= t0;
|
||||
n0 = t0 * t0 * gi0.dot2(x0, y0); // (x,y) of grad3 used for 2D gradient
|
||||
}
|
||||
var t1 = 0.5 - x1*x1-y1*y1;
|
||||
if(t1<0) {
|
||||
n1 = 0;
|
||||
} else {
|
||||
t1 *= t1;
|
||||
n1 = t1 * t1 * gi1.dot2(x1, y1);
|
||||
}
|
||||
var t2 = 0.5 - x2*x2-y2*y2;
|
||||
if(t2<0) {
|
||||
n2 = 0;
|
||||
} else {
|
||||
t2 *= t2;
|
||||
n2 = t2 * t2 * gi2.dot2(x2, y2);
|
||||
}
|
||||
// Add contributions from each corner to get the final noise value.
|
||||
// The result is scaled to return values in the interval [-1,1].
|
||||
return 70 * (n0 + n1 + n2);
|
||||
};
|
||||
|
||||
// 3D simplex noise
|
||||
functions.simplex3 = function(xin, yin, zin) {
|
||||
var n0, n1, n2, n3; // Noise contributions from the four corners
|
||||
|
||||
// Skew the input space to determine which simplex cell we're in
|
||||
var s = (xin+yin+zin)*F3; // Hairy factor for 2D
|
||||
var i = Math.floor(xin+s);
|
||||
var j = Math.floor(yin+s);
|
||||
var k = Math.floor(zin+s);
|
||||
|
||||
var t = (i+j+k)*G3;
|
||||
var x0 = xin-i+t; // The x,y distances from the cell origin, unskewed.
|
||||
var y0 = yin-j+t;
|
||||
var z0 = zin-k+t;
|
||||
|
||||
// For the 3D case, the simplex shape is a slightly irregular tetrahedron.
|
||||
// Determine which simplex we are in.
|
||||
var i1, j1, k1; // Offsets for second corner of simplex in (i,j,k) coords
|
||||
var i2, j2, k2; // Offsets for third corner of simplex in (i,j,k) coords
|
||||
if(x0 >= y0) {
|
||||
if(y0 >= z0) { i1=1; j1=0; k1=0; i2=1; j2=1; k2=0; }
|
||||
else if(x0 >= z0) { i1=1; j1=0; k1=0; i2=1; j2=0; k2=1; }
|
||||
else { i1=0; j1=0; k1=1; i2=1; j2=0; k2=1; }
|
||||
} else {
|
||||
if(y0 < z0) { i1=0; j1=0; k1=1; i2=0; j2=1; k2=1; }
|
||||
else if(x0 < z0) { i1=0; j1=1; k1=0; i2=0; j2=1; k2=1; }
|
||||
else { i1=0; j1=1; k1=0; i2=1; j2=1; k2=0; }
|
||||
}
|
||||
// A step of (1,0,0) in (i,j,k) means a step of (1-c,-c,-c) in (x,y,z),
|
||||
// a step of (0,1,0) in (i,j,k) means a step of (-c,1-c,-c) in (x,y,z), and
|
||||
// a step of (0,0,1) in (i,j,k) means a step of (-c,-c,1-c) in (x,y,z), where
|
||||
// c = 1/6.
|
||||
var x1 = x0 - i1 + G3; // Offsets for second corner
|
||||
var y1 = y0 - j1 + G3;
|
||||
var z1 = z0 - k1 + G3;
|
||||
|
||||
var x2 = x0 - i2 + 2 * G3; // Offsets for third corner
|
||||
var y2 = y0 - j2 + 2 * G3;
|
||||
var z2 = z0 - k2 + 2 * G3;
|
||||
|
||||
var x3 = x0 - 1 + 3 * G3; // Offsets for fourth corner
|
||||
var y3 = y0 - 1 + 3 * G3;
|
||||
var z3 = z0 - 1 + 3 * G3;
|
||||
|
||||
// Work out the hashed gradient indices of the four simplex corners
|
||||
i &= 255;
|
||||
j &= 255;
|
||||
k &= 255;
|
||||
var gi0 = gradP[i+ perm[j+ perm[k ]]];
|
||||
var gi1 = gradP[i+i1+perm[j+j1+perm[k+k1]]];
|
||||
var gi2 = gradP[i+i2+perm[j+j2+perm[k+k2]]];
|
||||
var gi3 = gradP[i+ 1+perm[j+ 1+perm[k+ 1]]];
|
||||
|
||||
// Calculate the contribution from the four corners
|
||||
var t0 = 0.6 - x0*x0 - y0*y0 - z0*z0;
|
||||
if(t0<0) {
|
||||
n0 = 0;
|
||||
} else {
|
||||
t0 *= t0;
|
||||
n0 = t0 * t0 * gi0.dot3(x0, y0, z0); // (x,y) of grad3 used for 2D gradient
|
||||
}
|
||||
var t1 = 0.6 - x1*x1 - y1*y1 - z1*z1;
|
||||
if(t1<0) {
|
||||
n1 = 0;
|
||||
} else {
|
||||
t1 *= t1;
|
||||
n1 = t1 * t1 * gi1.dot3(x1, y1, z1);
|
||||
}
|
||||
var t2 = 0.6 - x2*x2 - y2*y2 - z2*z2;
|
||||
if(t2<0) {
|
||||
n2 = 0;
|
||||
} else {
|
||||
t2 *= t2;
|
||||
n2 = t2 * t2 * gi2.dot3(x2, y2, z2);
|
||||
}
|
||||
var t3 = 0.6 - x3*x3 - y3*y3 - z3*z3;
|
||||
if(t3<0) {
|
||||
n3 = 0;
|
||||
} else {
|
||||
t3 *= t3;
|
||||
n3 = t3 * t3 * gi3.dot3(x3, y3, z3);
|
||||
}
|
||||
// Add contributions from each corner to get the final noise value.
|
||||
// The result is scaled to return values in the interval [-1,1].
|
||||
return 32 * (n0 + n1 + n2 + n3);
|
||||
|
||||
};
|
||||
|
||||
// ##### Perlin noise stuff
|
||||
|
||||
function fade(t) {
|
||||
return t*t*t*(t*(t*6-15)+10);
|
||||
}
|
||||
|
||||
function lerp(a, b, t) {
|
||||
return (1-t)*a + t*b;
|
||||
}
|
||||
|
||||
// 2D Perlin Noise
|
||||
functions.perlin2 = function(x, y) {
|
||||
// Find unit grid cell containing point
|
||||
var X = Math.floor(x), Y = Math.floor(y);
|
||||
// Get relative xy coordinates of point within that cell
|
||||
x = x - X; y = y - Y;
|
||||
// Wrap the integer cells at 255 (smaller integer period can be introduced here)
|
||||
X = X & 255; Y = Y & 255;
|
||||
|
||||
// Calculate noise contributions from each of the four corners
|
||||
var n00 = gradP[X+perm[Y]].dot2(x, y);
|
||||
var n01 = gradP[X+perm[Y+1]].dot2(x, y-1);
|
||||
var n10 = gradP[X+1+perm[Y]].dot2(x-1, y);
|
||||
var n11 = gradP[X+1+perm[Y+1]].dot2(x-1, y-1);
|
||||
|
||||
// Compute the fade curve value for x
|
||||
var u = fade(x);
|
||||
|
||||
// Interpolate the four results
|
||||
return lerp(
|
||||
lerp(n00, n10, u),
|
||||
lerp(n01, n11, u),
|
||||
fade(y));
|
||||
};
|
||||
|
||||
// 3D Perlin Noise
|
||||
functions.perlin3 = function(x, y, z) {
|
||||
// Find unit grid cell containing point
|
||||
var X = Math.floor(x), Y = Math.floor(y), Z = Math.floor(z);
|
||||
// Get relative xyz coordinates of point within that cell
|
||||
x = x - X; y = y - Y; z = z - Z;
|
||||
// Wrap the integer cells at 255 (smaller integer period can be introduced here)
|
||||
X = X & 255; Y = Y & 255; Z = Z & 255;
|
||||
|
||||
// Calculate noise contributions from each of the eight corners
|
||||
var n000 = gradP[X+ perm[Y+ perm[Z ]]].dot3(x, y, z);
|
||||
var n001 = gradP[X+ perm[Y+ perm[Z+1]]].dot3(x, y, z-1);
|
||||
var n010 = gradP[X+ perm[Y+1+perm[Z ]]].dot3(x, y-1, z);
|
||||
var n011 = gradP[X+ perm[Y+1+perm[Z+1]]].dot3(x, y-1, z-1);
|
||||
var n100 = gradP[X+1+perm[Y+ perm[Z ]]].dot3(x-1, y, z);
|
||||
var n101 = gradP[X+1+perm[Y+ perm[Z+1]]].dot3(x-1, y, z-1);
|
||||
var n110 = gradP[X+1+perm[Y+1+perm[Z ]]].dot3(x-1, y-1, z);
|
||||
var n111 = gradP[X+1+perm[Y+1+perm[Z+1]]].dot3(x-1, y-1, z-1);
|
||||
|
||||
// Compute the fade curve value for x, y, z
|
||||
var u = fade(x);
|
||||
var v = fade(y);
|
||||
var w = fade(z);
|
||||
|
||||
// Interpolate
|
||||
return lerp(
|
||||
lerp(
|
||||
lerp(n000, n100, u),
|
||||
lerp(n001, n101, u), w),
|
||||
lerp(
|
||||
lerp(n010, n110, u),
|
||||
lerp(n011, n111, u), w),
|
||||
v);
|
||||
};
|
||||
return functions;
|
||||
})(this);
|
||||
/*
|
||||
* A speed-improved perlin and simplex noise algorithms for 2D.
|
||||
*
|
||||
* Based on example code by Stefan Gustavson (stegu@itn.liu.se).
|
||||
* Optimisations by Peter Eastman (peastman@drizzle.stanford.edu).
|
||||
* Better rank ordering method by Stefan Gustavson in 2012.
|
||||
* Converted to Javascript by Joseph Gentle.
|
||||
* Converted to NPM Package by Jacob Schneider
|
||||
*
|
||||
* Version 2012-03-09
|
||||
*
|
||||
* This code was placed in the public domain by its original author,
|
||||
* Stefan Gustavson. You may use it as you see fit, but
|
||||
* attribution is appreciated.
|
||||
*
|
||||
*/
|
||||
|
||||
module.exports = (function(global){
|
||||
var functions = global.noise = {};
|
||||
|
||||
function Grad(x, y, z) {
|
||||
this.x = x; this.y = y; this.z = z;
|
||||
}
|
||||
|
||||
Grad.prototype.dot2 = function(x, y) {
|
||||
return this.x*x + this.y*y;
|
||||
};
|
||||
|
||||
Grad.prototype.dot3 = function(x, y, z) {
|
||||
return this.x*x + this.y*y + this.z*z;
|
||||
};
|
||||
|
||||
var grad3 = [new Grad(1,1,0),new Grad(-1,1,0),new Grad(1,-1,0),new Grad(-1,-1,0),
|
||||
new Grad(1,0,1),new Grad(-1,0,1),new Grad(1,0,-1),new Grad(-1,0,-1),
|
||||
new Grad(0,1,1),new Grad(0,-1,1),new Grad(0,1,-1),new Grad(0,-1,-1)];
|
||||
|
||||
var p = [151,160,137,91,90,15,
|
||||
131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
|
||||
190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
|
||||
88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
|
||||
77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
|
||||
102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
|
||||
135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
|
||||
5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
|
||||
223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
|
||||
129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
|
||||
251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
|
||||
49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
|
||||
138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180];
|
||||
// To remove the need for index wrapping, double the permutation table length
|
||||
var perm = new Array(512);
|
||||
var gradP = new Array(512);
|
||||
|
||||
// This isn't a very good seeding function, but it works ok. It supports 2^16
|
||||
// different seed values. Write something better if you need more seeds.
|
||||
functions.seed = function(seed) {
|
||||
if(seed > 0 && seed < 1) {
|
||||
// Scale the seed out
|
||||
seed *= 65536;
|
||||
}
|
||||
|
||||
seed = Math.floor(seed);
|
||||
if(seed < 256) {
|
||||
seed |= seed << 8;
|
||||
}
|
||||
|
||||
for(var i = 0; i < 256; i++) {
|
||||
var v;
|
||||
if (i & 1) {
|
||||
v = p[i] ^ (seed & 255);
|
||||
} else {
|
||||
v = p[i] ^ ((seed>>8) & 255);
|
||||
}
|
||||
|
||||
perm[i] = perm[i + 256] = v;
|
||||
gradP[i] = gradP[i + 256] = grad3[v % 12];
|
||||
}
|
||||
};
|
||||
|
||||
functions.seed(0);
|
||||
|
||||
/*
|
||||
for(var i=0; i<256; i++) {
|
||||
perm[i] = perm[i + 256] = p[i];
|
||||
gradP[i] = gradP[i + 256] = grad3[perm[i] % 12];
|
||||
}*/
|
||||
|
||||
// Skewing and unskewing factors for 2, 3, and 4 dimensions
|
||||
var F2 = 0.5*(Math.sqrt(3)-1);
|
||||
var G2 = (3-Math.sqrt(3))/6;
|
||||
|
||||
var F3 = 1/3;
|
||||
var G3 = 1/6;
|
||||
|
||||
// 2D simplex noise
|
||||
functions.simplex2 = function(xin, yin) {
|
||||
var n0, n1, n2; // Noise contributions from the three corners
|
||||
// Skew the input space to determine which simplex cell we're in
|
||||
var s = (xin+yin)*F2; // Hairy factor for 2D
|
||||
var i = Math.floor(xin+s);
|
||||
var j = Math.floor(yin+s);
|
||||
var t = (i+j)*G2;
|
||||
var x0 = xin-i+t; // The x,y distances from the cell origin, unskewed.
|
||||
var y0 = yin-j+t;
|
||||
// For the 2D case, the simplex shape is an equilateral triangle.
|
||||
// Determine which simplex we are in.
|
||||
var i1, j1; // Offsets for second (middle) corner of simplex in (i,j) coords
|
||||
if(x0>y0) { // lower triangle, XY order: (0,0)->(1,0)->(1,1)
|
||||
i1=1; j1=0;
|
||||
} else { // upper triangle, YX order: (0,0)->(0,1)->(1,1)
|
||||
i1=0; j1=1;
|
||||
}
|
||||
// A step of (1,0) in (i,j) means a step of (1-c,-c) in (x,y), and
|
||||
// a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y), where
|
||||
// c = (3-sqrt(3))/6
|
||||
var x1 = x0 - i1 + G2; // Offsets for middle corner in (x,y) unskewed coords
|
||||
var y1 = y0 - j1 + G2;
|
||||
var x2 = x0 - 1 + 2 * G2; // Offsets for last corner in (x,y) unskewed coords
|
||||
var y2 = y0 - 1 + 2 * G2;
|
||||
// Work out the hashed gradient indices of the three simplex corners
|
||||
i &= 255;
|
||||
j &= 255;
|
||||
var gi0 = gradP[i+perm[j]];
|
||||
var gi1 = gradP[i+i1+perm[j+j1]];
|
||||
var gi2 = gradP[i+1+perm[j+1]];
|
||||
// Calculate the contribution from the three corners
|
||||
var t0 = 0.5 - x0*x0-y0*y0;
|
||||
if(t0<0) {
|
||||
n0 = 0;
|
||||
} else {
|
||||
t0 *= t0;
|
||||
n0 = t0 * t0 * gi0.dot2(x0, y0); // (x,y) of grad3 used for 2D gradient
|
||||
}
|
||||
var t1 = 0.5 - x1*x1-y1*y1;
|
||||
if(t1<0) {
|
||||
n1 = 0;
|
||||
} else {
|
||||
t1 *= t1;
|
||||
n1 = t1 * t1 * gi1.dot2(x1, y1);
|
||||
}
|
||||
var t2 = 0.5 - x2*x2-y2*y2;
|
||||
if(t2<0) {
|
||||
n2 = 0;
|
||||
} else {
|
||||
t2 *= t2;
|
||||
n2 = t2 * t2 * gi2.dot2(x2, y2);
|
||||
}
|
||||
// Add contributions from each corner to get the final noise value.
|
||||
// The result is scaled to return values in the interval [-1,1].
|
||||
return 70 * (n0 + n1 + n2);
|
||||
};
|
||||
|
||||
// 3D simplex noise
|
||||
functions.simplex3 = function(xin, yin, zin) {
|
||||
var n0, n1, n2, n3; // Noise contributions from the four corners
|
||||
|
||||
// Skew the input space to determine which simplex cell we're in
|
||||
var s = (xin+yin+zin)*F3; // Hairy factor for 2D
|
||||
var i = Math.floor(xin+s);
|
||||
var j = Math.floor(yin+s);
|
||||
var k = Math.floor(zin+s);
|
||||
|
||||
var t = (i+j+k)*G3;
|
||||
var x0 = xin-i+t; // The x,y distances from the cell origin, unskewed.
|
||||
var y0 = yin-j+t;
|
||||
var z0 = zin-k+t;
|
||||
|
||||
// For the 3D case, the simplex shape is a slightly irregular tetrahedron.
|
||||
// Determine which simplex we are in.
|
||||
var i1, j1, k1; // Offsets for second corner of simplex in (i,j,k) coords
|
||||
var i2, j2, k2; // Offsets for third corner of simplex in (i,j,k) coords
|
||||
if(x0 >= y0) {
|
||||
if(y0 >= z0) { i1=1; j1=0; k1=0; i2=1; j2=1; k2=0; }
|
||||
else if(x0 >= z0) { i1=1; j1=0; k1=0; i2=1; j2=0; k2=1; }
|
||||
else { i1=0; j1=0; k1=1; i2=1; j2=0; k2=1; }
|
||||
} else {
|
||||
if(y0 < z0) { i1=0; j1=0; k1=1; i2=0; j2=1; k2=1; }
|
||||
else if(x0 < z0) { i1=0; j1=1; k1=0; i2=0; j2=1; k2=1; }
|
||||
else { i1=0; j1=1; k1=0; i2=1; j2=1; k2=0; }
|
||||
}
|
||||
// A step of (1,0,0) in (i,j,k) means a step of (1-c,-c,-c) in (x,y,z),
|
||||
// a step of (0,1,0) in (i,j,k) means a step of (-c,1-c,-c) in (x,y,z), and
|
||||
// a step of (0,0,1) in (i,j,k) means a step of (-c,-c,1-c) in (x,y,z), where
|
||||
// c = 1/6.
|
||||
var x1 = x0 - i1 + G3; // Offsets for second corner
|
||||
var y1 = y0 - j1 + G3;
|
||||
var z1 = z0 - k1 + G3;
|
||||
|
||||
var x2 = x0 - i2 + 2 * G3; // Offsets for third corner
|
||||
var y2 = y0 - j2 + 2 * G3;
|
||||
var z2 = z0 - k2 + 2 * G3;
|
||||
|
||||
var x3 = x0 - 1 + 3 * G3; // Offsets for fourth corner
|
||||
var y3 = y0 - 1 + 3 * G3;
|
||||
var z3 = z0 - 1 + 3 * G3;
|
||||
|
||||
// Work out the hashed gradient indices of the four simplex corners
|
||||
i &= 255;
|
||||
j &= 255;
|
||||
k &= 255;
|
||||
var gi0 = gradP[i+ perm[j+ perm[k ]]];
|
||||
var gi1 = gradP[i+i1+perm[j+j1+perm[k+k1]]];
|
||||
var gi2 = gradP[i+i2+perm[j+j2+perm[k+k2]]];
|
||||
var gi3 = gradP[i+ 1+perm[j+ 1+perm[k+ 1]]];
|
||||
|
||||
// Calculate the contribution from the four corners
|
||||
var t0 = 0.6 - x0*x0 - y0*y0 - z0*z0;
|
||||
if(t0<0) {
|
||||
n0 = 0;
|
||||
} else {
|
||||
t0 *= t0;
|
||||
n0 = t0 * t0 * gi0.dot3(x0, y0, z0); // (x,y) of grad3 used for 2D gradient
|
||||
}
|
||||
var t1 = 0.6 - x1*x1 - y1*y1 - z1*z1;
|
||||
if(t1<0) {
|
||||
n1 = 0;
|
||||
} else {
|
||||
t1 *= t1;
|
||||
n1 = t1 * t1 * gi1.dot3(x1, y1, z1);
|
||||
}
|
||||
var t2 = 0.6 - x2*x2 - y2*y2 - z2*z2;
|
||||
if(t2<0) {
|
||||
n2 = 0;
|
||||
} else {
|
||||
t2 *= t2;
|
||||
n2 = t2 * t2 * gi2.dot3(x2, y2, z2);
|
||||
}
|
||||
var t3 = 0.6 - x3*x3 - y3*y3 - z3*z3;
|
||||
if(t3<0) {
|
||||
n3 = 0;
|
||||
} else {
|
||||
t3 *= t3;
|
||||
n3 = t3 * t3 * gi3.dot3(x3, y3, z3);
|
||||
}
|
||||
// Add contributions from each corner to get the final noise value.
|
||||
// The result is scaled to return values in the interval [-1,1].
|
||||
return 32 * (n0 + n1 + n2 + n3);
|
||||
|
||||
};
|
||||
|
||||
// ##### Perlin noise stuff
|
||||
|
||||
function fade(t) {
|
||||
return t*t*t*(t*(t*6-15)+10);
|
||||
}
|
||||
|
||||
function lerp(a, b, t) {
|
||||
return (1-t)*a + t*b;
|
||||
}
|
||||
|
||||
// 2D Perlin Noise
|
||||
functions.perlin2 = function(x, y) {
|
||||
// Find unit grid cell containing point
|
||||
var X = Math.floor(x), Y = Math.floor(y);
|
||||
// Get relative xy coordinates of point within that cell
|
||||
x = x - X; y = y - Y;
|
||||
// Wrap the integer cells at 255 (smaller integer period can be introduced here)
|
||||
X = X & 255; Y = Y & 255;
|
||||
|
||||
// Calculate noise contributions from each of the four corners
|
||||
var n00 = gradP[X+perm[Y]].dot2(x, y);
|
||||
var n01 = gradP[X+perm[Y+1]].dot2(x, y-1);
|
||||
var n10 = gradP[X+1+perm[Y]].dot2(x-1, y);
|
||||
var n11 = gradP[X+1+perm[Y+1]].dot2(x-1, y-1);
|
||||
|
||||
// Compute the fade curve value for x
|
||||
var u = fade(x);
|
||||
|
||||
// Interpolate the four results
|
||||
return lerp(
|
||||
lerp(n00, n10, u),
|
||||
lerp(n01, n11, u),
|
||||
fade(y));
|
||||
};
|
||||
|
||||
// 3D Perlin Noise
|
||||
functions.perlin3 = function(x, y, z) {
|
||||
// Find unit grid cell containing point
|
||||
var X = Math.floor(x), Y = Math.floor(y), Z = Math.floor(z);
|
||||
// Get relative xyz coordinates of point within that cell
|
||||
x = x - X; y = y - Y; z = z - Z;
|
||||
// Wrap the integer cells at 255 (smaller integer period can be introduced here)
|
||||
X = X & 255; Y = Y & 255; Z = Z & 255;
|
||||
|
||||
// Calculate noise contributions from each of the eight corners
|
||||
var n000 = gradP[X+ perm[Y+ perm[Z ]]].dot3(x, y, z);
|
||||
var n001 = gradP[X+ perm[Y+ perm[Z+1]]].dot3(x, y, z-1);
|
||||
var n010 = gradP[X+ perm[Y+1+perm[Z ]]].dot3(x, y-1, z);
|
||||
var n011 = gradP[X+ perm[Y+1+perm[Z+1]]].dot3(x, y-1, z-1);
|
||||
var n100 = gradP[X+1+perm[Y+ perm[Z ]]].dot3(x-1, y, z);
|
||||
var n101 = gradP[X+1+perm[Y+ perm[Z+1]]].dot3(x-1, y, z-1);
|
||||
var n110 = gradP[X+1+perm[Y+1+perm[Z ]]].dot3(x-1, y-1, z);
|
||||
var n111 = gradP[X+1+perm[Y+1+perm[Z+1]]].dot3(x-1, y-1, z-1);
|
||||
|
||||
// Compute the fade curve value for x, y, z
|
||||
var u = fade(x);
|
||||
var v = fade(y);
|
||||
var w = fade(z);
|
||||
|
||||
// Interpolate
|
||||
return lerp(
|
||||
lerp(
|
||||
lerp(n000, n100, u),
|
||||
lerp(n001, n101, u), w),
|
||||
lerp(
|
||||
lerp(n010, n110, u),
|
||||
lerp(n011, n111, u), w),
|
||||
v);
|
||||
};
|
||||
return functions;
|
||||
})(this);
|
||||
|
|
36
tileinfo.js
36
tileinfo.js
|
@ -1,18 +1,18 @@
|
|||
const tileTypes =
|
||||
[
|
||||
{name: "Grass", textureID: 0, buildPrice: 20, capturePrice:10, capturePower: 10, captureTime: 2, sellPrice:5, recapturePrice: 15, recapturePower: 100, recaptureTime: 10},
|
||||
{name: "Hills", textureID: 1, buildPrice: 20, capturePrice:10, capturePower: 10, captureTime: 2, sellPrice:5, recapturePrice: 15, recapturePower: 100, recaptureTime: 10},
|
||||
{name: "Sea", textureID: 2, buildPrice: 20, capturePrice:10, capturePower: 10, captureTime: 2, sellPrice:5, recapturePrice: 15, recapturePower: 100, recaptureTime: 10}
|
||||
];
|
||||
|
||||
const structureTypes =
|
||||
[
|
||||
{name: "Air", textureID:null, claimable: true, buildable: false, destroyable: false, maxQuantity:null, buildPrice: null, sellPrice: null, buildableOn: null},
|
||||
{name: "Rock", textureID:4, claimable: false, buildable: false, destroyable: false, maxQuantity:null, buildPrice: null, sellPrice: null, buildableOn: [0,1]},
|
||||
{name: "Town", textureID:32, claimable: false, buildable: true, destroyable: true, maxQuantity:10, buildPrice: 10, sellPrice: 5, buildableOn: [0,2]},
|
||||
{name: "City", textureID:33, claimable: false, buildable: true, destroyable: true, maxQuantity:10, buildPrice: 20, sellPrice: 10, buildableOn: [0,2]},
|
||||
{name: "Capitol", textureID:34, claimable: false, buildable: true, destroyable: false, maxQuantity:1, buildPrice: 30, sellPrice: 20, buildableOn: [0,2]},
|
||||
]
|
||||
|
||||
|
||||
module.exports = {tileTypes, structureTypes}
|
||||
const tileTypes =
|
||||
[
|
||||
{name: "Grass", textureID: 0, buildPrice: 20, capturePrice:10, capturePower: 10, captureTime: 2, sellPrice:5, recapturePrice: 15, recapturePower: 100, recaptureTime: 10},
|
||||
{name: "Hills", textureID: 1, buildPrice: 20, capturePrice:10, capturePower: 10, captureTime: 2, sellPrice:5, recapturePrice: 15, recapturePower: 100, recaptureTime: 10},
|
||||
{name: "Sea", textureID: 2, buildPrice: 20, capturePrice:10, capturePower: 10, captureTime: 2, sellPrice:5, recapturePrice: 15, recapturePower: 100, recaptureTime: 10}
|
||||
];
|
||||
|
||||
const structureTypes =
|
||||
[
|
||||
{name: "Air", textureID:null, claimable: true, buildable: false, destroyable: false, maxQuantity:null, buildPrice: null, sellPrice: null, buildableOn: null},
|
||||
{name: "Rock", textureID:4, claimable: false, buildable: false, destroyable: false, maxQuantity:null, buildPrice: null, sellPrice: null, buildableOn: [0,1]},
|
||||
{name: "Town", textureID:32, claimable: false, buildable: true, destroyable: true, maxQuantity:10, buildPrice: 10, sellPrice: 5, buildableOn: [0,2]},
|
||||
{name: "City", textureID:33, claimable: false, buildable: true, destroyable: true, maxQuantity:10, buildPrice: 20, sellPrice: 10, buildableOn: [0,2]},
|
||||
{name: "Capitol", textureID:34, claimable: false, buildable: true, destroyable: false, maxQuantity:1, buildPrice: 30, sellPrice: 20, buildableOn: [0,2]},
|
||||
]
|
||||
|
||||
|
||||
module.exports = {tileTypes, structureTypes}
|
||||
|
|
20
tt.js
20
tt.js
|
@ -1,10 +1,10 @@
|
|||
|
||||
let os = require('os');
|
||||
var i = 0;
|
||||
var j = 0;
|
||||
var jh = 0
|
||||
|
||||
|
||||
process.stdout.write('Hello World' + os.EOL);
|
||||
console.log(Boolean(process.stdout.isTTY))
|
||||
process.title = "Server"
|
||||
|
||||
let os = require('os');
|
||||
var i = 0;
|
||||
var j = 0;
|
||||
var jh = 0
|
||||
|
||||
|
||||
process.stdout.write('Hello World' + os.EOL);
|
||||
console.log(Boolean(process.stdout.isTTY))
|
||||
process.title = "Server"
|
||||
|
|
14
util.js
14
util.js
|
@ -1,7 +1,7 @@
|
|||
function randomNumber(min, max) {
|
||||
return Math.floor(Math.random() * (max - min) + min);
|
||||
}
|
||||
function clamp(number, min, max) {
|
||||
return Math.max(min, Math.min(number, max));
|
||||
}
|
||||
module.exports = {randomNumber, clamp}
|
||||
function randomNumber(min, max) {
|
||||
return Math.floor(Math.random() * (max - min) + min);
|
||||
}
|
||||
function clamp(number, min, max) {
|
||||
return Math.max(min, Math.min(number, max));
|
||||
}
|
||||
module.exports = {randomNumber, clamp}
|
||||
|
|
80
worldgen.js
80
worldgen.js
|
@ -1,40 +1,40 @@
|
|||
var noise = require('./perlin.js');
|
||||
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, color: null, 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 = util.randomNumber(1,4)
|
||||
}
|
||||
}
|
||||
return tempWorld;
|
||||
}
|
||||
module.exports = { generateWorld };
|
||||
var noise = require('./perlin.js');
|
||||
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, color: null, 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 = util.randomNumber(1,4)
|
||||
}
|
||||
}
|
||||
return tempWorld;
|
||||
}
|
||||
module.exports = { generateWorld };
|
||||
|
|
|
@ -1,35 +1,46 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
|
||||
<script type="text/javascript" src="socket.io.js"></script>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
</head>
|
||||
<body>
|
||||
<!-- Canvas used to generate individual sprites off one sprite atlas -->
|
||||
<canvas class="hidden" id="spriteJank" width=24 height=24></canvas>
|
||||
<div class="container" id="container" style="display: none;">
|
||||
<h1>No Longer Secret Project</h1>
|
||||
<div class="wrapper">
|
||||
<div class="canvasStack">
|
||||
<canvas oncontextmenu="return false;" class="canvas1" id="canvas" width=0 height=0></canvas>
|
||||
<canvas oncontextmenu="return false;" class="canvas2" id="hud" width="0" height="0"></canvas>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="menu" id="menu">
|
||||
<form id="form">
|
||||
<input type="text" id="room" value="room">
|
||||
<input type="text" id="name" value="bob">
|
||||
<input type="submit" id="join" value="join">
|
||||
</form>
|
||||
</div>
|
||||
<div class="status">
|
||||
<footer id="status">Connection Status</footer>
|
||||
</div>
|
||||
</body>
|
||||
<script src='script.js'></script>
|
||||
</html>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
|
||||
<script type="text/javascript" src="socket.io.js"></script>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
</head>
|
||||
<body>
|
||||
<!-- Canvas used to generate individual sprites off one sprite atlas -->
|
||||
<canvas class="hidden" id="spriteJank" width=24 height=24></canvas>
|
||||
<div class="container" id="container" style="display: none;">
|
||||
<h1>Project</h1>
|
||||
|
||||
<div class="wrapper" id="wrapper">
|
||||
<div class="top">
|
||||
<h4 id="status">Connection Status</h4>
|
||||
</div>
|
||||
<span class ="left"><p>left</p></span>
|
||||
<span class="canvasStack">
|
||||
<canvas oncontextmenu="return false;" class="canvas1" id="canvas" width=0 height=0></canvas>
|
||||
<canvas oncontextmenu="return false;" class="canvas2" id="hud" width="0" height="0"></canvas>
|
||||
</span>
|
||||
<span class ="right"><p>right</p></span>
|
||||
|
||||
<div class="bottom">
|
||||
<div class="buttonBar" id="buttonBar">
|
||||
<!-- <span class="button" no="1"></span>
|
||||
<span class="button" no="2"></span>
|
||||
<span class="button" no="3"></span>
|
||||
<span class="button" no="4"></span>
|
||||
<span class="button" no="null"></span> -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="menu" id="menu">
|
||||
<input type="text" id="room" value="room">
|
||||
<input type="text" id="name" value="bob">
|
||||
<input type="submit" id="submit" value="join">
|
||||
</div>
|
||||
</body>
|
||||
<script src='script.js'></script>
|
||||
</html>
|
||||
|
|
508
www/script.js
508
www/script.js
|
@ -1,224 +1,284 @@
|
|||
// const perlinScale = 3;
|
||||
const IP_ADDRESS = 'http://127.0.0.1:8082/'
|
||||
|
||||
|
||||
var SERVER_CONNECTION = "disconnected"
|
||||
|
||||
const tileSize = 24;
|
||||
const gridSize = [18, 18];
|
||||
var cash = 99;
|
||||
var world
|
||||
var tiles = []
|
||||
|
||||
var canvas = document.getElementById('canvas');
|
||||
var hud = document.getElementById('hud');
|
||||
var ctx = canvas.getContext('2d');
|
||||
var hctx = hud.getContext('2d');
|
||||
var socket = io.connect(IP_ADDRESS);
|
||||
function joinGame(socket, data){
|
||||
socket.emit('joinGame', data);
|
||||
}
|
||||
function leaveGame(socket){
|
||||
socket.emit('leaveGame', {});
|
||||
}
|
||||
|
||||
socket.on('connect', function(data){
|
||||
SERVER_CONNECTION = "connected"
|
||||
updateConnectionStatus();
|
||||
})
|
||||
socket.on('disconnect', function(data){
|
||||
SERVER_CONNECTION = "disconnected"
|
||||
updateConnectionStatus();
|
||||
})
|
||||
|
||||
socket.on('illegalAction', function(data){
|
||||
let action
|
||||
switch (data) {
|
||||
case 1:
|
||||
action = "You must be in game to do this."
|
||||
break;
|
||||
case 20:
|
||||
action = "That name is already taken."
|
||||
break;
|
||||
default:
|
||||
action = "Unknown action."
|
||||
|
||||
}
|
||||
console.log(`Illegal Action. ${action}`)
|
||||
alert(`Illegal Action, ${action}`)
|
||||
})
|
||||
|
||||
function updateConnectionStatus() {
|
||||
document.getElementById("status").textContent = `Server Connection: ${SERVER_CONNECTION}`
|
||||
}
|
||||
|
||||
class Cursor {
|
||||
constructor(){
|
||||
this.x = 0
|
||||
this.y = 0
|
||||
this.xold = 0
|
||||
this.yold = 0
|
||||
}
|
||||
|
||||
}
|
||||
var cursor = new Cursor();
|
||||
|
||||
window.onbeforeunload = function(){
|
||||
socket.disconnect();
|
||||
world = []
|
||||
}
|
||||
|
||||
socket.on('playerList', function(data){
|
||||
console.log(data)
|
||||
});
|
||||
|
||||
socket.on('sync', function (sync){
|
||||
world = sync.world;
|
||||
render()
|
||||
})
|
||||
|
||||
function loadSprites(){
|
||||
var spriteJank = document.getElementById('spriteJank');
|
||||
var ctxj = spriteJank.getContext('2d');
|
||||
var spriteSheet = new Image();
|
||||
|
||||
spriteSheet.src = '/sheet.png'
|
||||
spriteSheet.onload = function() {
|
||||
|
||||
|
||||
for (y = 0; y < 16; y++) {
|
||||
for (x = 0; x < 16; x++) {
|
||||
ctxj.drawImage(spriteSheet, -x*24,-y*24)
|
||||
var tmp = new Image();
|
||||
tmp.src = spriteJank.toDataURL();
|
||||
ctxj.clearRect(0, 0, 24, 24);
|
||||
tiles.push(tmp)
|
||||
}
|
||||
}
|
||||
}
|
||||
spriteJank.remove();
|
||||
}
|
||||
|
||||
function submit(event) {
|
||||
|
||||
document.getElementById('menu').style = "display: none;"
|
||||
document.getElementById('container').style = ""
|
||||
const room = document.getElementById("room").value
|
||||
const name = document.getElementById("name").value
|
||||
if (room == '' || name == '' || SERVER_CONNECTION == 'disconnected') return
|
||||
|
||||
joinGame(socket, {room: room, name: name})
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
|
||||
|
||||
window.onload = function () {
|
||||
// Register Events
|
||||
const form = document.getElementById('form');
|
||||
form.addEventListener('submit', submit);
|
||||
|
||||
hud.addEventListener('mousemove', e => {
|
||||
mouseMoved(e)
|
||||
});
|
||||
|
||||
hud.addEventListener("mousedown", function(e)
|
||||
{
|
||||
getMousePosition(canvas, e);
|
||||
});
|
||||
|
||||
//Set canvases to be ready
|
||||
canvas.width = tileSize*gridSize[0];
|
||||
canvas.height = tileSize*gridSize[1];
|
||||
hud.width = canvas.width
|
||||
hud.height = canvas.height
|
||||
|
||||
//Load all sprites into memory
|
||||
loadSprites()
|
||||
}
|
||||
|
||||
function randomNumber(min, max) {
|
||||
return Math.floor(Math.random() * (max - min) + min);
|
||||
}
|
||||
|
||||
function render() { // DRAW THE IMAGE TO THE CANVAS.
|
||||
let x, y = 0
|
||||
for(x = 0; x < gridSize[0]; x++){
|
||||
for(y = 0; y < gridSize[1]; y++){
|
||||
const xu = x*tileSize;
|
||||
const yu = y*tileSize;
|
||||
|
||||
// Draw buildings
|
||||
switch (world[x][y].type) {
|
||||
case (0):
|
||||
ctx.drawImage(tiles[0], xu,yu)
|
||||
break;
|
||||
case (1):
|
||||
ctx.drawImage(tiles[2], xu,yu)
|
||||
break;
|
||||
case (2):
|
||||
ctx.drawImage(tiles[1], xu,yu)
|
||||
break;
|
||||
}
|
||||
|
||||
// Draw Structures
|
||||
switch (world[x][y].structure) {
|
||||
case (1):
|
||||
ctx.drawImage(tiles[4], xu,yu)
|
||||
break;
|
||||
case (2):
|
||||
ctx.drawImage(tiles[32], xu,yu)
|
||||
break;
|
||||
case (3):
|
||||
ctx.drawImage(tiles[33], xu,yu)
|
||||
break;
|
||||
case (4):
|
||||
ctx.drawImage(tiles[34], xu,yu)
|
||||
break;
|
||||
}
|
||||
|
||||
// Draw Property overlays
|
||||
if (world[x][y].color != null){
|
||||
ctx.beginPath();
|
||||
ctx.fillStyle = world[x][y].color;
|
||||
|
||||
ctx.rect(xu, yu, tileSize, tileSize)
|
||||
ctx.globalAlpha = 0.6;
|
||||
ctx.fill()
|
||||
ctx.globalAlpha = 1;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
console.log("image Rendered")
|
||||
}
|
||||
|
||||
function getMousePosition(canvas, event) {
|
||||
// Get mouse position on canvas
|
||||
const rect = canvas.getBoundingClientRect();
|
||||
const x = event.clientX - rect.left;
|
||||
const y = event.clientY - rect.top;
|
||||
// const xu = Math.floor(x/tileSize)
|
||||
// const yu = Math.floor(y/tileSize)
|
||||
const xu = cursor.x
|
||||
const yu = cursor.y
|
||||
// Convert canvas coordinates to usable coordinates within the coordinate system
|
||||
|
||||
|
||||
console.log("Click!")
|
||||
console.log(xu,yu)
|
||||
socket.emit('clickCanvas', {tilePosition: [xu,yu], structure: 2});
|
||||
|
||||
}
|
||||
function mouseMoved(event) {
|
||||
const x = Math.floor(event.offsetX/tileSize)
|
||||
const y = Math.floor(event.offsetY/tileSize)
|
||||
if (cursor.xold != x || cursor.yold != y) {
|
||||
cursor.x = x
|
||||
cursor.y = y
|
||||
hctx.clearRect(cursor.xold*tileSize, cursor.yold*tileSize, tileSize, tileSize)
|
||||
hctx.drawImage(tiles[80], x*tileSize,y*tileSize)
|
||||
cursor.xold = x
|
||||
cursor.yold = y
|
||||
}
|
||||
}
|
||||
// const perlinScale = 3;
|
||||
const IP_ADDRESS = 'http://127.0.0.1:8082/'
|
||||
var SERVER_CONNECTION = "disconnected"
|
||||
var IN_GAME = false
|
||||
|
||||
const tileSize = 24;
|
||||
const gridSize = [18, 18];
|
||||
var world
|
||||
var tiles = []
|
||||
var button
|
||||
|
||||
var canvas = document.getElementById('canvas');
|
||||
var hud = document.getElementById('hud');
|
||||
var ctx = canvas.getContext('2d');
|
||||
var hctx = hud.getContext('2d');
|
||||
var socket = io.connect(IP_ADDRESS);
|
||||
function joinGame(socket, data){
|
||||
socket.emit('joinGame', data);
|
||||
}
|
||||
function leaveGame(socket){
|
||||
socket.emit('leaveGame', {});
|
||||
}
|
||||
|
||||
socket.on('connect', function(data){
|
||||
SERVER_CONNECTION = "connected"
|
||||
updateConnectionStatus();
|
||||
})
|
||||
socket.on('disconnect', function(data){
|
||||
|
||||
SERVER_CONNECTION = "disconnected"
|
||||
updateConnectionStatus();
|
||||
})
|
||||
|
||||
socket.on('illegalAction', function(data){
|
||||
let action
|
||||
switch (data) {
|
||||
case 1:
|
||||
action = "You must be in game to do this."
|
||||
break;
|
||||
case 20:
|
||||
action = "That name is already taken."
|
||||
break;
|
||||
case 23:
|
||||
action = "Invalid Placement location."
|
||||
break;
|
||||
default:
|
||||
action = "Unknown action."
|
||||
|
||||
}
|
||||
console.log(`Illegal Action. ${action}`)
|
||||
alert(`Illegal Action, ${action}`)
|
||||
})
|
||||
|
||||
function updateConnectionStatus() {
|
||||
let obj = document.getElementById("status")
|
||||
obj.textContent = `Server Connection: ${SERVER_CONNECTION}`
|
||||
switch (SERVER_CONNECTION) {
|
||||
case "connected":
|
||||
obj.style.color = "green";
|
||||
break;
|
||||
case "disconnected":
|
||||
obj.style.color = "red";
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class Cursor {
|
||||
constructor(){
|
||||
this.x = 0
|
||||
this.y = 0
|
||||
this.xold = 0
|
||||
this.yold = 0
|
||||
}
|
||||
|
||||
}
|
||||
var cursor = new Cursor();
|
||||
|
||||
window.onbeforeunload = function(){
|
||||
socket.disconnect();
|
||||
world = []
|
||||
}
|
||||
|
||||
socket.on('playerList', function(data){
|
||||
console.log(data)
|
||||
});
|
||||
|
||||
socket.on('inGame', function(data){
|
||||
if (!IN_GAME) {changeScene()}
|
||||
IN_GAME = true;
|
||||
})
|
||||
|
||||
socket.on('sync', function (sync){
|
||||
world = sync.world;
|
||||
render()
|
||||
})
|
||||
function changeScene() {
|
||||
document.getElementById('menu').style = "display: none;"
|
||||
document.getElementById('container').style = ""
|
||||
for(i=0;i < 5;i++) {
|
||||
let span = document.createElement('span')
|
||||
span.className = "button"
|
||||
let n;
|
||||
switch (i) {
|
||||
case (1):
|
||||
n = 4
|
||||
break;
|
||||
case (2):
|
||||
n = 32
|
||||
break;
|
||||
case (3):
|
||||
n = 33
|
||||
break;
|
||||
case (4):
|
||||
n = 34
|
||||
break;
|
||||
default:
|
||||
n = 5
|
||||
}
|
||||
span.appendChild(tiles[n]);
|
||||
document.getElementById("buttonBar").appendChild(span);
|
||||
span.no = i;
|
||||
span.addEventListener('click', e => {
|
||||
clickSelector(e)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
function loadSprites() {
|
||||
var spriteJank = document.getElementById('spriteJank');
|
||||
var ctxj = spriteJank.getContext('2d');
|
||||
var spriteSheet = new Image();
|
||||
|
||||
spriteSheet.src = '/sheet.png'
|
||||
spriteSheet.onload = function() {
|
||||
|
||||
|
||||
for (y = 0; y < 16; y++) {
|
||||
for (x = 0; x < 16; x++) {
|
||||
ctxj.drawImage(spriteSheet, -x*24,-y*24)
|
||||
var tmp = new Image();
|
||||
tmp.src = spriteJank.toDataURL();
|
||||
ctxj.clearRect(0, 0, 24, 24);
|
||||
tiles.push(tmp)
|
||||
}
|
||||
}
|
||||
}
|
||||
spriteJank.remove();
|
||||
}
|
||||
|
||||
function submit(event) {
|
||||
const room = document.getElementById("room").value
|
||||
const name = document.getElementById("name").value
|
||||
if (room == '' || name == '' || SERVER_CONNECTION == 'disconnected') return
|
||||
joinGame(socket, {room: room, name: name})
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
function clickSelector(e) {
|
||||
document.querySelectorAll('.button').forEach(item => {
|
||||
item.style ="";
|
||||
})
|
||||
event.target.style = "background: lightslategray;"
|
||||
button = event.target.no
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
window.onload = function () {
|
||||
|
||||
document.getElementById("submit").addEventListener("click", e => {
|
||||
submit(e)
|
||||
});
|
||||
|
||||
hud.addEventListener('mousemove', e => {
|
||||
mouseMoved(e)
|
||||
});
|
||||
|
||||
hud.addEventListener("mousedown", function(e)
|
||||
{
|
||||
getMousePosition(canvas, e);
|
||||
});
|
||||
|
||||
//Set canvases to be ready
|
||||
canvas.width = tileSize*gridSize[0];
|
||||
canvas.height = tileSize*gridSize[1];
|
||||
hud.width = canvas.width
|
||||
hud.height = canvas.height
|
||||
|
||||
//Load all sprites into memory
|
||||
loadSprites()
|
||||
}
|
||||
|
||||
function randomNumber(min, max) {
|
||||
return Math.floor(Math.random() * (max - min) + min);
|
||||
}
|
||||
|
||||
function render() { // DRAW THE IMAGE TO THE CANVAS.
|
||||
let x, y = 0
|
||||
for(x = 0; x < gridSize[0]; x++){
|
||||
for(y = 0; y < gridSize[1]; y++){
|
||||
const xu = x*tileSize;
|
||||
const yu = y*tileSize;
|
||||
|
||||
// Draw buildings
|
||||
switch (world[x][y].type) {
|
||||
case (0):
|
||||
ctx.drawImage(tiles[0], xu,yu)
|
||||
break;
|
||||
case (1):
|
||||
ctx.drawImage(tiles[2], xu,yu)
|
||||
break;
|
||||
case (2):
|
||||
ctx.drawImage(tiles[1], xu,yu)
|
||||
break;
|
||||
}
|
||||
|
||||
// Draw Structures
|
||||
switch (world[x][y].structure) {
|
||||
case (1):
|
||||
ctx.drawImage(tiles[4], xu,yu)
|
||||
break;
|
||||
case (2):
|
||||
ctx.drawImage(tiles[32], xu,yu)
|
||||
break;
|
||||
case (3):
|
||||
ctx.drawImage(tiles[33], xu,yu)
|
||||
break;
|
||||
case (4):
|
||||
ctx.drawImage(tiles[34], xu,yu)
|
||||
break;
|
||||
}
|
||||
|
||||
// Draw Property overlays
|
||||
if (world[x][y].color != null){
|
||||
ctx.beginPath();
|
||||
ctx.fillStyle = world[x][y].color;
|
||||
|
||||
ctx.rect(xu, yu, tileSize, tileSize)
|
||||
ctx.globalAlpha = 0.6;
|
||||
ctx.fill()
|
||||
ctx.globalAlpha = 1;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
console.log("image Rendered")
|
||||
}
|
||||
|
||||
function getMousePosition(canvas, event) {
|
||||
// Get mouse position on canvas
|
||||
const rect = canvas.getBoundingClientRect();
|
||||
const x = event.clientX - rect.left;
|
||||
const y = event.clientY - rect.top;
|
||||
// const xu = Math.floor(x/tileSize)
|
||||
// const yu = Math.floor(y/tileSize)
|
||||
const xu = cursor.x
|
||||
const yu = cursor.y
|
||||
// Convert canvas coordinates to usable coordinates within the coordinate system
|
||||
|
||||
|
||||
console.log("Click!")
|
||||
console.log(xu,yu)
|
||||
socket.emit('clickCanvas', {tilePosition: [xu,yu], structure: button*1});
|
||||
|
||||
}
|
||||
function mouseMoved(event) {
|
||||
const x = Math.floor(event.offsetX/tileSize)
|
||||
const y = Math.floor(event.offsetY/tileSize)
|
||||
if (cursor.xold != x || cursor.yold != y) {
|
||||
cursor.x = x
|
||||
cursor.y = y
|
||||
hctx.clearRect(cursor.xold*tileSize, cursor.yold*tileSize, tileSize, tileSize)
|
||||
hctx.drawImage(tiles[80], x*tileSize,y*tileSize)
|
||||
cursor.xold = x
|
||||
cursor.yold = y
|
||||
}
|
||||
}
|
||||
|
|
413
www/style.css
413
www/style.css
|
@ -1,161 +1,252 @@
|
|||
canvas {
|
||||
-webkit-user-select: none; /* Chrome all / Safari all */
|
||||
-moz-user-select: none; /* Firefox all */
|
||||
-ms-user-select: none; /* IE 10+ */
|
||||
-o-user-select: none;
|
||||
user-select: none;
|
||||
image-rendering: -moz-crisp-edges;
|
||||
image-rendering: -webkit-crisp-edges;
|
||||
image-rendering: pixelated;
|
||||
image-rendering: crisp-edges;
|
||||
border: solid white;
|
||||
border-radius: 6px;
|
||||
/* display: inline-block; */
|
||||
/* margin: auto; */
|
||||
}
|
||||
|
||||
.status{
|
||||
color: green;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.canvas1{
|
||||
z-index: 0;
|
||||
position: fixed;
|
||||
left: 50%;
|
||||
transform: translate(-50%, 0);
|
||||
}
|
||||
|
||||
.canvas2 {
|
||||
z-index: 1;
|
||||
position: fixed;
|
||||
left: 50%;
|
||||
transform: translate(-50%, 0);
|
||||
}
|
||||
|
||||
.canvasStack {
|
||||
position: fixed;
|
||||
top: 150px;
|
||||
|
||||
}
|
||||
|
||||
body {
|
||||
text-align: center;
|
||||
background-color: #2c2f33;
|
||||
color: white;
|
||||
font-variant: normal;
|
||||
font-family: verdana;
|
||||
}
|
||||
|
||||
/* .wrapper {
|
||||
position: fixed;
|
||||
left: 50%;
|
||||
transform: translate(-50%, 0);
|
||||
background-color: #ff00ff;
|
||||
} */
|
||||
.container{
|
||||
margin: 0px;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
.startButton {
|
||||
width: 100.5%;
|
||||
background-color: #4CAF50;
|
||||
color: white;
|
||||
padding-top: 14px;
|
||||
padding-bottom: 14px;
|
||||
margin-top: 4px;
|
||||
margin-bottom: 4px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.subSection {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
font-size: 12pt;
|
||||
color: white;
|
||||
padding: 0;
|
||||
background-color: #4d5259;
|
||||
border-style: solid;
|
||||
border: solid white;
|
||||
border-radius: 6px;
|
||||
padding-bottom: 2px;
|
||||
padding-top: 2px;
|
||||
margin-top: 3px;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
|
||||
.slider {
|
||||
-webkit-appearance: none;
|
||||
width: 98%;
|
||||
background: none;
|
||||
outline: none;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
height: 1px;
|
||||
border: 2px solid #white;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.slider::-webkit-slider-thumb {
|
||||
-webkit-appearance: none;
|
||||
border: 1px solid #bdc3c7;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background: #4CAF50;
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.slider::-moz-range-thumb {
|
||||
border: 1px solid #bdc3c7;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background: #4CAF50;
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.slider::-moz-range-track {
|
||||
width: 100%;
|
||||
height: 5px;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.inline{
|
||||
display:inline-block;
|
||||
margin: auto;
|
||||
}
|
||||
span.spacer{
|
||||
display:inline-block;
|
||||
width: 1px;
|
||||
height: 25px;
|
||||
color: #fff;
|
||||
background-color: #fff;
|
||||
border: 1px solid #fff;
|
||||
border-radius: 6px;
|
||||
|
||||
|
||||
}
|
||||
canvas {
|
||||
-webkit-user-select: none; /* Chrome all / Safari all */
|
||||
-moz-user-select: none; /* Firefox all */
|
||||
-ms-user-select: none; /* IE 10+ */
|
||||
-o-user-select: none;
|
||||
user-select: none;
|
||||
image-rendering: -moz-crisp-edges;
|
||||
image-rendering: -webkit-crisp-edges;
|
||||
image-rendering: pixelated;
|
||||
image-rendering: crisp-edges;
|
||||
border: solid white;
|
||||
border-radius: 6px;
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.left{
|
||||
display: block;
|
||||
transform: translate(0, 50px);
|
||||
float:left;
|
||||
width: 100px;
|
||||
height: 437px;
|
||||
background: darkolivegreen;
|
||||
}
|
||||
|
||||
.right{
|
||||
display: block;
|
||||
transform: translate(0, 50px);
|
||||
float:right;
|
||||
width: 100px;
|
||||
height: 437px;
|
||||
background: darkolivegreen;
|
||||
}
|
||||
|
||||
.top {
|
||||
position: absolute;
|
||||
background: salmon;
|
||||
width: 632px;
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.bottom{
|
||||
position: absolute;
|
||||
background: coral;
|
||||
width:632px;
|
||||
height:100px;
|
||||
transform: translate(0, 486px);
|
||||
}
|
||||
|
||||
|
||||
#mydiv {
|
||||
position: absolute;
|
||||
cursor: move;
|
||||
z-index: 10;
|
||||
background: coral;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border: 1px solid #d3d3d3;
|
||||
}
|
||||
|
||||
|
||||
|
||||
span.button > img {
|
||||
pointer-events: none;
|
||||
image-rendering: optimizeSpeed; /* STOP SMOOTHING, GIVE ME SPEED */
|
||||
image-rendering: -moz-crisp-edges; /* Firefox */
|
||||
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;
|
||||
background: lightgray;
|
||||
}
|
||||
|
||||
span.button {
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
display: inline-block;
|
||||
background: tan;
|
||||
width:90px;
|
||||
height:90px;
|
||||
margin: 5px 5px 5px 5px;
|
||||
vertical-align: middle;
|
||||
border-radius: 3px;
|
||||
white-space: normal;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
|
||||
}
|
||||
|
||||
span.button:hover {
|
||||
background: gray;
|
||||
}
|
||||
|
||||
.canvas1{
|
||||
z-index: 0;
|
||||
position: absolute;
|
||||
transform: translate(-50%, 0);
|
||||
}
|
||||
|
||||
.canvas2 {
|
||||
z-index: 1;
|
||||
position: absolute;
|
||||
transform: translate(-50%, 0);
|
||||
|
||||
|
||||
}
|
||||
|
||||
.canvasStack {
|
||||
position: absolute;
|
||||
top: 50px;
|
||||
background: darkslategray;
|
||||
/* display: block; */
|
||||
/* position: relative; */
|
||||
/* top: 150px; */
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
left: 50%;
|
||||
transform: translate(-50%, 0);
|
||||
position: absolute;
|
||||
background: khaki;
|
||||
width: 632px;
|
||||
height: 586px;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
body {
|
||||
text-align: center;
|
||||
background-color: #2c2f33;
|
||||
color: white;
|
||||
font-variant: normal;
|
||||
font-family: verdana;
|
||||
}
|
||||
|
||||
/* .wrapper {
|
||||
position: fixed;
|
||||
left: 50%;
|
||||
transform: translate(-50%, 0);
|
||||
background-color: #ff00ff;
|
||||
} */
|
||||
.container{
|
||||
margin: 0px;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
.startButton {
|
||||
width: 100.5%;
|
||||
background-color: #4CAF50;
|
||||
color: white;
|
||||
padding-top: 14px;
|
||||
padding-bottom: 14px;
|
||||
margin-top: 4px;
|
||||
margin-bottom: 4px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.subSection {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
font-size: 12pt;
|
||||
color: white;
|
||||
padding: 0;
|
||||
background-color: #4d5259;
|
||||
border-style: solid;
|
||||
border: solid white;
|
||||
border-radius: 6px;
|
||||
padding-bottom: 2px;
|
||||
padding-top: 2px;
|
||||
margin-top: 3px;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
|
||||
.slider {
|
||||
-webkit-appearance: none;
|
||||
width: 98%;
|
||||
background: none;
|
||||
outline: none;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
height: 1px;
|
||||
border: 2px solid #white;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.slider::-webkit-slider-thumb {
|
||||
-webkit-appearance: none;
|
||||
border: 1px solid #bdc3c7;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background: #4CAF50;
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.slider::-moz-range-thumb {
|
||||
border: 1px solid #bdc3c7;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background: #4CAF50;
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.slider::-moz-range-track {
|
||||
width: 100%;
|
||||
height: 5px;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.inline{
|
||||
display:inline-block;
|
||||
margin: auto;
|
||||
}
|
||||
span.spacer{
|
||||
display:inline-block;
|
||||
width: 1px;
|
||||
height: 25px;
|
||||
color: #fff;
|
||||
background-color: #fff;
|
||||
border: 1px solid #fff;
|
||||
border-radius: 6px;
|
||||
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue