本文へスキップ

spryte を単体で使う ​

spryte は debuff の中のレンダラーですが、debuff がなくても動きます。canvas さえあれば(エディタ、ビジュアライゼーション、自作エンジン、小さなゲーム)、小さくて明快な API で高速な 2D 描画が手に入ります。単体でセットアップするのに必要なことを、ここに全部まとめました。

インストールと作成 ​

bash
npm install spryte
ts
import { createRenderer } from "spryte";

const canvas = document.querySelector("canvas")!;
const draw = createRenderer(canvas, { smooth: false }); // ピクセルアートなら smooth: false
await draw.ready;                                       // WebGL2 なら即座に完了。そうでなければフォールバックを待つ
console.log(draw.kind);                                 // "webgl2"、Canvas 2D フォールバックなら "2d"

createRenderer は使えるなら WebGL2 を使います。使えなければ Canvas 2D バックエンドを読み込みます。これは別の小さなチャンクで、WebGL2 対応ブラウザがダウンロードすることはありません。WebGL2 を必須にするなら { backend: "webgl2" }、フォールバックを強制するなら "2d" を渡します。

くっきりしたピクセルのために canvas のサイズを決める ​

spryte はあなたが決めた論理単位で描画し、canvas の実際のピクセルサイズはあなたが管理します。ディスプレイに合わせてサイズを決め、それを spryte に伝えます。

ts
function resize(): number {
  const dpr = devicePixelRatio || 1;
  const w = Math.round(canvas.clientWidth * dpr);
  const h = Math.round(canvas.clientHeight * dpr);
  if (canvas.width !== w || canvas.height !== h) {
    canvas.width = w;
    canvas.height = h;
    draw.resize(w, h);
  }
  return dpr;
}

フレームループ ​

毎フレーム、begin、描きたいものを奥から順に、そして end です。

ts
function frame() {
  const dpr = resize();
  const w = canvas.clientWidth;
  const h = canvas.clientHeight;
  draw.begin("#111", w, h, dpr); // クリア色、論理的な幅と高さ、1 単位あたりの実ピクセル数
  draw.rect(10, 10, 40, 20, "#cffb2d");
  draw.sprite(hero, w / 2, h / 2, { rotation: t, tint: "#ffffff" });
  draw.text(`${draw.kind} · ${draw.drawCalls} draw calls`, 8, 8, { font: "14px sans-serif" });
  draw.end();
  requestAnimationFrame(frame);
}
requestAnimationFrame(frame);

ピクセルアートで解像度を固定したいなら、たとえば 320×180 の論理単位で scale = canvas.width / 320 として描き、canvas のレターボックスはブラウザに任せましょう。

画像 ​

spryte は HTMLImageElement、HTMLCanvasElement、OffscreenCanvas、ImageBitmap を描画できます。どれも初めて描くときに GPU へアップロードされ、オブジェクトごとにキャッシュされます。

  • 描く前に画像の読み込みが終わっていることを確認してください。await img.decode() を使うか、createImageBitmap を使いましょう。
  • スプライトシートなら、Frame({ image, x, y, w, h })を渡すと画像の一部を描けます。
  • 描画元の canvas を書き換えたら、draw.invalidate(thatCanvas) を呼んで spryte に再アップロードさせてください。

コンテキストロスト ​

スマートフォンでは、バックグラウンドに回ったタブからブラウザが GPU を取り上げることがあります。spryte はこれに対応しています。draw.contextLost が true の間は描画をスキップし、コンテキストが戻ってきたら GPU の状態を作り直して、画像は次に使うときに再アップロードします。唯一戻ってこないのはレンダーターゲットの中身です。毎フレーム描き直すか、contextLost が false に戻ったところで描き直してください。

後片付け ​

ts
draw.dispose(); // GPU オブジェクトとリスナーをすべて解放

dispose() のあとにその Draw を使うと、黙って失敗するのではなく、わかりやすいエラーが投げられます。2 回 dispose しても問題ありません。

デバッグ ​

  • draw.kind:どのバックエンドで動いているか。
  • draw.quads と draw.drawCalls:このフレームでどれだけ描いたか、そして何回の GPU 呼び出しで描いたか。
  • draw.raw:spryte の外に出る必要があるときのための、元の WebGL2RenderingContext または CanvasRenderingContext2D(変更した状態は元に戻してください)。

次は draw.sprites でパーティクルと弾を描く と spryte でポストプロセス をどうぞ。完全な API リファレンス もこのサイトにあります。