Oyun mantığı için Web Workers
Web Workers, JavaScript'i bir arka plan iş parçacığında çalıştırmanızı sağlar. Oyunlarda bu, fizik, yapay zekâ ve prosedürel üretimin kare kaybına yol açmadan çalışabileceği anlamına gelir.
1) Workers ne zaman kullanılmalı?
Uygun kullanım alanları:
- Fizik simülasyonu
- Yol bulma (A*, navmesh)
- Yapay zekâ karar verme
- Prosedürel üretim
- Varlık işleme (görüntü düzenleme, sıkıştırma)
- Karmaşık matematiksel işlemler (FFT, çarpışma algılama)
Şunlar için ideal değildir:
- Render işlemleri (Workers, DOM/Canvas'a doğrudan erişemez)
- Çok küçük görevler (iş parçacığı ek yüküne değmez)
2) Temel bir Worker oluşturma
worker.js:
self.onmessage = (e) => {
const { type, data } = e.data
if (type === 'calculate') {
const result = heavyCalculation(data)
self.postMessage({ type: 'result', data: result })
}
}
function heavyCalculation(input) {
// Yoğun işlem burada
return input * 2
}main.js:
const worker = new Worker('worker.js')
worker.onmessage = (e) => {
const { type, data } = e.data
if (type === 'result') {
console.log('Sonuç alındı:', data)
}
}
worker.postMessage({ type: 'calculate', data: 42 })3) Satır içi Workers (ayrı dosya olmadan)
function createInlineWorker(fn) {
const blob = new Blob([`(${fn.toString()})()`], { type: 'text/javascript' })
return new Worker(URL.createObjectURL(blob))
}
const worker = createInlineWorker(() => {
self.onmessage = (e) => {
const result = e.data * 2
self.postMessage(result)
}
})4) ES modülü Workers
Worker kodunu bir ES modülü olarak yazabilir ve importScripts yerine içinde import kullanabilirsiniz. Oluşturucuya { type: 'module' } iletin:
const worker = new Worker('physics-worker.js', { type: 'module' })Ardından Worker içinde paylaşılan matematik, çarpışma veya yapay zekâ yardımcılarını ana iş parçacığında olduğu gibi import edebilirsiniz; böylece oyun mantığı yinelenmez. Modül Workers, Chrome ve Edge 80+, Safari 15+ ve Firefox 114+ sürümlerinde desteklenir.
5) Fizik Worker örneği
physics-worker.js:
const bodies = []
const FIXED_DT = 1 / 60
self.onmessage = (e) => {
const { type, data } = e.data
switch (type) {
case 'init':
initWorld(data)
break
case 'step':
step()
break
case 'addBody':
bodies.push(data)
break
}
}
function initWorld(config) {
// Fizik dünyasını başlat
}
function step() {
// Fiziği güncelle
for (const body of bodies) {
body.vy += 9.8 * FIXED_DT // Yer çekimi
body.x += body.vx * FIXED_DT
body.y += body.vy * FIXED_DT
}
// Konumları geri gönder
self.postMessage({
type: 'positions',
data: bodies.map(b => ({ id: b.id, x: b.x, y: b.y, rotation: b.rotation }))
})
}6) Performans için aktarılabilir nesneler
Büyük veriler kopyalanmadan aktarılabilir:
// Ana iş parçacığı
const positions = new Float32Array(1000)
worker.postMessage(positions, [positions.buffer])
// positions artık burada kullanılamaz (aktarıldı)
// Worker
self.onmessage = (e) => {
const positions = e.data
// Konumlarla çalış
self.postMessage(positions, [positions.buffer])
}7) Yol bulma Worker'ı
pathfinding-worker.js:
let grid = null
self.onmessage = (e) => {
const { type, data } = e.data
if (type === 'setGrid') {
grid = data
}
if (type === 'findPath') {
const path = aStar(data.start, data.end, grid)
self.postMessage({ type: 'path', id: data.id, path })
}
}
function aStar(start, end, grid) {
// A* uygulaması
const openSet = [start]
const cameFrom = new Map()
const gScore = new Map()
gScore.set(key(start), 0)
while (openSet.length > 0) {
// ... A* mantığı
}
return reconstructPath(cameFrom, end)
}
function key(pos) {
return `${pos.x},${pos.y}`
}8) Paralel görevler için Worker havuzu
class WorkerPool {
constructor(workerUrl, size = navigator.hardwareConcurrency || 4) {
this.workers = []
this.queue = []
this.available = []
for (let i = 0; i < size; i++) {
const worker = new Worker(workerUrl)
worker.onmessage = (e) => this.handleResult(worker, e)
this.workers.push(worker)
this.available.push(worker)
}
}
run(data) {
return new Promise((resolve) => {
const task = { data, resolve }
if (this.available.length > 0) {
this.dispatch(this.available.pop(), task)
} else {
this.queue.push(task)
}
})
}
dispatch(worker, task) {
worker._currentTask = task
worker.postMessage(task.data)
}
handleResult(worker, e) {
const task = worker._currentTask
task.resolve(e.data)
if (this.queue.length > 0) {
this.dispatch(worker, this.queue.shift())
} else {
this.available.push(worker)
}
}
terminate() {
this.workers.forEach(w => w.terminate())
}
}9) Gerçek zamanlı senkronizasyon için SharedArrayBuffer
Kaynaklar arası yalıtım etkinleştirildiğinde belleği paylaşabilirsiniz:
// Ana iş parçacığı
const shared = new SharedArrayBuffer(1024)
const positions = new Float32Array(shared)
worker.postMessage({ type: 'init', buffer: shared })
// Worker, paylaşılan belleği doğrudan okur/yazar
// Konum güncellemelerinde postMessage ek yükü yoktur10) Workers için OffscreenCanvas
Render işlemlerini bir Worker içinde gerçekleştirin. OffscreenCanvas artık Chrome, Edge, Firefox ve Safari genelinde Baseline Widely Available durumundadır (Safari desteği macOS ve iOS'ta 17.0 sürümüyle eklendi):
// Ana iş parçacığı
const canvas = document.getElementById('game')
const offscreen = canvas.transferControlToOffscreen()
worker.postMessage({ canvas: offscreen }, [offscreen])
// Worker
self.onmessage = (e) => {
const canvas = e.data.canvas
const ctx = canvas.getContext('2d')
function render() {
ctx.clearRect(0, 0, canvas.width, canvas.height)
// Çiz...
requestAnimationFrame(render)
}
render()
}11) Hata yönetimi
worker.onerror = (e) => {
console.error('Worker hatası:', e.message, e.filename, e.lineno)
}
// Worker içinde
self.onerror = (e) => {
self.postMessage({ type: 'error', message: e.message })
}İlgili içerikler
- Hızlı yüklenen bir web oyunu yayınlayın
- Wasm iş parçacıklarını etkinleştirin (SharedArrayBuffer)
- Canvas 2D oyun döngüsü
- Oyun fiziği kütüphaneleri — Rapier veya Cannon-es'i bir Worker içinde çalıştırma
- Akışla varlık yükleme — varlıkları ana iş parçacığı dışında çözme
- 2026'da Web Oyunları Teknoloji Yığını — Workers'ın WebGL/WebGPU/Wasm yığınına nasıl uyduğu
Harici Kaynaklar
- MDN: Web Workers API — eksiksiz API referansı
- MDN: Web Workers Kullanımı — adım adım kılavuz
- MDN: Aktarılabilir nesneler — sıfır kopyalı veri aktarımı
- MDN: SharedArrayBuffer — iş parçacıkları arasında paylaşılan bellek