mirror of
https://github.com/NohamR/Pocket-Bird.git
synced 2026-05-25 12:17:22 +00:00
Add hat placeholder
This commit is contained in:
@@ -78,6 +78,7 @@ const WINDOW_PIXEL_SIZE = CANVAS_PIXEL_SIZE * BIRB_CSS_SCALE;
|
||||
const STYLESHEET = `___STYLESHEET___`;
|
||||
const SPRITE_SHEET = "__SPRITE_SHEET__";
|
||||
const FEATHER_SPRITE_SHEET = "__FEATHER_SPRITE_SHEET__";
|
||||
const HATS_SPRITE_SHEET = "__HATS_SPRITE_SHEET__";
|
||||
|
||||
// Element IDs
|
||||
const FIELD_GUIDE_ID = "birb-field-guide";
|
||||
@@ -123,17 +124,20 @@ export async function initializeApplication(context) {
|
||||
log("Loading sprite sheets...");
|
||||
const birbPixels = await loadSpriteSheetPixels(SPRITE_SHEET);
|
||||
const featherPixels = await loadSpriteSheetPixels(FEATHER_SPRITE_SHEET);
|
||||
startApplication(birbPixels, featherPixels);
|
||||
const hatsPixels = await loadSpriteSheetPixels(HATS_SPRITE_SHEET);
|
||||
startApplication(birbPixels, featherPixels, hatsPixels);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string[][]} birbPixels
|
||||
* @param {string[][]} featherPixels
|
||||
* @param {string[][]} hatsPixels
|
||||
*/
|
||||
function startApplication(birbPixels, featherPixels) {
|
||||
function startApplication(birbPixels, featherPixels, hatsPixels) {
|
||||
|
||||
const SPRITE_SHEET = birbPixels;
|
||||
const FEATHER_SPRITE_SHEET = featherPixels;
|
||||
const HATS_SPRITE_SHEET = hatsPixels;
|
||||
|
||||
const featherLayers = {
|
||||
feather: new Layer(getLayerPixels(FEATHER_SPRITE_SHEET, 0, FEATHER_SPRITE_WIDTH)),
|
||||
@@ -321,7 +325,7 @@ function startApplication(birbPixels, featherPixels) {
|
||||
styleElement.textContent = STYLESHEET;
|
||||
document.head.appendChild(styleElement);
|
||||
|
||||
birb = new Birb(BIRB_CSS_SCALE, CANVAS_PIXEL_SIZE, SPRITE_SHEET, SPRITE_WIDTH, SPRITE_HEIGHT);
|
||||
birb = new Birb(BIRB_CSS_SCALE, CANVAS_PIXEL_SIZE, SPRITE_SHEET, SPRITE_WIDTH, SPRITE_HEIGHT, HATS_SPRITE_SHEET);
|
||||
birb.setAnimation(Animations.BOB);
|
||||
|
||||
window.addEventListener("scroll", () => {
|
||||
@@ -1021,8 +1025,9 @@ function loadSpriteSheetPixels(dataUri, templateColors = true) {
|
||||
continue;
|
||||
}
|
||||
if (SPRITE_SHEET_COLOR_MAP[hex] === undefined) {
|
||||
error(`Unknown color: ${hex}`);
|
||||
row.push(PALETTE.TRANSPARENT);
|
||||
// Return the color as-is if not found in the map
|
||||
row.push(hex);
|
||||
continue;
|
||||
}
|
||||
row.push(SPRITE_SHEET_COLOR_MAP[hex]);
|
||||
}
|
||||
|
||||
85
src/birb.js
85
src/birb.js
@@ -2,7 +2,7 @@ import { Directions, getLayerPixels, getWindowHeight, getFixedWindowHeight } fro
|
||||
import Layer from './animation/layer.js';
|
||||
import Frame from './animation/frame.js';
|
||||
import Anim from './animation/anim.js';
|
||||
import { BirdType } from './animation/sprites.js';
|
||||
import { BirdType, PALETTE } from './animation/sprites.js';
|
||||
|
||||
/**
|
||||
* @typedef {keyof typeof Animations} AnimationType
|
||||
@@ -31,8 +31,9 @@ export class Birb {
|
||||
* @param {string[][]} spriteSheet The loaded sprite sheet pixel data
|
||||
* @param {number} spriteWidth
|
||||
* @param {number} spriteHeight
|
||||
* @param {string[][]} hatSpriteSheet The loaded hat sprite sheet pixel data
|
||||
*/
|
||||
constructor(birbCssScale, canvasPixelSize, spriteSheet, spriteWidth, spriteHeight) {
|
||||
constructor(birbCssScale, canvasPixelSize, spriteSheet, spriteWidth, spriteHeight, hatSpriteSheet) {
|
||||
this.birbCssScale = birbCssScale;
|
||||
this.canvasPixelSize = canvasPixelSize;
|
||||
this.windowPixelSize = canvasPixelSize * birbCssScale;
|
||||
@@ -53,12 +54,16 @@ export class Birb {
|
||||
happyEye: new Layer(getLayerPixels(spriteSheet, 9, this.spriteWidth)),
|
||||
};
|
||||
|
||||
// Build hat layers
|
||||
const hatLayer = this.buildHatLayer(hatSpriteSheet, "top-hat", false);
|
||||
const downHatLayer = this.buildHatLayer(hatSpriteSheet, "top-hat", false, 1);
|
||||
|
||||
// Build frames from layers
|
||||
this.frames = {
|
||||
base: new Frame([this.layers.base, this.layers.tuftBase]),
|
||||
headDown: new Frame([this.layers.down, this.layers.tuftDown]),
|
||||
wingsDown: new Frame([this.layers.base, this.layers.tuftBase, this.layers.wingsDown]),
|
||||
wingsUp: new Frame([this.layers.down, this.layers.tuftDown, this.layers.wingsUp]),
|
||||
base: new Frame([this.layers.base, this.layers.tuftBase, hatLayer]),
|
||||
headDown: new Frame([this.layers.down, this.layers.tuftDown, downHatLayer]),
|
||||
wingsDown: new Frame([this.layers.base, this.layers.tuftBase, this.layers.wingsDown, hatLayer]),
|
||||
wingsUp: new Frame([this.layers.down, this.layers.tuftDown, this.layers.wingsUp, downHatLayer]),
|
||||
heartOne: new Frame([this.layers.base, this.layers.tuftBase, this.layers.happyEye, this.layers.heartOne]),
|
||||
heartTwo: new Frame([this.layers.base, this.layers.tuftBase, this.layers.happyEye, this.layers.heartTwo]),
|
||||
heartThree: new Frame([this.layers.base, this.layers.tuftBase, this.layers.happyEye, this.layers.heartThree]),
|
||||
@@ -129,6 +134,74 @@ export class Birb {
|
||||
return anim.draw(this.ctx, this.direction, this.animStart, this.canvasPixelSize, species);
|
||||
}
|
||||
|
||||
buildHatLayer(spriteSheet, hatName, outlineBottom = false, yOffset = 0) {
|
||||
const LEFT_PADDING = 6;
|
||||
const RIGHT_PADDING = 14;
|
||||
const TOP_PADDING = 4 + yOffset;
|
||||
const BOTTOM_PADDING = Math.max(0, 16 - yOffset);
|
||||
|
||||
const hatPixels = getLayerPixels(spriteSheet, 0, 12);
|
||||
const paddedHatPixels = [];
|
||||
|
||||
// Top padding
|
||||
for (let y = 0; y < TOP_PADDING; y++) {
|
||||
paddedHatPixels.push(Array(hatPixels[0].length + LEFT_PADDING + RIGHT_PADDING)
|
||||
.fill(PALETTE.TRANSPARENT)
|
||||
);
|
||||
}
|
||||
// Left and right padding
|
||||
for (let y = 0; y < hatPixels.length; y++) {
|
||||
const row = [];
|
||||
for (let x = 0; x < LEFT_PADDING; x++) {
|
||||
row.push(PALETTE.TRANSPARENT);
|
||||
}
|
||||
|
||||
for (let x = 0; x < hatPixels[y].length; x++) {
|
||||
row.push(hatPixels[y][x]);
|
||||
}
|
||||
|
||||
for (let x = 0; x < RIGHT_PADDING; x++) {
|
||||
row.push(PALETTE.TRANSPARENT);
|
||||
}
|
||||
|
||||
paddedHatPixels.push(row);
|
||||
}
|
||||
// Bottom padding
|
||||
for (let y = 0; y < BOTTOM_PADDING; y++) {
|
||||
paddedHatPixels.push(Array(hatPixels[0].length + LEFT_PADDING + RIGHT_PADDING)
|
||||
.fill(PALETTE.TRANSPARENT)
|
||||
);
|
||||
}
|
||||
|
||||
// Add outline
|
||||
let neighborOffsets = [
|
||||
[-1, 0],
|
||||
[1, 0],
|
||||
[0, -1],
|
||||
[-1, -1],
|
||||
[1, -1],
|
||||
];
|
||||
if (outlineBottom) {
|
||||
neighborOffsets.push([0, 1], [-1, 1], [1, 1]);
|
||||
}
|
||||
for (let y = 0; y < paddedHatPixels.length; y++) {
|
||||
for (let x = 0; x < paddedHatPixels[y].length; x++) {
|
||||
const pixel = paddedHatPixels[y][x];
|
||||
if (pixel !== PALETTE.TRANSPARENT && pixel !== PALETTE.BORDER) {
|
||||
for (let [dx, dy] of neighborOffsets) {
|
||||
const newX = x + dx;
|
||||
const newY = y + dy;
|
||||
if (newY >= 0 && newY < paddedHatPixels.length && newX >= 0 && newX < paddedHatPixels[newY].length && paddedHatPixels[newY][newX] === PALETTE.TRANSPARENT) {
|
||||
paddedHatPixels[newY][newX] = PALETTE.BORDER;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return new Layer(paddedHatPixels);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @returns {AnimationType} The current animation key
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user