Water, swimming and floating
Water and lava, swimming, floating on the waves, and water that hurts.
Don't make water out of a blue plane. The API reference ("Water3D and Buoyancy") has every field.
The default path: one Water3D
import { Transform } from '@onceworlds/engine';
import { Water3D } from '@onceworlds/engine/modules';
world.spawn([Transform({ position: [0, 0, 0] }), Water3D.preset('lake', { size: [80, 80] })]);
The surface is the entity's height and spreads size (x, z) around it. It moves with waves, shows the sky, gets clear and soft at
the shore and foams where it meets things, by itself. In a scene it is a node of kind Water3D.
| Preset | For |
|---|---|
ocean |
Big swell, deep blue, whitecaps: islands, boats, pirates. waves 0.7 m. |
lake |
Calm, green-blue, small ripples: most levels. The defaults. |
pool |
Clear turquoise, almost still: pools, fountains, a bathhouse. |
lava |
Glowing, crusted, slow: a floor that hurts. Nobody swims in it (swim: false). |
toxic |
Bright green sludge: swamps, labs, sewers. |
Change it with fields (waves, waveLength, shallow, deep, clarity, foam, glow...) rather than drawing your own. A scene
file keeps values: a node that names a preset and leaves its values out gets a lake, and the loader prints the line to write.
Swimming
A character with Character3D swims in any Water3D once more than its swimDepth (0.9 m) is under: jump swims up, drop or crouch dives, and at
the surface it stays afloat until it jumps out. Nothing to add.
Things that float
Give a dynamic body Buoyancy and it floats on whatever water is under it, riding and tipping with the waves:
import { Body3D, Buoyancy, Collider3D, Mesh, Material } from '@onceworlds/engine/modules';
world.spawn([
Transform({ position: [0, 1, 0] }),
Body3D.dynamic({ mass: 60 }),
Collider3D.box({ size: [3, 0.4, 2] }),
Buoyancy(), // float 1: half under, like wood
...Mesh.box([3, 0.4, 2], Material.standard('#8a5a32')),
]);
float is how it sits: 2 rides high (a beach ball), 1 half under, 0.5 just under, less sinks slowly (a stone: 0.2). drag is how
much the water slows it. The mass doesn't matter: the push is relative to its own weight. Needs Physics3D.
Hurting in lava, and other rules
waterAt(world, x, z) is the water at a point: { surface, bottom, density, swim, entity }, the same waves the player sees.
import { defineSystem } from '@onceworlds/engine';
import { waterAt } from '@onceworlds/engine/modules';
const Burn = defineSystem({ // Health is the game's own component
name: 'burn',
stage: 'fixed',
query: [Health, Transform],
run({ query, world, time }) {
query.each((_e, health, tr) => {
const lava = waterAt(world, tr.position.x, tr.position.z);
if (lava && !lava.swim && tr.position.y < lava.surface) health.hp -= 40 * time.dt;
});
},
});
Islands and coasts
Terrain3D.preset('island') falls below 0 at its edges: put Water3D.preset('ocean') at height 0 over it and the shallows,
beaches and deep water colour come by themselves (see terrain.md).
Limits
- Turn water about y only; its surface is flat in its own x and z.
- Each page moves the waves by its own clock: in a multiplayer game a floating body the host simulates bobs on the host's waves. Keep waves small where floating things matter to the rules.
- On phones (the low tier) the shore effects and foam lines are off and the surface has fewer vertices; it still reads as water.