阳菜,放晴! | ce4a641 | 2025-06-08 14:35:23 +0800 | [diff] [blame^] | 1 | import React, { useEffect, useRef, useState } from 'react'; |
| 2 | import styles from './pet.module.css'; // 确保这个路径对 |
San3yuan | 30e245f | 2025-06-07 20:04:23 +0800 | [diff] [blame] | 3 | |
阳菜,放晴! | ce4a641 | 2025-06-08 14:35:23 +0800 | [diff] [blame^] | 4 | const PetGame: React.FC = () => { |
| 5 | const petRef = useRef<HTMLDivElement>(null); |
| 6 | const [mood, setMood] = useState(50); |
| 7 | const [hunger, setHunger] = useState(50); |
San3yuan | 30e245f | 2025-06-07 20:04:23 +0800 | [diff] [blame] | 8 | |
阳菜,放晴! | ce4a641 | 2025-06-08 14:35:23 +0800 | [diff] [blame^] | 9 | // 从 localStorage 恢复状态 |
San3yuan | 30e245f | 2025-06-07 20:04:23 +0800 | [diff] [blame] | 10 | useEffect(() => { |
阳菜,放晴! | ce4a641 | 2025-06-08 14:35:23 +0800 | [diff] [blame^] | 11 | const saved = localStorage.getItem('petState'); |
| 12 | if (saved) { |
| 13 | const { mood: savedMood, hunger: savedHunger } = JSON.parse(saved); |
| 14 | setMood(savedMood); |
| 15 | setHunger(savedHunger); |
| 16 | } |
| 17 | }, []); |
San3yuan | 30e245f | 2025-06-07 20:04:23 +0800 | [diff] [blame] | 18 | |
阳菜,放晴! | ce4a641 | 2025-06-08 14:35:23 +0800 | [diff] [blame^] | 19 | // 每分钟更新状态并保存 |
| 20 | useEffect(() => { |
| 21 | const interval = setInterval(() => { |
| 22 | setMood(prev => { |
| 23 | const newMood = Math.min(prev + 1, 100); |
| 24 | savePetState(newMood, hunger); |
| 25 | return newMood; |
| 26 | }); |
| 27 | setHunger(prev => { |
| 28 | const newHunger = Math.max(prev - 1, 0); |
| 29 | savePetState(mood, newHunger); |
| 30 | return newHunger; |
| 31 | }); |
| 32 | }, 60000); // 每分钟一次 |
| 33 | |
| 34 | return () => clearInterval(interval); |
| 35 | }, [mood, hunger]); |
| 36 | |
| 37 | // 保存状态到 localStorage |
| 38 | const savePetState = (newMood: number, newHunger: number) => { |
| 39 | localStorage.setItem('petState', JSON.stringify({ mood: newMood, hunger: newHunger })); |
| 40 | }; |
| 41 | |
| 42 | // 拖动功能(保留) |
| 43 | useEffect(() => { |
| 44 | const pet = petRef.current; |
| 45 | if (!pet) return; |
| 46 | |
| 47 | let offsetX = 0; |
| 48 | let offsetY = 0; |
| 49 | let isDragging = false; |
| 50 | |
| 51 | const handleMouseDown = (e: MouseEvent) => { |
| 52 | isDragging = true; |
| 53 | const rect = pet.getBoundingClientRect(); |
| 54 | offsetX = e.clientX - rect.left; |
| 55 | offsetY = e.clientY - rect.top; |
| 56 | }; |
| 57 | |
| 58 | const handleMouseMove = (e: MouseEvent) => { |
| 59 | if (isDragging && pet) { |
| 60 | pet.style.left = `${e.clientX - offsetX}px`; |
| 61 | pet.style.top = `${e.clientY - offsetY}px`; |
| 62 | } |
| 63 | }; |
| 64 | |
| 65 | const handleMouseUp = () => { |
| 66 | isDragging = false; |
| 67 | }; |
| 68 | |
| 69 | pet.addEventListener('mousedown', handleMouseDown); |
| 70 | document.addEventListener('mousemove', handleMouseMove); |
| 71 | document.addEventListener('mouseup', handleMouseUp); |
| 72 | |
| 73 | return () => { |
| 74 | pet.removeEventListener('mousedown', handleMouseDown); |
| 75 | document.removeEventListener('mousemove', handleMouseMove); |
| 76 | document.removeEventListener('mouseup', handleMouseUp); |
| 77 | }; |
| 78 | }, []); |
| 79 | |
| 80 | // 喂食按钮逻辑 |
San3yuan | 30e245f | 2025-06-07 20:04:23 +0800 | [diff] [blame] | 81 | const handleFeed = () => { |
阳菜,放晴! | ce4a641 | 2025-06-08 14:35:23 +0800 | [diff] [blame^] | 82 | const newHunger = Math.min(hunger + 10, 100); |
| 83 | setHunger(newHunger); |
| 84 | savePetState(mood, newHunger); |
San3yuan | 30e245f | 2025-06-07 20:04:23 +0800 | [diff] [blame] | 85 | }; |
| 86 | |
阳菜,放晴! | ce4a641 | 2025-06-08 14:35:23 +0800 | [diff] [blame^] | 87 | // 互动按钮逻辑 |
| 88 | const handleInteract = () => { |
| 89 | const newMood = Math.min(mood + 10, 100); |
| 90 | setMood(newMood); |
| 91 | savePetState(newMood, hunger); |
San3yuan | 30e245f | 2025-06-07 20:04:23 +0800 | [diff] [blame] | 92 | }; |
| 93 | |
San3yuan | 30e245f | 2025-06-07 20:04:23 +0800 | [diff] [blame] | 94 | return ( |
阳菜,放晴! | ce4a641 | 2025-06-08 14:35:23 +0800 | [diff] [blame^] | 95 | <div className={styles.cardContainer}> |
| 96 | <div className={styles.card}> |
| 97 | <p className={styles.text}>情绪:{mood}</p> |
| 98 | <p className={styles.text}>饥饿值:{hunger}/100</p> |
San3yuan | 30e245f | 2025-06-07 20:04:23 +0800 | [diff] [blame] | 99 | |
阳菜,放晴! | ce4a641 | 2025-06-08 14:35:23 +0800 | [diff] [blame^] | 100 | <button className={styles.feedButton} onClick={handleFeed}> |
| 101 | 🍖 喂食 |
| 102 | </button> |
San3yuan | 30e245f | 2025-06-07 20:04:23 +0800 | [diff] [blame] | 103 | |
阳菜,放晴! | ce4a641 | 2025-06-08 14:35:23 +0800 | [diff] [blame^] | 104 | <button className={styles.feedButton} onClick={handleInteract}> |
| 105 | 🐾 摸摸头 / 玩游戏 |
| 106 | </button> |
San3yuan | 30e245f | 2025-06-07 20:04:23 +0800 | [diff] [blame] | 107 | </div> |
| 108 | </div> |
| 109 | ); |
| 110 | }; |
| 111 | |
| 112 | export default PetGame; |