spryte を単体で使う
spryte は debuff の中のレンダラーですが、debuff がなくても動きます。canvas さえあれば(エディタ、ビジュアライゼーション、自作エンジン、小さなゲーム)、小さくて明快な API で高速な 2D 描画が手に入ります。単体でセットアップするのに必要なことを、ここに全部まとめました。
インストールと作成
npm install spryteimport { 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 に伝えます。
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 です。
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 に戻ったところで描き直してください。
後片付け
draw.dispose(); // GPU オブジェクトとリスナーをすべて解放dispose() のあとにその Draw を使うと、黙って失敗するのではなく、わかりやすいエラーが投げられます。2 回 dispose しても問題ありません。
デバッグ
draw.kind:どのバックエンドで動いているか。draw.quadsとdraw.drawCalls:このフレームでどれだけ描いたか、そして何回の GPU 呼び出しで描いたか。draw.raw:spryte の外に出る必要があるときのための、元のWebGL2RenderingContextまたはCanvasRenderingContext2D(変更した状態は元に戻してください)。
次は draw.sprites でパーティクルと弾を描く と spryte でポストプロセス をどうぞ。完全な API リファレンス もこのサイトにあります。