neoboxels/js/gravity.js
2025-05-16 21:44:56 -04:00

109 lines
No EOL
3 KiB
JavaScript

/*
Code for gravity.
mass: Density (in kg/cm^3)
fluid: Spread of substance
saturation: Maximum mass for gravity reactions to occur
*/
let gravityTable = [];
function gravity(event, mass, fluid, saturation) {
if (event.type != 'tick') return;
let cx = event.data[0];
let cy = event.data[1];
let chunks = event.canvas;
let dirX = 0;
let dirY = 0;
let forceX = 0;
let forceY = 0;
let density = 0;
let currBlock = chunks.getBlock(cx, cy);
for (let x = -1; x < 2; x++) {
let x2 = x / fluid;
let x3 = x2 * x2;
for (let y = -1; y < 2; y++) {
let blok = chunks.getBlock(cx + x, cy + y);
if (blok == -1) continue;
let mass2 = gravityTable[blok];
density += mass2;
if (density > saturation) break;
if (blok == currBlock || mass == mass2) continue;
let massDiff = (mass / mass2) - (mass2 / mass);
if (Math.abs(massDiff) < 0.001) continue;
let y3 = y * y;
let dirDiff = (y - 1 + fluid);
if (y == 0 && x == 0) dirDiff = 0;
if (isNaN(dirDiff)) dirDiff = 0;
if (dirDiff != 0)
dirDiff /= (1 / 8 * (x3 - y3 + 8) * (x3 + y3));
if (isNaN(dirDiff)) dirDiff = 0;
forceX += massDiff * x2;
forceY += massDiff * dirDiff * y;
}
if (density > saturation) break;
}
dirX = (Math.abs(forceX) < .5) ? 0 : Math.sign(forceX);
dirY = (Math.abs(forceY) < .5) ? 0 : Math.sign(forceY);
if (density > saturation) {
return;
}
let offBlock = chunks.getBlock(cx + dirX, cy + dirY);
if (currBlock == offBlock && density <= saturation) {
dirX = Math.sign(forceX);
offBlock = chunks.getBlock(cx + dirX, cy + dirY);
}
if (currBlock == -1 || offBlock == -1 || currBlock == offBlock || offBlock == undefined || mainTiles.tiles[offBlock].attributes.saturation / 9 < mass || chunks.noTick[(cx + dirX) * chunks.height + (cy + dirY)]) return;
if (!canGravity[offBlock]) return;
chunks.noTick[cx * chunks.height + cy] = true;
chunks.noTick[(cx + dirX) * chunks.height + (cy + dirY)] = true;
chunks.setBlock(cx, cy, offBlock);
chunks.setBlock(cx + dirX, cy + dirY, currBlock);
let t = chunks.getBlock(cx, cy, true);
let t2 = chunks.getBlock(cx + dirX, cy + dirY, true);
chunks.setBlock(cx, cy, t2, true);
chunks.setBlock(cx + dirX, cy + dirY, t, true);
return true;
}
Tile.prototype.gravity = function (mass, fluid, saturation) {
this.interactions.push(function (event) {
gravity(event, mass, fluid, saturation)
});
this.attributes.mass = mass;
this.attributes.saturation = saturation;
let that = this;
this.hook.push(function () {
gravityTable[mainTiles.tiles.findIndex((x, i) => x.id == that.id)] = that.attributes.mass;
})
return this;
}
Tile.prototype.unGravity = function () {
this.attributes.noGravity = true;
return this;
}