You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
434 lines
11 KiB
434 lines
11 KiB
2 years ago
|
let trees = [],
|
||
|
birds = [],
|
||
|
clouds = [],
|
||
|
humans = [],
|
||
|
ground = [],
|
||
|
time = 12, // in hours
|
||
|
cycleTime = 10, // in minutes
|
||
|
worldWidth = 40000,
|
||
|
viewPort = {x: Math.round(worldWidth / 2 - window.innerWidth / 2), y: 0, v: 20},
|
||
|
waveDispo = 0,
|
||
|
cliffDispo = 25,
|
||
|
STRAIGHT_GROUND = 0,
|
||
|
SMALL_HILLS = 1,
|
||
|
LARGE_HILL = 2,
|
||
|
LAKE = 3,
|
||
|
gameIsRunning = false;
|
||
|
|
||
|
function setup(){
|
||
|
setFrameRate(120);
|
||
|
createCanvas(window.innerWidth, window.innerHeight);
|
||
|
background(160, 160, 255);
|
||
|
noStroke();
|
||
|
$("#saveLink").hide();
|
||
|
$("#fileBrowser").hide();
|
||
|
$("#toolBarOpener").hide();
|
||
|
$("#infoWrapper").hide();
|
||
|
$("button").on("click", function(){this.blur();});
|
||
|
}
|
||
|
|
||
|
function createWorld(){
|
||
|
$("#restoreWorld, #createWorld").hide();
|
||
|
fill(80);
|
||
|
rect(width * 0.1, height * 0.5 - 25, width * 0.8, 50);
|
||
|
fill(0, 255, 0);
|
||
|
let x = 0,
|
||
|
createProgress = 0,
|
||
|
y = random(height * 0.7, height * 0.8),
|
||
|
treeDist = 0,
|
||
|
a = 0, c = 1, b = 0,
|
||
|
biome,
|
||
|
biomeX = 0,
|
||
|
biomeDistance = 1,
|
||
|
usedBiomes = [],
|
||
|
biomes = [STRAIGHT_GROUND, SMALL_HILLS, LARGE_HILL, LAKE],
|
||
|
isWooden;
|
||
|
|
||
|
function create(){
|
||
|
//Updating progressbar
|
||
|
createProgress++;
|
||
|
rect(width * 0.1, height * 0.5 - 25, width * 0.8 * (createProgress / (worldWidth * 2)), 50);
|
||
|
|
||
|
//Main creating
|
||
|
if (ground.length < worldWidth){
|
||
|
//Ground
|
||
|
let biomeRemainder = (x - biomeX) % biomeDistance;
|
||
|
if (biomeRemainder == 0){
|
||
|
biome = random(biomes);
|
||
|
if (usedBiomes.includes(biome)) biome = random(biomes);
|
||
|
usedBiomes.push(biome);
|
||
|
biomeX = x;
|
||
|
isWooden = biome == LAKE ? false : random([true, false]);
|
||
|
biomeDistance = round(random(1000, 1500));
|
||
|
a = 0, c = 1, b = 0;
|
||
|
}
|
||
|
switch (biome){
|
||
|
case STRAIGHT_GROUND:
|
||
|
a = 0;
|
||
|
if (y < height * 0.3) a = -1;
|
||
|
if (y > height * 0.95) a = 1;
|
||
|
//y = noise(x / 100, y / 100) * height;
|
||
|
y += random(-0.25 - a, 0.25 - a);
|
||
|
break;
|
||
|
case SMALL_HILLS:
|
||
|
if (biomeRemainder == round(biomeDistance / 12)
|
||
|
|| biomeRemainder == round(biomeDistance * 5 / 12)
|
||
|
|| biomeRemainder == round(biomeDistance * 0.75))
|
||
|
c = -1;
|
||
|
if (biomeRemainder == round(biomeDistance * 0.25)
|
||
|
|| biomeRemainder == round(biomeDistance * 7 / 12)
|
||
|
|| biomeRemainder == round(biomeDistance * 11 / 12))
|
||
|
c = 1;
|
||
|
if (y < height * 0.3){
|
||
|
c = -1;
|
||
|
b = -0.5;
|
||
|
}
|
||
|
else if (y > height * 0.9){
|
||
|
c = 1;
|
||
|
b = 0.5;
|
||
|
}
|
||
|
else b = 0;
|
||
|
a -= random(0.005, 0.015) * c;
|
||
|
y += random(2 * a - b);
|
||
|
break;
|
||
|
case LARGE_HILL:
|
||
|
if (biomeRemainder == round(biomeDistance * 0.25)) c = -1;
|
||
|
if (biomeRemainder == round(biomeDistance * 0.75)) c = 1;
|
||
|
if (y < height * 0.3){
|
||
|
c = -1;
|
||
|
b = -1;
|
||
|
}
|
||
|
else if (y > height * 0.9){
|
||
|
c = 1;
|
||
|
b = 1;
|
||
|
}
|
||
|
else b = 0;
|
||
|
a -= random(0.0025, 0.0075) * c;
|
||
|
y += random(2 * a - b);
|
||
|
break;
|
||
|
}
|
||
|
ground[x] = {y: y, biome: biome, isWooden: isWooden};
|
||
|
|
||
|
//Trees
|
||
|
let treeH, treeW, valid;
|
||
|
treeDist++;
|
||
|
if (isWooden) valid = random(100) < 1 ? true : false;
|
||
|
if (!isWooden) valid = random(1000) < 0.5 ? true : false;
|
||
|
treeH = random(height * 0.3, height * 0.5),
|
||
|
treeW = random(40, 60);
|
||
|
if (treeDist < treeH * 0.25) valid = false;
|
||
|
try{if (ground[round(x - treeW / 2)].biome == LAKE || biomeRemainder > biomeDistance - treeW || y - treeH < height * 0.15) valid = false;}
|
||
|
catch(e){}
|
||
|
if (valid){
|
||
|
trees.push(new Tree(x, treeW, treeH));
|
||
|
treeDist = 0;
|
||
|
}
|
||
|
|
||
|
//Clouds
|
||
|
let cloudY, cloudW, cloudH;
|
||
|
valid = random(1000) < 1 ? true : false;
|
||
|
if (valid){
|
||
|
cloudY = random(0, 200),
|
||
|
cloudW = random(100, 500),
|
||
|
cloudH = random(50, 80);
|
||
|
clouds.push(new Cloud(x, cloudY, cloudW, cloudH));
|
||
|
}
|
||
|
|
||
|
//Birds
|
||
|
valid = random(1000) < 1 ? true : false;
|
||
|
if (valid){
|
||
|
birds.push(new Bird(x));
|
||
|
}
|
||
|
|
||
|
x++;
|
||
|
}
|
||
|
|
||
|
//Reset some variables
|
||
|
if (x == worldWidth){
|
||
|
x = 0;
|
||
|
a = 0;
|
||
|
}
|
||
|
|
||
|
//Ground details
|
||
|
if (ground.length == worldWidth){
|
||
|
try{
|
||
|
if (ground[x].biome != LAKE && ground[x + cliffDispo * 2].biome == LAKE){
|
||
|
a++;
|
||
|
ground[x].y += a * a * 0.01;
|
||
|
}
|
||
|
else if (ground[x].biome != LAKE && ground[x - cliffDispo * 2].biome == LAKE){
|
||
|
a--;
|
||
|
ground[x].y += a * a * 0.01;
|
||
|
}
|
||
|
else if (ground[x].biome == LAKE) a = cliffDispo * 2;
|
||
|
else a = 0;
|
||
|
}catch(e){}
|
||
|
x++;
|
||
|
}
|
||
|
|
||
|
//End progress if bar is full
|
||
|
if (createProgress == worldWidth * 2){
|
||
|
clearInterval(interval);
|
||
|
trees.shuffle();
|
||
|
clouds.shuffle();
|
||
|
birds.shuffle();
|
||
|
$("#toolBarOpener").show();
|
||
|
gameIsRunning = true;
|
||
|
}
|
||
|
if (createProgress < worldWidth * 2){
|
||
|
setTimeout(create, 0);
|
||
|
}
|
||
|
}
|
||
|
let interval = setInterval(create, 0);
|
||
|
}
|
||
|
|
||
|
function downloadWorld(){
|
||
|
let newGround = [],
|
||
|
newTrees = [],
|
||
|
newBirds = [],
|
||
|
newClouds= [],
|
||
|
worldValues = [{time: time, viewPort: {x: viewPort.x, y: viewPort.y}}];
|
||
|
for (let g of ground) newGround.push({y: round(g.y), b: g.biome, w: g.isWooden ? 1 : 0});
|
||
|
for (let t of trees) newTrees.push({x: round(t.x), w: round(t.width), h: round(t.height), c: t.color});
|
||
|
for (let b of birds) newBirds.push({x: round(b.x), y: round(b.y), v: round(b.v * 100) / 100, l: round(b.length)});
|
||
|
for (let c of clouds) newClouds.push({x: round(c.x), y: round(c.y), w: round(c.width), h: round(c.height), b: round(c.brightness * 100) / 100});
|
||
|
let str =
|
||
|
JSON.stringify(newGround.partitiate(1)) + ", "
|
||
|
+ JSON.stringify(newTrees.partitiate(1)) + ", "
|
||
|
+ JSON.stringify(newBirds.partitiate(1)) + ", "
|
||
|
+ JSON.stringify(newClouds.partitiate(1)) + ", "
|
||
|
+ JSON.stringify(worldValues);
|
||
|
let data = 'data:application/json;charset=utf-8,['+ encodeURIComponent(str) + "]";
|
||
|
$("#saveLink").attr("href", data);
|
||
|
$("#saveLink")[0].click();
|
||
|
}
|
||
|
|
||
|
function uploadWorld(){
|
||
|
gameIsRunning = false;
|
||
|
let files = document.getElementById("fileBrowser").files;
|
||
|
let fr = new FileReader(), recovery = {ground: ground, trees: trees, birds: birds, clouds: clouds, time: time, viewPort: viewPort};
|
||
|
fr.onload = function(e){
|
||
|
try{
|
||
|
let data = JSON.parse(e.target.result);
|
||
|
let newGround = data[0].departitiate();
|
||
|
let newTrees = data[1].departitiate();
|
||
|
let newBirds = data[2].departitiate();
|
||
|
let newClouds = data[3].departitiate();
|
||
|
|
||
|
ground = [], trees = [], birds = [], clouds = [];
|
||
|
|
||
|
for (let g of newGround) ground.push({y: g.y, biome: g.b, isWooden: g.w == 1 ? true : false});
|
||
|
for (let t of newTrees){
|
||
|
let i = newTrees.indexOf(t);
|
||
|
trees.push(new Tree(t.x, t.w, t.h));
|
||
|
trees[i].color = t.c;
|
||
|
}
|
||
|
for (let b of newBirds){
|
||
|
let i = newBirds.indexOf(b);
|
||
|
birds.push(new Bird(b.x));
|
||
|
birds[i].y = b.y;
|
||
|
birds[i].v = b.v;
|
||
|
birds[i].length = b.l;
|
||
|
}
|
||
|
for (let c of newClouds){
|
||
|
let i = newClouds.indexOf(c);
|
||
|
clouds.push(new Cloud(c.x, c.y, c.w, c.h));
|
||
|
clouds[i].brightness = c.b;
|
||
|
}
|
||
|
|
||
|
time = data[4][0].time;
|
||
|
viewPort = {x: data[4][0].viewPort.x, y: data[4][0].viewPort.y, v: recovery.viewPort.v};
|
||
|
$("#restoreWorld, #createWorld").hide();
|
||
|
$("#toolBarOpener").show();
|
||
|
|
||
|
} catch(e){
|
||
|
ground = recovery.ground;
|
||
|
trees = recovery.trees;
|
||
|
birds = recovery.birds;
|
||
|
clouds = recovery.clouds;
|
||
|
time = recovery.time;
|
||
|
viewPort = recovery.viewPort;
|
||
|
waveDispo = recovery.waveDispo;
|
||
|
window.alert("Data is damaged!");
|
||
|
}
|
||
|
|
||
|
if (ground.length > 0) gameIsRunning = true;
|
||
|
else {$("#restoreWorld, #createWorld").show();}
|
||
|
}
|
||
|
fr.readAsText(files.item(0));
|
||
|
}
|
||
|
|
||
|
function draw(){
|
||
|
if (gameIsRunning){
|
||
|
clear();
|
||
|
translate(-viewPort.x, -viewPort.y);
|
||
|
updateUnits();
|
||
|
updateGround();
|
||
|
updateTime();
|
||
|
checkViewPort();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function updateUnits(){
|
||
|
//Sky
|
||
|
background(160, 160, 255);
|
||
|
|
||
|
//Clouds
|
||
|
for (let c of clouds){
|
||
|
c.move();
|
||
|
c.show();
|
||
|
}
|
||
|
|
||
|
//Birds
|
||
|
for (let b of birds){
|
||
|
b.move();
|
||
|
b.show();
|
||
|
}
|
||
|
|
||
|
//Trees
|
||
|
for (let t of trees){
|
||
|
t.show();
|
||
|
}
|
||
|
|
||
|
//Humans
|
||
|
for (let h of humans){
|
||
|
h.move();
|
||
|
h.show();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function updateGround(){
|
||
|
let x, y, lake = false, grassH = 20, waveH = 2;
|
||
|
waveDispo += 1;
|
||
|
waveDispo %= 8 * PI;
|
||
|
function wave(x){
|
||
|
return sin((0.25 * (x - waveDispo))) * 3;
|
||
|
}
|
||
|
|
||
|
// grass
|
||
|
fill(100, 200, 100);
|
||
|
beginShape();
|
||
|
for (x = viewPort.x; x <= viewPort.x + width; x++){
|
||
|
//console.log(x);
|
||
|
let g = ground[x];
|
||
|
if (g.biome == LAKE)
|
||
|
vertex(x, height);
|
||
|
else
|
||
|
vertex(x, g.y);
|
||
|
}
|
||
|
for (x = viewPort.x + width; x >= viewPort.x; x--){
|
||
|
let g = ground[x];
|
||
|
if (g.biome == LAKE)
|
||
|
vertex(x, height);
|
||
|
else
|
||
|
vertex(x, g.y + grassH);
|
||
|
}
|
||
|
endShape();
|
||
|
|
||
|
// water
|
||
|
fill(100, 100, 255);
|
||
|
beginShape();
|
||
|
for (x = viewPort.x; x <= viewPort.x + width; x++){
|
||
|
let g = ground[x];
|
||
|
if (g.biome == LAKE)
|
||
|
vertex(x, g.y + grassH / 2 + waveH + cliffDispo + wave(x));
|
||
|
else
|
||
|
vertex(x, height);
|
||
|
}
|
||
|
for (x = viewPort.x + width - 1; x >= viewPort.x; x--){
|
||
|
vertex(x, height);
|
||
|
}
|
||
|
endShape();
|
||
|
|
||
|
// water --> waves
|
||
|
fill(50, 50, 255);
|
||
|
beginShape();
|
||
|
for (x = viewPort.x; x <= viewPort.x + width; x++){
|
||
|
let g = ground[x];
|
||
|
if (g.biome == LAKE)
|
||
|
vertex(x, g.y + grassH / 2 + cliffDispo + wave(x));
|
||
|
else
|
||
|
vertex(x, height);
|
||
|
}
|
||
|
for (x = viewPort.x + width - 1; x >= viewPort.x; x--){
|
||
|
let g = ground[x];
|
||
|
if (g.biome == LAKE)
|
||
|
vertex(x, g.y + grassH / 2 + cliffDispo + wave(x) + waveH);
|
||
|
else
|
||
|
vertex(x, height);
|
||
|
}
|
||
|
endShape();
|
||
|
|
||
|
// dirt
|
||
|
fill(80, 60, 40);
|
||
|
beginShape();
|
||
|
for (x = viewPort.x; x <= viewPort.x + width; x++){
|
||
|
let g = ground[x];
|
||
|
if (g.biome == LAKE)
|
||
|
vertex(x, height);
|
||
|
else
|
||
|
vertex(x, g.y + grassH);
|
||
|
}
|
||
|
for (x = viewPort.x + width; x >= viewPort.x; x--){
|
||
|
vertex(x, height);
|
||
|
}
|
||
|
endShape();
|
||
|
}
|
||
|
|
||
|
function updateTime(){
|
||
|
function getDayBrightness(){
|
||
|
let value = sin(PI / 12 * (time - 8)) + 0.25;
|
||
|
value = value > 1 ? 1 : value;
|
||
|
value = value < 0.1 ? 0.1 : value;
|
||
|
return value;
|
||
|
}
|
||
|
let timeTick = 24 / (60 * cycleTime * frameRate());
|
||
|
time += (timeTick == Infinity ? 0 : timeTick);
|
||
|
fill(0, 0, 0, 255 - 255 * getDayBrightness());
|
||
|
rect(viewPort.x, viewPort.y, width, height);
|
||
|
}
|
||
|
|
||
|
function checkViewPort(){
|
||
|
let scrollBegin = 100;
|
||
|
if (winMouseX <= scrollBegin && viewPort.x > 0)
|
||
|
viewPort.x -= round(viewPort.v * (scrollBegin - winMouseX) / scrollBegin);
|
||
|
if (winMouseX >= width - scrollBegin && viewPort.x < worldWidth - width - viewPort.v)
|
||
|
viewPort.x += round(viewPort.v * (winMouseX - (width - scrollBegin)) / scrollBegin);
|
||
|
if (viewPort.x < 0) viewPort.x = 0;
|
||
|
if (viewPort.x >= worldWidth + width) viewPort.x = worldWidth - width - 1;
|
||
|
}
|
||
|
|
||
|
function togglePause(obj){
|
||
|
gameIsRunning = !gameIsRunning;
|
||
|
if (gameIsRunning) $(obj).html("||");
|
||
|
else $(obj).html("►");
|
||
|
}
|
||
|
|
||
|
function toggleToolBar(obj){
|
||
|
if ($(obj).css("top") == "0px"){
|
||
|
$(obj).animate({top: 103}, {top: "easeOut"});
|
||
|
$("#toolBar").animate({top: 0}, {top: "easeOut"});
|
||
|
}
|
||
|
if ($(obj).css("top") == "103px"){
|
||
|
$(obj).animate({top: 0}, {top: "easeOut"});
|
||
|
$("#toolBar").animate({top: -103}, {top: "easeOut"});
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function toggleInfo(){
|
||
|
$("#pauseButton")[0].click();
|
||
|
$("#infoWrapper").toggle();
|
||
|
}
|
||
|
|
||
|
Array.prototype.departitiate = function(){
|
||
|
let newArr = [];
|
||
|
for (let i = 0; i < this.length; i++){
|
||
|
let a = this[i];
|
||
|
for (let j = 0; j < a.length; j++){
|
||
|
let object = a[j];
|
||
|
newArr.push(object);
|
||
|
//for (let k = 0; k < b.length; k++){}
|
||
|
}
|
||
|
}
|
||
|
return newArr;
|
||
|
}
|