JavaScript dalam Engine
API skrip Engine: lifecycle, perangkap koordinat, tiga cara untuk mencipta satu objek, dan bagaimana menggerakkannya tanpa berjalan menembusi dinding.
Secara ringkas#
Setiap entiti boleh membawa satu skrip JavaScript. Ia berjalan dalam pelayar, dalam tab anda, terhadap adegan hidup itu, dan ia adalah API skrip yang kanonik: dialek BASIC, dan pandangan Python, C# serta Rust dalam editor, semuanya dikompil turun kepada permukaan yang sama.
Senarai lengkapnya ialah rujukan API: 538 ahli dalam 50 namespace, satu halaman bagi setiap satu, dengan satu carian. Halaman ini adalah apa yang perlu anda tahu sebelum membacanya.
Lifecycle#
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 dan entity adalah global; getComponent(type)
membaca satu komponen daripada entiti yang memiliki skrip itu.
Perlanggaran dan trigger tercetus dalam 2D dan 3D, dan setiap sisi
menerima normal sentuhannya sendiri: other.contact.normal menunjuk daripada
entiti yang lain ke arah entiti ini. Itulah yang membolehkan satu skrip
membezakan "saya mendarat di atasnya" daripada "ia mendarat di atas saya",
satu hentakan platformer membaca other.contact.normal.y > 0.5.
Dua perangkap koordinat#
Kedua-duanya memakan masa penyahpepijatan yang nyata, dan tiada satu pun gagal dengan bunyi yang jelas.
Tetikus: page berbanding canvas#
input.mousePosition dalam koordinat page. scene.pick() mahukan
koordinat canvas. Menghantar satu untuk yang lain tidak terlepas
langsung, ia mengena satu titik yang offset oleh kedudukan viewport dalam
tetingkap itu, jadi satu klik-untuk-bergerak membawa wira anda berjalan ke
suatu tempat yang munasabah tetapi salah.
Panggil scene.pick() tanpa argumen (ia menyasar kursor), atau gunakan
input.mouseViewport apabila anda memerlukan nombor-nombor itu.
Kawalan maya dalam piksel canvas#
input.addVirtualJoystick(id, x, y, size) dan input.addVirtualButton(...)
meletakkan pusatnya dalam ruang yang sama seperti mouseViewport. Satu
joystick memulangkan satu vektor X/Y ternormal selepas zon matinya yang
radial; satu butang mendedahkan held, pressed-this-frame dan
released-this-frame secara berasingan. Penunjuknya ditangkap dan
digunakan, jadi satu sentuhan pada kawalan itu tidak turut dilaporkan
sebagai satu tindakan canvas mentah.
Joystick lalai bersifat bersatu.
input.getJoystickX/Y()memilih satu vektor lengkap daripada stick di skrin, satu gamepad fizikal, atau papan kekunci (WASD/anak panah), mana-mana sumber yang paling kuat. Satu pad yang disambungkan tetapi diam tidak melumpuhkan pergerakan papan kekunci. Paksi Y-nya mengikut ruang skrin 2D: atas ialah-1.
Tiga cara mencipta satu objek, dan ia tidak boleh ditukar ganti#
| Apa yang dihasilkannya | Bertahan untuk | |
|---|---|---|
scene.createEntity(def) | satu entiti berkarya: ia muncul dalam Scene Graph dan Inspector | projek itu, ia disimpan |
game.spawn(type, pos) | satu primitif kosong: tiada health, tiada AI, tiada tingkah laku | sesi permainan itu |
game.spawnFrom(template, pos, opts) | satu salinan satu entiti penuh: komponen, jasad fizik, tag, layer, skala dan stack tingkah laku terkompil | sesi permainan itu |
game.spawn sesuai untuk serpihan dan prototaip dan tidak berguna untuk
musuh: satu spawner yang disuap dengannya menghasilkan bola-bola lengai.
Template yang disalin oleh spawnFrom adalah satu entiti biasa yang anda
susun dalam editor dan matikan dengan mata hierarki itu: tiada format
berasingan, tiada editor kedua, jadi apa yang anda lihat adalah apa yang
muncul.
// 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 menerima satu id, satu nama atau satu tag. Salinan yang dibuat
semasa permainan bersifat play-scoped, jadi stop() membuangnya dan adegan
sunting tidak pernah tercemar.
Mematikan satu entiti bermaksud tersembunyi DAN senyap: nod dimatikan, skrip dihentikan, jasad fizik tidak lagi bertindak balas. Menyembunyikan sahaja akan meninggalkan satu musuh yang tidak kelihatan tetapi masih memukul anda.
game.setEnabled(id, on)mengawalnya daripada satu skrip, ikon mata mengawalnya daripada hierarki.
Menggerakkan sesuatu: tolak satu jasad, jangan teleport#
Menulis transform.position setiap bingkai berjalan menembusi dinding,
menembusi raksasa lain dan menembusi lantai. Kawal velocity sebaliknya,
tetapi hanya apabila ada sesuatu untuk dikawal:
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 tanpa satu jasad mengisi satu medan yang tidak
diintegrasikan oleh sesiapa, dan entiti itu berhenti terus. Itulah sebabnya
physics.hasBody wujud, dan itulah sebabnya setiap tingkah laku bergerak
dalam katalog bertanya soalan itu berbanding menganggap satu jawapan.
Berhenti bermaksud membatalkan velocity itu: tidak melakukan apa-apa
meninggalkan jasad itu terus meluncur.
Menulis satu kedudukan kini benar-benar menggerakkan satu jasad fizik. Havok mengawal transform itu, tidak pernah sebaliknya, jadi menugaskan
transform.positionpada satu jasad dinamik dahulu akan ditimpa pada langkah seterusnya: setiap teleport gagal secara senyap pada satu entiti fizikal. Proksi kedudukan itu kini melakukan sync semula jasad itu, cara yang sama seperti proksi putaran sentiasa lakukan.
Pathfinding adalah satu snapshot#
pathfinding.createGrid() melakukan raycast pada satu grid sekali sahaja,
berpusat di tempat ia dipanggil. Meninggalkan kotak itu memulangkan null,
dan kebanyakan pemanggil kemudian jatuh kembali kepada satu garis lurus,
menembusi dinding, tanpa sepatah kata.
Grid itu berpusat semula pada perjalanan yang diminta secara lalai.
setAutoRecenter(false) menolak keluar pada satu dunia tetap, di mana
membina semula memakan kos satu laluan raycast dengan sia-sia.
console.log mencatat log. Print melukis.#
Konsol itu ialah console.log / warn / error, seperti di mana-mana
sahaja. Print BASIC melukis pada skrin dan dipanggil setiap bingkai,
kedua-duanya adalah
arahan yang sengaja berasingan, dan mengelirukan
kedua-duanya adalah apa yang memenuhi satu konsol dengan satu gelung
bingkai.
Di mana satu skrip berjalan#
Dalam editor dan dalam satu binaan web, skrip berjalan dalam pelayar. Dalam satu binaan desktop atau mudah alih native, ia berjalan tidak berubah pada satu runtime QuickJS terbenam, sumber yang sama, bukan satu port.
Skrip disimpan dalam pangkalan data pelayar itu sendiri semasa anda menyunting, jadi satu buffer yang belum disimpan bertahan satu muat semula; ia disimpan ke dalam projek bersama segala-galanya yang lain.
Had dan masalah biasa#
scene.pick()dengan satu argumen mahukan koordinat canvas. Lihat di atas; itulah pepijat salah-tempat yang paling biasa.game.spawnmenghasilkan satu primitif, bukan satu watak. GunakanspawnFrom.- Satu jasad dicipta untuk entiti yang lahir semasa permainan. Fizik dahulu hanya dibina semasa Play, jadi apa-apa yang di-spawn selepas itu jatuh menembusi dunia secara senyap manakala jirannya yang diletakkan secara manual berkelakuan biasa.
- Lapan langkah adalah siling rakan sepasukan AI, bukan siling anda.
Satu gelung skrip tiada had sedemikian; satu
whileyang tidak terkawal akan menggantungkan bingkai itu seperti di tempat lain. - Empat pandangan bahasa lain ditranspil daripada yang ini. Menyunting satu pandangan Python atau Rust dan bertukar semula melalui JavaScript yang disimpan itu, lihat halaman BASIC untuk sebabnya.