holodepth

HTML5 Canvas · Sprite ve varlık sistemi

Resim yükleme: Canvas 2D için Image nesnesi ve ön yükleme

drawImage çağrısı, elinizde hazır bir piksel kaynağı ( HTMLImageElement, video karesi veya başka bir tuval ) olduğunda anlam kazanır; tarayıcıdaki raster dosyalar çoğu zaman ağdan asenkron gelir. Bu sayfa yükleme–çizim sırasını, decode ile boyutların ne zaman güvenilir olduğunu ve dış kaynaklarda CORS ayarının tuvali «kirletmeden» nasıl korunacağını Canvas bakış açısıyla sabitler. Sprite dilimleme ve animasyon Sprite levhaları ile Kare animasyonu başlıklarında; önbellek stratejileri Varlık önbellekleme ile derinleşir.

Tuval yaşam döngüsü ve çizim alışkanlıkları için Temizle ve yeniden çiz, Kare yönetimi ile birlikte düşünün; bağlam girişi 2D bağlam sayfasına bağlanır.

Özet: rasterın yolu

Adım Amaç Dikkat
Kaynak URL Dosya veya veri URI CORS ihtiyacını erken belirleyin
Image + olay Yüklemeyi asenkron tamamlayın onload öncesi drawImage yok
decode() Boyut / piksel hazır Eski tarayıcıda yok; yedek: onload
drawImage Tuvalde gösterim complete ve ölçek argümanları
Önbellek Tekrar istekleri azalt Önbellekleme sayfası

Görüntü ve tuval: drawImage öncesi hazırlık

CanvasRenderingContext2D.drawImage aşırı yüklenmiş bir ailedir; raster dosya için en yaygın yol new Image() ( document.createElement("img") eşdeğeri ) oluşturup src atamaktır. Atama anında istek başlar; görüntü hazır olana kadar genişlik / yükseklik sıfır veya eski değerde kalabilir — yerleşim hesabını onload veya decode sonrasına bırakmak düzeni korur.

Kısa döngülerde «her karede yeni Image» üretmek bellek ve ağ israfıdır; sprite tabanlı oyunda kimlik → görüntü eşlemesi tek sefer yüklenir ve oyun boyunca elde tutulur. Tek tuval prototiplerinde bile küçük bir Map veya nesne sözlüğü düzen getirir. Çizim kodu yalnız hazır görselleri tüketir; yükleyici katmanı ayrı dosyada tutmak test yazımını kolaylaştırır.

naturalWidth / naturalHeight piksel cinsinden kaynak boyutunu verir; CSS ile sayfada küçültülmüş olsa bile çizimde orijinal çözünürlük üzerinden karar verirsiniz. Tuvalde ölçek ( 9 dilim, geri uyumlu büyütme ) başka başlıkların konusudur; burada yalnız hazır pikselin varlığı işlenir.

Asenkron yükleme: olaylar ve Promise sarımı

Klasik model: onload ve onerror geri çağrıları; modern akışta aynı mantık Promise ile sarılır ve async/await ile okunur. src atandıktan sonra aynı nesneye tekrar farklı src vermek yeni istek başlatır — önbellek isabeti olsa bile olay sırasını karıştırmamak için üretimde tek nesne–tek URL disiplini veya yükleme kimliği ( sayaç ) kullanılır.

fetch ile Blob alıp createObjectURL üretmek mümkündür; bu sayfada yalın Image yolu tercih edilir çünkü tarayıcı önbelleği ve sıralama ile iyi çalışır. İleri senaryolar ( Service Worker, parça parça indirme ) burada açılmaz.

Birden çok görüntü için Promise.all «hepsi veya hiçbiri» verir; kısmi başarı istiyorsanız allSettled ve harita bazında hata toplama daha güvenlidir. Oyun başlangıcında kritik set ( arayüz atlası ) ile isteğe bağlı set ( dekor ) ayırmak yükleme deneyimini yumuşatır.

/**
 * crossOrigin: örn. "anonymous" — src'den ÖNCE atanmalı (export güvenli tuval için).
 * Güvenilmeyen URL'lere bağlanmayın; kullanıcı girdisini doğrudan src yapmayın.
 */
function loadImage(src, { crossOrigin } = {}) {
  return new Promise((resolve, reject) => {
    const img = new Image();
    if (crossOrigin) img.crossOrigin = crossOrigin;
    img.onload = () => resolve(img);
    img.onerror = () => reject(new Error("Image load failed"));
    img.src = src;
  });
}

