holodepth

HTML5 Canvas · Oyun mantığı ve çarpışma

Oyun durumu mantığı: durum makinesi ve tek kaynak gerçek

Canvas tabanlı 2D oyunda «ne oluyor?» sorusunun cevabı yalnızca pikseller çizmek değildir; kare döngüsü her turda hangi kuralların işlendiği ile belirlenir. Oyun durumu: menü mü, oynuyor mu, duraklatıldı mı, bitti mi — ve bunun altında skor, seviye bayrakları, varlık listesi gibi tek yerde tutulması gereken veriler. Bu sayfa durum geçişlerini, kare fazlarına oturtmayı ve giriş ile fizik katmanları arasındaki sınırı Canvas bakış açısıyla sabitler; hareket denklemleri Hız ve hareket, kuvvet modeli Temel fizik, geometri AABB / Daire komşu başlıklardadır.

Kare yaşam döngüsü ve zaman politikası için Kare yönetimi ve Update vs render; süre ölçeği için Delta time ile birlikte okunmalıdır.

Özet: kare içi faz sırası

Faz Tipik iş Durumla ilişki
Giriş toplama Olayları kuyruğa al veya anında bayrakla Menüde imleç, oyunda kontrol
Ön mantık Duraklatma / geçiş istekleri FSM dispatch
Simülasyon Fizik ve çarpışma (oynanırken) Faz kapısı: yalnız Play
Oyun kuralları Skor, bölüm bitişi, power-up Olay tüketimi
Çizim Tuval temizle, sahneyi çiz, UI Duruma göre farklı HUD

Tekil oyun durumu ve katmanlar: menü ayrı, dünya ayrı

«Single source of truth» pratiği: aynı bilgiyi hem düğüm ağacında hem rastgele bayraklarda saklamak senkronu bozar. Canvas demosunda genelde küçük bir game nesnesi ( faz, skor, oyuncu referansı, varlık dizisi ) yeterlidir; menü öğeleri için ayrı hafif bir model veya doğrudan DOM üstü arayüz kullanılabilir — ikisini karıştırmadan bağlayın. Menüden «oyna»ya geçerken dünya durumunu ya sıfırdan kurun ya da kontrollü bir yükleme fonksiyonuna delege edin.

UI bayrakları ( muted, showHitboxes ) ile oyun fazı ( menu, play ) farklı lifecyle’e sahiptir; birincisi çoğu zaman anında uygulanır, ikincisi geçiş tablosu gerektirir. Canvas çizimi aynı tuvalde menü arka planı + düğmeler veya tam ekan oyun sahnesi gösterebilir — kritik olan, aynı karede iki mantığın birbirinin girdisini çiğnememesi ( örn. duraklatılmışken fizik entegrasyonu çalıştırmamak ).

Kalıcı kayıt, ayarlar ve çoklu dil gibi «oturum dışı» veriler oyun durumunun parçası olabilir ama kare döngüsünün sıcak yolunda tutulmamalıdır; her kare diske yazmak veya localStorage taramak gecikme üretir. Prototipte bile bu ayrımı kodda klasör / modül sınırı gibi düşünmek ileride büyümeyi kolaylaştırır.

Durum makinesi ve izinli geçişler

Sınırlı sayıda faz ( boot, menü, oyun, duraklat, sonuç ) için finite state machine en okunabilir yapıdır. Geçiş tablosu: «şu fazdayken şu olay gelirse şu faza git» — tablo dışı istekleri yok saymak veya günlüklemek hataları erken keser. Büyük projeler hierarchical FSM veya davranış ağaçlarına geçer; Canvas öğretim hedefinde düz tablo çoğu zaman yeterlidir.

Yan etkiler ( ses çal, istatistik gönder, sahneyi sıfırla ) geçiş anında mı yoksa «girişte bir kare» gecikmeli mi çalışmalı? Erken karar: geçiş fonksiyonu içinde ağır iş yapmamak, gerekirse kısa bir «geçiş odağı» ( transient durum ) eklemek jank’i azaltır. Aynı tuş «ESC» hem menüde çıkış hem oyunda duraklatma anlamına geliyorsa, önce faz sonra tuş yorumlanır.

Durum makinesi kodda metin dizisi ( "play" ) veya sabit nesne ( Phase.Play ) ile temsil edilebilir; yazım hatalarına karşı küçük projede const veya enum benzeri harita tercih edilir. Geçmiş fazı hata ayıklama için saklamak geçerli bir seçenektir.

/** Basit FSM: geçiş yoksa false döner — spam ve hatalı faz birleşimleri azalır. */
const Phase = {
  Menu: "menu",
  Play: "play",
  Pause: "pause",
  GameOver: "gameover",
};

