CHAPTER 05 · 全23項目
文字列からドット絵を作る
X と . の配列を画像に変換し、2コマのスプライトとして再利用します。画面の英数字も同じ考え方のドット文字です。
主な参照先:makeSprite / TYPES / withGlow / prerender / FONT_SHEETS / GLYPHS
X のマスを塗るだけで画像になる
function makeSprite(rows, color, scale = 2) {
const c = document.createElement("canvas");
c.width = rows[0].length * scale;
c.height = rows.length * scale;
const g = c.getContext("2d");
g.fillStyle = color;
rows.forEach((row, y) => {
for (let x = 0; x < row.length; x++) if (row[x] === "X") g.fillRect(x * scale, y * scale, scale, scale);
});
return c;
}rows は1行ずつの文字列を入れた配列です。X の位置だけを四角く塗り、ほかは透明のまま残します。scale = 2 なら、文字列の1文字を2 × 2 pxに変換します。生成した Canvas はそのまま drawImage() の画像として使えます。
実験:文字列を描き換える
X が塗るマス、. が透明なマスです。下の見本は編集するとすぐに変わります。
データと描画処理を分ける
敵の TYPES には得点 pts、色 color、2コマ分の frames をまとめています。起動時に frames を画像へ変換し、戦闘中は form.anim でどちらを描くか選びます。文字列を毎フレーム解析する必要はありません。
a: { // トゲ型エイリアン
pts: 30, color: "#ff6ad5",
frames: [[
".X..XX..X.",
"..X.XX.X..",
".XXXXXXXX.",
"XXX.XX.XXX",
"XXXXXXXXXX",
".XXXXXXXX.",
"..X....X..",
".X......X.",
], [光彩も先に作る
withGlow() は元画像をぼかした別画像を作ります。ぼかしが端で切れないよう余白 pad を持たせ、描くときにその分だけ位置を戻します。prerender() も同じ考え方で、タイトルやボスの船体など変わりにくい絵を一度だけ描いて使い回します。
文字もドット絵にする
// 文字表: 各行に、同じ高さの点の並びを文字の順に横へ書き並べる。1 文字は 5 列で、文字どうしは空白 1 列で区切る。
// 上から 7 行目の下がベースライン。g・j・p・q・y の下に伸びる部分だけ 8・9 行目を使う。
const FONT_SHEETS = [
["ABCDEFGHIJKLM", [
".XXX. XXXX. .XXX. XXXX. XXXXX XXXXX .XXX. X...X .XXX. ..XXX X...X X.... X...X",
"X...X X...X X...X X...X X.... X.... X...X X...X ..X.. ...X. X..X. X.... XX.XX",
"X...X X...X X.... X...X X.... X.... X.... X...X ..X.. ...X. X.X.. X.... X.X.X",
"XXXXX XXXX. X.... X...X XXXX. XXXX. X.XXX XXXXX ..X.. ...X. XX... X.... X.X.X",
"X...X X...X X.... X...X X.... X.... X...X X...X ..X.. ...X. X.X.. X.... X...X",
"X...X X...X X...X X...X X.... X.... X...X X...X ..X.. X..X. X..X. X.... X...X",
"X...X XXXX. .XXX. XXXX. XXXXX X.... .XXXX X...X .XXX. .XX.. X...X XXXXX X...X",
]],画面の英数字と記号も、本作で描いた5 × 7ドットの文字です。1文字ずつ配列を書く代わりに「文字表」として、同じ高さの点の並びを文字の順に横へ並べています。1文字は5列で、文字どうしは空白1列で区切ります。続けて N〜Z、小文字、数字(× と ♪ を含む)、記号の表があります。上から7行目の下がベースラインで、g・j・p・q・y の下に伸びる部分だけが8・9行目にはみ出します。
const GLYPH_W = 5, GLYPH_H = 7, GLYPH_ADVANCE = 6; // 1 文字の幅・ベースラインより上の高さ・次の文字までの間隔(ドット数)
// 文字 → 横に続く点をまとめた長方形 [x, y, 幅] の一覧。描くときは長方形 1 つにつき 1 回で済む。
const GLYPHS = new Map([[" ", []]]);
for (const [chars, rows] of FONT_SHEETS) {
[...chars].forEach((ch, i) => {
const runs = [];
rows.forEach((row, y) => {
const bits = row.slice(i * (GLYPH_W + 1), i * (GLYPH_W + 1) + GLYPH_W);
for (let x = 0; x < GLYPH_W; x++) {
if (bits[x] !== "X") continue;
let w = 1;
while (bits[x + w] === "X") w++;
runs.push([x, y, w]);
x += w - 1;
}
});
GLYPHS.set(ch, runs);
});
}起動時に文字表を1文字ずつ切り出し、GLYPHS に「文字 → 長方形の一覧」として登録します。横に続く X は1つの長方形 [x, y, 幅] にまとめるので、例えば「E」は点が18個あっても長方形は7つで済みます。実際に描く処理は「04 Canvas の座標と描画」の drawTextOn() です。