Decode ve boyut: ne zaman çizmek güvenli

HTMLImageElement.decode() görüntünün asenkron olarak piksele çözülmesini bekler; bazı tarayıcılarda onload sonrasında bile ilk karede boş çizim görülmesini azaltır. Destek yoksa yedek olarak yalnız onload yeterlidir — özellik çağrısını özellik algılama ile sarın.

Oyun döngüsünde «yükleniyor» durumunda boş bir yer tutucu ( renk blok veya düşük çözünürlüklü önizleme ) çizmek kullanıcıya geri bildirim verir; metin tabanlı hata yerine üretimde günlük ve sayaç tercih edilir. Animasyonlu yükleme çubuğu Canvas veya DOM; burada mesele rasterın hazır olduğu ana kadar ana spriteları çizmemektir.

Çok büyük dokular mobilde bellek baskısı yaratır; çözünürlük seçimi ve sıkıştırma formatı ( PNG şeffaflık, WebP / AVIF desteği ) yükleme katmanından önce tasarım kararıdır — bu sayfa format savaşını işlemez, yalnız hazır olduktan sonra çizimi ele alır.

async function loadImageDecoded(src, opts) {
  const img = await loadImage(src, opts);
  if (typeof img.decode === "function") {
    try {
      await img.decode();
    } catch {
      /* bazı bozuk dosyalarda decode hata verebilir; onload ile yine de elde tutuldu */
    }
  }
  return img;
}

Kaynak güvenliği ve CORS: kirlenmiş tuval

Başka kökten ( cross-origin ) yüklenen görüntü, crossOrigin özelliği uygun ayarlanmadıysa tuvali kirletir ( tainted ); bu durumda getImageData, toDataURL ve benzeri okuma işlemleri güvenlik nedeniyle hata verir veya boş veri döner. Aynı kök veya veri URL'leri genelde sorunsuzdur; harici CDN kullanıyorsanız CDN'in CORS başlıkları ve sizin crossOrigin = "anonymous" sırası kritiktir — önce crossOrigin, sonra src.

Kullanıcıdan gelen rastgele URL'leri yüklemek ( açık uçlu ) güvenlik ve gizlilik riski taşır; eğitim kodunda bile sabit liste veya sunucu ara köprüsü tercih edin. Örnek fonksiyon güvenilmeyen girdiyi src yapmaz; çağıran kod beyaz liste uygulamalıdır.

Ekran görüntüsü veya kayıt özelliği geliştiriyorsanız kirlenme kuralını baştan bilirsiniz; yalnız görüntüleme yeterliyse ve piksel okumayacaksanız CORS ihtiyacı düşebilir — ürün hedefinize göre mimari seçin ve tek dokümanda kararları sabitleyin.

Toplu yükleme: anahtarlı atlas ve sıra politikası

Seviye başına onlarca küçük dosya yerine tek sprite levhası ( levha sayfası ) çoğu zaman daha az istek sayısı verir; yine de levha yüklemesi de asenkron kalır. Yükleme haritası: dize kimliği → URL; tamamlanınca Map doldurulur. Büyük projelerde istekleri önceliklendirin ( oyuncu önce, dekor sonra ).

Promise.all bir dosya düşerse tüm zinciri reddeder; giriş ekranında «kritik paket» için katı, arka planda «gevşek» toplama için ayrı yol ayrımı yapılabilir. Hata mesajını kullanıcıya kopyalanabilir kod veya kısa kimlikle göstermek destek sürecini hızlandırır.

Yükleme sırasında tuvali zorla sürekli yeniden çizmek ( her olayda tam sahne ) pil tüketir; «hazır olan kadarını çiz» veya düşük frekanslı ilerleme güncellemesi yeterlidir — kare yönetimi ile uyumludur.

/** entries: [["player","/a.png"],["ground","/b.png"]] — kritik yol için all yerine allSettled düşünün. */
async function preloadDecodedImages(entries, opts) {
  const map = new Map();
  const jobs = entries.map(async ([key, src]) => {
    const img = await loadImageDecoded(src, opts);
    map.set(key, img);
  });
  await Promise.all(jobs);
  return map;
}

Tekilleştirme ve önbellek katmanı: tekrar yüklemeyi engelle

Aynı URL için ikinci kez new Image() üretmek gereksizdir; modül düzeyinde Map ( url → Promise veya HTMLImageElement ) tutmak tekilleştirme sağlar. İnce taneli içerik güncellemesinde sürüm sorgu parametresi ( ?v=2 ) önbellek kırmak için kullanılır — Varlık önbellekleme sayfasına bırakılan stratejilerle uyumludur.

