Oyun geliştirme · Web oyun döngüsü
Sahne & Entity Hafif Modeli: Mesh'ten Oyun Nesnesine
Three Mesh görsel temsilidir; oyun mantığı için hafif
entity katmanı gerekir. Bu sayfa mesh ile oyun nesnesini eşler,
update hook'larını döngüye bağlar: tam ECS veya archetype derinliği değil,
Hexovian sınırında kalır.
Holodepth bu yaprağı «sahne grafiği nedir» 101 olarak yazmaz. Döngü ve girdi Loop & zaman bütçesi / Girdi & durum makinesi yapraklarındadır. Animasyon döngüsü saati Three.js · Animasyon döngüsü yaprağındadır. Performans dilimi Platform · FPS yaprağındadır. Tam ECS, component storage, netcode entity senkronu Hexovian sınırındadır.
Sayfayı bitirdiğinizde şu cümleyi kurabilmelisiniz: «Entity mantık taşır; mesh görsel taşır; map ile bağlanır; update hook döngüde çalışır; spawn/dispose yazılır; lite component yeter; fizik köprüsü bir sonraki izlekte mesh pozisyonunu dışarıdan yazar.»
Bu ayrımı erken kurmanın somut faydası, fizik köprüsüne geçişte ortaya çıkar: entity zaten mesh'ten bağımsız bir kimlik taşıyorsa, fizik gövdesi bu kimliğe yeni bir alan olarak eklenir — mevcut kod yeniden yazılmaz, genişletilir.
Bu sayfanın sınırı · komşu konularla ayrım
Bu sayfa web/Three oyununda hafif entity modeli anlatır:
- Mesh ↔ game object lite eşlemesi
- Update / fixedUpdate hook önizlemesi
- Spawn, pool, dispose
- İzlek handoff: fizik köprüsü
Bilinçli olarak dışarıda bırakılan konular:
- Tam ECS, query, archetype → Hexovian
- Rapier/Cannon adımı → Three + fizik köprüsü
- glTF şema, asset pipeline
- Netcode entity replikasyonu
Kısa ayrım: Bu sayfa «mantık nesnesi nasıl yaşar?» · Hexovian ECS «depolama ve sorgu» · Fizik köprüsü «dış motor pozisyon yazar».
Mesh ≠ oyun nesnesi
THREE.Mesh draw için vardır; can, skor, hız, AI durumu mesh
üzerinde taşınmamalı. Holodepth: düz JavaScript nesnesi veya küçük sınıf
«entity»; mesh yalnız view referansıdır. Bu ayrım fizik
köprüsünde kritik olur: motor body ile mesh ayrı yaşar, köprü senkronlar.
Pratik test: bir entity'nin mesh'i sahneden kaldırılsa (ör. görünürlük optimizasyonu) oyun mantığı hâlâ doğru çalışmalı — can azalmalı, çarpışma sayılmalı. Eğer mantık mesh'in var olmasına bağlıysa, ayrım henüz tam kurulmamıştır.
Görsel sahne grafı ile oyun state'i aynı çizelge değildir.
Lite entity map
Holodepth minimal model: id, tags,
transform (mantık uzayı), view (Object3D),
components (düz kayıt). Map veya dizi; ürün ölçeğine göre.
Tam ECS'teki SOA layout ve query iterator burada yok; yüzlerce nesne için
yeter, binlerce benzer için instance veya Hexovian yönü düşünülür.
id alanı hem debug loglarında hem çarpışma hook'larında
ortak anahtar olarak kullanılır; mesh referansını anahtar yapmak (ör.
Map<Mesh, Entity>) dispose sırasında sızıntıya
açıktır — string veya sayısal id daha güvenli bir sözleşmedir.
Update hook'ları
Döngü onTick(dt) içinde entity listesi gezilir:
update(dt, input, fsm) mantık; ardından
syncToView() mesh pozisyonuna yazar. Holodepth sırası:
girdi → FSM → entity update → view sync → render. Fizik geldiğinde
fixedUpdate ayrı saatte çalışabilir; bu yaprakta yalnızca
hook imzası bırakılır.
update() içinde doğrudan THREE.Object3D
API'sine dokunmak (ör. mesh.position.set) ayrımı
bulanıklaştırır; mantık kendi transform alanını yazsın,
syncToView() tek sorumlu olarak bu değeri mesh'e aktarsın.
Sahne grafı köprüsü
Entity spawn olduğunda mesh sahneye eklenir; dispose'da geometry/material
ve sahneden çıkarma yapılır. Parent group ile katmanlama (dünya, aktör,
UI 3D) ürün kararıdır. Holodepth: userData.entityId ile ters
arama nadiren; tercih tek yönlü map.
Katmanlama aynı zamanda raycast performansını etkiler: aktör grubunu ayrı tutmak, picking'in dekor mesh'lerini taramasını önler. Bu, Three raycast omurgasındaki filtre pratiğiyle aynı motivasyonu taşır.
Yaşam döngüsü: spawn, pool, ölüm
Mermi ve parçacık gibi sık doğan nesnelerde object pool düşünülür; her
spawn'da new Mesh GC baskısı yapar. Ölüm: listeden çıkar,
view dispose, referans null. Holodepth: «ölü» entity'yi gizlemek yetmez;
kaynak serbest bırakılmalıdır.
- Spawn: entity + view oluştur, sahneye ekle
- Pool get: sıfırla, yeniden kullan
- Despawn: dispose, map'ten sil
Pool'dan çekilen bir entity'nin önceki tur kalıntıları (eski hız, eski hedef referansı) sıfırlanmadan yeniden kullanılması sinsi bir hatadır — «pool get» adımı yalnızca nesneyi geri vermemeli, tüm mutable alanları varsayılana döndürmelidir.
Component lite (ECS değil)
«Health», «Velocity», «PlayerControl» düz obje alanları olarak yaşar;
sistemler ayrı fonksiyonlar (movementSystem,
healthSystem). Holodepth bu kalıbı «ECS tadında» ama
depolama SOA olmadan sunar. Archetype, chunk iterator ve parallel query
Hexovian'da kalır.
Sistem fonksiyonlarını entity listesini elle gezen küçük döngüler olarak
yazın; «genel amaçlı query motoru» erken bir soyutlamadır — birkaç
düzine entity için düz for döngüsü, sorgu planlayıcısından
daha hızlı yazılır ve okunur.
Güvenli entity katmanı: simüle kod
Örnekler öğretim amaçlıdır; gerçek oyunda tip ve sınır doğrulaması eklenir. Aşağıdaki iskelet entity factory'sini ve mesh'e tek yönlü senkron adımını gösterir.
Simüle · entity factory + view sync.
import * as THREE from 'three'
let nextId = 1
const MAX_ENTITIES = 256 // Ürün tavanı · kullanıcı girdisiyle şişirme
export function createEntityRegistry(scene) {
const list = []
function spawnBox({ x = 0, y = 0, z = 0, tags = [] } = {}) {
if (list.length >= MAX_ENTITIES) return null
const geo = new THREE.BoxGeometry(0.5, 0.5, 0.5)
const mat = new THREE.MeshStandardMaterial({ color: '#6ec8ff' })
const mesh = new THREE.Mesh(geo, mat)
mesh.position.set(x, y, z)
scene.add(mesh)
const entity = {
id: nextId++,
tags,
transform: { x, y, z, yaw: 0 },
velocity: { x: 0, y: 0, z: 0 },
view: mesh,
alive: true,
syncToView() {
if (!this.view) return
this.view.position.set(this.transform.x, this.transform.y, this.transform.z)
this.view.rotation.y = this.transform.yaw
},
dispose() {
if (this.view) {
scene.remove(this.view)
this.view.geometry?.dispose()
this.view.material?.dispose()
this.view = null
}
this.alive = false
},
}
list.push(entity)
return entity
}
function updateAll(dt, input) {
for (const e of list) {
if (!e.alive) continue
// Örnek: basit WASD · gerçek oyunda component/system ayrılır
const speed = 4
if (input.hold.has('left')) e.transform.x -= speed * dt
if (input.hold.has('right')) e.transform.x += speed * dt
if (input.hold.has('up')) e.transform.z -= speed * dt
if (input.hold.has('down')) e.transform.z += speed * dt
e.syncToView()
}
}
function despawnDead() {
for (let i = list.length - 1; i >= 0; i--) {
if (!list[i].alive) list.splice(i, 1)
}
}
return { list, spawnBox, updateAll, despawnDead }
}
Simüle · döngü entegrasyonu.
import { pollInput } from './input-surface.js'
import { createFsm } from './game-fsm.js'
import { createEntityRegistry } from './entity-lite.js'
export function wireGameTick({ scene, onTick }) {
const fsm = createFsm('menu')
const world = createEntityRegistry(scene)
const player = world.spawnBox({ tags: ['player'] })
function gameTick(dt) {
const input = pollInput()
for (const edge of input.edges) {
if (edge === 'pause') fsm.dispatch(fsm.state === 'playing' ? 'pause' : 'resume')
if (edge === 'start' && fsm.state === 'menu') fsm.dispatch('start')
}
if (fsm.state === 'playing' && player) {
world.updateAll(dt, input)
}
world.despawnDead()
if (typeof onTick === 'function') onTick(dt, { fsm, world })
}
return { gameTick, fsm, world, player }
}
Yanlış entity kalıpları
Bu kalıpların bir kısmı «çalışıyor gibi görünür» çünkü küçük ölçekte hata gizlenir; entity sayısı veya oturum süresi arttığında bellek ve tutarlılık sorunları belirginleşir.
- Tüm mantığı
mesh.userDataiçinde taşımak - Her kare yeni mesh spawn (GC)
- Dispose atlamak
- Sınırsız entity sayısı (kullanıcı girdisi)
- Pool'dan çekilen entity'yi sıfırlamadan yeniden kullanmak
- ECS beklentisiyle lite modeli suçlamak
- Fizik body ile mesh'i tek nesne sanmak
Üç entity profili
Üç profil de aynı mesh/entity ayrımını paylaşır; farklılaşan şey entity sayısının büyüklük mertebesi ve pool politikasıdır.
-
01 · Entity
Tek kahraman
- Model
- Bir player entity
- Sync
- Her tik syncToView
- Risk
- Mantık mesh'te
-
02 · Entity
Düşman listesi
- Model
- Dizi + pool
- Tavan
- MAX_ENTITIES
- Risk
- Çizgi içi O(n) her tik
-
03 · Entity
Fizik hazırlık
- Model
- Body id alanı rezerv
- Hook
- fixedUpdate slot
- Risk
- İki yönlü sync karmaşası
Hexovian sınırı: ECS nerede biter?
Holodepth lite model web vitrini ve küçük arcade için yeter. Yüzlerce heterojen component, paralel sistem, ağ doğrulamalı state için Hexovian ECS ve motor izleğine geçilir. Burada öğrenilen «mantık / görsel ayrımı» orada da geçerlidir; yalnızca depolama ve çizelgeleme derinleşir.
Geçiş sinyali genelde nettir: entity sayısı birkaç yüzü aştığında veya her sistemin her entity'yi düz döngüyle taraması profilerde görünür bir maliyete dönüştüğünde, SOA depolama ve query cache konuşulmaya başlar. Bu sayfa o eşiğe gelene kadar yeterli bir üretim yüzeyidir.
Holodepth perspektifleri
Tek yönlü sync varsayılanı
Mantık → view yazılır; view'dan mantık okumak istisnadır (picking hariç ayrı kanal). Bu yön tersine çevrildiğinde debug edilmesi en zor sınıf hatalar ortaya çıkar.
Tavan yazın
MAX_ENTITIES ürün sabiti; profil ile doğrulanır. Sabiti kod içine gömmek yerine bir yapılandırma değeri olarak tutmak, farklı cihaz sınıfları için farklı tavan denemesine izin verir.
Pool, erken optimizasyon değil
Object pool yalnızca sık spawn/despawn olan nesne sınıfları için gereklidir; sahnede sabit sayıda uzun ömürlü entity varsa pool eklemek gereksiz karmaşıklıktır.
Teşhis maddeleri
- Mesh'te oyun state'i kaldı mı?
- syncToView tek yerde mi?
- Spawn/dispose simetrik mi?
- Pool gereksiz new'i kesti mi?
- Döngü hook sırası korunuyor mu?
- Fizik body alanı ayrıldı mı?
- glTF veya tam ECS sızmış mı?
Holodepth içgörüsü
Hafif entity, «oyun nesnesi» dilini Three sahnesinden ayırır; fizik köprüsü ve netcode için zemin hazırlar. Web oyun döngüsü izleği burada mantık katmanını mühürler.
İzlek handoff: Three + fizik köprüsü
Web oyun döngüsü izleği (döngü → girdi → entity) bu yaprakla kapanır. Sonraki izlek Rapier / Cannon yüzeyi ile devam eder: dış fizik motoru body üretir, pozisyon entity view'a köprülenir; sabit adım ve çarpışma tepkisi orada derinleşir. Holodepth omurgası Three animasyon ve Platform FPS ile ölçümde kalır.