From 1c068b1672a99312ccd1b98a5ec0ccb8e838d105 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 20:08:15 +0800 Subject: [PATCH] good version --- src/components/BallGame.vue | 307 +++++++++++++++++++++++++++++ src/components/PetGame.vue | 103 +++++++++- src/components/TrainingGame.vue | 330 ++++++++++++++++++++++++++++++++ 3 files changed, 737 insertions(+), 3 deletions(-) create mode 100644 src/components/BallGame.vue create mode 100644 src/components/TrainingGame.vue diff --git a/src/components/BallGame.vue b/src/components/BallGame.vue new file mode 100644 index 0000000..79129b0 --- /dev/null +++ b/src/components/BallGame.vue @@ -0,0 +1,307 @@ + + + + + diff --git a/src/components/PetGame.vue b/src/components/PetGame.vue index fb73d2d..3713d49 100644 --- a/src/components/PetGame.vue +++ b/src/components/PetGame.vue @@ -190,7 +190,7 @@ v-if="showPetInfo" :petName="CURRENT_PRESET.name" :stage="stage" - :poopCount="poopCount" + :poopCount="stats?.poopCount || 0" :baseStats="baseStats" :hunger="stats?.hunger || 100" :happiness="stats?.happiness || 100" @@ -212,6 +212,20 @@ @close="currentGame = ''" @complete="handleGameComplete" /> + + + + { + if (newGame === 'training') { + // Move pet to right side for training + if (containerRef.value) { + const cw = containerRef.value.clientWidth; + const ch = containerRef.value.clientHeight; + // Position on right side (approx 260px for 300px width) + petX.value = cw - 60; + petY.value = ch - height - 20; // Bottom aligned with padding + // 根據使用者的反饋,這裡調整面向 + // 如果原本 false 是錯的,那我們改成 true + isFacingRight.value = true; + } + } +}); + +function handleTrainingAttack() { + // Trigger attack animation (open mouth) + isMouthOpen.value = true; + setTimeout(() => { + isMouthOpen.value = false; + }, 300); +} + console.log('currentGame is now:', currentGame.value); + + function handleGameComplete(won) { console.log('Game completed, won:', won); currentGame.value = ''; if (won) { - // Reward: increase happiness - emit('action', 'play'); + // 訓練完成,觸發開心事件 + triggerState('happy', 3000); + + // 顯示頭頂音符動畫 + eventAnimation.value = { + type: 'float-up', + iconClass: 'pixel-note' + }; + setTimeout(() => { + eventAnimation.value = null; + }, 2000); + + // 增加一些數值作為獎勵 + stats.value.happiness = Math.min(100, stats.value.happiness + 10); + stats.value.hunger = Math.max(0, stats.value.hunger - 5); // 運動會餓 + } +} + +function handleBallGameUpdate(x) { + petX.value = x; + // 根據移動方向改變面向 (簡單判斷:如果 x 變大則向右,變小則向左) + // 這裡 BallGame 已經處理了邏輯,我們只需要更新位置 +} + +function handleBallGameComplete(won) { + console.log('Ball game completed, won:', won); + currentGame.value = ''; + + if (won) { + triggerState('happy', 3000); + // 顯示頭頂音符動畫 + eventAnimation.value = { + type: 'float-up', + iconClass: 'pixel-note' + }; + setTimeout(() => { + eventAnimation.value = null; + }, 2000); + + stats.value.happiness = Math.min(100, stats.value.happiness + 15); + stats.value.hunger = Math.max(0, stats.value.hunger - 10); } } @@ -862,6 +945,9 @@ function moveRandomly() { return; } + // Training mode: pet stays in position + if (currentGame.value === 'training') return; + console.log('moveRandomly called. State:', props.state); if (props.state === 'sleep' || props.state === 'dead' || props.state === 'eating' || isMedicineActive.value) { updateHeadIconsPosition(); @@ -1711,6 +1797,17 @@ defineExpose({ background: #fff; } +.pixel-note { + box-shadow: + 1px -2px #000, 2px -2px #000, + 1px -1px #000, 2px -1px #000, 3px -1px #000, + 1px 0px #000, 3px 0px #000, + 1px 1px #000, 3px 1px #000, + -2px 2px #000, -1px 2px #000, 1px 2px #000, 3px 2px #000, + -2px 3px #000, -1px 3px #000, 1px 3px #000, 3px 3px #000; + background: #000; +} + .event-animation.float-up { animation: floatUp 2s ease-out forwards; } diff --git a/src/components/TrainingGame.vue b/src/components/TrainingGame.vue new file mode 100644 index 0000000..a6857e7 --- /dev/null +++ b/src/components/TrainingGame.vue @@ -0,0 +1,330 @@ + + + + +