Add procedural pixel-art sprite engine
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
/* ============================================================
|
||||
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 };
|
||||
})();
|
||||
Reference in New Issue
Block a user