JavaScript in the Engine
Enginen skripti-API: elinkaari, koordinaattiansat, kolme tapaa luoda objekti, ja miten liikutat sitä kävelemättä seinien läpi.
Yhdellä lauseella#
Jokainen entiteetti voi kantaa JavaScript-skriptiä. Se toimii selaimessa, sinun välilehdessäsi, elävää kohtausta vasten, ja se on skriptaus-API:n kanoninen muoto: BASIC-murre, sekä editorin Python-, C#- ja Rust-näkymät, kääntyvät kaikki samaksi rajapinnaksi.
Tyhjentävä lista on API-viite: 538 jäsentä 50 nimiavaruudessa, oma sivunsa kullekin, hakutoiminnolla. Tämä sivu kertoo sen, mitä sinun täytyy tietää ennen sen lukemista.
Elinkaari#
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 ja entity ovat globaaleja; getComponent(type)
lukee komponentin siltä entiteetiltä, joka omistaa skriptin.
Törmäykset ja liipaisimet laukeavat sekä 2D:ssä että 3D:ssä, ja
kumpikin puoli saa oman kosketusnormaalinsa: other.contact.normal osoittaa
toisesta entiteetistä kohti tätä. Juuri se antaa skriptin erottaa "minä
laskeuduin sen päälle" ja "se laskeutui minun päälleni": tasohyppelyn
tallonta lukee other.contact.normal.y > 0.5.
Kaksi koordinaattiansaa#
Molemmat maksavat oikeaa debug-aikaa, eivätkä kumpikaan epäonnistu äänekkäästi.
Hiiri: sivu versus canvas#
input.mousePosition on sivun koordinaateissa. scene.pick() haluaa
canvasin koordinaatit. Toisen antaminen toisen sijaan ei osu ohi, se osuu
pisteeseen, joka on siirtynyt näyttöikkunan sijainnin verran ikkunassa, joten
napsauta-liikkuaksesi-hahmo kävelee jonnekin uskottavan näköiseen mutta
väärään paikkaan.
Kutsu scene.pick() ilman argumenttia (se tähtää kohdistimeen), tai käytä
input.mouseViewport-arvoa, kun tarvitset luvut.
Virtuaaliset ohjaimet ovat canvas-pikseleissä#
input.addVirtualJoystick(id, x, y, size) ja input.addVirtualButton(...)
sijoittavat keskipisteensä samaan tilaan kuin mouseViewport. Joystick
palauttaa normalisoidun X/Y:n sen radiaalisen kuolleen alueen jälkeen; nappi
paljastaa held, pressed-this-frame ja released-this-frame erikseen.
Niiden osoitin kaapataan ja kulutetaan, joten kosketus ohjaimeen ei raportoidu
myös raakana canvas-toimintona.
Oletusjoystick on yhtenäinen.
input.getJoystickX/Y()poimii yhden täydellisen vektorin ruudulla olevasta sauvasta, fyysisestä ohjaimesta, tai näppäimistöstä (WASD/nuolet), kumpi lähde onkin vahvin. Joutilas kytketty ohjain ei siis kytke näppäimistöliikettä pois päältä. Sen Y-akseli seuraa 2D-näyttötilaa: ylös on-1.
Kolme tapaa luoda objekti, eivätkä ne ole keskenään vaihdettavissa#
| Mitä se luo | Elää | |
|---|---|---|
scene.createEntity(def) | auktorisoidun entiteetin: se näkyy Scene Graphissa ja Inspectorissa | projektin ajan, se tallennetaan |
game.spawn(type, pos) | paljaan primitiivin: ei terveyttä, ei AI:ta, ei käytöstä | pelisession ajan |
game.spawnFrom(template, pos, opts) | kopion kokonaisesta entiteetistä: komponentit, fysiikkakappale, tagit, kerros, skaala ja käännetty käytöspino | pelisession ajan |
game.spawn on oikea valinta roskalle ja prototyypeille ja hyödytön
vihollisille: sillä ruokittu spawner tuottaa elottomia palloja. Malli, jonka
spawnFrom kopioi, on tavallinen entiteetti, jonka sävellät editorissa ja
kytket pois hierarkian silmällä: ei erillistä formaattia, ei toista editoria,
joten se, minkä näet, on se, mikä ilmestyy.
// 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 hyväksyy id:n, nimen tai tagin. Pelin aikana tehdyt kopiot ovat
peli-scope: stop() poistaa ne, eikä muokkauskohtaus koskaan saastu.
Entiteetin kytkeminen pois päältä tarkoittaa piiloon JA hiljaiseksi: solmu poissa käytöstä, skripti pysäytetty, fysiikkakappale ei enää vastaa. Pelkkä piilottaminen jättäisi näkymättömän vihollisen yhä osumaan sinuun.
game.setEnabled(id, on)ohjaa sitä skriptistä, silmäikoni ohjaa sitä hierarkiasta.
Jonkin liikuttaminen: työnnä kappaletta, älä teleporttaa#
transform.position-arvon kirjoittaminen joka ruudulla kävelee seinien,
muiden hirviöiden ja lattian läpi. Ohjaa sen sijaan nopeutta, mutta vain
kun jotain on ohjattavana:
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 ilman kappaletta täyttää kentän, jota kukaan ei
integroi, ja entiteetti pysähtyy täysin. Siksi physics.hasBody on olemassa,
ja siksi jokainen luettelon liikekäytös kysyy kysymyksen sen sijaan, että
olettaisi vastauksen. Pysähtyminen tarkoittaa nopeuden peruuttamista:
tekemättä jättäminen jättää kappaleen liukumaan.
Sijainnin kirjoittaminen liikuttaa nyt oikeasti fysiikkakappaletta. Havok ohjaa transformia, ei koskaan toisin päin, joten
transform.position- arvon asettaminen dynaamiselle kappaleelle ylikirjoitettiin ennen seuraavassa askeleessa: jokainen teleporttaus epäonnistui hiljaa fyysisellä entiteetillä. Sijaintiproksi synkronoi kappaleen uudelleen, samaan tapaan kuin rotaatioproksi on aina tehnyt.
Reitinhaku on tilannekuva#
pathfinding.createGrid() raycastaa ruudukon kerran, keskitettynä
kutsuhetken kohtaan. Sen laatikosta poistuminen palauttaa nullin, ja
useimmat kutsujat turvautuvat sitten suoraan viivaan, seinien läpi, sanaakaan
sanomatta.
Ruudukko keskittyy uudelleen jokaisella pyydetyllä matkalla oletuksena.
setAutoRecenter(false) kieltäytyy tästä kiinteässä maailmassa, jossa
uudelleenrakentaminen maksaisi raycast-läpikäynnin turhaan.
console.log lokittaa. Print piirtää.#
Konsoli on console.log / warn / error, kuten missä tahansa muualla.
BASIC-kielen Print piirtää ruudulle ja sitä kutsutaan joka ruudulla,
nämä kaksi ovat tarkoituksella erilliset komennot, ja
niiden sekoittaminen on se, mikä täyttää konsolin ruutuluupilla.
Missä skripti toimii#
Editorissa ja web-buildissa skriptit toimivat selaimessa. Natiivissa työpöytä- tai mobiilibuildissa ne toimivat muuttumattomana upotetulla QuickJS-ajonaikaisella ympäristöllä, samasta lähteestä, ei porttina.
Skriptit tallennetaan selaimen omaan tietokantaan muokkauksen ajan, joten tallentamaton puskuri selviytyy uudelleenlatauksesta; ne tallennetaan projektiin kaiken muun mukana.
Rajoitukset ja yleiset sudenkuopat#
scene.pick()argumentin kanssa haluaa canvas-koordinaatit. Katso yllä; se on yleisin väärä-paikka-bugi.game.spawntekee primitiivin, ei hahmoa. KäytäspawnFromia.- Kappale luodaan pelin aikana syntyneille entiteeteille. Fysiikka rakennettiin ennen vain Play-hetkellä, joten mikä tahansa sen jälkeen synnytetty putosi maailman läpi hiljaa, kun sen käsin sijoitetut naapurit käyttäytyivät normaalisti.
- Kahdeksan askelta on AI-tiimikaverin katto, ei sinun. Skriptiluupilla ei
ole tällaista rajaa; karkaava
whilejumittaa ruudun samalla tavalla kuin missä tahansa muuallakin. - Neljä muuta kielinäkymää on transpiloitu tästä. Python- tai Rust- näkymän muokkaaminen ja takaisin vaihtaminen kulkee tallennetun JavaScriptin kautta, katso BASIC-sivu, miksi näin on.