1293 lines
52 KiB
HTML
1293 lines
52 KiB
HTML
<html>
|
||
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<title>Sandbox Game</title>
|
||
<link href="https://fonts.googleapis.com/css?family=Press+Start+2P" rel="stylesheet">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
|
||
<style>
|
||
html, body {
|
||
width: 100%;
|
||
height: 100%;
|
||
margin: 0;
|
||
}
|
||
body {
|
||
font-family: 'Press Start 2P';
|
||
background-color: #000000;
|
||
color: #ffffff;
|
||
}
|
||
h1 {
|
||
padding: 10px;
|
||
}
|
||
#gameDiv { /*game canvas*/
|
||
border: 1px solid #ffffff;
|
||
position: absolute;
|
||
left: 50%;
|
||
transform: translate(-50%, -0%);
|
||
-webkit-touch-callout: none; /* iOS Safari */
|
||
-webkit-user-select: none; /* Safari */
|
||
-khtml-user-select: none; /* Konqueror HTML */
|
||
-moz-user-select: none; /* Old versions of Firefox */
|
||
-ms-user-select: none; /* Internet Explorer/Edge */
|
||
user-select: none;
|
||
}
|
||
button, input[type="submit"], input[type="reset"] {
|
||
background: none;
|
||
color: inherit;
|
||
border: none;
|
||
padding: 0;
|
||
font: inherit;
|
||
cursor: pointer;
|
||
outline: inherit;
|
||
}
|
||
#underBox {
|
||
position: absolute;
|
||
left: 50%;
|
||
transform: translate(-50%, -0%);
|
||
margin-top: 10px;
|
||
width: 100%;
|
||
}
|
||
#controls button {
|
||
padding: 5px 10px;
|
||
border-radius: 5px;
|
||
font-size: 1em;
|
||
text-shadow: 0.5px 1px 4px #000000;
|
||
color: rgba(255, 255, 255, 0.75);
|
||
border: 1px solid #797979;
|
||
margin: 0px 5px 5px 5px;
|
||
font-variant: small-caps;
|
||
}
|
||
#controls button.bright {
|
||
text-shadow: 0.5px 1px 4px #ffffff;
|
||
color: rgba(0, 0, 0, 0.75);
|
||
}
|
||
/*Darken when active*/
|
||
#controls button:active, #controls button:active:hover {
|
||
filter: brightness(60%);
|
||
}
|
||
#controls button:hover {
|
||
filter: brightness(90%);
|
||
}
|
||
#controls button:disabled {
|
||
cursor: not-allowed;
|
||
}
|
||
#controls button[current="true"], #controls button[on="true"] {
|
||
border: 1px solid #ffffff;
|
||
filter: brightness(110%);
|
||
box-shadow: 0 5px 15px rgba(255, 255, 255, .4);
|
||
color: rgba(255, 255, 255, 1);
|
||
}
|
||
#controls button.bright[current="true"] {
|
||
color: rgba(0, 0, 0, 1);
|
||
}
|
||
#controls button[on="true"] {
|
||
border-color:lime;
|
||
color:lime;
|
||
}
|
||
#controls div {
|
||
display:block;
|
||
}
|
||
.stat {
|
||
margin-right: 25px;
|
||
margin-bottom: 5px;
|
||
float:right;
|
||
}
|
||
#stats {
|
||
margin: 0px 5px 5px 5px;
|
||
font-size: 0.75em;
|
||
height: 2em;
|
||
}
|
||
#stat-pos, #stat-pixels, #stat-shift, #stat-tps, #stat-ticks {
|
||
float:left;
|
||
}
|
||
</style>
|
||
|
||
<script>
|
||
//replaceAll polyfill
|
||
if (!String.prototype.replaceAll) {String.prototype.replaceAll = function(str, newStr){if (Object.prototype.toString.call(str).toLowerCase() === '[object regexp]') {return this.replace(str, newStr);}return this.replace(new RegExp(str, 'g'), newStr);};}
|
||
</script>
|
||
|
||
<script>
|
||
|
||
behaviors = {
|
||
"POWDER": [
|
||
"XX|XX|XX",
|
||
"XX|XX|XX",
|
||
"M2|M1|M2",
|
||
],
|
||
"AGPOWDER": [
|
||
"M2|M1|M2",
|
||
"XX|XX|XX",
|
||
"XX|XX|XX",
|
||
],
|
||
"LIQUID": [
|
||
"XX|XX|XX",
|
||
"M2|XX|M2",
|
||
"M2|M1|M2",
|
||
],
|
||
"WALL": [
|
||
"XX|XX|XX",
|
||
"XX|XX|XX",
|
||
"XX|XX|XX",
|
||
],
|
||
"UL_UR": [
|
||
"M1|M1|M1",
|
||
"M2|XX|M2",
|
||
"XX|XX|XX",
|
||
],
|
||
"GAS": [
|
||
"M2|M1|M2",
|
||
"M1|XX|M1",
|
||
"M2|M2|M2",
|
||
],
|
||
"DGAS": [
|
||
"M2|M1|M2",
|
||
"M1|DL%5|M1",
|
||
"M2|M2|M2",
|
||
],
|
||
"SUPPORT": [
|
||
"XX|XX|XX",
|
||
"SP|XX|SP",
|
||
"XX|M1|XX",
|
||
],
|
||
"SUPPORTPOWDER": [
|
||
"XX|XX|XX",
|
||
"SP|XX|SP",
|
||
"M2|M1|M2",
|
||
],
|
||
"DELETE": [
|
||
"XX|DL|XX",
|
||
"DL|XX|DL",
|
||
"XX|DL|XX",
|
||
],
|
||
"FILL": [
|
||
"XX|CL|XX",
|
||
"CL|XX|CL",
|
||
"XX|CL|XX",
|
||
],
|
||
|
||
}
|
||
|
||
airDensity = 1.225; // kg/m^3
|
||
airTemp = 20; // Celsius
|
||
// Object storing various powders, called elements
|
||
// name - name of the element
|
||
// color - color of the element's pixel
|
||
// density - density of the element [unused currently] (kg/m^3)
|
||
// behavior - behavior of the element
|
||
// flam - temperature of combustion [unused currently]
|
||
// temp - default temperature of the element (Celsius)
|
||
// tempHigh - highest temperature before state change
|
||
// tempLow - lowest temperature before state change
|
||
// stateHigh - element transformed into when tempHigh is reached
|
||
// stateLow - element transformed into when tempLow is reached
|
||
// viscosity - how slow a liquid will move (higher = slower) (cps)
|
||
|
||
// [Future]
|
||
// changeAfter - seconds before element dissolves
|
||
// change - element transformed into after time
|
||
elements = {
|
||
"sand": {
|
||
"name": "sand",
|
||
"color": "#e6d577",
|
||
"behavior": behaviors.POWDER,
|
||
"density": 1602,
|
||
"tempHigh": 1700,
|
||
"stateHigh": "molten_glass",
|
||
},
|
||
"water": {
|
||
"name": "water",
|
||
"color": "#2167ff",
|
||
"behavior": behaviors.LIQUID,
|
||
"density": 997,
|
||
"tempHigh": 100,
|
||
"stateHigh": "steam",
|
||
"tempLow": 0,
|
||
"stateLow": "ice",
|
||
"viscosity": 1,
|
||
},
|
||
"heat": {
|
||
"name": "heat",
|
||
"color": "#ff0000",
|
||
"behavior": behaviors.WALL,
|
||
"temp": 2,
|
||
},
|
||
"cool": {
|
||
"name": "cool",
|
||
"color": "#0000ff",
|
||
"behavior": behaviors.WALL,
|
||
"temp": -2,
|
||
},
|
||
"wall": {
|
||
"name": "wall",
|
||
"color": "#808080",
|
||
"behavior": behaviors.WALL,
|
||
"density": 0,
|
||
},
|
||
"steam": {
|
||
"name": "steam",
|
||
"color": "#abd6ff",
|
||
"behavior": behaviors.GAS,
|
||
"density": 0.013,
|
||
"temp": 100,
|
||
"tempLow": 95,
|
||
"stateLow": "water",
|
||
},
|
||
"ice": {
|
||
"name": "ice",
|
||
"color": "#c5e9f0",
|
||
"behavior": behaviors.WALL,
|
||
"density": 917,
|
||
"temp": 0,
|
||
"tempHigh": 5,
|
||
"stateHigh": "water",
|
||
},
|
||
"snow": {
|
||
"name": "snow",
|
||
"color": "#e1f8fc",
|
||
"behavior": behaviors.POWDER,
|
||
"density": 100,
|
||
"temp": 0,
|
||
"tempHigh": 5,
|
||
"stateHigh": "water",
|
||
},
|
||
"packed_snow": {
|
||
"name": "packed snow",
|
||
"color": "#bcdde3",
|
||
"behavior": behaviors.SUPPORTPOWDER,
|
||
"density": 100,
|
||
"temp": 0,
|
||
"tempHigh": 20,
|
||
"stateHigh": "water",
|
||
},
|
||
"wood": {
|
||
"name": "wood",
|
||
"color": "#a0522d",
|
||
"behavior": behaviors.WALL,
|
||
"density": 745,
|
||
"tempHigh": 230,
|
||
"stateHigh": "fire",
|
||
},
|
||
"fire": {
|
||
"name": "fire",
|
||
"color": ["#ff6b21","#ffa600","#ff4000"],
|
||
"behavior": behaviors.UL_UR,
|
||
"density": 1300,
|
||
"temp":400,
|
||
"tempChange":-1,
|
||
"tempLow":350,
|
||
"stateLow": "smoke",
|
||
"tempHigh": 6095,
|
||
"stateHigh": "plasma",
|
||
},
|
||
"smoke": {
|
||
"name": "smoke",
|
||
"color": "#383838",
|
||
"behavior": behaviors.DGAS,
|
||
"density": 1180,
|
||
"temp": 114,
|
||
"tempHigh": 605,
|
||
"stateHigh": "fire",
|
||
"deleteAfter": 100,
|
||
},
|
||
"rock": {
|
||
"name": "rock",
|
||
"color": ["#808080","#4f4f4f","#949494"],
|
||
"behavior": behaviors.POWDER,
|
||
"density": 2700,
|
||
"tempHigh": 950,
|
||
"stateHigh": "magma",
|
||
},
|
||
"magma": {
|
||
"name": "magma",
|
||
"color": ["#ff6f00","#ff8c00","#ff4d00"],
|
||
"behavior": behaviors.LIQUID,
|
||
"temp": 950,
|
||
"tempLow": 800,
|
||
"stateLow": "rock",
|
||
"viscosity": 10000,
|
||
},
|
||
"concrete": {
|
||
"name": "concrete",
|
||
"color": "#ababab",
|
||
"behavior": behaviors.SUPPORT,
|
||
"density": 2400,
|
||
"tempHigh": 1500,
|
||
"stateHigh": "magma",
|
||
},
|
||
"plasma": {
|
||
"name": "plasma",
|
||
"color": ["#8800ff","#b184d9","#8800ff"],
|
||
"behavior": behaviors.GAS,
|
||
"temp":12750,
|
||
"tempChange":-25,
|
||
"tempLow":10000,
|
||
"stateLow": "fire",
|
||
},
|
||
"iron": {
|
||
"name": "iron",
|
||
"color": "#cbcdcd",
|
||
"behavior": behaviors.WALL,
|
||
"tempHigh": 1538,
|
||
},
|
||
"glass": {
|
||
"name": "glass",
|
||
"color": "#616869",
|
||
"behavior": behaviors.WALL,
|
||
"tempHigh": 1500,
|
||
},
|
||
"blood": {
|
||
"name": "blood",
|
||
"color": "#ff0000",
|
||
"behavior": behaviors.LIQUID,
|
||
"viscosity": 10,
|
||
},
|
||
"honey": {
|
||
"name": "honey",
|
||
"color": ["#ffd700","#ffae00"],
|
||
"behavior": behaviors.LIQUID,
|
||
"viscosity": 10000,
|
||
},
|
||
"ketchup": {
|
||
"name": "ketchup",
|
||
"color": "#ff3119",
|
||
"behavior": behaviors.LIQUID,
|
||
"viscosity": 50000,
|
||
},
|
||
"molasses": {
|
||
"name": "molasses",
|
||
"color": "#240f00",
|
||
"behavior": behaviors.LIQUID,
|
||
"viscosity": 7500,
|
||
},
|
||
"filler": {
|
||
"name": "filler",
|
||
"color": "#ae4cd9",
|
||
"behavior": behaviors.FILL,
|
||
},
|
||
"dirt": {
|
||
"name": "dirt",
|
||
"color": ["#9e6b4b","#9e6b4b","#9e6b4b","#9e6b4b","#9e6b4b","#9e6b4b","#9e6b4b","#9e6b4b","#9e6b4b","#9e6b4b","#9e6b4b","#9e6b4b","#9e6b4b","#9e6b4b","#b0a39b"],
|
||
"behavior": behaviors.POWDER,
|
||
},
|
||
"gravel": {
|
||
"name": "gravel",
|
||
"color": "#454b51",
|
||
"behavior": behaviors.POWDER,
|
||
},
|
||
"slime": {
|
||
"name": "slime",
|
||
"color": "#81cf63",
|
||
"behavior": behaviors.LIQUID,
|
||
"viscosity": 5000,
|
||
},
|
||
"ruins": {
|
||
"name": "ruins",
|
||
"color": "#5c5c5c",
|
||
"behavior": [
|
||
"XX|SP|XX",
|
||
"XX|XX|XX",
|
||
"M2%1|M1|M2%1"
|
||
],
|
||
},
|
||
"void": {
|
||
"name": "void",
|
||
"color": "#262626",
|
||
"behavior": behaviors.DELETE,
|
||
},
|
||
"flea": {
|
||
"name": "flea",
|
||
"color": "#9e4732",
|
||
"behavior": [
|
||
"M2|XX|M2",
|
||
"DL:blood|XX|DL:blood",
|
||
"M2|M1|M2",
|
||
],
|
||
},
|
||
"fly": {
|
||
"name": "fly",
|
||
"color": "#303012",
|
||
"behavior": [
|
||
"M1|XX|M1",
|
||
"XX|XX|XX",
|
||
"M1|M2|M1",
|
||
],
|
||
},
|
||
"smoke_grenade": {
|
||
"name": "smoke grenade",
|
||
"color": "#2b382c",
|
||
"behavior": [
|
||
"XX|CR:smoke|XX",
|
||
"XX|XX|XX",
|
||
"M2|M1|M2",
|
||
],
|
||
},
|
||
"torch": {
|
||
"name": "torch",
|
||
"color": "#d68542",
|
||
"behavior": [
|
||
"XX|CR:fire|XX",
|
||
"XX|XX|XX",
|
||
"XX|XX|XX",
|
||
],
|
||
},
|
||
"water_spout": {
|
||
"name": "water spout",
|
||
"color": "#606378",
|
||
"behavior": [
|
||
"XX|CR:water|XX",
|
||
"CR:water|XX|CR:water",
|
||
"XX|CR:water|XX",
|
||
],
|
||
},
|
||
"bone_marrow": {
|
||
"name": "bone marrow",
|
||
"color": "#c97265",
|
||
"behavior": [
|
||
"XX|CR:blood,bone|XX",
|
||
"CR:blood,bone|XX|CR:blood,bone",
|
||
"XX|CR:blood,bone|XX",
|
||
],
|
||
},
|
||
"bone": {
|
||
"name": "bone",
|
||
"color": "#d9d9d9",
|
||
"behavior": behaviors.SUPPORT
|
||
},
|
||
"anti_powder": {
|
||
"name": "anti powder",
|
||
"color": "#ebd1d8",
|
||
"behavior": behaviors.AGPOWDER
|
||
},
|
||
"vertical": {
|
||
"name": "vertical",
|
||
"color": "#d9d9d9",
|
||
"behavior": [
|
||
"XX|M1|XX",
|
||
"CR:wall|XX|CR:wall",
|
||
"XX|XX|XX",
|
||
]
|
||
},
|
||
"horizontal": {
|
||
"name": "horizontal",
|
||
"color": "#d9d9d9",
|
||
"behavior": [
|
||
"XX|CR:wall|XX",
|
||
"XX|XX|M1",
|
||
"XX|CR:wall|XX",
|
||
]
|
||
},
|
||
"rain_cloud": {
|
||
"name": "rain cloud",
|
||
"color": "#636b78",
|
||
"behavior": [
|
||
"XX|XX|XX",
|
||
"XX|XX|XX",
|
||
"XX|CR:water%1|XX",
|
||
]
|
||
},
|
||
"snow_cloud": {
|
||
"name": "snow cloud",
|
||
"color": "#7e8691",
|
||
"behavior": [
|
||
"XX|XX|XX",
|
||
"XX|XX|XX",
|
||
"XX|CR:packed_snow%1|XX",
|
||
]
|
||
},
|
||
"plant": {
|
||
"name": "plant",
|
||
"color": "#00bf00",
|
||
"behavior": behaviors.WALL
|
||
},
|
||
"seed": {
|
||
"name": "seed",
|
||
"color": "#57eb57",
|
||
"behavior": behaviors.POWDER
|
||
},
|
||
|
||
}
|
||
|
||
// Loop through behaviors and each behavior, if it is a string, split the items and replace the value with the array
|
||
for (var behavior in behaviors) {
|
||
if (typeof behaviors[behavior][0] === "string") {
|
||
var newbehavior = [];
|
||
for (var i = 0; i < behaviors[behavior].length; i++) {
|
||
newbehavior.push(behaviors[behavior][i].split("|"));
|
||
}
|
||
behaviors[behavior] = newbehavior;
|
||
}
|
||
}
|
||
|
||
// Loop through each element. If it has a tempHigh, but not a stateHigh, create a new molten element
|
||
for (element in elements) {
|
||
if (elements[element].tempHigh && !elements[element].stateHigh) {
|
||
var newname = "molten_"+element;
|
||
elements[element].stateHigh = newname;
|
||
elements[newname] = {
|
||
"name": newname.replaceAll("_"," "),
|
||
"color": ["#ff6f00","#ff8c00","#ff4d00"],
|
||
"behavior": behaviors.LIQUID,
|
||
"density": elements[element].density,
|
||
"temp": elements[element].tempHigh,
|
||
"tempLow": elements[element].tempHigh-100,
|
||
"stateLow": element,
|
||
"viscosity": 10000,
|
||
"hidden": true,
|
||
}
|
||
}
|
||
if (elements[element].behavior && typeof elements[element].behavior[0] === "string") {
|
||
var newbehavior = [];
|
||
for (var i = 0; i < elements[element].behavior.length; i++) {
|
||
newbehavior.push(elements[element].behavior[i].split("|"));
|
||
}
|
||
elements[element].behavior = newbehavior;
|
||
}
|
||
}
|
||
|
||
function hexToRGB(hex) {
|
||
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
||
return result ? {
|
||
r: parseInt(result[1], 16),
|
||
g: parseInt(result[2], 16),
|
||
b: parseInt(result[3], 16)
|
||
} : null;
|
||
}
|
||
// convert every color in the elements object to rgb
|
||
for (var key in elements) {
|
||
if (elements.hasOwnProperty(key)) {
|
||
// if the color is an array, loop over each one
|
||
if (elements[key].color instanceof Array) {
|
||
var rgbs = [];
|
||
var rgbos = [];
|
||
for (var i = 0; i < elements[key].color.length; i++) {
|
||
var c = elements[key].color[i];
|
||
if (c.startsWith("#")) {
|
||
var rgb = hexToRGB(c);
|
||
rgbs.push("rgb("+rgb.r+","+rgb.g+","+rgb.b+")");
|
||
rgbos.push(rgb);
|
||
}
|
||
else {
|
||
rgbs.push(c);
|
||
}
|
||
}
|
||
elements[key].color = rgbs;
|
||
elements[key].colorObject = rgbos;
|
||
} else {
|
||
// if elements[key].color starts with #
|
||
if (elements[key].color.startsWith("#")) {
|
||
var rgb = hexToRGB(elements[key].color);
|
||
elements[key].color = "rgb("+rgb.r+","+rgb.g+","+rgb.b+")";
|
||
elements[key].colorObject = rgb;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
currentPixels = [];
|
||
currentID = 0;
|
||
// Pixel class, with attributes such as x, y, and element
|
||
class Pixel {
|
||
constructor(x, y, element) {
|
||
this.x = x;
|
||
this.y = y;
|
||
this.element = element;
|
||
var elementInfo = elements[element];
|
||
this.color = pixelColorPick(this);
|
||
// If element doesn't have temp attribute, set temp to airTemp
|
||
if (elementInfo.temp==undefined) {
|
||
this.temp = airTemp;
|
||
} else {
|
||
this.temp = elementInfo.temp;
|
||
}
|
||
this.start = pixelTicks;
|
||
this.id = currentID;
|
||
currentID++;
|
||
pixelMap[x][y] = this;
|
||
}
|
||
}
|
||
pixelSize = 10;
|
||
|
||
function outOfBounds(x,y) {
|
||
// Returns true if the pixel is out of bounds
|
||
return y > height-1 || y < 1 || x > width-1 || x < 1
|
||
}
|
||
function isEmpty(x, y, ignoreBounds=false) {
|
||
if (outOfBounds(x,y)) {
|
||
return ignoreBounds;
|
||
}
|
||
return pixelMap[x][y] == undefined;
|
||
}
|
||
function canMove(pixel,x,y) {
|
||
if (isEmpty(x,y)) {
|
||
return true;
|
||
}
|
||
}
|
||
function movePixel(pixel,x,y,leaveBehind=null) {
|
||
// if the pixel isn't in currentPixels, return
|
||
if (!currentPixels.includes(pixel)) {
|
||
return;
|
||
}
|
||
// Delete the pixel from the old position
|
||
delete pixelMap[pixel.x][pixel.y];
|
||
if (leaveBehind != null) { createPixel(leaveBehind,x,y); }
|
||
pixel.x = x;
|
||
pixel.y = y;
|
||
pixelMap[x][y] = pixel;
|
||
}
|
||
function clonePixel(pixel,x,y) {
|
||
currentPixels.push(new Pixel(x, y, pixel.element));
|
||
}
|
||
function createPixel(element,x,y) {
|
||
currentPixels.push(new Pixel(x, y, element));
|
||
}
|
||
function deletePixel(x,y,id=null) {
|
||
delete pixelMap[x][y];
|
||
if (id != null) {
|
||
for (var i = 0; i < currentPixels.length; i++) {
|
||
if (currentPixels[i].id == id) {
|
||
currentPixels.splice(i, 1);
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
for (var i = 0; i < currentPixels.length; i++) {
|
||
if (currentPixels[i].x == x && currentPixels[i].y == y) {
|
||
currentPixels.splice(i, 1);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
function swapPixels(pixel1,pixel2) {
|
||
var tempX = pixel1.x;
|
||
var tempY = pixel1.y;
|
||
pixel1.x = pixel2.x;
|
||
pixel1.y = pixel2.y;
|
||
pixel2.x = tempX;
|
||
pixel2.y = tempY;
|
||
//pixel1 = Object.assign(Object.create(Object.getPrototypeOf(pixel1)), pixel1);
|
||
//pixel2 = Object.assign(Object.create(Object.getPrototypeOf(pixel2)), pixel2);
|
||
pixelMap[pixel1.x][pixel1.y] = pixel2;
|
||
pixelMap[pixel2.x][pixel2.y] = pixel1;
|
||
}
|
||
|
||
function behaviorCoords(x,y,bx,by) {
|
||
bx -= 1;
|
||
by -= 1;
|
||
x += bx;
|
||
y += by;
|
||
return {x:x,y:y};
|
||
}
|
||
/* New Behavior Example (Sand)
|
||
[
|
||
["XX","XX","XX"],
|
||
["XX","XX","XX"],
|
||
["M2","M1","M2"]
|
||
] */
|
||
/* Behavior Rules
|
||
XX = Ignore
|
||
M1 = Move (First Priority)
|
||
M2 = Move (Second Priority)
|
||
SP = Support (Doesn't move if all aren't empty)
|
||
DL = Delete
|
||
CL = Clone
|
||
CH = Change
|
||
RP = Replace (Move to an existing element)
|
||
CR:element_name = Create a pixel of element_name
|
||
LB:element_name = Leave behind a pixel of element_name when moved (Must be center cell)
|
||
%(num) = Chance of rule happening
|
||
*/
|
||
function pixelTick(pixel) {
|
||
if (pixel.start == pixelTicks) {return}
|
||
var info = elements[pixel.element];
|
||
var behavior = info.behavior;
|
||
var x = pixel.x;
|
||
var y = pixel.y;
|
||
var move1Spots = [];
|
||
var move2Spots = [];
|
||
var supportSpots = [];
|
||
var replaceSpots = [];
|
||
var deleted = false;
|
||
var leaveBehind = null;
|
||
// Parse behavior
|
||
for (var by = 0; by < behavior.length; by++) {
|
||
for (var bx = 0; bx < behavior[by].length; bx++) {
|
||
var b = behavior[by][bx].trim();
|
||
var arg = null;
|
||
if (b.includes(":")) {
|
||
arg = b.split(":")[1].split(/[\:\%]/)[0];
|
||
if (!b.includes("%")) {
|
||
b = b.split(/[\:\%]/)[0];
|
||
}
|
||
}
|
||
// If b has "%" followed by a number in it, it's a chance to move
|
||
if (b.includes("%")) {
|
||
// Split the string at the "%" and use the second half as the chance (float)
|
||
var chance = parseFloat(b.split("%")[1]);
|
||
//console.log(b+": "+(Math.random()*100 < chance));
|
||
b = b.split(/[\:\%]/)[0];
|
||
}
|
||
else { var chance = 100; }
|
||
if (b == "XX" || b=="") {continue}
|
||
if (Math.random()*100 < chance) {
|
||
var newCoords = behaviorCoords(x,y,bx,by);
|
||
if (b == "M1") {
|
||
if (!((Math.random()*100) < 100 / ((info.viscosity || 1) ** 0.25))) {
|
||
newCoords.x = x;
|
||
}
|
||
move1Spots.push(newCoords);
|
||
}
|
||
else if (b == "M2") {
|
||
if (!((Math.random()*100) < 100 / ((info.viscosity || 1) ** 0.25))) {
|
||
newCoords.x = x;
|
||
}
|
||
move2Spots.push(newCoords);
|
||
}
|
||
else if (b == "SP") {
|
||
supportSpots.push(newCoords);
|
||
}
|
||
else if (b == "DL") {
|
||
if ((!isEmpty(newCoords.x,newCoords.y)) && !outOfBounds(newCoords.x,newCoords.y)) {
|
||
// if the pixel at newCoords is the same element as the pixel, ignore
|
||
if ((!(pixelMap[newCoords.x][newCoords.y].element == pixel.element)) || (newCoords.x == x && newCoords.y == y)) {
|
||
if (pixelMap[newCoords.x][newCoords.y].element == arg || arg == null) {
|
||
deletePixel(newCoords.x,newCoords.y);
|
||
if (newCoords.x == x && newCoords.y == y) {
|
||
deleted = true;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else if (b == "CL") {
|
||
if (isEmpty(newCoords.x,newCoords.y)) {
|
||
clonePixel(pixel,newCoords.x,newCoords.y);
|
||
}
|
||
}
|
||
//Change pixel
|
||
else if (b == "CH") {
|
||
if (!isEmpty(newCoords.x,newCoords.y) && !outOfBounds(newCoords.x,newCoords.y)) {
|
||
var newPixel = pixelMap[newCoords.x][newCoords.y];
|
||
newPixel.element = arg;
|
||
newPixel.color = pixelColorPick(newPixel);
|
||
newPixel.start = pixelTicks;
|
||
}
|
||
}
|
||
//Replace pixel
|
||
/*else if (b == "RP") {
|
||
replaceSpots.push({x:newCoords.x,y:newCoords.y,arg:arg});
|
||
}*/
|
||
//Create pixel
|
||
else if (b == "CR") {
|
||
if (isEmpty(newCoords.x,newCoords.y)) {
|
||
if (arg == null) {
|
||
arg = pixel.element;
|
||
}
|
||
else if (arg.includes(",")) {
|
||
arg = arg.split(",")[Math.floor(Math.random()*arg.split(",").length)];
|
||
}
|
||
createPixel(arg,newCoords.x,newCoords.y);
|
||
}
|
||
}
|
||
//Leave behind element
|
||
else if (b == "LB") {
|
||
if (arg.includes(",")) {
|
||
arg = arg.split(",")[Math.floor(Math.random()*arg.split(",").length)];
|
||
}
|
||
leaveBehind = arg;
|
||
}
|
||
|
||
|
||
}
|
||
}
|
||
}
|
||
if (deleted) {return;}
|
||
var move = true;
|
||
if (supportSpots.length > 0) {
|
||
var supportCount = 0;
|
||
var allEmpty = true;
|
||
for (var i = 0; i < supportSpots.length; i++) {
|
||
var bx = supportSpots[i].x;
|
||
var by = supportSpots[i].y;
|
||
if (!isEmpty(bx,by)) {
|
||
supportCount++;
|
||
}
|
||
}
|
||
if (supportCount == supportSpots.length) {
|
||
move = false;
|
||
}
|
||
}
|
||
/*replaceSpotsCopy = replaceSpots.slice();
|
||
if (replaceSpots.length > 0) {
|
||
while (move1Spots.length > 0) {
|
||
// coords = random item of replaceSpots
|
||
var newCoords = replaceSpots[Math.floor(Math.random()*replaceSpots.length)];
|
||
if (!isEmpty(newCoords.x,newCoords.y) && !outOfBounds(newCoords.x,newCoords.y)) {
|
||
if (newPixel.element == newCoords.arg || newCoords.arg == null) {
|
||
var newPixel = pixelMap[newCoords.x][newCoords.y];
|
||
var newCoords = replaceSpots[Math.floor(Math.random()*replaceSpots.length)];
|
||
deletePixel(newCoords.x,newCoords.y);
|
||
pixelMap[newCoords.x][newCoords.y] = pixel;
|
||
pixel.x = newCoords.x;
|
||
pixel.y = newCoords.y;
|
||
moved = true;
|
||
replaceSpotsCopy.splice(replaceSpotsCopy.indexOf(newCoords),1);
|
||
break;
|
||
}
|
||
}
|
||
replaceSpots.splice(replaceSpots.indexOf(newCoords),1);
|
||
}
|
||
}
|
||
if (replaceSpotsCopy.length > 0 && !moved) {
|
||
// combine replaceSpotsCopy and move2Spots
|
||
move2Spots = move2Spots.concat(replaceSpotsCopy);
|
||
}*/
|
||
|
||
|
||
var moved = false;
|
||
// Move First Priority
|
||
if (move) {
|
||
if (move1Spots.length > 0) {
|
||
// While move1Spots is not empty
|
||
while (move1Spots.length > 0) {
|
||
// coords = random item of move1Spots
|
||
var coords = move1Spots[Math.floor(Math.random()*move1Spots.length)];
|
||
var nx = coords.x;
|
||
var ny = coords.y;
|
||
if (isEmpty(nx,ny)) { // If coords is empty, move to coords
|
||
movePixel(pixel,nx,ny,leaveBehind);
|
||
moved = true;
|
||
break;
|
||
}
|
||
else { // Remove from move1Spots
|
||
move1Spots.splice(move1Spots.indexOf(coords),1);
|
||
}
|
||
}
|
||
}
|
||
// Move Second Priority
|
||
if (!moved && move2Spots.length > 0) {
|
||
// While move2Spots is not empty
|
||
while (move2Spots.length > 0) {
|
||
// coords = random item of move2Spots
|
||
var coords = move2Spots[Math.floor(Math.random()*move2Spots.length)];
|
||
var nx = coords.x;
|
||
var ny = coords.y;
|
||
if (isEmpty(nx,ny)) { // If coords is empty, move to coords
|
||
movePixel(pixel,nx,ny,leaveBehind);
|
||
moved = true;
|
||
break;
|
||
}
|
||
else { // Remove from move2Spots
|
||
move2Spots.splice(move2Spots.indexOf(coords),1);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if (info.tempChange != undefined) {
|
||
pixel.temp += info.tempChange;
|
||
pixelTempCheck(pixel);
|
||
}
|
||
|
||
|
||
}
|
||
function pixelColorPick(pixel) {
|
||
var element = pixel.element;
|
||
var elementInfo = elements[element];
|
||
if (elementInfo.behavior instanceof Array) {
|
||
var rgb = elements[element].colorObject; // {r, g, b}
|
||
// If rgb is an array, choose a random item
|
||
if (Array.isArray(rgb)) {
|
||
rgb = rgb[Math.floor(Math.random() * rgb.length)];
|
||
}
|
||
// Randomly darken or lighten the RGB color
|
||
var coloroffset = Math.floor(Math.random() * (Math.random() > 0.5 ? -1 : 1) * Math.random() * 15);
|
||
var r = rgb.r + coloroffset;
|
||
var g = rgb.g + coloroffset;
|
||
var b = rgb.b + coloroffset;
|
||
// Make sure the color is within the RGB range
|
||
r = Math.max(0, Math.min(255, r));
|
||
g = Math.max(0, Math.min(255, g));
|
||
b = Math.max(0, Math.min(255, b));
|
||
var color = "rgb("+r+","+g+","+b+")";
|
||
}
|
||
else {
|
||
var color = elementInfo.color;
|
||
if (Array.isArray(color)) {
|
||
color = color[Math.floor(Math.random() * color.length)];
|
||
}
|
||
}
|
||
return color;
|
||
}
|
||
function pixelTempCheck(pixel) {
|
||
var elementInfo = elements[pixel.element];
|
||
// If the pixel's temp >= the elementInfo tempHigh, change pixel.element to elementInfo.stateHigh
|
||
if (pixel.temp >= elementInfo.tempHigh) {
|
||
pixel.element = elementInfo.stateHigh;
|
||
pixel.color = pixelColorPick(pixel);
|
||
}
|
||
// If the pixel's temp <= the elementInfo tempLow, change pixel.element to elementInfo.stateLow
|
||
else if (pixel.temp <= elementInfo.tempLow) {
|
||
pixel.element = elementInfo.stateLow;
|
||
pixel.color = pixelColorPick(pixel);
|
||
}
|
||
}
|
||
function getNeighbors(pixel) {
|
||
var neighbors = [];
|
||
var x = pixel.x;
|
||
var y = pixel.y;
|
||
if (!isEmpty(x-1,y,true)) { neighbors.push(pixelMap[x-1][y]); }
|
||
if (!isEmpty(x+1,y,true)) { neighbors.push(pixelMap[x+1][y]); }
|
||
if (!isEmpty(x,y-1,true)) { neighbors.push(pixelMap[x][y-1]); }
|
||
if (!isEmpty(x,y+1,true)) { neighbors.push(pixelMap[x][y+1]); }
|
||
return neighbors;
|
||
}
|
||
function drawPixels(forceTick=false) {
|
||
var canvas = document.getElementById("game");
|
||
var ctx = canvas.getContext("2d");
|
||
// Draw the current pixels
|
||
// newCurrentPixels = shuffled currentPixels
|
||
var newCurrentPixels = currentPixels.slice();
|
||
newCurrentPixels.sort(function() {return 0.5 - Math.random()});
|
||
for (var i = 0; i < newCurrentPixels.length; i++) {
|
||
pixel = newCurrentPixels[i];
|
||
if (pixelMap[pixel.x][pixel.y] == undefined) {continue}
|
||
if ((!paused) || forceTick) {pixelTick(pixel);};
|
||
ctx.fillStyle = pixel.color;
|
||
ctx.fillRect(pixel.x*10, pixel.y*10, 10, 10);
|
||
}
|
||
if ((!paused) || forceTick) {pixelTicks++};
|
||
}
|
||
function tick() {
|
||
// If mouseIsDown, do mouseAction
|
||
if (mouseIsDown) {
|
||
mouseAction(null,mousePos.x,mousePos.y);
|
||
}
|
||
// Get the canvas
|
||
var canvas = document.getElementById("game");
|
||
var ctx = canvas.getContext("2d");
|
||
// Clear the canvas
|
||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||
drawPixels();
|
||
|
||
var mouseOffset = Math.trunc(mouseSize/2);
|
||
var topLeft = [mousePos.x-mouseOffset,mousePos.y-mouseOffset];
|
||
var bottomRight = [mousePos.x+mouseOffset,mousePos.y+mouseOffset];
|
||
// Draw a rectangle around the mouse
|
||
ctx.strokeStyle = "white";
|
||
ctx.strokeRect(topLeft[0]*10,topLeft[1]*10,(bottomRight[0]-topLeft[0]+1)*10,(bottomRight[1]-topLeft[1]+1)*10);
|
||
updateStats();
|
||
ticks ++;
|
||
}
|
||
|
||
currentElement = "sand";
|
||
mouseIsDown = false;
|
||
mouseType = null;
|
||
function mouseClick(e) {
|
||
mouseIsDown = true;
|
||
// If it's a left click
|
||
if (e.button == 0) {
|
||
mouseType = "left";
|
||
}
|
||
else if (e.button == 2) {
|
||
mouseType = "right";
|
||
}
|
||
mouseMove(e);
|
||
}
|
||
function mouseUp(e) {
|
||
mouseIsDown = false;
|
||
}
|
||
|
||
function getMousePos(canvas, evt) {
|
||
// If evt.touches is defined, use the first touch
|
||
if (evt.touches) {
|
||
evt = evt.touches[0];
|
||
}
|
||
var rect = canvas.getBoundingClientRect();
|
||
return {
|
||
// Round to nearest pixel
|
||
x: Math.round((evt.clientX - rect.left)/pixelSize-0.5),
|
||
y: Math.round((evt.clientY - rect.top)/pixelSize-0.5)
|
||
};
|
||
}
|
||
function mouseMove(e) {
|
||
if (mouseIsDown) {
|
||
mouseAction(e);
|
||
}
|
||
else {
|
||
var canvas = document.getElementById("game");
|
||
mousePos = getMousePos(canvas, e);
|
||
}
|
||
}
|
||
function mouseAction(e,mouseX=undefined,mouseY=undefined) {
|
||
if (mouseType == "left") { mouse1Action(e,mouseX,mouseY); }
|
||
else if (mouseType == "right") { mouse2Action(e,mouseX,mouseY); }
|
||
}
|
||
mouseSize = 5;
|
||
mousePos = {x:0,y:0};
|
||
function mouseRange(mouseX,mouseY) {
|
||
var coords = [];
|
||
var mouseOffset = Math.trunc(mouseSize/2);
|
||
var topLeft = [mouseX-mouseOffset,mouseY-mouseOffset];
|
||
var bottomRight = [mouseX+mouseOffset,mouseY+mouseOffset];
|
||
// Starting at the top left, go through each pixel
|
||
for (var x = topLeft[0]; x <= bottomRight[0]; x++) {
|
||
for (var y = topLeft[1]; y <= bottomRight[1]; y++) {
|
||
// If the pixel is empty, add it to coords
|
||
coords.push([x,y]);
|
||
}
|
||
}
|
||
return coords;
|
||
}
|
||
function mouse1Action(e,mouseX=undefined,mouseY=undefined) {
|
||
// If x and y are undefined, get the mouse position
|
||
if (mouseX == undefined && mouseY == undefined) {
|
||
var canvas = document.getElementById("game");
|
||
var ctx = canvas.getContext("2d");
|
||
mousePos = getMousePos(canvas, e);
|
||
var mouseX = mousePos.x;
|
||
var mouseY = mousePos.y;
|
||
}
|
||
var coords = mouseRange(mouseX,mouseY);
|
||
var element = elements[currentElement];
|
||
// For each x,y in coords
|
||
for (var i = 0; i < coords.length; i++) {
|
||
var x = coords[i][0];
|
||
var y = coords[i][1];
|
||
|
||
// If element name is heat or cool
|
||
if (currentElement == "heat" || currentElement == "cool") {
|
||
if (!isEmpty(x,y,false)) {
|
||
if (outOfBounds(x,y)) {
|
||
continue;
|
||
}
|
||
var pixel = pixelMap[x][y];
|
||
if (shiftDown) {pixel.temp += element.temp*10;}
|
||
else {pixel.temp += element.temp;}
|
||
pixelTempCheck(pixel);
|
||
}
|
||
}
|
||
else if (placeMode == "replace") {
|
||
if (outOfBounds(x,y)) {
|
||
continue;
|
||
}
|
||
// Remove pixel at position from currentPixels
|
||
var index = currentPixels.indexOf(pixelMap[x][y]);
|
||
if (index > -1) {
|
||
currentPixels.splice(index, 1);
|
||
}
|
||
currentPixels.push(new Pixel(x, y, currentElement));
|
||
}
|
||
else if (isEmpty(x, y)) {
|
||
currentPixels.push(new Pixel(x, y, currentElement));
|
||
}
|
||
}
|
||
}
|
||
function mouse2Action(e,mouseX=undefined,mouseY=undefined) {
|
||
// Erase pixel at mouse position
|
||
if (mouseX == undefined && mouseY == undefined) {
|
||
var canvas = document.getElementById("game");
|
||
var ctx = canvas.getContext("2d");
|
||
mousePos = getMousePos(canvas, e);
|
||
var mouseX = mousePos.x;
|
||
var mouseY = mousePos.y;
|
||
}
|
||
var coords = mouseRange(mouseX,mouseY);
|
||
// For each x,y in coords
|
||
for (var i = 0; i < coords.length; i++) {
|
||
var x = coords[i][0];
|
||
var y = coords[i][1];
|
||
|
||
if (!isEmpty(x, y)) {
|
||
if (outOfBounds(x,y)) {
|
||
continue
|
||
}
|
||
var pixel = pixelMap[x][y];
|
||
delete pixelMap[x][y];
|
||
// Remove pixel from currentPixels
|
||
for (var j = 0; j < currentPixels.length; j++) {
|
||
if (currentPixels[j].x == x && currentPixels[j].y == y) {
|
||
currentPixels.splice(j, 1);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
function selectElement(element) {
|
||
var e1 = document.getElementById("elementButton-"+currentElement)
|
||
if (e1 != null) { e1.setAttribute("current","false"); }
|
||
currentElement = element;
|
||
var e2 = document.getElementById("elementButton-"+element)
|
||
if (e2 != null) { e2.setAttribute("current","true"); }
|
||
}
|
||
function clearAll() {
|
||
currentPixels = [];
|
||
pixelMap = [];
|
||
for (var i = 0; i < width; i++) {
|
||
pixelMap[i] = [];
|
||
for (var j = 0; j < height; j++) {
|
||
pixelMap[i][j] = undefined;
|
||
}
|
||
}
|
||
pixelTicks = 0;
|
||
}
|
||
|
||
// Update stats
|
||
function updateStats() {
|
||
var statsDiv = document.getElementById("stats");
|
||
statsDiv.innerHTML = "<span id='stat-pos' class='stat'>x"+mousePos.x+",y"+mousePos.y+"</span>";
|
||
statsDiv.innerHTML += "<span id='stat-pixels' class='stat'>Pxls:" + currentPixels.length+"</span>";
|
||
statsDiv.innerHTML += "<span id='stat-tps' class='stat'>" + tps+"tps</span>";
|
||
statsDiv.innerHTML += "<span id='stat-ticks' class='stat'>" + pixelTicks+"</span>";
|
||
if (pixelMap[mousePos.x] != undefined) {
|
||
var currentPixel = pixelMap[mousePos.x][mousePos.y];
|
||
if (currentPixel != undefined) {
|
||
statsDiv.innerHTML += "<span id='stat-element' class='stat'>Elem:"+currentPixel.element.toUpperCase()+"</span>";
|
||
statsDiv.innerHTML += "<span id='stat-temperature' class='stat'>Temp:"+currentPixel.temp+"°C</span>";
|
||
}
|
||
if (shiftDown) {
|
||
statsDiv.innerHTML += "<span id='stat-shift' class='stat'>[↑ ]</span>";
|
||
}
|
||
}
|
||
}
|
||
|
||
// On window load, run tick() 20 times per second
|
||
tps = 30;
|
||
tickInterval = window.setInterval(tick, 1000/tps);
|
||
function resetInterval(newtps=30) {
|
||
window.clearInterval(tickInterval);
|
||
tickInterval = window.setInterval(tick, 1000/newtps);
|
||
}
|
||
ticks = 0;
|
||
pixelTicks = 0;
|
||
|
||
placeMode = null;
|
||
paused = false;
|
||
function focusGame() { document.getElementById("game").focus(); }
|
||
//on window load
|
||
window.onload = function() {
|
||
// While the mouse is down, run mouseDown()
|
||
var gameCanvas = document.getElementById("game");
|
||
// Get context
|
||
var ctx = gameCanvas.getContext("2d");
|
||
var newWidth = Math.ceil(window.innerWidth*0.9 / 10) * 10;
|
||
var newHeight = Math.ceil(window.innerHeight*0.675 / 10) * 10;
|
||
// If the new width is greater than 800, set it to 800
|
||
if (newWidth > 1000) { newWidth = 1000; }
|
||
// If we are on a desktop and the new height is greater than 600, set it to 600
|
||
if (window.innerWidth > 1000 && newHeight > 600) { newHeight = 600; }
|
||
ctx.canvas.width = newWidth;
|
||
ctx.canvas.height = newHeight;
|
||
|
||
width = Math.round(newWidth/pixelSize)-1;
|
||
height = Math.round(newHeight/pixelSize)-1;
|
||
// Object with width arrays of pixels starting at 0
|
||
pixelMap = {};
|
||
for (var i = 0; i < width; i++) {
|
||
pixelMap[i] = [];
|
||
}
|
||
//...drawing code...
|
||
gameCanvas.addEventListener("mousedown", mouseClick);
|
||
gameCanvas.addEventListener("touchstart", mouseClick);
|
||
gameCanvas.addEventListener("mouseup", mouseUp);
|
||
gameCanvas.addEventListener("touchend", mouseUp);
|
||
gameCanvas.addEventListener("mousemove", mouseMove);
|
||
gameCanvas.addEventListener("touchmove", mouseMove);
|
||
gameCanvas.ontouchstart = function(e) {
|
||
if (e.touches) e = e.touches[0];
|
||
return false;
|
||
}
|
||
shiftDown = false;
|
||
// If the user presses [, decrease the mouse size by 2
|
||
document.addEventListener("keydown", function(e) {
|
||
if (e.keyCode == 219) {
|
||
if (shiftDown) {mouseSize = 1}
|
||
else {
|
||
mouseSize -= 2;
|
||
if (mouseSize < 1) { mouseSize = 1; }
|
||
}
|
||
}
|
||
// If the user presses ], increase the mouse size by 2
|
||
else if (e.keyCode == 221) {
|
||
if (shiftDown) {mouseSize = 15}
|
||
else {mouseSize += 2;}
|
||
// if height>width and mouseSize>height, set mouseSize to height, if width>height and mouseSize>width, set mouseSize to width
|
||
if (mouseSize > (height > width ? height : width)) { mouseSize = (height > width ? height : width); }
|
||
}
|
||
else if (e.keyCode == 16 || e.keyCode == 18) { shiftDown = true; }
|
||
// p = pause
|
||
else if (e.keyCode == 80) {
|
||
paused = !paused;
|
||
if (paused) {
|
||
document.getElementById("pauseButton").setAttribute("on","true");
|
||
}
|
||
else {
|
||
document.getElementById("pauseButton").setAttribute("on","false");
|
||
}
|
||
}
|
||
});
|
||
// If the user releases either shift
|
||
document.addEventListener("keyup", function(e) {
|
||
if (e.keyCode == 16 || e.keyCode == 18) { shiftDown = false; }
|
||
});
|
||
|
||
// Create buttons for elements
|
||
// For each element type in elements, create a button in controls that sets the current element to that type
|
||
// Loop through object named elements
|
||
for (var element in elements) {
|
||
if (elements[element].hidden) { continue; }
|
||
var button = document.createElement("button");
|
||
button.innerHTML = elements[element].name
|
||
//capitalize first letter of each word
|
||
button.innerHTML = button.innerHTML.replace("."," ").replace(/\w\S*/g, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();}).replace(" ",".").replace(/ /g, "");
|
||
//set attribute of element to the element
|
||
button.setAttribute("element", element);
|
||
button.setAttribute("current", "false");
|
||
button.className = "elementButton";
|
||
//color of the element
|
||
// if the element color is an array, make a gradient background color, otherwise, set the background color to the element color
|
||
if (elements[element].color instanceof Array) {
|
||
button.style.backgroundImage = "linear-gradient(to bottom right, "+elements[element].color.join(", ")+")";
|
||
}
|
||
else {
|
||
button.style.background = elements[element].color;
|
||
var colorObject = elements[element].colorObject;
|
||
if ((colorObject.r+colorObject.g+colorObject.b)/3 > 200) {
|
||
button.className += " bright"
|
||
}
|
||
}
|
||
button.id = "elementButton-" + element;
|
||
button.onclick = function() {
|
||
selectElement(this.getAttribute("element"));
|
||
}
|
||
document.getElementById("elementControls").appendChild(button);
|
||
}
|
||
selectElement(currentElement);
|
||
focusGame();
|
||
|
||
}
|
||
</script>
|
||
</head>
|
||
|
||
<body>
|
||
<h1>Sandbox Game</h1>
|
||
<div id="gameDiv">
|
||
<canvas id="game" width="800" height="600" oncontextmenu="return false;">
|
||
Your browser does not support the HTML5 canvas tag.
|
||
</canvas>
|
||
<div id="underDiv">
|
||
<div id="stats"></div>
|
||
<div id="controls">
|
||
<div id="toolControls">
|
||
<button id="pauseButton" title="Pause/play the simulation" class="controlButton" onclick='if (paused) {paused = false;this.setAttribute("on","false");}else {paused = true;this.setAttribute("on","true");};focusGame();' on="false">Pause</button><button id="frameButton" title="Pause and play one frame" class="controlButton" onclick='if (!paused) {paused=true;document.getElementById("pauseButton").setAttribute("on","true");}drawPixels(true);focusGame();' on="false">Step</button><button id="sizeUpButton" title="Increase the brush size" class="controlButton" onclick="mouseSize+=2;focusGame();">↑</button><button id="sizeDownButton" title="Decrease the brush size" class="controlButton" onclick="mouseSize-=2;focusGame();">↓</button><button id="resetButton" title="Clear the entire scene" class="controlButton" onclick="if (confirm('Are you sure you want to clear the whole scene?')) {clearAll();};focusGame();">Reset</button><button id="replaceButton" title="Override existing pixels when placing" class="controlButton" onclick='if (placeMode == "replace") {placeMode = null;this.setAttribute("on","false");}else {placeMode = "replace";this.setAttribute("on","true");};focusGame();' on="false">Replace</button><button id="elemSelectButton" title="Select an element by ID" class="controlButton" onclick='var e = prompt("Enter the element’s ID").replaceAll(" ","_");if (elements[e] != undefined) {currentElement = e;var btn = document.getElementById("elementButton-"+e);if (btn != null) {btn.setAttribute("current","true");}};focusGame();'>E</button><button id="tpsButton" title="Change the simulation Ticks Per Second (TPS)" class="controlButton" onclick='var newtps = prompt("Enter the new simulation Ticks Per Second (TPS). This is how many updates per second the simulation will run.\n\nThe default is 30.\n\nThe current TPS is " + tps + ".");if (newtps == null || newtps == "" || newtps == "0") {alert("You did not enter a valid TPS. The TPS will be reset.");tps = 30;}else if (newtps > 1000) {alert("You entered a TPS that is too high. The TPS will be set to the maximum, 1000.");tps = 1000;}else {tps = parseInt(newtps);if (isNaN(tps)) {alert("You did not enter a valid TPS. The TPS will be reset.");tps = 30;}}resetInterval(newtps);focusGame();'>TPS</button>
|
||
</div>
|
||
<div id="elementControls"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</body>
|
||
|
||
</html> |