function createGameFsm(initialPhase) {
  let phase = initialPhase;
  const next = {
    [Phase.Menu]: { start: Phase.Play },
    [Phase.Play]: { pause: Phase.Pause, lose: Phase.GameOver, toMenu: Phase.Menu },
    [Phase.Pause]: { resume: Phase.Play, toMenu: Phase.Menu },
    [Phase.GameOver]: { retry: Phase.Play, toMenu: Phase.Menu },
  };

  return {
    getPhase() {
      return phase;
    },
    dispatch(event) {
      const row = next[phase];
      const to = row && row[event];
      if (!to) return false;
      phase = to;
      return true;
    },
  };
}

Kare döngüsünde fazlar: update ve render ayrımı

Tek requestAnimationFrame geri çağrısında akış şöyle kurulabilir: ölçülen dt, giriş tüketimi, durum makinesi isteği, ardından yalnız «oynanır» fazındayken fizik güncellemesi, en sonda çizim. Çizim kodu duruma göre menüyü veya sahneyi seçer — amaç fizik fonksiyonlarının içine
if (paused) return; doldurmak yerine çağırmamak veya çok ince erken dönüştür. Böylece ileride «arka planda yalnız AI» gibi istisnaları eklemek kolaylaşır.

Çoklu sabit pozisyon adımı ( fizik iç içe ) kullanıyorsanız, duraklatma bayrağı fizik birikimcisini de durdurmalıdır; aksi halde sekme dönüşünde «birikmiş saniye» tek hamlede oynatılır. Bu köprü kare yönetimi ile birlikte tasarlanır — oyun durumu yalnız kapı değil, zaman politikasının ortağıdır.

HUD animasyonları ( sayı sayacı ) bazen simülasyondan bağımsız interpolasyonla çizilir; yine de skorun gerçek «kanonik» değeri tek yerde tutulmalıdır. Aksi halde çarpışma anında skor artıyor ama ekranda bir kare gecikmeli görünüyor gibi algı sorunları ortaya çıkar — bu bir durum tutarsızlığıdır, grafik optimizasyonu değil.

Giriş ve faz: olayların yorumlanması

Aynı ham tuş veya imleç olayı faz değiştik anda farklı anlama gelir; dinleyicilerde erken preventDefault kararları ( kaydırma kilidi, oyun içi ) menüde istenmeyen yan etki üretir. Pratik düzen: düşük seviye dinleyici sadece tamponlar veya kuyruğa yazar; yorumlama tek fonksiyonda faz kontrolü ile yapılır. Böylece «menüde space ile tıkla, oyunda zıpla» çakışması tek yerde çözülür.

Parmak / kalem koordinat dönüşümleri event koordinatları ile hizalanmalıdır; durum makinesi «tıklandı» dediğinde geometri katmanı zaten tuval uzayında çalışır. Sürükleme ve jestler için işaretçi sistemi sayfası ayrıntı verir — burada yalnız «giriş → eylem» kararının fazdan geçtiği vurgulanır.

Tekrarlanan tuş basımı ( key repeat ) platforma göre değişir; menüde ok ile seçim, oyunda sürekli hareket gibi iki rejimi karıştırmamak için repeat bayrağını bilinçli ele alın. Odağı kaybetme ( blur ) olayında duraklatma, sekme görünürlüğü ( Page Visibility ) ile dondurma bir ürün kararıdır ve durum geçişiyle bağlanır.

Dünya durumu: varlıklar, yaşam döngüsü ve sahne yükleme

Oyun oynanırken mutasyon gören koleksiyonlar ( düşman listesi, mermiler ) için net kurallar: ekleme genelde kare sonunda, ölü varlıklar işaretlendiğinde temizlik aşamasında silinir — fizik ortasında dizi yeniden boyutlanırsa indeks hataları yaygındır. Küçük dizilerde filtreleme ( filter ) kabul edilebilir; çok nesnede nesne havuzu ( pool ) düşünülür — o da durum modelinin parçasıdır.

Saha ( level ) değişimi yeni bir durum olabilir veya oynanır faz içinde alt durum; her iki durumda da fizik başlangıç değerleri ( oyuncu spawn, kamera, çarpışıcılar ) tek fonksiyonda toplanmalıdır. Yarı yüklenmiş sahne «oyun başladı» bayrağını yanlış zamanda açarsa oyuncu zeminin içinde doğar — bu tür hatalar durum sırası bozulduğunda görülür.

Script ile kontrol edilen keskin sahneler yoksa bile «bölüm hazır» onayı: çarpışma ızgarası, düşman dalga sayacı, hedef skor — hepsi dünya nesnesinde tutulup çizimden bağımsız doğrulanır. Böylece fizik ve çarpışma katmanları saf matematik kalır, üstte kurallar oyun durumuna konuşur.

