From ee5ab45cfbae91b81e833d710d1d79cd9a1b4679 Mon Sep 17 00:00:00 2001 From: asraelite Date: Tue, 6 Mar 2018 22:16:54 +0000 Subject: [PATCH] Add start of procedural world generation --- dist/img/celestials/green_1.svg | 231 ++++++++++++++++++++++++++++++++ js/assets.mjs | 3 +- js/consts.mjs | 6 +- js/world/index.mjs | 5 +- js/world/sector.mjs | 51 ------- js/world/ship.mjs | 33 +++-- js/world/spawn.mjs | 73 ++++++++++ 7 files changed, 328 insertions(+), 74 deletions(-) create mode 100644 dist/img/celestials/green_1.svg delete mode 100644 js/world/sector.mjs diff --git a/dist/img/celestials/green_1.svg b/dist/img/celestials/green_1.svg new file mode 100644 index 0000000..5014144 --- /dev/null +++ b/dist/img/celestials/green_1.svg @@ -0,0 +1,231 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/js/assets.mjs b/js/assets.mjs index d6bf871..02820a3 100644 --- a/js/assets.mjs +++ b/js/assets.mjs @@ -27,7 +27,8 @@ export const images = { }, celestials: { green: { - "0": 'celestials/green_0.svg' + '0': 'celestials/green_0.svg', + '1': 'celestials/green_1.svg' } } }; diff --git a/js/consts.mjs b/js/consts.mjs index c2b7860..5cb31bd 100644 --- a/js/consts.mjs +++ b/js/consts.mjs @@ -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; diff --git a/js/world/index.mjs b/js/world/index.mjs index 2f3e829..7e7aa4e 100644 --- a/js/world/index.mjs +++ b/js/world/index.mjs @@ -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(); } diff --git a/js/world/sector.mjs b/js/world/sector.mjs deleted file mode 100644 index 7ec9ebe..0000000 --- a/js/world/sector.mjs +++ /dev/null @@ -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; -} diff --git a/js/world/ship.mjs b/js/world/ship.mjs index d64559d..bd1940c 100644 --- a/js/world/ship.mjs +++ b/js/world/ship.mjs @@ -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}) { diff --git a/js/world/spawn.mjs b/js/world/spawn.mjs index bb2a9dd..b900ead 100644 --- a/js/world/spawn.mjs +++ b/js/world/spawn.mjs @@ -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);