Engine'de JavaScript
Engine'in betik API'si: yaşam döngüsü, koordinat tuzakları, bir nesne oluşturmanın üç yolu ve birini duvarlardan geçmeden nasıl hareket ettireceğiniz.
Tek cümleyle#
Her varlık bir JavaScript betiği taşıyabilir. Tarayıcınızda, kendi sekmenizde, canlı sahneye karşı çalışır ve kanonik betik API'sidir: BASIC lehçesi ve editördeki Python, C# ve Rust görünümlerinin tümü aynı yüzeye derlenir.
Eksiksiz liste API referansıdır: 50 ad alanında 538 üye, her biri için bir sayfa, ve bir arama. Bu sayfa, onu okumadan önce bilmeniz gereken şeydir.
Yaşam döngüsü#
function start() {} // bir kez, varlık başladığında
function update(dt) {} // her karede, dt saniye cinsinden
function fixedUpdate(dt) {} // sabit zaman adımı, fizik için
function onCollisionEnter(other) {} // temasın ilk karesi
function onCollisionStay(other) {} // temas süren her kare
function onCollisionExit(other) {} // temas az önce bitti
function onTriggerEnter(other) {} // bir tetikleyici hacme girildi
function onTriggerExit(other) {}
function onMessage(msg, data, senderId) {} // varlıklar arası mesajlaşma
function onAnimationEvent(name, data) {}
function onDestroy() {}
function main() {} // konsol oyunu girişi, async serbest
deltaTime, time, entityId ve entity, genel değişkenlerdir;
getComponent(type), betiği taşıyan varlıktan bir bileşen okur.
Çarpışmalar ve tetikleyiciler hem 2D'de hem 3D'de tetiklenir, ve her
taraf kendi temas normalini alır: other.contact.normal, diğer varlıktan
bu varlığa doğru işaret eder. Bir betiğin "üzerine indim" ile "üzerime indi"
arasında ayrım yapmasını sağlayan şey budur; bir platform oyununda üstüne
basma other.contact.normal.y > 0.5 olarak okunur.
İki koordinat tuzağı#
İkisi de gerçek hata ayıklama saatlerine mal olur, ve hiçbiri gürültülü başarısız olmaz.
Fare: sayfa mı, tuval mi#
input.mousePosition, sayfa koordinatlarındadır. scene.pick(),
tuval koordinatları ister. Birini diğeri yerine geçirmek hedefi kaçırmaz;
görüntü alanının pencere içindeki konumu kadar kaymış bir noktaya çarpar, bu
yüzden tıklayarak hareket eden bir kahraman makul ama yanlış bir yere yürür.
scene.pick()'i argümansız çağırın (imleci hedefler), ya da sayılara ihtiyaç
duyduğunuzda input.mouseViewport kullanın.
Sanal kontroller tuval piksellerindedir#
input.addVirtualJoystick(id, x, y, size) ve input.addVirtualButton(...),
merkezlerini mouseViewport ile aynı uzaya yerleştirir. Bir joystick, radyal
ölü bölgesinden sonra normalize edilmiş bir X/Y döndürür; bir düğme basılı
tutulan, bu karede basılan ve bu karede bırakılan durumlarını ayrı ayrı
sunar. İşaretçileri yakalanır ve tüketilir, bu yüzden kontrol üzerindeki bir
dokunuş aynı zamanda ham bir tuval eylemi olarak da bildirilmez.
Varsayılan joystick birleşiktir.
input.getJoystickX/Y(), ekrandaki çubuk, fiziksel bir oyun kolu ya da klavyeden (WASD/oklar) hangisi daha güçlüyse ondan tek, tam bir vektör seçer. Bu yüzden bağlı ama boşta duran bir kol klavye hareketini devre dışı bırakmaz. Y ekseni 2D ekran uzayını izler: yukarı-1'dir.
Bir nesne oluşturmanın üç yolu, ve bunlar birbirinin yerine geçmez#
| Ne oluşturur | Ne kadar yaşar | |
|---|---|---|
scene.createEntity(def) | yazarın oluşturduğu bir varlık: Scene Graph'ta ve Inspector'da görünür | proje boyunca, kaydedilir |
game.spawn(type, pos) | çıplak bir ilkel: canı, yapay zekâsı, davranışı yok | oyun oturumu boyunca |
game.spawnFrom(template, pos, opts) | bütün bir varlığın kopyası: bileşenler, fizik gövdesi, etiketler, katman, ölçek ve derlenmiş davranış yığını | oyun oturumu boyunca |
game.spawn, moloz ve prototipler için doğrudur ve düşmanlar için
işe yaramaz: onunla beslenen bir üretici cansız toplar üretir.
spawnFrom'un kopyaladığı şablon, editörde bileşimlediğiniz ve hiyerarşinin
gözüyle kapattığınız sıradan bir varlıktır: ayrı bir biçim yok, ikinci bir
editör yok, yani gördüğünüz şey görünecek olan şeydir.
// Bir kez, başlangıçta: eksik bir şablon bunu söylemeli, her dalgada sessizce başarısız olmamalı
if (!game.hasTemplate('Skeleton')) console.warn('no Skeleton template');
const mob = game.spawnFrom('Skeleton', { x, y, z }, { tag: 'Enemy' });
template, bir kimlik, bir isim ya da bir etiket kabul eder. Oyun sırasında
yapılan kopyalar oyuna özeldir, bu yüzden stop() onları kaldırır ve
düzenleme sahnesi hiçbir zaman kirlenmez.
Bir varlığı kapatmak hem görünmez HEM sessiz olması demektir: düğüm devre dışı, betik durdurulmuş, fizik gövdesi artık yanıt vermiyor. Yalnızca gizlemek, görünmez bir düşmanın size vurmaya devam etmesine izin verirdi.
game.setEnabled(id, on)bunu bir betikten yönetir, hiyerarşideki göz simgesi de aynısını oradan yapar.
Bir şeyi hareket ettirmek: bir gövdeyi itin, ışınlamayın#
transform.position'ı her karede yazmak, duvarların, diğer canavarların ve
zeminin içinden geçer. Bunun yerine hızı sürün, ama yalnızca sürülecek bir
şey varsa:
if (physics.hasBody) {
const v = physics.getVelocity();
physics.setVelocity({ x: vx, y: v.y, z: vz }); // gerçek bir gövdeyi iter
} else {
transform.position.x += vx * dt; // uçan bir şey için meşru
}
physics.setVelocity, gövdesiz çağrıldığında kimsenin entegre etmediği bir
alanı doldurur ve varlık anında durur. physics.hasBody'nin var olmasının,
ve katalogdaki her hareketli davranışın bir yanıt varsaymak yerine bu soruyu
sormasının nedeni budur. Durmak, hızı iptal etmek demektir: hiçbir şey
yapmamak, gövdeyi serbest sürüklenmede bırakır.
Bir konum yazmak artık gerçekten bir fizik gövdesini hareket ettiriyor. Havok, dönüşümü sürer, hiçbir zaman tersini değil: dinamik bir gövde üzerinde
transform.position'a atama yapmak, bir sonraki adımda üzerine yazılırdı; yani fiziksel bir varlıkta her ışınlanma sessizce başarısız olurdu. Konum vekili artık gövdeyi yeniden senkronlar, tıpkı dönüş vekilinin her zaman yaptığı gibi.
Yol bulma bir anlık görüntüdür#
pathfinding.createGrid(), çağrıldığı yere ortalanmış bir gridi bir kez
ışın taramasıyla oluşturur. O kutudan çıkmak null döndürür ve çoğu çağıran
bunun üzerine, hiç ses çıkarmadan, duvarların içinden geçen düz bir çizgiye
döner.
Grid, varsayılan olarak istenen yolculuğa yeniden ortalanır.
setAutoRecenter(false), yeniden inşanın boşuna bir ışın taraması geçişine
mal olduğu sabit bir dünyada bundan vazgeçmenizi sağlar.
console.log günlüğe yazar. Print çizer.#
Konsol, her yerde olduğu gibi console.log / warn / error'dır. BASIC'in
Print'i ekrana çizer ve her karede çağrılır; ikisi
bilerek ayrılmış komutlardır, ve bunları
karıştırmak, bir kare döngüsüyle bir konsolu dolduran şeydir.
Bir betik nerede çalışır#
Editörde ve bir web derlemesinde, betikler tarayıcıda çalışır. Bir native masaüstü ya da mobil derlemede, aynı kaynak, bir liman değil, gömülü bir QuickJS çalışma zamanında değişmeden çalışır.
Betikler, siz düzenlerken tarayıcının kendi veritabanında saklanır; bu yüzden kaydedilmemiş bir arabellek bir yeniden yüklemeden kurtulur. Geri kalan her şeyle birlikte projeye kaydedilirler.
Sınırlar ve sık karşılaşılan arızalar#
- Bir argümanla
scene.pick(), tuval koordinatları ister. Yukarıya bakın; bu, en sık karşılaşılan yanlış-yer hatasıdır. game.spawn, bir karakter değil, bir ilkel üretir.spawnFromkullanın.- Oyun ortasında doğan varlıklar için bir gövde oluşturulur. Fizik eskiden yalnızca Play anında inşa edilirdi, bu yüzden ondan sonra üretilen her şey, elle yerleştirilmiş komşuları normal davranırken sessizce dünyanın içinden düşerdi.
- Sekiz adım, yapay zekâ takım arkadaşının tavanıdır, sizinki değil. Bir
betik döngüsünün böyle bir sınırı yoktur; başıboş bir
while, her yerde olduğu gibi kareyi kilitler. - Diğer dört dil görünümü, bundan aktarılır. Bir Python ya da Rust görünümünü düzenleyip geri dönmek, saklanan JavaScript üzerinden geçer; nedeni için BASIC sayfasına bakın.