Olay kuyruğu: çarpışma ve kural tetikleri

Çarpışma çözümü çoğu zaman aynı kare içinde konum düzeltir; «can azalt», «puan ver», «ses çal» ise oyun kuralıdır ve bazen sıraya alınması daha güvenlidir. Basit yaklaşım: fizik sonrası kuyrukta biriken olayları tek geçişte işle; aynı çift gövde için çift ödül vermezsiniz. Kuyruk üst sınırı ( bellek ve sonsuz döngü koruması ) mobil tarafta özellikle faydalıdır.

Gecikmeli eylem ( 0.5 sn sonra patla ) için durum makinesi yerine küçük bir zamanlayıcı listesi veya tek «gecikmeli olay» koleksiyonu yeterlidir — bunu da oyun durumu nesnesinde tutun; zaman sayaçları dt ile azalır, delta time ile ölçeklenir.

Çarpışma geometrisinin kendisi AABB ve daire sayfalarında; burada mesele «çakışma tespit edildi» sinyalinin nerede üretilip nerede tüketildiğidir. Kuyruk üreticisi düşük seviye, tüketici kural katmanı olarak ayrılırsa test yazımı kolaylaşır.

/** Basit üst sınırlı kuyruk: sonsuz büyümeyi önler, oyun mantığı tüketir. */
function createBoundedQueue(maxLen = 256) {
  const items = [];
  return {
    push(x) {
      if (items.length < maxLen) items.push(x);
    },
    clear() {
      items.length = 0;
    },
    /** Kopya döner; iç tablo sıfırlanır — tüketim tek yerde toplanır */
    drain() {
      if (!items.length) return [];
      const out = items.slice();
      items.length = 0;
      return out;
    },
    get length() {
      return items.length;
    },
  };
}

Duraklatma, odak ve zaman: dış dünya ile uyum

Duraklatma yalnız çizimi dondurmak değildir: zamanlayıcılar, AI, ağ ( eşzamanlı oyun dışı ) için de politika gerekir. Tek oyunculu Canvas’ta en güvenli model: duraklatıldığında simülasyon çağrılmaz ve dt birikimi sıfırlanır veya yutulur. Yarı şeffaf örtü ile devam eden arka plan animasyonu istiyorsanız «dünya dondur, arayüz animasyonu çalışsın» diye iki zaman hattı ayırın — karmaşıklık artar, dokümante edin.

Sayfa görünürlüğü API’si sekmeler arası geçişte oyunu otomatik durdurmak için kullanılır; bu, kullanıcı dostu varsayılandır ve durum makinesine «dışarıdan gelen duraklat» olayı olarak bağlanabilir. Klavye odağı canvas üzerinde değilse tuşların kaybolması yaygın bir destek talebidir; erişilebilirlik için alternatif odak yönetimi veya görünür odak halkası düşünün.

Yarış modu veya demodaya hazırlıkta «her zaman aynı seed ve sabit adım» ile kayıt oynatımı isteyebilirsiniz; bu, durum makinesinden bağımsız değil — kayıt hangi fazda başladıysa o fazdan deterministik ilerlemelidir. Bu derinlik rehber düzeyinde tutulur.

Anti-kalıplar: bayrak çorbası ve çift gerçek

isPlaying && !isPaused && !isDialogOpen ...: Koşul zincirleri yerine faz makinesi veya tek türlü üst durum kullanın; aksi halde imkânsız kombinasyonlar oluşur.

Çizim içinde yan etki: draw() skor artırmak veya fizik çağırmak kare sırasını kırar; çizim salt okunur tüketici olmalıdır.

Her karede rastgele yeniden başlatma: Sahne kurulumunu yalnız geçiş veya yükleme olayına bağlayın; yoksa performans ve durum drift eder.

Olayları iki kez işlemek: Kuyruk tüketildikten sonra aynı listeyi tekrar dolaşmayın; tek tüketim noktası seçin.

Bu sayfanın sınırı

Çok oyunculu senkronizasyon, sunucu otoritesi, geniş ECS mimarisi ve kurumsal oyun motoru mimarileri burada işlenmez. Amaç: tek dosyalı Canvas prototiplerinde okunabilir durum ve faz yönetimi kurmaktır.

  • Tekil oyun nesnesi ve faz kaynağı net mi?
  • Fizik ve simülasyon yalnız oynanırken mi çağrılıyor?
  • Giriş yorumu fazdan bağımsız tek yerde mi?
  • Oyun kuralı olayları kuyrukta mı toplanıyor?
  • Duraklatmada dt birikimi kontrol altında mı?