organisms.js
86 lines · in natura-src-1.0.0.zip as natura/organisms.js · a module · its entry in the module reference · its test: organisms-test.js
// organisms.js -- a GENERAL Natura LIFE system: a population of ENTITIES (animals AND phototroph plants alike) that
// each wear the shared ontology VERBS, driven by the world's LOCAL sun and fields. Render-FREE (touches no canvas).
//
// One system, many biomes: a biome supplies a SPECIES REGISTRY -- data plus a small render-free behave() -- and this
// system gives every entity the shared lifecycle for free: its activity read from its CHRONOTYPE against the LOCAL
// sun (sampled from a structure field if present, else the world's clock/celestial), and access to the OTHER species
// (for forage/flee). Entities are layered STATE BAGS per SCHEMA.md (kind/species/pos/vel/state), not a class tree;
// a plant is just an entity with a phototroph chronotype and a growth behave. Follows the Natura system interface
// (init/step/fields) so it composes in a World and couples via ctx.fields. Coordinates are the biome's own [0,1]
// space (the renderer maps to pixels); the system never assumes a grid. UMD (node / window.Organisms).
(function (root, factory) {
if (typeof module !== 'undefined' && module.exports) module.exports = factory(require('./verbs'));
else root.Organisms = factory(root.Verbs);
})(typeof self !== 'undefined' ? self : this, function (Verbs) {
'use strict';
const TAU = Math.PI * 2, clamp = (v, a, b) => v < a ? a : v > b ? b : v;
// resolve the world's AMBIENT sun elevation [-1,1] from whatever the coupling provides (celestial > explicit sun >
// the clock's day phase). A structure field may override this PER-POSITION via sunAt(x,y) in step().
function ambientSun(ctx) {
const F = ctx.fields || {};
if (F.celestial && F.celestial.sunAltitude != null) return Verbs.sunFromSinAlt(Math.sin(F.celestial.sunAltitude));
if (F.sun && F.sun.value != null) return clamp(F.sun.value, -1, 1);
if (ctx.clock && ctx.clock.dayPhase) return Verbs.sunFromDayPhase(ctx.clock.dayPhase());
return 1;
}
// makeOrganisms({ name?, species, structure? }) -> a Natura system spec.
// species = { name: { chronotype, count, band:[y0,y1], spawn(entity,rng)?, behave(entity, api)? } }
// structure = the name of a coupled field system exposing sunAt(x,y) (e.g. a canopy) -- optional.
// behave(entity, api): api = { dt, ctx, of(name)->entities, struct, sun0, Verbs, clock }. Render-FREE.
function makeOrganisms(config) {
config = config || {};
const species = config.species || {};
const names = Object.keys(species);
const structName = config.structure || null;
return {
name: config.name || 'organisms',
domain: 'life',
scale: 'local',
params: config,
init(rng, params, clock) {
const entities = [], bySpecies = {}; let id = 0;
for (const nm of names) {
const s = species[nm]; bySpecies[nm] = [];
const n = s.count || 0, band = s.band || [0, 1];
for (let i = 0; i < n; i++) {
const e = {
id: id++, kind: 'organism', species: nm, chronotype: s.chronotype || 'diurnal',
pos: [rng(), band[0] + rng() * (band[1] - band[0])], vel: [0, 0], ph: rng() * TAU,
state: { active: 1, rest: 0 }
};
if (s.spawn) s.spawn(e, rng);
entities.push(e); bySpecies[nm].push(e);
}
}
return { entities: entities, bySpecies: bySpecies };
},
step(state, ctx, dt) {
const struct = (structName && ctx.fields) ? ctx.fields[structName] : null;
const sun0 = ambientSun(ctx);
const of = nm => state.bySpecies[nm] || [];
const api = { dt: dt, ctx: ctx, of: of, struct: struct, sun0: sun0, Verbs: Verbs, clock: ctx.clock };
for (const e of state.entities) {
const localSun = (struct && struct.sunAt) ? struct.sunAt(e.pos[0], e.pos[1]) : sun0; // ITS layer/region's sun
const a = Verbs.activity(localSun, e.chronotype);
e.state.active = a.active; e.state.rest = a.rest; e.state.sun = localSun; // inherited lifecycle: wear the verb
const s = species[e.species]; if (s.behave) s.behave(e, api); // the species' own render-free act
}
return state;
},
fields(state) {
return {
entities: state.entities, bySpecies: state.bySpecies, count: state.entities.length,
of: nm => state.bySpecies[nm] || []
};
}
};
}
return { makeOrganisms };
});