From 687a83922fa609cf2f57480b85b1b88b3d4e8359 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A7=E9=A9=8A?= Date: Sat, 22 Nov 2025 12:53:14 +0800 Subject: [PATCH] good version --- src/App.vue | 15 ++++-- src/components/PetGame.vue | 100 ++++++++++++++++++++++++++++++++++--- 2 files changed, 104 insertions(+), 11 deletions(-) diff --git a/src/App.vue b/src/App.vue index fb1ebbb..185892a 100644 --- a/src/App.vue +++ b/src/App.vue @@ -51,10 +51,19 @@ function handleAction(action) { sleep(); break; case 'medicine': - // Heal the pet + // Heal the pet with animation if (state.value === 'sick') { - stats.value.health = 100; - state.value = 'idle'; + if (petGameRef.value) { + // Trigger medicine animation + petGameRef.value.startFeeding('medicine').then(() => { + stats.value.health = 100; + state.value = 'idle'; + }); + } else { + // Fallback if ref not ready + stats.value.health = 100; + state.value = 'idle'; + } } break; case 'stats': diff --git a/src/components/PetGame.vue b/src/components/PetGame.vue index c5382f6..9a394b8 100644 --- a/src/components/PetGame.vue +++ b/src/components/PetGame.vue @@ -62,7 +62,7 @@
{ + [...row].forEach((ch, x) => { + if (ch === '0') return; + + // Bite logic: Eat from bottom-left/bottom + // Stage 1: Remove bottom chunk + if (stage === 1 && (y > 7 || (y > 5 && x < 4))) return; + // Stage 2: Remove most of it + if (stage === 2 && y > 4) return; + + pxs.push({ + x, y, + color: pillPalette[ch] + }); + }); + }); + return pxs; + } + const sprite = FOOD_SPRITES[foodStage.value]; const pxs = []; if(!sprite) return pxs; @@ -774,7 +826,7 @@ function moveRandomly() { } console.log('moveRandomly called. State:', props.state); - if (props.state === 'sleep' || props.state === 'dead' || props.state === 'eating') { + if (props.state === 'sleep' || props.state === 'dead' || props.state === 'eating' || isMedicineActive.value) { updateHeadIconsPosition(); return; } @@ -841,10 +893,26 @@ function moveRandomly() { } // Feeding Logic -async function startFeeding() { - // Reset food + +async function startFeeding(type) { + console.log('Starting feeding:', type); + + if (type === 'medicine') { + currentFoodType.value = 'medicine'; + isMedicineActive.value = true; + } else { + // If default feeding, ensure we don't override medicine + if (isMedicineActive.value) { + console.log('Skipping default feeding because medicine is active'); + return; + } + currentFoodType.value = 'food'; + isMedicineActive.value = false; + } + foodStage.value = 0; foodVisible.value = true; + console.log('Food visible:', foodVisible.value); // Calculate food position: in front of pet, at mouth height // Food drops in front (not directly at mouth) @@ -886,6 +954,10 @@ async function startFeeding() { // Move pet to food const targetPetX = isFacingRight.value ? targetFoodX - width - 5 : targetFoodX + (10 * pixelSize) + 5; + // Force pet to be at the correct position to eat + // This ensures that even if the food was moved due to bounds/poop, the pet is there + petX.value = targetPetX; + // Simple animation sequence // 1. Drop food // 2. Pet moves to food @@ -938,6 +1010,7 @@ async function startFeeding() { // Finish eating foodVisible.value = false; + isMedicineActive.value = false; emit('update:state', 'idle'); } @@ -1030,11 +1103,21 @@ onUnmounted(() => { watch(() => props.state, (newState) => { updateHeadIconsPosition(); if (newState === 'eating') { - startFeeding(); + // Only start default feeding if we aren't already doing medicine + if (!isMedicineActive.value) { + startFeeding(); + } } else { // Reset feeding state if interrupted - isMouthOpen.value = false; - foodVisible.value = false; + if (newState !== 'eating') { + isMouthOpen.value = false; + foodVisible.value = false; + isMedicineActive.value = false; + // Reset type back to food when done + if (!foodVisible.value) { + currentFoodType.value = 'food'; + } + } } }); @@ -1065,7 +1148,8 @@ async function shakeHead() { // Expose shakeHead function to parent component defineExpose({ - shakeHead + shakeHead, + startFeeding });