diff --git a/js/comfy/comfy.js b/js/comfy/comfy.js index 9b106b7..e094ba0 100644 --- a/js/comfy/comfy.js +++ b/js/comfy/comfy.js @@ -25,6 +25,8 @@ export class ComfyNode extends LiteGraph.LGraphNode { this.isVirtualNode = true; this.renderCount = 0; + + this.buttons = [] } /** @@ -37,6 +39,7 @@ export class ComfyNode extends LiteGraph.LGraphNode { } this.render(ctx) + this.renderButtons(ctx) // This animation loop renders frames // continuously, not only when mouse moves. @@ -53,17 +56,71 @@ export class ComfyNode extends LiteGraph.LGraphNode { this.renderCount++; } + /** + * Returns mouse pos relative to this node + * @note - the Y is wrong for this because it doesn't + * take into account the node's header + */ + getRelativeMouseWithinNode() { + const [boundingX, boundingY, boundingWidth, boundingHeight] = this.getBounding(); + const [mouseX, mouseY] = app.canvas.canvas_mouse; + + // Litegraph node header size + var font_size = LiteGraph.DEFAULT_GROUP_FONT_SIZE || 24; + var height = font_size * 1.4; + + const relativeMouseX = mouseX - boundingX; + const relativeMouseY = mouseY - boundingY; + + // is mouse within node? + if( + relativeMouseX > 0 && + relativeMouseX < boundingWidth && + relativeMouseY > 0 && + relativeMouseY < boundingHeight + ) { + return [relativeMouseX, relativeMouseY - height]; + } else { + return false + } + } + + renderButtons(ctx) { + for (let i = 0; i < this.buttons.length; i++) { + const button = this.buttons[i]; + button.render(ctx) + + } + } + + onMouseDown() { + const [mouseX, mouseY] = this.getRelativeMouseWithinNode() + + for (let i = 0; i < this.buttons.length; i++) { + const button = this.buttons[i]; + if(button.inBounds(mouseX, mouseY)) { + button.onClick() + } + } + } + /** * Add a button to the ComfyUI node */ - addButton(buttonText, callback) { - this.addWidget("button", buttonText, "image", callback) + addButton(buttonText, options, callback) { + //this.addWidget("button", buttonText, "image", callback) + var b = new Button("Hello world", '#eeaa00', '#001122') + b.onClick = callback + this.buttons.push(b) + + return b; } /** * Only renders when the user moves their mouse */ + // eslint-disable-next-line render(ctx) { // This function renders a single frame. It is called // every time you move your mouse @@ -72,9 +129,69 @@ export class ComfyNode extends LiteGraph.LGraphNode { /** * Renders on init */ + // eslint-disable-next-line renderOnce(ctx) { // This function renders a single frame when the node // is initialized } } +export class Button { + constructor(text, fillColor, textColor) { + this.x = 0; + this.y = 0; + this.width = 100; + this.height = 48; + this.text = text; + this.color = textColor; + this.fillColor = fillColor; + + this.fontSize = "16"; + this.fontFamily = "Arial"; + this.fontWeight = "regular"; + } + + inBounds(mouseX, mouseY) { + return !(mouseX < this.x || mouseX > this.x + this.width || mouseY < this.y || mouseY > this.y + this.height); + } + + onClick() { + // implement + } + + /** + * Default button styles + */ + render(ctx) { + ctx.fillStyle = this.fillColor; + ctx.beginPath(); + ctx.roundRect( + this.x, + this.y, + this.width, + this.height, + 8 + ); + ctx.fill() + + // draw the button text + ctx.fillStyle = "#fff"//this.color; + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + + //console.log(this.fontSize, this.fontWeight, this.fontFamily) + + if(this.fontWeight == 'regular') { + ctx.font = `${this.fontSize}px ${this.fontFamily}`; + } else { + ctx.font = `${this.fontWeight} ${this.fontSize}px ${this.fontFamily}`; + } + + ctx.fillText( + this.text, + this.x + this.width / 2, + this.y + this.height / 2, + //this.button + ); + } +} diff --git a/js/game/buttons.js b/js/game/buttons.js new file mode 100644 index 0000000..7279087 --- /dev/null +++ b/js/game/buttons.js @@ -0,0 +1,88 @@ +import { Button } from '../comfy/comfy.js'; +import { darkenHexColor } from '../utils.js'; + +/** + * General styling + */ +export class BaseComfyPetsButton extends Button { + constructor(text, fillColor, textColor) { + super(text, fillColor, textColor) + } + + render(ctx) { + + // Darken by 10% + const buttonFillDark = darkenHexColor(this.fillColor, 10); + + ctx.fillStyle = buttonFillDark; + ctx.beginPath(); + ctx.roundRect( + this.x, + this.y, + this.width, + this.height, + 8 + ); // draw the button text + ctx.fill() + + ctx.fillStyle = this.fillColor; + ctx.beginPath(); + ctx.roundRect( + this.x, + this.y, + this.width, + this.height - 4, + 8 + ); + ctx.fill() + + ctx.fillStyle = this.color; + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + + if(this.fontWeight == 'regular') { + ctx.font = `${this.fontSize}px ${this.fontFamily}`; + } else { + ctx.font = `${this.fontWeight} ${this.fontSize}px ${this.fontFamily}`; + } + + ctx.fillText( + this.text, + this.x + this.width / 2, + this.y + this.height / 2, + //this.button + ); + + + ctx.fillText( + this.text, + this.x + this.width / 2, + this.y + this.height / 2, + ); + } +} + +/** + * Button sizes + */ +export class SmallButton extends BaseComfyPetsButton { + constructor(text, fillColor, textColor) { + super(text, fillColor, textColor) + this.width = 100; + this.height = 24; + } +} +export class MediumButton extends BaseComfyPetsButton { + constructor(text, fillColor, textColor) { + super(text, fillColor, textColor) + this.width = 100; + this.height = 32; + } +} +export class LargeButton extends BaseComfyPetsButton { + constructor(text, fillColor, textColor) { + super(text, fillColor, textColor) + this.width = 100; + this.height = 48; + } +} diff --git a/js/game/core.js b/js/game/core.js index 4e4e0f9..16b8a36 100644 --- a/js/game/core.js +++ b/js/game/core.js @@ -24,3 +24,4 @@ export class GameObject { this.isActive = false; } } + diff --git a/js/game/stage.js b/js/game/stage.js index 4935fb8..bfef068 100644 --- a/js/game/stage.js +++ b/js/game/stage.js @@ -5,6 +5,9 @@ import { Pet } from './pet.js'; import { Food } from './food.js'; import { startGame } from './endless_runner/index.js'; import { addFoodEvent } from '../apiClient.js'; +import { MediumButton } from './buttons.js'; + + /** @@ -16,10 +19,15 @@ export class ComfyPetsStage extends ComfyNode { super() this.title = "Comfy Pet", - this.addButton("Feed pet", () => { + this.feedButton = this.addButton("Feed pet", {}, () => { this.addFood() addFoodEvent() }) + this.feedButton.x = 8 + this.feedButton.y = 8 + this.feedButton.fontSize = 14; + this.feedButton.fontWeight = "bold"; + this.feedButton.fontFamily = "Courier New"; // @todo this.addButton("Play", () => { @@ -38,7 +46,7 @@ export class ComfyPetsStage extends ComfyNode { } addPet() { - const [height] = this.size + const height = this.size[1]; const petWidth = 75; const petHeight = 50; @@ -70,8 +78,21 @@ export class ComfyPetsStage extends ComfyNode { this.foods.push(food) } + /** + * Add a button to the ComfyUI node + */ + addButton(buttonText, options, callback) { + //this.addWidget("button", buttonText, "image", callback) + var b = new MediumButton(buttonText, '#eeaa00', '#fff') + b.onClick = callback + this.buttons.push(b) + + return b; + } + renderPets(ctx) { - const [width, height] = this.size + const [width] = this.size + for (let i = 0; i < this.pets.length; i++) { const pet = this.pets[i]; @@ -107,7 +128,7 @@ export class ComfyPetsStage extends ComfyNode { ctx.drawImage( pet.petGif.image, // img src pet.x, // x - height - pet.height, // y + pet.y, // y pet.width, // width pet.height // height ); @@ -118,8 +139,6 @@ export class ComfyPetsStage extends ComfyNode { } renderFoods(ctx) { - const [height] = this.size - for (let i = 0; i < this.foods.length; i++) { const food = this.foods[i] @@ -127,11 +146,10 @@ export class ComfyPetsStage extends ComfyNode { this.foods.splice(i, 1); } - //ctx.fillStyle = "blue"; ctx.drawImage( food.image, food.x, - height - food.height, + food.y, food.width, food.height ); @@ -149,8 +167,12 @@ export class ComfyPetsStage extends ComfyNode { render(ctx) { this.renderBackground(ctx) + //this.renderButtons(ctx) this.renderFoods(ctx) this.renderPets(ctx) // render pet onto canvas } } + + + diff --git a/js/utils.js b/js/utils.js index 570d9f4..f3d6175 100644 --- a/js/utils.js +++ b/js/utils.js @@ -1,3 +1,26 @@ +export function darkenHexColor(hexColor, percent) { + // Ensure the percent is between 0 and 100 + percent = Math.min(100, Math.max(0, percent)); + + // Convert hex to RGB + let r = parseInt(hexColor.slice(1, 3), 16); + let g = parseInt(hexColor.slice(3, 5), 16); + let b = parseInt(hexColor.slice(5, 7), 16); + + // Calculate the darkness factor + let darkness = 1 - percent / 100; + + // Apply darkness to each RGB component + r = Math.round(r * darkness); + g = Math.round(g * darkness); + b = Math.round(b * darkness); + + // Convert back to hex + const darkHexColor = `#${(r << 16 | g << 8 | b).toString(16).padStart(6, '0')}`; + + return darkHexColor; +} + export function getRandomNumber(min, max) { return Math.random() * (max - min) + min; }