JavaScript v Engine
Skriptovací API Engine: životní cyklus, souřadnicové pasti, tři způsoby, jak vytvořit objekt, a jak ho pohnout, aniž by procházel zdmi.
V jedné větě#
Každá entita může nést skript v JavaScriptu. Běží v prohlížeči, ve vaší záložce, proti živé scéně, a je to kanonické API pro skriptování: dialekt BASIC a pohledy Python, C# a Rust v editoru se všechny kompilují do stejného povrchu.
Vyčerpávající seznam je reference API: 538 členů v 50 jmenných prostorech, jedna stránka na každý, s vyhledáváním. Tato stránka je to, co potřebujete vědět předtím, než si ji přečtete.
Životní cyklus#
function start() {} // once, when the entity starts
function update(dt) {} // every frame, dt in seconds
function fixedUpdate(dt) {} // fixed timestep, for physics
function onCollisionEnter(other) {} // first frame of contact
function onCollisionStay(other) {} // every frame while touching
function onCollisionExit(other) {} // contact just ended
function onTriggerEnter(other) {} // entered a trigger volume
function onTriggerExit(other) {}
function onMessage(msg, data, senderId) {} // entity-to-entity messaging
function onAnimationEvent(name, data) {}
function onDestroy() {}
function main() {} // console-game entry, async allowed
deltaTime, time, entityId a entity jsou globální proměnné;
getComponent(type) čte komponentu z entity, které skript patří.
Kolize a triggery se spouští v 2D i 3D, a každá strana dostane svůj vlastní
kontaktní normál: other.contact.normal míří od té druhé entity k této. Právě
to umožňuje skriptu rozlišit "dopadl jsem na to" od "to dopadlo na mě", stomp v
plošinovce čte other.contact.normal.y > 0.5.
Dvě souřadnicové pasti#
Obě stojí skutečný čas ladění, a žádná neselhává nahlas.
Myš: page versus canvas#
input.mousePosition je v souřadnicích page. scene.pick() chce
souřadnice canvas. Předání jedněch místo druhých nemine úplně, trefí bod
posunutý o pozici viewportu v okně, takže hrdina, kterého ovládáte kliknutím,
dojde někam věrohodně vypadajícího, ale špatného místa.
Volejte scene.pick() bez argumentu (zamíří na kurzor), nebo použijte
input.mouseViewport, když potřebujete čísla.
Virtuální ovládací prvky jsou v pixelech canvasu#
input.addVirtualJoystick(id, x, y, size) a input.addVirtualButton(...) umístí
svůj střed do stejného prostoru jako mouseViewport. Joystick vrátí
normalizované X/Y po své radiální mrtvé zóně; tlačítko odhaluje odděleně
held, pressed-this-frame a released-this-frame. Jejich pointer se zachytí
a spotřebuje, takže dotyk na ovládacím prvku se nehlásí zároveň jako syrová
akce canvasu.
Výchozí joystick je jednotný.
input.getJoystickX/Y()vybere jeden kompletní vektor z ovládacího prvku na obrazovce, fyzického gamepadu, nebo klávesnice (WASD/šipky), podle toho, který zdroj je nejsilnější. Nečinný připojený gamepad tedy nevypíná ovládání klávesnicí. Jeho osa Y sleduje 2D prostor obrazovky: nahoru je-1.
Tři způsoby, jak vytvořit objekt, a nejsou zaměnitelné#
| Co vytváří | Žije po dobu | |
|---|---|---|
scene.createEntity(def) | autorskou entitu: objeví se ve Scene Graph a v Inspectoru | projektu, ukládá se |
game.spawn(type, pos) | holý primitiv: žádné zdraví, žádná AI, žádné chování | herního sezení |
game.spawnFrom(template, pos, opts) | kopii celé entity: komponenty, fyzikální tělo, tagy, vrstvu, měřítko a zkompilovaný zásobník chování | herního sezení |
game.spawn se hodí na trosky a prototypy a je k ničemu pro nepřátele:
spawner živený tímto příkazem produkuje netečné koule. Šablona, kterou kopíruje
spawnFrom, je obyčejná entita, kterou složíte v editoru a vypnete okem v
hierarchii: žádný samostatný formát, žádný druhý editor, takže co vidíte, je to,
co se objeví.
// Once, at start: a missing template should say so, not fail every wave silently
if (!game.hasTemplate('Skeleton')) console.warn('no Skeleton template');
const mob = game.spawnFrom('Skeleton', { x, y, z }, { tag: 'Enemy' });
template přijímá id, jméno nebo tag. Kopie vytvořené během hraní jsou vázané
na hru, takže stop() je odstraní a editační scéna se nikdy neznečistí.
Vypnutí entity znamená skrytá A tichá zároveň: uzel deaktivovaný, skript zastavený, fyzikální tělo už nereaguje. Pouhé skrytí by nechalo neviditelného nepřítele, který vás pořád zasahuje.
game.setEnabled(id, on)to řídí ze skriptu, ikona oka to řídí z hierarchie.
Pohyb objektu: postrčte tělo, neteleportujte ho#
Zapisování transform.position každý snímek prochází zdmi, jinými nestvůrami
i podlahou. Místo toho řiďte rychlost (velocity), ale jen tam, kde je co
řídit:
if (physics.hasBody) {
const v = physics.getVelocity();
physics.setVelocity({ x: vx, y: v.y, z: vz }); // pushes a real body
} else {
transform.position.x += vx * dt; // legitimate for a flyer
}
physics.setVelocity bez těla vyplní pole, které nikdo neintegruje, a entita
tvrdě zastaví. Proto existuje physics.hasBody, a proto se každé pohybové
chování v katalogu na tuto otázku ptá místo toho, aby předpokládalo odpověď.
Zastavení znamená zrušit rychlost: nedělat nic nechá tělo dál klouzat.
Zápis pozice teď fyzikální tělo skutečně pohne. Havok řídí transform, nikdy naopak, takže přiřazení
transform.positionna dynamické tělo bývalo na dalším kroku přepsáno: každý teleport na fyzikální entitě tiše selhal. Proxy pozice teď tělo znovu synchronizuje, tak jako to vždy dělala proxy rotace.
Pathfinding je snímek v čase#
pathfinding.createGrid() jednou provede raycast mřížky, vystředěný tam, kde
byl zavolán. Opuštění toho boxu vrátí null, a většina volajících se pak vrátí
k přímé čáře, skrz zdi, beze slova.
Mřížka se ve výchozím stavu znovu vystředí na požadovanou trasu.
setAutoRecenter(false) to vypne na pevném světě, kde by přestavba stála
raycast navíc zbytečně.
console.log loguje. Print kreslí.#
Konzole je console.log / warn / error, jako kdekoli jinde. Print z
BASICu kreslí na obrazovku a volá se každý snímek, ty dva jsou
záměrně oddělené příkazy, a jejich záměna je to, co
zaplaví konzoli.
Kde skript běží#
V editoru a v buildu pro web skripty běží v prohlížeči. V nativním buildu pro desktop nebo mobil běží beze změny na vestavěném runtime QuickJS, stejný zdroj, ne port.
Skripty se během editace ukládají do vlastní databáze prohlížeče, takže neuložený buffer přežije obnovení stránky; ukládají se do projektu spolu se vším ostatním.
Limity a časté zádrhely#
scene.pick()s argumentem chce souřadnice canvasu. Viz výše; je to nejčastější chyba ve špatném místě.game.spawnvytváří primitiv, ne postavu. PoužijtespawnFrom.- Tělo se vytváří i pro entity vzniklé uprostřed hry. Fyzika se dřív budovala jen při Play, takže cokoli spawnutého později tiše propadalo světem, zatímco jeho ručně umístění sousedé se chovali normálně.
- Osm kroků je strop AI parťáka, ne váš. Skriptová smyčka žádný takový
limit nemá; utržená
whilezamrazí snímek stejně jako kdekoli jinde. - Ostatní čtyři jazykové pohledy jsou transpilované z tohoto. Úprava pohledu Python nebo Rust a přepnutí zpět prochází přes uloženou verzi v JavaScriptu, viz stránka o BASICu pro důvod.