const BIASES = { 0xc8ff50: 1, 0x46aafa: 0.5, 0xff0000: 0.75, 0x0000ff: 0.4, }; function validXY(x, y) { if (x < 0 || x >= 3200) return false; if (y < 0 || y >= 1600) return false; return true; } function getRGBA(data, i, out) { for (let j = i * 4; j < i * 4 + 4; j++) { out[j - i*4] = data[j]; } return out; } function setRGBA(data, i, input) { for (let j = i * 4; j < i * 4 + 4; j++) { data[j] = input[j - i * 4]; } } function isLand(data) { if (data[0] == 255 && data[1] == 255 && data[2] == 255 && data[3] == 255) return false; return true; } function Game(baseMap) { this.img = new Image(); this.baseMap = baseMap; } Game.prototype.main = function() { var {biomes, ctx, colonized} = this; var dat = ctx.getImageData(0,0,3200,1600); var data = dat.data; var out = new Uint8Array(4); for (let k = 0; k < 3200*1600/10; k++) { let i = Math.floor(Math.random() * biomes.data.length / 4); if (!colonized[i]) continue; var x = i % 3200; var y = Math.floor(i / 3200); let rgba = getRGBA(biomes.data,i,out); if (isLand(rgba)) setRGBA(data,i,[255,128,128,255]); let weight = 10; let broken = false; for (let dx = -1; dx <= 1; dx++) { for (let dy = -1; dy <= 1; dy++ ) { weight--; let x2 = x + dx; let y2 = y + dy; let i = x2 + y2 * 3200; if (!validXY(x2,y2)) continue; let rgba = getRGBA(biomes.data,i,out); let rgbaH = rgba[0] * 0x10000 + rgba[1] * 0x100 + rgba[2]; if (Math.random() > ((rgbaH in BIASES) ? BIASES[rgbaH] : 0.2) / weight) { continue; } if (colonized[y2 * 3200 + x2] == 1) { continue; } colonized[y2 * 3200 + x2] = 1; broken = true; break; } if (broken) break; } } ctx.putImageData(dat,0,0,0,0,3200,1600); } Game.prototype.map = function() { var {biomes, ctx} = this; var dat = ctx.getImageData(0,0,3200,1600); var data = dat.data; var out = new Uint8Array(4); for (let i = 0; i < biomes.data.length; i++) { let rgba = getRGBA(biomes.data,i, out); if (!isLand(rgba,i)) { setRGBA(data,i,[255,255,255,255]) } else { setRGBA(data,i,[0,0,0,255]); } } ctx.putImageData(dat,0,0,0,0,3200,1600); } Game.prototype.place = function() { var {biomes,ctx,colonized} = this; var out = new Uint8Array(4); let i = 0; while (true) { i = Math.floor(Math.random() * biomes.data.length / 4); let rgba = getRGBA(biomes.data,i,out); if (isLand(rgba)) break; } colonized[i] = 1; } Game.prototype.loop = function() { let that = this; setInterval(function() { that.main() } ,1000 / 60); } Game.prototype.startGame = function() { var canvas = document.querySelector("#canvas"); var ctx = canvas.getContext("2d",{ willReadFrequently: true }); this.ctx = ctx; ctx.drawImage(this.img,0, 0,3200,1600); var dat = ctx.getImageData(0,0,3200,1600); this.biomes = dat; this.colonized = new Uint8Array(3200*1600); this.map(); this.place(); this.loop(); } Game.prototype.init = function() { let that = this; this.img.src = this.baseMap; this.img.onload = function() { that.startGame() }; } new Game("base.png").init();