Add start of procedural world generation
This commit is contained in:
parent
62b8c74f57
commit
ee5ab45cfb
7 changed files with 328 additions and 74 deletions
231
dist/img/celestials/green_1.svg
vendored
Normal file
231
dist/img/celestials/green_1.svg
vendored
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 66 KiB |
|
@ -27,7 +27,8 @@ export const images = {
|
|||
},
|
||||
celestials: {
|
||||
green: {
|
||||
"0": 'celestials/green_0.svg'
|
||||
'0': 'celestials/green_0.svg',
|
||||
'1': 'celestials/green_1.svg'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
export const EPSILON = 1e-8;
|
||||
// Don't change these.
|
||||
export const TAU = Math.PI * 2;
|
||||
// Unit length of sector. Only for internal representation.
|
||||
// Unit length of sector. May affect spawning a bit.
|
||||
export const SECTOR_SIZE = 512;
|
||||
// G, G-boy, The big G, Mr. G, g's big brother, G-dog
|
||||
export const GRAVITATIONAL_CONSTANT = 0.002;
|
||||
|
@ -32,3 +32,7 @@ export const MAX_PARENT_CELESTIAL_DISTANCE = 120;
|
|||
export const EDIT_MARGIN = 2;
|
||||
// Floating items.
|
||||
export const ENTITY_ROTATION_RATE = 0.01;
|
||||
// World generation.
|
||||
export const PLANET_SPAWN_RATE = 0.00002;
|
||||
export const ENTITY_SPAWN_RATE = 0.3;
|
||||
export const MIN_CELESTIAL_SPACING = 15;
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
import * as sector from './sector.mjs';
|
||||
import * as spawn from './spawn.mjs';
|
||||
import * as graphics from '../graphics/index.mjs';
|
||||
|
||||
export {getSectorFromWorld, getContainedSectors} from './sector.mjs';
|
||||
|
||||
export const entities = new Set();
|
||||
export const celestials = new Set();
|
||||
export const ships = new Set();
|
||||
|
@ -25,6 +22,7 @@ export function init() {
|
|||
spawn.player();
|
||||
let p = spawn.startPlanet();
|
||||
spawn.testEntity(p);
|
||||
spawn.tick();
|
||||
}
|
||||
|
||||
export function tick() {
|
||||
|
@ -33,4 +31,5 @@ export function tick() {
|
|||
entities.forEach(e => e.tick());
|
||||
ships.forEach(s => s.tick());
|
||||
if (graphics.trace) tracers.forEach(t => t.tick());
|
||||
spawn.tick();
|
||||
}
|
||||
|
|
|
@ -1,51 +0,0 @@
|
|||
import {SECTOR_SIZE} from '../consts.mjs';
|
||||
|
||||
const sectors = new Map();
|
||||
|
||||
export default class Sector {
|
||||
constructor(x, y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.size = SECTOR_SIZE;
|
||||
this.wx = this.size * this.x;
|
||||
this.wy = this.size * this.y;
|
||||
this.id = getId(this.x, this.y);
|
||||
this.numId = getNumId(this.x, this.y);
|
||||
}
|
||||
|
||||
containsPoint(wx, wy) {
|
||||
return wx >= this.wx && wy >= this.wy &&
|
||||
wx < this.wx + SECTOR_SIZE && wy < this.wy + SECTOR_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
function getId(x, y) {
|
||||
return `${x}.${y}`;
|
||||
}
|
||||
|
||||
function getNumId(x, y) {
|
||||
return Math.abs(x + (y * 3665)) % Number.MAX_SAFE_INTEGER;
|
||||
}
|
||||
|
||||
export function getSector(x, y) {
|
||||
if (!sectors.has(getId(x, y))) {
|
||||
sectors.set(getId(x, y), new Sector(x, y));
|
||||
}
|
||||
|
||||
return sectors.get(getId(x, y));
|
||||
}
|
||||
|
||||
export function getSectorFromWorld(wx, wy) {
|
||||
return getSector(wx / SECTOR_SIZE | 0, wy / SECTOR_SIZE | 0);
|
||||
}
|
||||
|
||||
export function getContainedSectors(startX, startY, endX, endY) {
|
||||
let sectors = [];
|
||||
|
||||
for (let x = startX; x < endX; x += SECTOR_SIZE)
|
||||
for (let y = startY; y < endY; y += SECTOR_SIZE) {
|
||||
sectors.push(getSectorFromWorld(x, y));
|
||||
}
|
||||
|
||||
return sectors;
|
||||
}
|
|
@ -15,6 +15,7 @@ export default class Ship extends Body {
|
|||
this.modules = new Set();
|
||||
this.maxRadius = 0;
|
||||
this.landed = false;
|
||||
this.lastContactModule = null;
|
||||
}
|
||||
|
||||
get com() {
|
||||
|
@ -110,22 +111,28 @@ export default class Ship extends Body {
|
|||
});
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
window.q.push([...this.com, 'green']);
|
||||
}
|
||||
|
||||
resolveCelestialCollision(pos, cel) {
|
||||
checkModuleCollision(module, body) {
|
||||
let p = this.getWorldPoint(...module.localCom);
|
||||
let dis = body.distanceTo({ com: p });
|
||||
if (dis < body.radius + 0.5 + consts.EPSILON) {
|
||||
this.approach(body, dis - (body.radius + 0.5));
|
||||
this.halt();
|
||||
this.resolveCelestialCollision(p, body, module);
|
||||
this.lastContactModule = module;
|
||||
}
|
||||
}
|
||||
|
||||
resolveCelestialCollision(pos, cel, module) {
|
||||
let celToCom = this.angleTo(...this.com, ...cel.com);
|
||||
let celToPoc = this.angleTo(...pos, ...cel.com);
|
||||
let pocToCom = this.angleTo(...this.com, ...pos);
|
||||
let shipAngle = this.r + Math.PI / 2;
|
||||
|
||||
window.q.push([...pos, 'blue']);
|
||||
let shipAngle = this.normalizeAngle(this.r + Math.PI / 2);
|
||||
|
||||
let turnAngle = this.angleDifference(celToPoc, pocToCom);
|
||||
let checkAngle = this.angleDifference(celToPoc, shipAngle);
|
||||
let correctionAngle = this.angleDifference(shipAngle, pocToCom);
|
||||
let correctionAngle = this.angleDifference(shipAngle, celToCom);
|
||||
|
||||
let [force] = this.rotateVector(0, 1, turnAngle);
|
||||
|
||||
|
@ -146,16 +153,6 @@ export default class Ship extends Body {
|
|||
this.rvel += force * consts.TIP_SPEED;
|
||||
}
|
||||
|
||||
checkModuleCollision(module, body) {
|
||||
let p = this.getWorldPoint(...module.localCom);
|
||||
let dis = body.distanceTo({ com: p });
|
||||
if (dis < body.radius + 0.5 + consts.EPSILON) {
|
||||
this.approach(body, dis - (body.radius + 0.5));
|
||||
this.halt();
|
||||
this.resolveCelestialCollision(p, body);
|
||||
}
|
||||
}
|
||||
|
||||
applyThrust({ forward = 0, left = 0, right = 0, back = 0,
|
||||
turnLeft = 0, turnRight = 0}) {
|
||||
|
||||
|
|
|
@ -5,6 +5,79 @@ import Entity from './entity.mjs';
|
|||
import Tracer from './tracer.mjs';
|
||||
import {modules} from '../data.mjs';
|
||||
import * as world from './index.mjs';
|
||||
import * as consts from '../consts.mjs';
|
||||
import {SECTOR_SIZE as SS} from '../consts.mjs';
|
||||
|
||||
let spawnedSectors = new Set();
|
||||
|
||||
const visibleRadius = (400 / consts.MIN_ZOOM) + SS;
|
||||
|
||||
export function tick() {
|
||||
let [px, py] = world.playerShip.com;
|
||||
|
||||
for (let x = px - visibleRadius; x < px + visibleRadius; x += SS)
|
||||
for (let y = py - visibleRadius; y < py + visibleRadius; y += SS) {
|
||||
let [sx, sy] = [x / SS | 0, y / SS | 0];
|
||||
let id = `${sx}.${sy}`;
|
||||
if (!spawnedSectors.has(id)) spawnSector(sx, sy);
|
||||
}
|
||||
}
|
||||
|
||||
function nearest(x, y, set) {
|
||||
let closest = null;
|
||||
let closestDis = 0;
|
||||
|
||||
set.forEach(e => {
|
||||
let dis = e.distanceTo({ com: [x, y] });
|
||||
if (closest === null || dis < closestDis) {
|
||||
closest = e;
|
||||
closestDis = dis;
|
||||
}
|
||||
});
|
||||
|
||||
return [closest, closestDis];
|
||||
}
|
||||
|
||||
function spawnSector(x, y) {
|
||||
let area = SS ** 2;
|
||||
|
||||
for (let i = 0; i < area / 10000; i++) {
|
||||
let [px, py] = [(x + Math.random()) * SS, (y + Math.random()) * SS];
|
||||
if (Math.random() > consts.PLANET_SPAWN_RATE) {
|
||||
randomPlanet(px, py);
|
||||
} else if (Math.random() > 0.01 ){
|
||||
randomEntity(px, py);
|
||||
}
|
||||
}
|
||||
|
||||
spawnedSectors.add(`${x}.${y}`);
|
||||
}
|
||||
|
||||
function randomPlanet(x, y) {
|
||||
let rad = Math.random() * 60 + 30;
|
||||
let [cel, dis] = nearest(x, y, world.celestials);
|
||||
let mcs = consts.MIN_CELESTIAL_SPACING;
|
||||
|
||||
if (dis < Math.max(rad, cel.radius) * mcs) return;
|
||||
|
||||
let planet = celestial(x, y, rad, {
|
||||
density: 3,
|
||||
type: 'green'
|
||||
});
|
||||
|
||||
for (let i = 1.5; i < 8; i += 1) {
|
||||
if (Math.random() > consts.ENTITY_SPAWN_RATE) {
|
||||
let e = randomEntity();
|
||||
e.orbit(planet, i * rad);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function randomEntity(x, y) {
|
||||
let entity = new Entity(x, y);
|
||||
world.entities.add(entity);
|
||||
return entity;
|
||||
}
|
||||
|
||||
export function player() {
|
||||
let ship = new Ship(0, -45);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue