// 动物系统类 class AnimalSystem { constructor(canvas) { this.animals = []; this.maxAnimals = 8; // 降低最大动物数量 this.canvas = canvas || document.getElementById('gameCanvas'); } update(deltaTime) { const dt = deltaTime * 0.001; for (let i = this.animals.length - 1; i >= 0; i--) { const animal = this.animals[i]; this.updateAnimal(animal, dt); // 移除离开屏幕或生命周期结束的动物 if (animal.shouldRemove) { this.animals.splice(i, 1); } } } updateAnimal(animal, dt) { switch (animal.state) { case 'entering': this.updateEntering(animal, dt); break; case 'seeking': this.updateSeeking(animal, dt); break; case 'eating': this.updateEating(animal, dt); break; case 'satisfied': this.updateSatisfied(animal, dt); break; case 'leaving': this.updateLeaving(animal, dt); break; } // 更新动画 animal.animationTime += dt; // 更新位置 animal.x += animal.vx * dt; animal.y += animal.vy * dt; // 更新生命周期 animal.lifeTime += dt; if (animal.maxLifeTime && animal.lifeTime > animal.maxLifeTime) { animal.shouldRemove = true; } } updateEntering(animal, dt) { // 动物从屏幕边缘进入 - 使用显示尺寸而不是内部像素尺寸 const rect = this.canvas ? this.canvas.getBoundingClientRect() : { width: 800, height: 600 }; const displayWidth = rect.width; const displayHeight = rect.height; const targetX = animal.side === 'left' ? 100 : displayWidth - 100; const targetY = displayHeight - 100; // 距离底部100像素 console.log(`Canvas显示尺寸: ${displayWidth}x${displayHeight}, 目标位置: (${targetX}, ${targetY})`); const dx = targetX - animal.x; const dy = targetY - animal.y; const distance = Math.sqrt(dx * dx + dy * dy); console.log(`动物${animal.type}进入中: 当前位置(${animal.x.toFixed(1)}, ${animal.y.toFixed(1)}), 目标位置(${targetX}, ${targetY}), 距离: ${distance.toFixed(1)}`); if (distance < 20) { animal.state = 'seeking'; animal.vx = 0; animal.vy = 0; console.log(`动物${animal.type}已进入屏幕,状态改为seeking`); } else { animal.vx = (dx / distance) * animal.speed; animal.vy = (dy / distance) * animal.speed; } } updateSeeking(animal, dt) { // 寻找食物 const food = this.findNearestFood(animal); if (food) { console.log(`${animal.type}找到食物: ${food.foodType}, 距离: ${Math.sqrt((food.x - animal.x)**2 + (food.y - animal.y)**2).toFixed(1)}`); const dx = food.x - animal.x; const dy = food.y - animal.y; const distance = Math.sqrt(dx * dx + dy * dy); if (distance < 30) { // 开始吃食物 animal.state = 'eating'; animal.targetFood = food; animal.eatingTime = 0; animal.vx = 0; animal.vy = 0; console.log(`${animal.type}开始吃食物!`); } else { // 移动向食物 animal.vx = (dx / distance) * animal.speed * 0.8; animal.vy = (dy / distance) * animal.speed * 0.8; } } else { // 没有找到食物,随机移动 if (Math.random() < 0.1) { // 增加调试输出频率 console.log(`${animal.type}没有找到食物,喜欢: ${animal.preferredFood}, 随机移动`); animal.vx = (Math.random() - 0.5) * animal.speed * 0.5; animal.vy = (Math.random() - 0.5) * animal.speed * 0.5; } } // 如果寻找时间太长,离开 if (animal.lifeTime > 10) { animal.state = 'leaving'; } } updateEating(animal, dt) { animal.eatingTime += dt; // 吃食物动画 if (animal.eatingTime > 0.5 && animal.targetFood) { // 移除食物粒子 this.removeFoodParticle(animal.targetFood); animal.targetFood = null; animal.foodEaten++; } if (animal.eatingTime > 1) { if (animal.foodEaten >= animal.maxFood) { animal.state = 'satisfied'; } else { animal.state = 'seeking'; } } } updateSatisfied(animal, dt) { // 满足后的短暂停留 animal.satisfiedTime = (animal.satisfiedTime || 0) + dt; if (animal.satisfiedTime > 2) { animal.state = 'leaving'; } } updateLeaving(animal, dt) { // 离开屏幕 const exitX = animal.side === 'left' ? -50 : this.canvas.width + 50; const dx = exitX - animal.x; const distance = Math.abs(dx); if (distance < 10) { animal.shouldRemove = true; } else { animal.vx = (dx / distance) * animal.speed * 1.2; animal.vy = 0; } } findNearestFood(animal) { // 从游戏主类获取粒子系统 if (!window.game || !window.game.particleSystem) return null; const particles = window.game.particleSystem.particles; let nearestFood = null; let nearestDistance = Infinity; let totalFood = 0; let groundedFood = 0; let matchingFood = 0; particles.forEach(particle => { if (particle.type === 'food') { totalFood++; if (particle.isGrounded) { groundedFood++; if (particle.foodType === animal.preferredFood) { matchingFood++; const dx = particle.x - animal.x; const dy = particle.y - animal.y; const distance = Math.sqrt(dx * dx + dy * dy); if (distance < nearestDistance) { nearestDistance = distance; nearestFood = particle; } } } } }); // 每隔一段时间输出调试信息 if (Math.random() < 0.01) { console.log(`${animal.type}寻找食物: 总食物=${totalFood}, 落地食物=${groundedFood}, 匹配食物=${matchingFood}, 喜欢=${animal.preferredFood}`); if (totalFood > 0) { console.log(`示例食物类型: ${particles.find(p => p.type === 'food')?.foodType}`); } } return nearestFood; } removeFoodParticle(foodParticle) { if (!window.game || !window.game.particleSystem) return; const particles = window.game.particleSystem.particles; const index = particles.indexOf(foodParticle); if (index > -1) { particles.splice(index, 1); // 创建吃食物的特效 window.game.particleSystem.createSparkleParticles( foodParticle.x, foodParticle.y, 5 ); } } createAnimal(foodType, side = 'left') { if (this.animals.length >= this.maxAnimals) { console.log(`已达到最大动物数量: ${this.maxAnimals}`); return null; } const animalType = this.getAnimalForFood(foodType); // 使用显示尺寸而不是内部像素尺寸 const rect = this.canvas ? this.canvas.getBoundingClientRect() : { width: 800, height: 600 }; const displayWidth = rect.width; const displayHeight = rect.height; const startX = side === 'left' ? -50 : displayWidth + 50; const startY = displayHeight - 60; console.log(`Canvas显示尺寸: ${displayWidth}x${displayHeight}, 动物起始位置: (${startX}, ${startY})`); const animal = { x: startX, y: startY, vx: 0, vy: 0, type: animalType, side: side, state: 'entering', speed: Math.random() * 30 + 40, size: Math.random() * 20 + 30, preferredFood: foodType, foodEaten: 0, maxFood: Math.floor(Math.random() * 3) + 2, animationTime: 0, lifeTime: 0, maxLifeTime: 30, // 30秒后自动离开 shouldRemove: false, color: this.getAnimalColor(animalType), emoji: this.getAnimalEmoji(animalType) }; this.animals.push(animal); console.log(`动物已创建: ${animalType}, 位置: (${animal.x}, ${animal.y}), 当前动物总数: ${this.animals.length}`); console.log(`动物详细信息:`, animal); return animal; } createLittleGirl(side = 'right') { // 使用显示尺寸而不是内部像素尺寸 const rect = this.canvas ? this.canvas.getBoundingClientRect() : { width: 800, height: 600 }; const displayWidth = rect.width; const displayHeight = rect.height; const startX = side === 'left' ? -50 : displayWidth + 50; const startY = displayHeight - 80; console.log(`小女孩Canvas显示尺寸: ${displayWidth}x${displayHeight}, 起始位置: (${startX}, ${startY})`); const girl = { x: startX, y: startY, vx: 0, vy: 0, type: 'girl', side: side, state: 'entering', speed: 60, size: 40, preferredFood: ['strawberry', 'watermelon'], foodEaten: 0, maxFood: 5, animationTime: 0, lifeTime: 0, maxLifeTime: 45, shouldRemove: false, color: '#FFB6C1', emoji: '👧', isSpecial: true }; this.animals.push(girl); console.log(`小女孩已创建: 位置: (${girl.x}, ${girl.y}), 当前动物总数: ${this.animals.length}`); return girl; } getAnimalForFood(foodType) { const animalMap = { 'apple': 'rabbit', 'banana': 'monkey', 'orange': 'bird', 'strawberry': 'bear', 'watermelon': 'elephant', 'grape': 'fox', 'pizza': 'cat', 'burger': 'dog', 'cake': 'mouse', 'cookie': 'squirrel', 'bread': 'duck', 'cheese': 'rat', 'fish': 'cat', 'chicken': 'dog', 'rice': 'bird', 'noodles': 'panda', 'carrot': 'rabbit', 'corn': 'chicken' }; return animalMap[foodType] || 'cat'; } getAnimalColor(animalType) { const colorMap = { 'rabbit': '#F5DEB3', 'monkey': '#DEB887', 'bird': '#87CEEB', 'bear': '#8B4513', 'elephant': '#A9A9A9', 'fox': '#FF8C00', 'cat': '#FFB6C1', 'dog': '#DEB887', 'mouse': '#C0C0C0', 'squirrel': '#D2691E', 'duck': '#FFFF00', 'rat': '#808080', 'panda': '#000000', 'chicken': '#FFFF00' }; return colorMap[animalType] || '#FFB6C1'; } getAnimalEmoji(animalType) { const emojiMap = { 'rabbit': '🐰', 'monkey': '🐵', 'bird': '🐦', 'bear': '🐻', 'elephant': '🐘', 'fox': '🦊', 'cat': '🐱', 'dog': '🐶', 'mouse': '🐭', 'squirrel': '🐿️', 'duck': '🦆', 'rat': '🐀', 'panda': '🐼', 'chicken': '🐔' }; return emojiMap[animalType] || '🐱'; } render(ctx) { if (this.animals.length > 0) { console.log(`渲染${this.animals.length}个动物`); } this.animals.forEach(animal => { this.renderAnimal(ctx, animal); }); } renderAnimal(ctx, animal) { ctx.save(); // 调试信息:在控制台显示渲染信息(仅首次) if (!animal.debugRendered) { console.log(`正在渲染动物: ${animal.type}, 位置: (${animal.x}, ${animal.y}), emoji: ${animal.emoji}, 尺寸: ${animal.size}`); animal.debugRendered = true; } // 移动到动物位置 ctx.translate(animal.x, animal.y); // 翻转方向 if (animal.vx < 0) { ctx.scale(-1, 1); } // 绘制阴影 ctx.fillStyle = 'rgba(0, 0, 0, 0.2)'; ctx.beginPath(); ctx.ellipse(0, animal.size * 0.4, animal.size * 0.6, animal.size * 0.2, 0, 0, Math.PI * 2); ctx.fill(); // 绘制动物主体 if (animal.emoji) { ctx.font = `${animal.size}px Arial`; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; ctx.fillStyle = '#000000'; ctx.fillText(animal.emoji, 0, -animal.size * 0.2); } else { // 备用:绘制简单的动物形状 this.renderSimpleAnimal(ctx, animal); } // 绘制调试信息(显示动物类型) ctx.font = '12px Arial'; ctx.fillStyle = '#FF0000'; ctx.fillText(animal.type, 0, animal.size * 0.6); // 绘制状态指示器 this.renderAnimalState(ctx, animal); // 绘制动画效果 this.renderAnimalEffects(ctx, animal); ctx.restore(); } renderSimpleAnimal(ctx, animal) { // 身体 ctx.fillStyle = animal.color; ctx.beginPath(); ctx.ellipse(0, 0, animal.size * 0.4, animal.size * 0.3, 0, 0, Math.PI * 2); ctx.fill(); // 头部 ctx.beginPath(); ctx.ellipse(0, -animal.size * 0.3, animal.size * 0.3, animal.size * 0.25, 0, 0, Math.PI * 2); ctx.fill(); // 眼睛 ctx.fillStyle = '#000000'; ctx.beginPath(); ctx.arc(-animal.size * 0.1, -animal.size * 0.35, 2, 0, Math.PI * 2); ctx.arc(animal.size * 0.1, -animal.size * 0.35, 2, 0, Math.PI * 2); ctx.fill(); } renderAnimalState(ctx, animal) { // 根据状态显示不同的指示器 switch (animal.state) { case 'eating': // 显示爱心 ctx.fillStyle = '#FF69B4'; ctx.font = '16px Arial'; ctx.textAlign = 'center'; ctx.fillText('💖', 0, -animal.size * 0.8); break; case 'satisfied': // 显示满足表情 ctx.fillStyle = '#32CD32'; ctx.font = '16px Arial'; ctx.textAlign = 'center'; ctx.fillText('😊', 0, -animal.size * 0.8); break; } } renderAnimalEffects(ctx, animal) { // 特殊动物的额外效果 if (animal.isSpecial) { // 小女孩的闪光效果 const sparkleCount = 3; const time = animal.animationTime * 2; ctx.fillStyle = '#FFD700'; for (let i = 0; i < sparkleCount; i++) { const angle = (i / sparkleCount) * Math.PI * 2 + time; const radius = animal.size * 0.8; const x = Math.cos(angle) * radius; const y = Math.sin(angle) * radius; ctx.beginPath(); ctx.arc(x, y, 3, 0, Math.PI * 2); ctx.fill(); } } // 移动时的灰尘效果 if (Math.abs(animal.vx) > 10 && animal.state !== 'eating') { ctx.fillStyle = 'rgba(139, 69, 19, 0.3)'; for (let i = 0; i < 3; i++) { const dustX = -animal.vx * 0.1 * (i + 1) + (Math.random() - 0.5) * 10; const dustY = animal.size * 0.3 + Math.random() * 5; ctx.beginPath(); ctx.arc(dustX, dustY, Math.random() * 3 + 1, 0, Math.PI * 2); ctx.fill(); } } } // 清理所有动物 clear() { this.animals = []; } // 获取动物数量 getAnimalCount() { return this.animals.length; } // 获取特定类型的动物数量 getAnimalCountByType(type) { return this.animals.filter(animal => animal.type === type).length; } // 移除指定的动物 removeAnimal(animal) { const index = this.animals.indexOf(animal); if (index > -1) { this.animals.splice(index, 1); } } // 让所有动物离开 makeAllAnimalsLeave() { this.animals.forEach(animal => { if (animal.state !== 'leaving') { animal.state = 'leaving'; } }); } }