feat: Implement pixel-art rendering with new level loading, tile maps, palettes, and pixel fonts, alongside a game over screen.

This commit is contained in:
Juan Sebastián Montoya 2026-01-06 17:21:15 -05:00
parent 5b15e63ac3
commit cf04677511
41 changed files with 793 additions and 331 deletions

80
src/core/PixelFont.js Normal file
View file

@ -0,0 +1,80 @@
/**
* Simple 5x7 Matrix Pixel Font
* Each character is a 5x7 bitmask
*/
const FONT_DATA = {
'A': [0x0E, 0x11, 0x11, 0x1F, 0x11, 0x11, 0x11],
'B': [0x1E, 0x11, 0x11, 0x1E, 0x11, 0x11, 0x1E],
'C': [0x0E, 0x11, 0x11, 0x10, 0x11, 0x11, 0x0E],
'D': [0x1E, 0x11, 0x11, 0x11, 0x11, 0x11, 0x1E],
'E': [0x1F, 0x10, 0x10, 0x1E, 0x10, 0x10, 0x1F],
'F': [0x1F, 0x10, 0x10, 0x1E, 0x10, 0x10, 0x10],
'G': [0x0F, 0x10, 0x10, 0x17, 0x11, 0x11, 0x0F],
'H': [0x11, 0x11, 0x11, 0x1F, 0x11, 0x11, 0x11],
'I': [0x0E, 0x04, 0x04, 0x04, 0x04, 0x04, 0x0E],
'J': [0x07, 0x02, 0x02, 0x02, 0x02, 0x12, 0x0C],
'K': [0x11, 0x12, 0x14, 0x18, 0x14, 0x12, 0x11],
'L': [0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1F],
'M': [0x11, 0x1B, 0x15, 0x15, 0x11, 0x11, 0x11],
'N': [0x11, 0x11, 0x19, 0x15, 0x13, 0x11, 0x11],
'O': [0x0E, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0E],
'P': [0x1E, 0x11, 0x11, 0x1E, 0x10, 0x10, 0x10],
'Q': [0x0E, 0x11, 0x11, 0x11, 0x15, 0x12, 0x0D],
'R': [0x1E, 0x11, 0x11, 0x1E, 0x14, 0x12, 0x11],
'S': [0x0E, 0x11, 0x10, 0x0E, 0x01, 0x11, 0x0E],
'T': [0x1F, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04],
'U': [0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0E],
'V': [0x11, 0x11, 0x11, 0x11, 0x11, 0x0A, 0x04],
'W': [0x11, 0x11, 0x11, 0x15, 0x15, 0x1B, 0x11],
'X': [0x11, 0x11, 0x0A, 0x04, 0x0A, 0x11, 0x11],
'Y': [0x11, 0x11, 0x0A, 0x04, 0x04, 0x04, 0x04],
'Z': [0x1F, 0x01, 0x02, 0x04, 0x08, 0x10, 0x1F],
'0': [0x0E, 0x11, 0x13, 0x15, 0x19, 0x11, 0x0E],
'1': [0x04, 0x0C, 0x04, 0x04, 0x04, 0x04, 0x0E],
'2': [0x0E, 0x11, 0x01, 0x02, 0x04, 0x08, 0x1F],
'3': [0x1F, 0x02, 0x04, 0x02, 0x01, 0x11, 0x0E],
'4': [0x02, 0x06, 0x0A, 0x12, 0x1F, 0x02, 0x02],
'5': [0x1F, 0x10, 0x1E, 0x01, 0x01, 0x11, 0x0E],
'6': [0x06, 0x08, 0x10, 0x1E, 0x11, 0x11, 0x0E],
'7': [0x1F, 0x01, 0x02, 0x04, 0x08, 0x08, 0x08],
'8': [0x0E, 0x11, 0x11, 0x0E, 0x11, 0x11, 0x0E],
'9': [0x0E, 0x11, 0x11, 0x0F, 0x01, 0x02, 0x0C],
':': [0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00],
'.': [0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00],
',': [0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x08],
'!': [0x04, 0x04, 0x04, 0x04, 0x04, 0x00, 0x04],
'?': [0x0E, 0x11, 0x01, 0x02, 0x04, 0x00, 0x04],
'+': [0x00, 0x04, 0x04, 0x1F, 0x04, 0x04, 0x00],
'-': [0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00],
'/': [0x01, 0x02, 0x04, 0x08, 0x10, 0x10, 0x10],
'(': [0x02, 0x04, 0x04, 0x04, 0x04, 0x04, 0x02],
')': [0x08, 0x04, 0x04, 0x04, 0x04, 0x04, 0x08],
' ': [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
'|': [0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04]
};
export const PixelFont = {
drawText(ctx, text, x, y, color = '#ffffff', scale = 1) {
ctx.save();
ctx.fillStyle = color;
let cursorX = x;
const chars = text.toUpperCase().split('');
chars.forEach(char => {
const glyph = FONT_DATA[char] || FONT_DATA['?'];
for (let row = 0; row < 7; row++) {
for (let col = 0; col < 5; col++) {
if ((glyph[row] >> (4 - col)) & 1) {
ctx.fillRect(cursorX + col * scale, y + row * scale, scale, scale);
}
}
}
cursorX += 6 * scale; // 5 width + 1 spacing
});
ctx.restore();
},
getTextWidth(text, scale = 1) {
return text.length * 6 * scale;
}
};