/* ============================================================ DSP ARCADE — procedural pixel-art sprites ============================================================ */ (function () { 'use strict'; const cache = {}; function makeSprite(map, palette, scale = 1) { const h = map.length; const w = Math.max(...map.map(r => r.length)); const cv = document.createElement('canvas'); cv.width = w; cv.height = h; const ctx = cv.getContext('2d'); for (let y = 0; y < h; y++) { for (let x = 0; x < map[y].length; x++) { const c = map[y][x]; if (c === '.' || c === ' ') continue; ctx.fillStyle = palette[c] || '#fff'; ctx.fillRect(x, y, 1, 1); } } if (scale > 1) { const big = document.createElement('canvas'); big.width = w * scale; big.height = h * scale; const bctx = big.getContext('2d'); bctx.imageSmoothingEnabled = false; bctx.drawImage(cv, 0, 0, w * scale, h * scale); return big; } return cv; } function sprite(map, palette, scale = 1, key) { const k = key || JSON.stringify([map, palette, scale]); if (!cache[k]) cache[k] = makeSprite(map, palette, scale); return cache[k]; } function draw(ctx, img, x, y) { ctx.drawImage(img, Math.round(x - img.width / 2), Math.round(y - img.height / 2)); } const SPRITES = { ship: { map: ['...W...','..WWW..','..WWW..','.WWWWWW','WWWWWWWW','W.W..W.W'], palette: { W: '#e8f4ff' }, }, shipAlt: { map: ['...C...','..CCC..','..CCC..','.CCCCCC','CCCCCCCC','C.C..C.C'], palette: { C: '#7df9ff' }, }, invader1: { map: ['..X...X..','...X.X...','..XXXXX..','.XX.X.XX.','XXXXXXXXX','X.XXXXX.X','X.X...X.X','...X.X...'], palette: { X: '#7dff5e' }, }, invader2: { map: ['...X.X...','..XXXXX..','.XXXXXXX.','XX.XXX.XX','XXXXXXXXX','..X...X..','.X.X.X.X.','X..X.X..X'], palette: { X: '#ff7de9' }, }, invader3: { map: ['..X...X..','.XXXXXXX.','XXXXXXXXX','XXX.X.XXX','XXXXXXXXX','.X.....X.','X..X.X..X','.X.....X.'], palette: { X: '#ffe14d' }, }, ufo: { map: ['...GGGG...','..GGGGGG..','.GGGGGGGG.','GGGRRRRGGG','GGGGGGGGGG','.G.G..G.G.'], palette: { G: '#9d7dff', R: '#ff4d6d' }, }, heart: { map: ['.XX.XX.','XXXXXXX','XXXXXXX','.XXXXX.','..XXX..','...X...'], palette: { X: '#ff2d95' }, }, heartEmpty: { map: ['.XX.XX.','X.....X','X.....X','.X...X.','..X.X..','...X...'], palette: { X: '#5a2a5a' }, }, star: { map: ['...X...','...X...','XXXXXXX','...X...','...X...'], palette: { X: '#ffffff' }, }, pellet: { map: ['XX','XX'], palette: { X: '#ffe14d' }, }, bonusCell: { map: ['.XXX.','X...X','X.X.X','X...X','.XXX.'], palette: { X: '#ff9d2d' }, }, ghostCell: { map: ['.XXX.','X...X','X.X.X','X...X','.XXX.'], palette: { X: '#7df9ff' }, }, }; function get(name, scale = 1) { const s = SPRITES[name]; return sprite(s.map, s.palette, scale, name + '_' + scale); } window.DSP_SPRITES = { get, sprite, draw, SPRITES }; })();