Making a game

Writing the look

How a game looks in 2D or 3D: renderers, sky, light, sea and particles.

How a game appears is set by the plugins its scene lists and by the <kind>.client.ts of each kind it draws. Every colour, size, light and camera number goes in the scene file or in a data file the scene's catalogue names, never in code.

Choose a renderer

  1. List one renderer in the scene's plugins: render2d for a PixiJS stage, or render3d for a three.js scene with points in metres, y up.
  2. Under render2d with a world.render2d, give every size on a definition in the world's units and draw it scaled by render2d.ground().

Switch a scene to 3D

  1. In <scene>.scene.json, put render3d in place of render2d and give it a camera, shadows and tone mapping.
  2. Add the light and sky, and the ground (below).
  3. Change every pos to [x, y, z] in metres, and the definitions' speeds and sizes to metres.
  4. Redraw every kind's .client.ts against render3d.

Draw a kind

  1. A kind drawn from a sheet, a rigged model, still solids or particles is listed in that plugin's table and needs no look file.
  2. Otherwise write games/<game>/<kind>.client.ts with setup, tick and remove, reading sizes and colours off the definition.
  3. Pass every 3D material through render3d.dress, so rain, snow and cloud shadow reach it, and set castShadow and receiveShadow on each mesh.
  4. Set a turn whole, as a quaternion: mesh.quaternion.setFromAxisAngle(up, row.data.turn), or quaternion.fromArray for a row that carries one. One Euler angle set alone, mesh.rotation.y = turn, turns the long way round every frame once the turn passes 90°.
  5. When a look puts its object somewhere new rather than along its way, a door to elsewhere or a respawn, raise its userData.teleport on that frame, as Smooth gameplay sets out.
  6. Read the camera and the store in tick, not setup.

Sky, ground and the rest

  1. Sky, sun, weather and fog: skydome3d, a row with one { "is": "skydome3d" } actor and its weathers file in the catalogue. For fixed lights and a flat floor, use environment3d instead.
  2. Ground: terrain3d, its colours and detail in its field file.
  3. Sea: ocean3d, a row with the prefab { "t": 0 }.
  4. Trees and rocks: scatter3d.
  5. Particles: particle3d or particle2d, a ledger row and an effects file.
  6. Darkness and lights in 2D: light2d, its layer the last of world.render2d.layers.

List skydome3d, terrain3d, ocean3d and scatter3d before render3d, and sprite2d before render2d; listed after, they draw one frame behind.

Connect them with mods

One plugin uses another's knowledge through a mod named in its world.<p>.mods:

  • world.skydome3d.mods.land: "terrain3d" stands rain splashes on the land.
  • world.ocean3d.mods: light and wind from skydome3d, land from terrain3d for a seabed.
  • world.scatter3d.mods: land and ground from terrain3d.
"plugins": ["loader", "scenemanager", "player", "terrain3d", "skydome3d", "render3d"]

Checking it

  1. Give the camera a far past the sky dome's radius, or the sky draws black.
  2. Test each look in <kind>.client.test.ts: size and colour from the definition, standing on the row's pos, dressed, and disposed when the row ends.
  3. Open the game's index.html as in Starting a game, and look at the sky, the ground and each thing up close from several angles.
  4. For a thing that judders, flips or turns the long way, record what is drawn for it every frame with render3d's drew(f), beside the row's value it came from and the step. The frame where the drawn value leaves the row's is the fault, and a single Euler angle set alone is the first thing to look for.