volley3dplugin
Launched rounds in a 3D world, rockets, shells, grenades and missiles, none of them a row.
Putting it in a scene
List it before particle3d, which is listed before render3d. A scene that does not name particle3d, or lists it earlier, fails, since a round is drawn through particle3d and would be drawn a frame late. The scene's sim lists the volley3d kind from #plugins/volley3d/volley3d.sim.ts, and the scene has one { "is": "volley3d" } actor, the ledger. A rule fires a round, which is one entry on the ledger naming a pattern, where it was fired from, which way, by whom, and its hurt, what it does to a body. Each step the entry is flown on and the line it flew in the step is asked what it met. The body met is hurt, and a splash hurts every body near. The ledger's prefab holds exactly next and live, since a prefab field goes onto the row and a row goes to every seat every step. A row field that is neither fails, and so does a field of world.volley3d that is none of the three below.
"plugins": ["loader", "scenemanager", "player", "volley3d", "particle3d", "render3d"],
"world": {
"loader": { "assets": { "rounds": { "type": "json", "url": "/games/mygame/assets/rounds.json", "preload": true } } },
"volley3d": {
"patterns": "rounds",
"hold": 1,
"mods": { "shoot": "hitscan3d", "bodies": "hitscan3d" }
}
},
"prefabs": {
"volley3d": { "next": 1, "live": [] }
}
The patterns file is { "patterns": { name: pattern } }:
{
"patterns": {
"rocket": { "speed": 30, "accel": 50, "max": 90, "life": 6, "radius": 0.2, "splash": 4,
"look": { "body": "rocketBody", "trail": "rocketSmoke", "burst": "explosion" } },
"grenade": { "speed": 18, "g": 9.8, "life": 3, "radius": 0.1, "splash": 5, "look": { "burst": "explosion" } },
"missile": { "speed": 40, "life": 8, "radius": 0.2, "splash": 3, "seek": 1.2,
"look": { "body": "missileBody", "trail": "missileSmoke", "burst": "explosion" } }
}
}
Properties
Read from world.volley3d. All lengths are metres and all times seconds.
.patterns : string
The loader catalogue name of the patterns file, a json entry.
.hold : number
Seconds an entry stays on the row once its round has ended, so that every page, which reads only the last packet it took, sees how it ended.
.mods : { shoot?, bodies? }
The plugins that say what a round meets (see Mods). Each is optional.
Patterns
| Key | Meaning |
|---|---|
speed | Metres a second along its aim the moment it is fired. Required. |
accel | Metres a second added to the speed every second, a negative one taking them away. Default 0. t seconds after it was fired, the speed along its aim is min(max, speed + accel · t). |
max | The speed along its aim it never goes over. None when left out. |
g | Metres a second² it falls, on its own, beside its speed along its aim. Default 0. After t seconds it has fallen g · t² / 2 down y. |
life | The seconds it flies before it ends where it is, having met nothing. Required. |
radius | Metres a body may be off its line and still be met: every body is met as if that much wider and longer at both ends. Default 0. The ground and the solids meet its middle. |
splash | Metres. Every body other than the one it met that is nearer than this to where it met something is splashed. Left out or 0, none is. A pattern that splashes needs its rounds' hurt.damage to be a number. |
seek | Radians a second its aim turns toward the target it was fired at. A pattern with none flies straight whatever it was fired at. |
look | { body, trail, burst }: the particle3d effects a page draws it with. body is carried with it while it flies, turned along the way it goes. trail is thrown from it as it goes. burst is thrown where it met something, back the way it came. One left out draws nothing. Required, though it may be empty. |
A round that ends at the end of its life, meeting nothing, stops its body and its trail and bursts nowhere.
The ledger
| Field | Meaning |
|---|---|
next | The id the next entry gets. |
live | The entries (below). |
Each entry is { id, pattern, at, dir, age, from, n, skip, hurt, target?, ride?, pos, vel, hit? }.
| Field | Meaning |
|---|---|
id | The ledger's next when it was fired. |
at, dir, age | The point it was fired from and its aim, as fired, and the seconds since. |
from, n | The row that fired it, and the count that row gives its rounds. [from, n] names the round, as a page's volleys() keys it. |
skip | Ids of the bodies it passes through, its shooter's. |
hurt | { damage, by, … }, hitscan3d's: what it does to a body it meets or splashes. damage is a number, or { [part]: number } by the part met. by is the row that fired it, and anything else the weapon carries goes with it. |
target | The id of the body it seeks, when it was fired at one. |
ride | { id, field }, when it was fired to ride a point: the row and the field of the point [x, y, z] it rides, a laser's spot, say, wherever it moves to, for as long as the row carries one there. |
pos, vel | Where it is, at at first, and how fast it goes, its speed along dir at first. |
hit | Written when it meets something: { point, what, id, age }. what is "ground", "solid", "body" or "intercepted". id is the body's, or null for the ground, a solid or an interception. age is the round's age as it met it, found along the step. |
How a round flies
Each step every entry in flight ages by a step and is flown to its new age or to the end of its life, whichever is sooner. A round fired in a tick or an after is sent where it was fired, and one fired in an act that a seat's message runs is sent a step on. An unguided round, one whose pattern has no seek or that was fired at no target or point, is where flight puts it. A guided round flies as flight would, but each step its aim is first turned toward the point it is after, by no more than seek times the step. There is no closed form of that, so its pos and vel are written each step. The point is its ride's while it has one. Otherwise it is the middle of its target's body, the middle of the box its shapes stand in. With neither, because a ride's row has ended or carries no point and the target is not among the bodies, the round flies on straight.
The line it flew in the step, from where it was to where it is, is asked of the shoot mod, passing through skip, with every body grown by radius and the round's hurt, so the body it meets is hurt. At the first thing met, its pos is the point met and it writes hit. Then, with a splash, every body but the one met whose far, the metres from the point to the nearest point of its shapes, is under splash is hurt: its row's hit act is called, as a rule's, with { ...hurt, damage: hurt.damage × (1 − far / splash), part: null, point, dir, what: "splash" }, dir the unit way from the point to the body's middle. Its shooter's body is among them, since skip is the line's alone, and its own hit says what a splash of its own does. A round that reaches the end of its life meeting nothing ends there, with no hit, and hurts nothing. An entry that has ended ages on and leaves the row hold seconds after it ended.
Methods
Acts
Defined by every kind a round can hurt, and called by volley3d on its row as a rule's, seat −1.
hit( struck )
hitscan3d's act that hurts a row. A round that meets a body hurts it through the shoot mod, with what: "body". A splash calls it with what: "splash" and part null, its damage scaled by the body's distance as above.
Rules
From #plugins/volley3d/volley3d.sim.ts.
fire( w, pattern, at, dir, by ) : Entry
Puts an entry on the ledger and hands it back. dir can be any length. by is { from, n, skip, hurt, target?, ride? }, as the entry's fields of those names. hurt is required.
intercept( w, id ) : boolean
Shoots down entry id where it is. A round still in flight ends there, its hit { point, what: "intercepted", id: null, age } at its pos and age, telling nobody, and the page bursts it there as it bursts any hit the server writes. Returns whether it did. An entry that has ended, or none of that id, is left as it is.
flight( pattern, at, dir, t ) : [x, y, z]
Where a round fired from at along dir is t seconds on when nothing turns it: its speed along its aim as above, along the unit dir, and its fall, g · t² / 2, down y.
velocity( pattern, dir, t ) : [x, y, z]
How fast it goes then.
speedOf( pattern, t ) : number
Its speed along its aim at t.
guided( pattern, entry ) : boolean
Whether a round of this pattern fired so is guided: the pattern has seek, and the entry has a target or a ride.
ended( entry, pattern ) : boolean
Whether an entry's round has ended: it met something, or its life is over.
far( body, point ) : number
The metres from a point to the nearest point of a body's shapes, 0 inside one.
middle( body ) : [x, y, z]
The middle of the box a body's shapes stand in, which a guided round turns toward. A body with no shapes is its pos.
On the page
Through plugins.volley3d. A round is drawn with the effects its pattern's look names, each the page's own, so they are left where they are thrown.
fire( pattern, at, dir ) : [0, k]
Draws a round of the page's alone, which the server has no entry of, at once, from at along dir. It returns its key, [0, k], since no row is row 0. Its age is 0 the frame it is fired and a step of the scene's dt more each frame after, and it is where flight puts it at that age. It meets nothing, and is drawn to the end of its flight and for hold seconds after.
volleys( ) : { key, pos, hit? }[]
Every round the page has: its key, where it is drawn, and the entry's hit once a packet has brought it. A server's round has the key [from, n] and leaves the list the frame its entry leaves the row. One of the page's alone leaves hold seconds after it ended.
Mods
Name them in world.volley3d.mods.
- hitscan3d
shoot:(w, from, dir, far, { skip, grow, hurt }) → { t, point, what, id?, part? } | undefined, the first thing a line fromfromalongdir, any length, meets withinfarmetres.whatis"ground","solid"or"body". A body met is hurt byhurt, itshitact called.skipis ids of bodies the line passes through andgrowis metres every body is taken wider by, and longer by at both ends. With noshoot, a round meets nothing.bodies:(w) → { id, pos, shapes }[], every body a round can reach now,posits feet andshapesits upright cylinders{ part, cylinder: { pos, radius, height } }and capsules{ part, capsule: { a, b, radius } }. It is what a splash reaches and what a guided round turns toward. With nobodies, no round splashes a body and none is guided.