Tarayıcı önbelleği dosyayı tutsa bile JavaScript tarafında çift yükleme yine bellekte çift görüntü oluşturabilir; tekilleştirme hem ağ hem RAM tasarrufu verir. İşçi iş parçacığı ( Worker ) içinde görüntü yükleme sınırları vardır; ana iş parçacığı modeli bu sayfanın varsayımıdır.

Büyük levhalarda «lazy» dilim çözümü ( sadece görünen bölgeler ) ileri optimizasyondur; temel sprite yüklemesinde tüm levha bir kez gelir, dilimleme koordinatları başka başlıkta uygulanır — sınırları karıştırmayın.

Hata ve düşüş: kullanıcı geri bildirimi

Ağ kesintisi, 404 ve bozuk görüntü dosyası onerror ile sinyallenir; yakalanmayan vaat reddi konsolu kirletir ve sessiz başarısızlık yaratır. Yükleme sarmalayıcılarında try/catch, günlük ve kullanıcıya «yeniden dene» düğmesi minimal bir ürün kaplamasıdır. Geliştirme ortamında eksik dosya en sık hatadır; üretimde CDN bölgesel kesintisi.

Kısmi başarı senaryosunda eksik görseller için düşük çözünürlüklü yedek veya düz renk sprite atanması oyunun tamamen kilitlenmesini önler; hangi varlığın kritik olduğunu tasarım belgeleriyle eşleştirin.

Erişilebilirlik: yalnız Canvas kullanıyorsanız ekran okuyucu için DOM'da kısa durum metni veya ARIA canlı bölge düşünmek, yükleme hatalarında da geçerlidir — görüntü yüklemesi teknik bir ayrıntıdır, ürün deneyimi değildir.

Anti-kalıplar: erken çizim ve yanlış CORS sırası

Aşağıdaki dört örnek, Canvas prototiplerinde sık görülür; çoğu ya ilk karede boş sprite ya da üretimde kirlenmiş tuval ve gereksiz ağ trafiği olarak geri döner. Çözümler bu sayfada zaten verilen sıra ve tekilleştirme disiplinine indirgenir — yeni kütüphane öğrenmeden düzeltilir.

drawImage hemen src sonrası: Tarayıcı isteği başlatır ama piksel henüz hazır olmayabilir; naturalWidth sıfır kalabilir veya ara durumda eski içerik görülebilir. Güvenilir yol: onload / Promise tamamı ve mümkünse decode sonrası çizim — yüklenene kadar yer tutucu çizmek ( hata ve düşüş ) kabul edilebilir bir ürün kararıdır.

crossOrigin src’den sonra: Özellik atanınca bazı tarayıcılar isteği yeniden yorumlamaz; sonuç kirlenmiş ( tainted ) tuval olur ve getImageData / toDataURL güvenilir olmaz. Kalıcı kural: önce crossOrigin, sonra src — aynı dosyayı yeniden yüklemek gerekebilir.

Her kare yeni Image: Nesne başına bellek ve olay maliyeti vardır; tarayıcı önbelleği dosyayı saklasa bile ortamda çift HTMLImageElement tutmak RAM’i şişirir. Tek URL için tek nesne veya «URL → Promise» eşlemesi ( tekilleştirme ) ile aynı sprite her karede yeniden drawImage edilir, yeniden yüklenmez.

Kullanıcı metnini doğrudan src yapmak: Form veya adres çubuğu girdisi beyaz liste veya sunucu tarafı çözümlemeden tuvala bağlanmamalı; kötü niyetli yönlendirme ve iz sürme riski doğar. Bu sayfa sabit URL veya güvendiğiniz CDN varsayar; dinamik listelerde kaynak doğrulaması yükleme katmanının dışında değil, onun önünde durmalıdır.

Bu sayfanın sınırı

WebGL dokuları, video akışı kareleri ve gelişmiş görüntü kod çözücü boru hatları burada işlenmez. Odak: Canvas 2D drawImage için güvenli ve sıra bilincinde raster yüklemedir.

  • Yükleme tamamlanmadan sahne sprite çizilmiyor mu?
  • Piksel okuma gerekiyorsa CORS sırası doğru mu?
  • Aynı URL tekrar tekrar yüklenmiyor mu?
  • Hatalı dosyalar yakalanıp kullanıcıya bildiriliyor mu?
  • Büyük levha yükü için bellek bütçesi düşünüldü mü?