Control hat type from application

This commit is contained in:
Idrees Hassan
2026-01-18 19:24:17 -05:00
parent 7c38bf9164
commit e09d4f9eea
11 changed files with 116 additions and 91 deletions

BIN
dist/extension.zip vendored

Binary file not shown.

View File

@@ -499,20 +499,21 @@
/** /**
* @param {CanvasRenderingContext2D} ctx * @param {CanvasRenderingContext2D} ctx
* @param {BirdType} [species] * @param {number} direction
* @param {number} direction
* @param {number} canvasPixelSize * @param {number} canvasPixelSize
* @param {{ [key: string]: string }} colorScheme
* @param {string[]} tags
*/ */
draw(ctx, direction, canvasPixelSize, species) { draw(ctx, direction, canvasPixelSize, colorScheme, tags) {
// Clear the canvas before drawing the new frame // Clear the canvas before drawing the new frame
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
const pixels = this.getPixels(species?.tags[0]); const pixels = this.getPixels(tags[0]);
for (let y = 0; y < pixels.length; y++) { for (let y = 0; y < pixels.length; y++) {
const row = pixels[y]; const row = pixels[y];
for (let x = 0; x < pixels[y].length; x++) { for (let x = 0; x < pixels[y].length; x++) {
const cell = direction === Directions.LEFT ? row[x] : row[pixels[y].length - x - 1]; const cell = direction === Directions.LEFT ? row[x] : row[pixels[y].length - x - 1];
ctx.fillStyle = species?.colors[cell] ?? cell; ctx.fillStyle = colorScheme[cell] ?? cell;
ctx.fillRect(x * canvasPixelSize, y * canvasPixelSize, canvasPixelSize, canvasPixelSize); ctx.fillRect(x * canvasPixelSize, y * canvasPixelSize, canvasPixelSize, canvasPixelSize);
} } } } } }
} }
@@ -575,10 +576,11 @@
* @param {number} direction * @param {number} direction
* @param {number} timeStart The start time of the animation in milliseconds * @param {number} timeStart The start time of the animation in milliseconds
* @param {number} canvasPixelSize The size of a canvas pixel in pixels * @param {number} canvasPixelSize The size of a canvas pixel in pixels
* @param {BirdType} [species] The species to use for the animation * @param {{ [key: string]: string }} colorScheme The color scheme to use for the animation
* @param {string[]} tags The tags to use for the animation
* @returns {boolean} Whether the animation is complete * @returns {boolean} Whether the animation is complete
*/ */
draw(ctx, direction, timeStart, canvasPixelSize, species) { draw(ctx, direction, timeStart, canvasPixelSize, colorScheme, tags) {
// Reset cache if animation was restarted // Reset cache if animation was restarted
if (this.lastTimeStart !== timeStart) { if (this.lastTimeStart !== timeStart) {
this.#clearCache(); this.#clearCache();
@@ -595,7 +597,7 @@
const currentFrameIndex = this.getCurrentFrameIndex(time); const currentFrameIndex = this.getCurrentFrameIndex(time);
if (this.#shouldRedraw(currentFrameIndex, direction)) { if (this.#shouldRedraw(currentFrameIndex, direction)) {
this.frames[currentFrameIndex].draw(ctx, direction, canvasPixelSize, species); this.frames[currentFrameIndex].draw(ctx, direction, canvasPixelSize, colorScheme, tags);
this.lastFrameIndex = currentFrameIndex; this.lastFrameIndex = currentFrameIndex;
this.lastDirection = direction; this.lastDirection = direction;
} }
@@ -699,7 +701,7 @@
} }
} }
} }
return new Layer(paddedHatPixels); return new Layer(paddedHatPixels, hatName);
} }
/** /**
@@ -823,12 +825,13 @@
/** /**
* Draw the current animation frame * Draw the current animation frame
* @param {BirdType} species The species color data * @param {BirdType} species The species data
* @param {string} [hat] The name of the current hat
* @returns {boolean} Whether the animation has completed (for non-looping animations) * @returns {boolean} Whether the animation has completed (for non-looping animations)
*/ */
draw(species) { draw(species, hat) {
const anim = this.animations[this.currentAnimation]; const anim = this.animations[this.currentAnimation];
return anim.draw(this.ctx, this.direction, this.animStart, this.canvasPixelSize, species); return anim.draw(this.ctx, this.direction, this.animStart, this.canvasPixelSize, species.colors, [...species.tags, hat || '']);
} }
@@ -2023,6 +2026,7 @@
let petStack = []; let petStack = [];
let currentSpecies = DEFAULT_BIRD; let currentSpecies = DEFAULT_BIRD;
let unlockedSpecies = [DEFAULT_BIRD]; let unlockedSpecies = [DEFAULT_BIRD];
let currentHat = HAT.TOP_HAT;
// let visible = true; // let visible = true;
let lastPetTimestamp = 0; let lastPetTimestamp = 0;
/** @type {StickyNote[]} */ /** @type {StickyNote[]} */
@@ -2243,7 +2247,7 @@
flySomewhere(); flySomewhere();
} }
if (birb.draw(SPECIES[currentSpecies])) { if (birb.draw(SPECIES[currentSpecies], currentHat)) {
birb.setAnimation(Animations.STILL); birb.setAnimation(Animations.STILL);
} }
@@ -2332,7 +2336,7 @@
if (!featherCtx) { if (!featherCtx) {
return; return;
} }
FEATHER_ANIMATIONS.feather.draw(featherCtx, Directions.LEFT, Date.now(), CANVAS_PIXEL_SIZE, type); FEATHER_ANIMATIONS.feather.draw(featherCtx, Directions.LEFT, Date.now(), CANVAS_PIXEL_SIZE, type.colors, type.tags);
document.body.appendChild(featherCanvas); document.body.appendChild(featherCanvas);
onClick(featherCanvas, () => { onClick(featherCanvas, () => {
unlockBird(birdType); unlockBird(birdType);
@@ -2478,7 +2482,7 @@
if (!speciesCtx) { if (!speciesCtx) {
return; return;
} }
birb.getFrames().base.draw(speciesCtx, Directions.RIGHT, CANVAS_PIXEL_SIZE, type); birb.getFrames().base.draw(speciesCtx, Directions.RIGHT, CANVAS_PIXEL_SIZE, type.colors, type.tags);
speciesElement.appendChild(speciesCanvas); speciesElement.appendChild(speciesCanvas);
content.appendChild(speciesElement); content.appendChild(speciesElement);
if (unlocked) { if (unlocked) {

34
dist/obsidian/main.js vendored
View File

@@ -504,20 +504,21 @@ module.exports = class PocketBird extends Plugin {
/** /**
* @param {CanvasRenderingContext2D} ctx * @param {CanvasRenderingContext2D} ctx
* @param {BirdType} [species] * @param {number} direction
* @param {number} direction
* @param {number} canvasPixelSize * @param {number} canvasPixelSize
* @param {{ [key: string]: string }} colorScheme
* @param {string[]} tags
*/ */
draw(ctx, direction, canvasPixelSize, species) { draw(ctx, direction, canvasPixelSize, colorScheme, tags) {
// Clear the canvas before drawing the new frame // Clear the canvas before drawing the new frame
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
const pixels = this.getPixels(species?.tags[0]); const pixels = this.getPixels(tags[0]);
for (let y = 0; y < pixels.length; y++) { for (let y = 0; y < pixels.length; y++) {
const row = pixels[y]; const row = pixels[y];
for (let x = 0; x < pixels[y].length; x++) { for (let x = 0; x < pixels[y].length; x++) {
const cell = direction === Directions.LEFT ? row[x] : row[pixels[y].length - x - 1]; const cell = direction === Directions.LEFT ? row[x] : row[pixels[y].length - x - 1];
ctx.fillStyle = species?.colors[cell] ?? cell; ctx.fillStyle = colorScheme[cell] ?? cell;
ctx.fillRect(x * canvasPixelSize, y * canvasPixelSize, canvasPixelSize, canvasPixelSize); ctx.fillRect(x * canvasPixelSize, y * canvasPixelSize, canvasPixelSize, canvasPixelSize);
} } } } } }
} }
@@ -580,10 +581,11 @@ module.exports = class PocketBird extends Plugin {
* @param {number} direction * @param {number} direction
* @param {number} timeStart The start time of the animation in milliseconds * @param {number} timeStart The start time of the animation in milliseconds
* @param {number} canvasPixelSize The size of a canvas pixel in pixels * @param {number} canvasPixelSize The size of a canvas pixel in pixels
* @param {BirdType} [species] The species to use for the animation * @param {{ [key: string]: string }} colorScheme The color scheme to use for the animation
* @param {string[]} tags The tags to use for the animation
* @returns {boolean} Whether the animation is complete * @returns {boolean} Whether the animation is complete
*/ */
draw(ctx, direction, timeStart, canvasPixelSize, species) { draw(ctx, direction, timeStart, canvasPixelSize, colorScheme, tags) {
// Reset cache if animation was restarted // Reset cache if animation was restarted
if (this.lastTimeStart !== timeStart) { if (this.lastTimeStart !== timeStart) {
this.#clearCache(); this.#clearCache();
@@ -600,7 +602,7 @@ module.exports = class PocketBird extends Plugin {
const currentFrameIndex = this.getCurrentFrameIndex(time); const currentFrameIndex = this.getCurrentFrameIndex(time);
if (this.#shouldRedraw(currentFrameIndex, direction)) { if (this.#shouldRedraw(currentFrameIndex, direction)) {
this.frames[currentFrameIndex].draw(ctx, direction, canvasPixelSize, species); this.frames[currentFrameIndex].draw(ctx, direction, canvasPixelSize, colorScheme, tags);
this.lastFrameIndex = currentFrameIndex; this.lastFrameIndex = currentFrameIndex;
this.lastDirection = direction; this.lastDirection = direction;
} }
@@ -704,7 +706,7 @@ module.exports = class PocketBird extends Plugin {
} }
} }
} }
return new Layer(paddedHatPixels); return new Layer(paddedHatPixels, hatName);
} }
/** /**
@@ -828,12 +830,13 @@ module.exports = class PocketBird extends Plugin {
/** /**
* Draw the current animation frame * Draw the current animation frame
* @param {BirdType} species The species color data * @param {BirdType} species The species data
* @param {string} [hat] The name of the current hat
* @returns {boolean} Whether the animation has completed (for non-looping animations) * @returns {boolean} Whether the animation has completed (for non-looping animations)
*/ */
draw(species) { draw(species, hat) {
const anim = this.animations[this.currentAnimation]; const anim = this.animations[this.currentAnimation];
return anim.draw(this.ctx, this.direction, this.animStart, this.canvasPixelSize, species); return anim.draw(this.ctx, this.direction, this.animStart, this.canvasPixelSize, species.colors, [...species.tags, hat || '']);
} }
@@ -2066,6 +2069,7 @@ module.exports = class PocketBird extends Plugin {
let petStack = []; let petStack = [];
let currentSpecies = DEFAULT_BIRD; let currentSpecies = DEFAULT_BIRD;
let unlockedSpecies = [DEFAULT_BIRD]; let unlockedSpecies = [DEFAULT_BIRD];
let currentHat = HAT.TOP_HAT;
// let visible = true; // let visible = true;
let lastPetTimestamp = 0; let lastPetTimestamp = 0;
/** @type {StickyNote[]} */ /** @type {StickyNote[]} */
@@ -2286,7 +2290,7 @@ module.exports = class PocketBird extends Plugin {
flySomewhere(); flySomewhere();
} }
if (birb.draw(SPECIES[currentSpecies])) { if (birb.draw(SPECIES[currentSpecies], currentHat)) {
birb.setAnimation(Animations.STILL); birb.setAnimation(Animations.STILL);
} }
@@ -2375,7 +2379,7 @@ module.exports = class PocketBird extends Plugin {
if (!featherCtx) { if (!featherCtx) {
return; return;
} }
FEATHER_ANIMATIONS.feather.draw(featherCtx, Directions.LEFT, Date.now(), CANVAS_PIXEL_SIZE, type); FEATHER_ANIMATIONS.feather.draw(featherCtx, Directions.LEFT, Date.now(), CANVAS_PIXEL_SIZE, type.colors, type.tags);
document.body.appendChild(featherCanvas); document.body.appendChild(featherCanvas);
onClick(featherCanvas, () => { onClick(featherCanvas, () => {
unlockBird(birdType); unlockBird(birdType);
@@ -2521,7 +2525,7 @@ module.exports = class PocketBird extends Plugin {
if (!speciesCtx) { if (!speciesCtx) {
return; return;
} }
birb.getFrames().base.draw(speciesCtx, Directions.RIGHT, CANVAS_PIXEL_SIZE, type); birb.getFrames().base.draw(speciesCtx, Directions.RIGHT, CANVAS_PIXEL_SIZE, type.colors, type.tags);
speciesElement.appendChild(speciesCanvas); speciesElement.appendChild(speciesCanvas);
content.appendChild(speciesElement); content.appendChild(speciesElement);
if (unlocked) { if (unlocked) {

View File

@@ -513,20 +513,21 @@
/** /**
* @param {CanvasRenderingContext2D} ctx * @param {CanvasRenderingContext2D} ctx
* @param {BirdType} [species] * @param {number} direction
* @param {number} direction
* @param {number} canvasPixelSize * @param {number} canvasPixelSize
* @param {{ [key: string]: string }} colorScheme
* @param {string[]} tags
*/ */
draw(ctx, direction, canvasPixelSize, species) { draw(ctx, direction, canvasPixelSize, colorScheme, tags) {
// Clear the canvas before drawing the new frame // Clear the canvas before drawing the new frame
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
const pixels = this.getPixels(species?.tags[0]); const pixels = this.getPixels(tags[0]);
for (let y = 0; y < pixels.length; y++) { for (let y = 0; y < pixels.length; y++) {
const row = pixels[y]; const row = pixels[y];
for (let x = 0; x < pixels[y].length; x++) { for (let x = 0; x < pixels[y].length; x++) {
const cell = direction === Directions.LEFT ? row[x] : row[pixels[y].length - x - 1]; const cell = direction === Directions.LEFT ? row[x] : row[pixels[y].length - x - 1];
ctx.fillStyle = species?.colors[cell] ?? cell; ctx.fillStyle = colorScheme[cell] ?? cell;
ctx.fillRect(x * canvasPixelSize, y * canvasPixelSize, canvasPixelSize, canvasPixelSize); ctx.fillRect(x * canvasPixelSize, y * canvasPixelSize, canvasPixelSize, canvasPixelSize);
} } } } } }
} }
@@ -589,10 +590,11 @@
* @param {number} direction * @param {number} direction
* @param {number} timeStart The start time of the animation in milliseconds * @param {number} timeStart The start time of the animation in milliseconds
* @param {number} canvasPixelSize The size of a canvas pixel in pixels * @param {number} canvasPixelSize The size of a canvas pixel in pixels
* @param {BirdType} [species] The species to use for the animation * @param {{ [key: string]: string }} colorScheme The color scheme to use for the animation
* @param {string[]} tags The tags to use for the animation
* @returns {boolean} Whether the animation is complete * @returns {boolean} Whether the animation is complete
*/ */
draw(ctx, direction, timeStart, canvasPixelSize, species) { draw(ctx, direction, timeStart, canvasPixelSize, colorScheme, tags) {
// Reset cache if animation was restarted // Reset cache if animation was restarted
if (this.lastTimeStart !== timeStart) { if (this.lastTimeStart !== timeStart) {
this.#clearCache(); this.#clearCache();
@@ -609,7 +611,7 @@
const currentFrameIndex = this.getCurrentFrameIndex(time); const currentFrameIndex = this.getCurrentFrameIndex(time);
if (this.#shouldRedraw(currentFrameIndex, direction)) { if (this.#shouldRedraw(currentFrameIndex, direction)) {
this.frames[currentFrameIndex].draw(ctx, direction, canvasPixelSize, species); this.frames[currentFrameIndex].draw(ctx, direction, canvasPixelSize, colorScheme, tags);
this.lastFrameIndex = currentFrameIndex; this.lastFrameIndex = currentFrameIndex;
this.lastDirection = direction; this.lastDirection = direction;
} }
@@ -713,7 +715,7 @@
} }
} }
} }
return new Layer(paddedHatPixels); return new Layer(paddedHatPixels, hatName);
} }
/** /**
@@ -837,12 +839,13 @@
/** /**
* Draw the current animation frame * Draw the current animation frame
* @param {BirdType} species The species color data * @param {BirdType} species The species data
* @param {string} [hat] The name of the current hat
* @returns {boolean} Whether the animation has completed (for non-looping animations) * @returns {boolean} Whether the animation has completed (for non-looping animations)
*/ */
draw(species) { draw(species, hat) {
const anim = this.animations[this.currentAnimation]; const anim = this.animations[this.currentAnimation];
return anim.draw(this.ctx, this.direction, this.animStart, this.canvasPixelSize, species); return anim.draw(this.ctx, this.direction, this.animStart, this.canvasPixelSize, species.colors, [...species.tags, hat || '']);
} }
@@ -2028,6 +2031,7 @@
let petStack = []; let petStack = [];
let currentSpecies = DEFAULT_BIRD; let currentSpecies = DEFAULT_BIRD;
let unlockedSpecies = [DEFAULT_BIRD]; let unlockedSpecies = [DEFAULT_BIRD];
let currentHat = HAT.TOP_HAT;
// let visible = true; // let visible = true;
let lastPetTimestamp = 0; let lastPetTimestamp = 0;
/** @type {StickyNote[]} */ /** @type {StickyNote[]} */
@@ -2248,7 +2252,7 @@
flySomewhere(); flySomewhere();
} }
if (birb.draw(SPECIES[currentSpecies])) { if (birb.draw(SPECIES[currentSpecies], currentHat)) {
birb.setAnimation(Animations.STILL); birb.setAnimation(Animations.STILL);
} }
@@ -2337,7 +2341,7 @@
if (!featherCtx) { if (!featherCtx) {
return; return;
} }
FEATHER_ANIMATIONS.feather.draw(featherCtx, Directions.LEFT, Date.now(), CANVAS_PIXEL_SIZE, type); FEATHER_ANIMATIONS.feather.draw(featherCtx, Directions.LEFT, Date.now(), CANVAS_PIXEL_SIZE, type.colors, type.tags);
document.body.appendChild(featherCanvas); document.body.appendChild(featherCanvas);
onClick(featherCanvas, () => { onClick(featherCanvas, () => {
unlockBird(birdType); unlockBird(birdType);
@@ -2483,7 +2487,7 @@
if (!speciesCtx) { if (!speciesCtx) {
return; return;
} }
birb.getFrames().base.draw(speciesCtx, Directions.RIGHT, CANVAS_PIXEL_SIZE, type); birb.getFrames().base.draw(speciesCtx, Directions.RIGHT, CANVAS_PIXEL_SIZE, type.colors, type.tags);
speciesElement.appendChild(speciesCanvas); speciesElement.appendChild(speciesCanvas);
content.appendChild(speciesElement); content.appendChild(speciesElement);
if (unlocked) { if (unlocked) {

View File

@@ -499,20 +499,21 @@
/** /**
* @param {CanvasRenderingContext2D} ctx * @param {CanvasRenderingContext2D} ctx
* @param {BirdType} [species] * @param {number} direction
* @param {number} direction
* @param {number} canvasPixelSize * @param {number} canvasPixelSize
* @param {{ [key: string]: string }} colorScheme
* @param {string[]} tags
*/ */
draw(ctx, direction, canvasPixelSize, species) { draw(ctx, direction, canvasPixelSize, colorScheme, tags) {
// Clear the canvas before drawing the new frame // Clear the canvas before drawing the new frame
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
const pixels = this.getPixels(species?.tags[0]); const pixels = this.getPixels(tags[0]);
for (let y = 0; y < pixels.length; y++) { for (let y = 0; y < pixels.length; y++) {
const row = pixels[y]; const row = pixels[y];
for (let x = 0; x < pixels[y].length; x++) { for (let x = 0; x < pixels[y].length; x++) {
const cell = direction === Directions.LEFT ? row[x] : row[pixels[y].length - x - 1]; const cell = direction === Directions.LEFT ? row[x] : row[pixels[y].length - x - 1];
ctx.fillStyle = species?.colors[cell] ?? cell; ctx.fillStyle = colorScheme[cell] ?? cell;
ctx.fillRect(x * canvasPixelSize, y * canvasPixelSize, canvasPixelSize, canvasPixelSize); ctx.fillRect(x * canvasPixelSize, y * canvasPixelSize, canvasPixelSize, canvasPixelSize);
} } } } } }
} }
@@ -575,10 +576,11 @@
* @param {number} direction * @param {number} direction
* @param {number} timeStart The start time of the animation in milliseconds * @param {number} timeStart The start time of the animation in milliseconds
* @param {number} canvasPixelSize The size of a canvas pixel in pixels * @param {number} canvasPixelSize The size of a canvas pixel in pixels
* @param {BirdType} [species] The species to use for the animation * @param {{ [key: string]: string }} colorScheme The color scheme to use for the animation
* @param {string[]} tags The tags to use for the animation
* @returns {boolean} Whether the animation is complete * @returns {boolean} Whether the animation is complete
*/ */
draw(ctx, direction, timeStart, canvasPixelSize, species) { draw(ctx, direction, timeStart, canvasPixelSize, colorScheme, tags) {
// Reset cache if animation was restarted // Reset cache if animation was restarted
if (this.lastTimeStart !== timeStart) { if (this.lastTimeStart !== timeStart) {
this.#clearCache(); this.#clearCache();
@@ -595,7 +597,7 @@
const currentFrameIndex = this.getCurrentFrameIndex(time); const currentFrameIndex = this.getCurrentFrameIndex(time);
if (this.#shouldRedraw(currentFrameIndex, direction)) { if (this.#shouldRedraw(currentFrameIndex, direction)) {
this.frames[currentFrameIndex].draw(ctx, direction, canvasPixelSize, species); this.frames[currentFrameIndex].draw(ctx, direction, canvasPixelSize, colorScheme, tags);
this.lastFrameIndex = currentFrameIndex; this.lastFrameIndex = currentFrameIndex;
this.lastDirection = direction; this.lastDirection = direction;
} }
@@ -699,7 +701,7 @@
} }
} }
} }
return new Layer(paddedHatPixels); return new Layer(paddedHatPixels, hatName);
} }
/** /**
@@ -823,12 +825,13 @@
/** /**
* Draw the current animation frame * Draw the current animation frame
* @param {BirdType} species The species color data * @param {BirdType} species The species data
* @param {string} [hat] The name of the current hat
* @returns {boolean} Whether the animation has completed (for non-looping animations) * @returns {boolean} Whether the animation has completed (for non-looping animations)
*/ */
draw(species) { draw(species, hat) {
const anim = this.animations[this.currentAnimation]; const anim = this.animations[this.currentAnimation];
return anim.draw(this.ctx, this.direction, this.animStart, this.canvasPixelSize, species); return anim.draw(this.ctx, this.direction, this.animStart, this.canvasPixelSize, species.colors, [...species.tags, hat || '']);
} }
@@ -2008,6 +2011,7 @@
let petStack = []; let petStack = [];
let currentSpecies = DEFAULT_BIRD; let currentSpecies = DEFAULT_BIRD;
let unlockedSpecies = [DEFAULT_BIRD]; let unlockedSpecies = [DEFAULT_BIRD];
let currentHat = HAT.TOP_HAT;
// let visible = true; // let visible = true;
let lastPetTimestamp = 0; let lastPetTimestamp = 0;
/** @type {StickyNote[]} */ /** @type {StickyNote[]} */
@@ -2228,7 +2232,7 @@
flySomewhere(); flySomewhere();
} }
if (birb.draw(SPECIES[currentSpecies])) { if (birb.draw(SPECIES[currentSpecies], currentHat)) {
birb.setAnimation(Animations.STILL); birb.setAnimation(Animations.STILL);
} }
@@ -2317,7 +2321,7 @@
if (!featherCtx) { if (!featherCtx) {
return; return;
} }
FEATHER_ANIMATIONS.feather.draw(featherCtx, Directions.LEFT, Date.now(), CANVAS_PIXEL_SIZE, type); FEATHER_ANIMATIONS.feather.draw(featherCtx, Directions.LEFT, Date.now(), CANVAS_PIXEL_SIZE, type.colors, type.tags);
document.body.appendChild(featherCanvas); document.body.appendChild(featherCanvas);
onClick(featherCanvas, () => { onClick(featherCanvas, () => {
unlockBird(birdType); unlockBird(birdType);
@@ -2463,7 +2467,7 @@
if (!speciesCtx) { if (!speciesCtx) {
return; return;
} }
birb.getFrames().base.draw(speciesCtx, Directions.RIGHT, CANVAS_PIXEL_SIZE, type); birb.getFrames().base.draw(speciesCtx, Directions.RIGHT, CANVAS_PIXEL_SIZE, type.colors, type.tags);
speciesElement.appendChild(speciesCanvas); speciesElement.appendChild(speciesCanvas);
content.appendChild(speciesElement); content.appendChild(speciesElement);
if (unlocked) { if (unlocked) {

34
dist/web/birb.js vendored
View File

@@ -499,20 +499,21 @@
/** /**
* @param {CanvasRenderingContext2D} ctx * @param {CanvasRenderingContext2D} ctx
* @param {BirdType} [species] * @param {number} direction
* @param {number} direction
* @param {number} canvasPixelSize * @param {number} canvasPixelSize
* @param {{ [key: string]: string }} colorScheme
* @param {string[]} tags
*/ */
draw(ctx, direction, canvasPixelSize, species) { draw(ctx, direction, canvasPixelSize, colorScheme, tags) {
// Clear the canvas before drawing the new frame // Clear the canvas before drawing the new frame
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
const pixels = this.getPixels(species?.tags[0]); const pixels = this.getPixels(tags[0]);
for (let y = 0; y < pixels.length; y++) { for (let y = 0; y < pixels.length; y++) {
const row = pixels[y]; const row = pixels[y];
for (let x = 0; x < pixels[y].length; x++) { for (let x = 0; x < pixels[y].length; x++) {
const cell = direction === Directions.LEFT ? row[x] : row[pixels[y].length - x - 1]; const cell = direction === Directions.LEFT ? row[x] : row[pixels[y].length - x - 1];
ctx.fillStyle = species?.colors[cell] ?? cell; ctx.fillStyle = colorScheme[cell] ?? cell;
ctx.fillRect(x * canvasPixelSize, y * canvasPixelSize, canvasPixelSize, canvasPixelSize); ctx.fillRect(x * canvasPixelSize, y * canvasPixelSize, canvasPixelSize, canvasPixelSize);
} } } } } }
} }
@@ -575,10 +576,11 @@
* @param {number} direction * @param {number} direction
* @param {number} timeStart The start time of the animation in milliseconds * @param {number} timeStart The start time of the animation in milliseconds
* @param {number} canvasPixelSize The size of a canvas pixel in pixels * @param {number} canvasPixelSize The size of a canvas pixel in pixels
* @param {BirdType} [species] The species to use for the animation * @param {{ [key: string]: string }} colorScheme The color scheme to use for the animation
* @param {string[]} tags The tags to use for the animation
* @returns {boolean} Whether the animation is complete * @returns {boolean} Whether the animation is complete
*/ */
draw(ctx, direction, timeStart, canvasPixelSize, species) { draw(ctx, direction, timeStart, canvasPixelSize, colorScheme, tags) {
// Reset cache if animation was restarted // Reset cache if animation was restarted
if (this.lastTimeStart !== timeStart) { if (this.lastTimeStart !== timeStart) {
this.#clearCache(); this.#clearCache();
@@ -595,7 +597,7 @@
const currentFrameIndex = this.getCurrentFrameIndex(time); const currentFrameIndex = this.getCurrentFrameIndex(time);
if (this.#shouldRedraw(currentFrameIndex, direction)) { if (this.#shouldRedraw(currentFrameIndex, direction)) {
this.frames[currentFrameIndex].draw(ctx, direction, canvasPixelSize, species); this.frames[currentFrameIndex].draw(ctx, direction, canvasPixelSize, colorScheme, tags);
this.lastFrameIndex = currentFrameIndex; this.lastFrameIndex = currentFrameIndex;
this.lastDirection = direction; this.lastDirection = direction;
} }
@@ -699,7 +701,7 @@
} }
} }
} }
return new Layer(paddedHatPixels); return new Layer(paddedHatPixels, hatName);
} }
/** /**
@@ -823,12 +825,13 @@
/** /**
* Draw the current animation frame * Draw the current animation frame
* @param {BirdType} species The species color data * @param {BirdType} species The species data
* @param {string} [hat] The name of the current hat
* @returns {boolean} Whether the animation has completed (for non-looping animations) * @returns {boolean} Whether the animation has completed (for non-looping animations)
*/ */
draw(species) { draw(species, hat) {
const anim = this.animations[this.currentAnimation]; const anim = this.animations[this.currentAnimation];
return anim.draw(this.ctx, this.direction, this.animStart, this.canvasPixelSize, species); return anim.draw(this.ctx, this.direction, this.animStart, this.canvasPixelSize, species.colors, [...species.tags, hat || '']);
} }
@@ -2008,6 +2011,7 @@
let petStack = []; let petStack = [];
let currentSpecies = DEFAULT_BIRD; let currentSpecies = DEFAULT_BIRD;
let unlockedSpecies = [DEFAULT_BIRD]; let unlockedSpecies = [DEFAULT_BIRD];
let currentHat = HAT.TOP_HAT;
// let visible = true; // let visible = true;
let lastPetTimestamp = 0; let lastPetTimestamp = 0;
/** @type {StickyNote[]} */ /** @type {StickyNote[]} */
@@ -2228,7 +2232,7 @@
flySomewhere(); flySomewhere();
} }
if (birb.draw(SPECIES[currentSpecies])) { if (birb.draw(SPECIES[currentSpecies], currentHat)) {
birb.setAnimation(Animations.STILL); birb.setAnimation(Animations.STILL);
} }
@@ -2317,7 +2321,7 @@
if (!featherCtx) { if (!featherCtx) {
return; return;
} }
FEATHER_ANIMATIONS.feather.draw(featherCtx, Directions.LEFT, Date.now(), CANVAS_PIXEL_SIZE, type); FEATHER_ANIMATIONS.feather.draw(featherCtx, Directions.LEFT, Date.now(), CANVAS_PIXEL_SIZE, type.colors, type.tags);
document.body.appendChild(featherCanvas); document.body.appendChild(featherCanvas);
onClick(featherCanvas, () => { onClick(featherCanvas, () => {
unlockBird(birdType); unlockBird(birdType);
@@ -2463,7 +2467,7 @@
if (!speciesCtx) { if (!speciesCtx) {
return; return;
} }
birb.getFrames().base.draw(speciesCtx, Directions.RIGHT, CANVAS_PIXEL_SIZE, type); birb.getFrames().base.draw(speciesCtx, Directions.RIGHT, CANVAS_PIXEL_SIZE, type.colors, type.tags);
speciesElement.appendChild(speciesCanvas); speciesElement.appendChild(speciesCanvas);
content.appendChild(speciesElement); content.appendChild(speciesElement);
if (unlocked) { if (unlocked) {

View File

@@ -59,10 +59,11 @@ class Anim {
* @param {number} direction * @param {number} direction
* @param {number} timeStart The start time of the animation in milliseconds * @param {number} timeStart The start time of the animation in milliseconds
* @param {number} canvasPixelSize The size of a canvas pixel in pixels * @param {number} canvasPixelSize The size of a canvas pixel in pixels
* @param {BirdType} [species] The species to use for the animation * @param {{ [key: string]: string }} colorScheme The color scheme to use for the animation
* @param {string[]} tags The tags to use for the animation
* @returns {boolean} Whether the animation is complete * @returns {boolean} Whether the animation is complete
*/ */
draw(ctx, direction, timeStart, canvasPixelSize, species) { draw(ctx, direction, timeStart, canvasPixelSize, colorScheme, tags) {
// Reset cache if animation was restarted // Reset cache if animation was restarted
if (this.lastTimeStart !== timeStart) { if (this.lastTimeStart !== timeStart) {
this.#clearCache(); this.#clearCache();
@@ -79,7 +80,7 @@ class Anim {
const currentFrameIndex = this.getCurrentFrameIndex(time); const currentFrameIndex = this.getCurrentFrameIndex(time);
if (this.#shouldRedraw(currentFrameIndex, direction)) { if (this.#shouldRedraw(currentFrameIndex, direction)) {
this.frames[currentFrameIndex].draw(ctx, direction, canvasPixelSize, species); this.frames[currentFrameIndex].draw(ctx, direction, canvasPixelSize, colorScheme, tags);
this.lastFrameIndex = currentFrameIndex; this.lastFrameIndex = currentFrameIndex;
this.lastDirection = direction; this.lastDirection = direction;
} }

View File

@@ -53,20 +53,21 @@ class Frame {
/** /**
* @param {CanvasRenderingContext2D} ctx * @param {CanvasRenderingContext2D} ctx
* @param {BirdType} [species] * @param {number} direction
* @param {number} direction
* @param {number} canvasPixelSize * @param {number} canvasPixelSize
* @param {{ [key: string]: string }} colorScheme
* @param {string[]} tags
*/ */
draw(ctx, direction, canvasPixelSize, species) { draw(ctx, direction, canvasPixelSize, colorScheme, tags) {
// Clear the canvas before drawing the new frame // Clear the canvas before drawing the new frame
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
const pixels = this.getPixels(species?.tags[0]); const pixels = this.getPixels(tags[0]);
for (let y = 0; y < pixels.length; y++) { for (let y = 0; y < pixels.length; y++) {
const row = pixels[y]; const row = pixels[y];
for (let x = 0; x < pixels[y].length; x++) { for (let x = 0; x < pixels[y].length; x++) {
const cell = direction === Directions.LEFT ? row[x] : row[pixels[y].length - x - 1]; const cell = direction === Directions.LEFT ? row[x] : row[pixels[y].length - x - 1];
ctx.fillStyle = species?.colors[cell] ?? cell; ctx.fillStyle = colorScheme[cell] ?? cell;
ctx.fillRect(x * canvasPixelSize, y * canvasPixelSize, canvasPixelSize, canvasPixelSize); ctx.fillRect(x * canvasPixelSize, y * canvasPixelSize, canvasPixelSize, canvasPixelSize);
}; };
}; };

View File

@@ -43,6 +43,7 @@ import {
switchMenuItems, switchMenuItems,
MENU_EXIT_ID MENU_EXIT_ID
} from './menu.js'; } from './menu.js';
import { HAT } from './hats.js';
/** /**
@@ -236,6 +237,7 @@ function startApplication(birbPixels, featherPixels, hatsPixels) {
let petStack = []; let petStack = [];
let currentSpecies = DEFAULT_BIRD; let currentSpecies = DEFAULT_BIRD;
let unlockedSpecies = [DEFAULT_BIRD]; let unlockedSpecies = [DEFAULT_BIRD];
let currentHat = HAT.TOP_HAT;
// let visible = true; // let visible = true;
let lastPetTimestamp = 0; let lastPetTimestamp = 0;
/** @type {StickyNote[]} */ /** @type {StickyNote[]} */
@@ -456,7 +458,7 @@ function startApplication(birbPixels, featherPixels, hatsPixels) {
flySomewhere(); flySomewhere();
} }
if (birb.draw(SPECIES[currentSpecies])) { if (birb.draw(SPECIES[currentSpecies], currentHat)) {
birb.setAnimation(Animations.STILL); birb.setAnimation(Animations.STILL);
} }
@@ -548,7 +550,7 @@ function startApplication(birbPixels, featherPixels, hatsPixels) {
if (!featherCtx) { if (!featherCtx) {
return; return;
} }
FEATHER_ANIMATIONS.feather.draw(featherCtx, Directions.LEFT, Date.now(), CANVAS_PIXEL_SIZE, type); FEATHER_ANIMATIONS.feather.draw(featherCtx, Directions.LEFT, Date.now(), CANVAS_PIXEL_SIZE, type.colors, type.tags);
document.body.appendChild(featherCanvas); document.body.appendChild(featherCanvas);
onClick(featherCanvas, () => { onClick(featherCanvas, () => {
unlockBird(birdType); unlockBird(birdType);
@@ -695,7 +697,7 @@ function startApplication(birbPixels, featherPixels, hatsPixels) {
if (!speciesCtx) { if (!speciesCtx) {
return; return;
} }
birb.getFrames().base.draw(speciesCtx, Directions.RIGHT, CANVAS_PIXEL_SIZE, type); birb.getFrames().base.draw(speciesCtx, Directions.RIGHT, CANVAS_PIXEL_SIZE, type.colors, type.tags);
speciesElement.appendChild(speciesCanvas); speciesElement.appendChild(speciesCanvas);
content.appendChild(speciesElement); content.appendChild(speciesElement);
if (unlocked) { if (unlocked) {

View File

@@ -126,12 +126,13 @@ export class Birb {
/** /**
* Draw the current animation frame * Draw the current animation frame
* @param {BirdType} species The species color data * @param {BirdType} species The species data
* @param {string} [hat] The name of the current hat
* @returns {boolean} Whether the animation has completed (for non-looping animations) * @returns {boolean} Whether the animation has completed (for non-looping animations)
*/ */
draw(species) { draw(species, hat) {
const anim = this.animations[this.currentAnimation]; const anim = this.animations[this.currentAnimation];
return anim.draw(this.ctx, this.direction, this.animStart, this.canvasPixelSize, species); return anim.draw(this.ctx, this.direction, this.animStart, this.canvasPixelSize, species.colors, [...species.tags, hat || '']);
} }

View File

@@ -2,7 +2,7 @@ import Layer from "./animation/layer.js";
import { PALETTE } from "./animation/sprites.js"; import { PALETTE } from "./animation/sprites.js";
import { getLayerPixels } from "./shared.js"; import { getLayerPixels } from "./shared.js";
const HAT = { export const HAT = {
TOP_HAT: 'top-hat' TOP_HAT: 'top-hat'
}; };
@@ -96,5 +96,5 @@ function buildHatLayer(spriteSheet, hatName, outlineBottom = false, yOffset = 0)
} }
} }
} }
return new Layer(paddedHatPixels); return new Layer(paddedHatPixels, hatName);
} }