JavaScript az Engine-ben
Az Engine szkript API-ja: az életciklus, a koordináta-csapdák, a három módja egy objektum létrehozásának, és hogyan mozgass egyet anélkül, hogy falakon sétálna át.
Egy mondatban#
Minden entitás hordozhat egy JavaScript szkriptet. A böngésződben fut, a saját lapodon, az élő jelenet ellen, és ez a kanonikus szkriptelési API: a BASIC nyelvjárás, valamint a Python, C# és Rust nézetek a szerkesztőben, mind ugyanarra a felületre fordulnak le.
A kimerítő lista az API referencia: 538 tag 50 névtérben, oldalanként egy, kereséssel. Ez az oldal az, amit érdemes tudni, mielőtt azt olvasnád.
Az életciklus#
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
A deltaTime, a time, az entityId és az entity globálisok; a
getComponent(type) egy komponenst olvas le arról az entitásról, amelyik
birtokolja a szkriptet.
Az ütközések és a triggerek 2D-ben és 3D-ben is elsülnek, és mindkét
oldal megkapja a saját érintkezési normálisát: az other.contact.normal a
másik entitástól mutat efelé. Ez teszi lehetővé, hogy egy szkript
megkülönböztesse, hogy "ráálltam erre" attól, hogy "ez rámállt", egy
platformer taposás az other.contact.normal.y > 0.5-öt olvassa.
A két koordináta-csapda#
Mindkettő valódi debugolási időbe kerül, és egyik sem hibázik hangosan.
Egér: oldal versus vászon#
Az input.mousePosition oldal-koordinátákban van. A scene.pick()
vászon-koordinátákat vár. Az egyiket a másik helyett átadni nem hibázik
látványosan, egy olyan pontot talál el, amely a nézetablak ablakon belüli
pozíciójával el van tolva, így egy kattintással mozgó hős valahová
elfogadhatóan, de rosszul sétál.
Hívd a scene.pick()-et argumentum nélkül (a kurzorra céloz), vagy használd
az input.mouseViewport-ot, amikor a számokra van szükséged.
A virtuális vezérlők vászon-pixelben vannak#
Az input.addVirtualJoystick(id, x, y, size) és az
input.addVirtualButton(...) ugyanabba a térbe helyezi a középpontjukat, mint
a mouseViewport. Egy joystick egy normalizált X/Y-t ad vissza a radiális
holtzónája után; egy gomb held, pressed-this-frame és
released-this-frame állapotokat mutat, külön-külön. A mutatójuk elfogott
és felhasznált, így egy érintés a vezérlőn nem jelentődik le egyúttal nyers
vászon-akcióként is.
Az alapértelmezett joystick egységesített. Az
input.getJoystickX/Y()egyetlen, teljes vektort választ ki a képernyőn megjelenő botból, egy fizikai gamepadből, vagy a billentyűzetből (WASD/nyilak), amelyik forrás a legerősebb. Egy tétlen, csatlakoztatott pad ezért nem tiltja le a billentyűzetes mozgást. Az Y tengelye a 2D képernyőteret követi: fel-1.
Három mód egy objektum létrehozására, és ezek nem felcserélhetők#
| Mit hoz létre | Meddig él | |
|---|---|---|
scene.createEntity(def) | egy megszerkesztett entitást: megjelenik a Scene Graph-ban és az Inspectorban | a projektig, mentve van |
game.spawn(type, pos) | egy csupasz primitívet: nincs élet, nincs AI, nincs viselkedés | a játékmenetig |
game.spawnFrom(template, pos, opts) | egy teljes entitás másolatát: komponensek, fizikai test, tag-ek, réteg, méret és az összeállított viselkedés-verem | a játékmenetig |
A game.spawn törmelékhez és prototípusokhoz jó, és haszontalan
ellenségekhez: egy vele táplált spawner élettelen golyókat termel. A
sablon, amit a spawnFrom másol, egy közönséges entitás, amit a
szerkesztőben állítasz össze, és a hierarchia szemével kapcsolsz ki: nincs
külön formátum, nincs második szerkesztő, így amit látsz, az jelenik meg.
// 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' });
A template elfogad egy id-t, egy nevet vagy egy tag-et. A játék közben
készült másolatok játékmenet-hatókörűek, így a stop() eltávolítja őket, és
a szerkesztő jelenet sosem szennyeződik be.
Egy entitás kikapcsolása azt jelenti: rejtett ÉS néma: a node letiltva, a szkript leállítva, a fizikai test már nem válaszol. A puszta elrejtés egy láthatatlan, de továbbra is támadó ellenséget hagyna maga után. A
game.setEnabled(id, on)egy szkriptből vezérli, a szem ikon a hierarchiából.
Valami mozgatása: told a testet, ne teleportálj#
A transform.position minden képkockán való írása falakon, más
szörnyeken és a padlón keresztül sétál. Ehelyett a sebességet vezéreld,
de csak akkor, ha van mit vezérelni:
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
}
A physics.setVelocity test nélkül egy olyan mezőt tölt ki, amit senki nem
integrál, és az entitás holtan megáll. Ezért létezik a physics.hasBody, és
ezért kérdez rá minden mozgó viselkedés a katalógusban ahelyett, hogy egy
választ feltételezne. A megállás azt jelenti: a sebesség törlése: a
semmittevés a testet tovább siklatja.
Egy pozíció írása most már mozgat egy fizikai testet. A Havok vezérli a transzformációt, sosem fordítva, így a
transform.positionbeállítása egy dinamikus testen régen felülíródott a következő lépésnél: minden teleportálás csendben meghiúsult egy fizikai entitáson. A pozíció-proxy most újraszinkronizálja a testet, ahogy a forgás-proxy mindig is tette.
A pathfinding egy pillanatfelvétel#
A pathfinding.createGrid() egyszer raycastel egy rácsot, ott
középpontosítva, ahol meghívták. Ezt a dobozt elhagyva null-t ad vissza, és
a legtöbb hívó ekkor egy egyenes vonalra esik vissza, falakon keresztül, szó
nélkül.
A rács alapértelmezés szerint újraközéppontosul a kért útra. A
setAutoRecenter(false) kilép ebből egy rögzített világon, ahol az
újraépítés hiába kerül egy raycast menetbe.
A console.log naplóz. A Print rajzol.#
A konzol a console.log / warn / error, mint bárhol máshol. A BASIC
Print a képernyőre rajzol, és minden képkockán meghívódik, a kettő
szándékosan külön parancs, és az összekeverésük az,
ami megtölt egy konzolt.
Hol fut egy szkript#
A szerkesztőben és egy webes buildben a szkriptek a böngészőben futnak. Egy natív asztali vagy mobil buildben változatlanul futnak egy beágyazott QuickJS futtatókörnyezeten, ugyanaz a forrás, nem egy port.
A szkriptek a böngésző saját adatbázisában tárolódnak, amíg szerkeszted, így egy mentetlen puffer túlél egy újratöltést; mindennel együtt a projektbe mentődnek.
Korlátok és gyakori buktatók#
- A
scene.pick()argumentummal vászon-koordinátákat vár. Lásd fent; ez az egyetlen leggyakoribb rossz-hely hiba. - A
game.spawnegy primitívet készít, nem egy karaktert. Használd aspawnFrom-ot. - Egy test létrejön a játék közben született entitásokhoz. A fizika régen csak a Play gombnál épült fel, így minden, ami azután spawnolt, csendben átesett a világon, miközben a kézzel elhelyezett szomszédai viselkedtek.
- Nyolc lépés az AI csapattárs plafonja, nem a tiéd. Egy szkriptciklusnak
nincs ilyen korlátja; egy elszabadult
whilelefagyasztja a képkockát, mint bárhol máshol. - A másik négy nyelvi nézet ebből van transzpilálva. Egy Python vagy Rust nézet szerkesztése és visszaváltás átmegy a tárolt JavaScripten, lásd a BASIC oldalt, miért.