MagicPot / js /animals.js
eithney's picture
Upload 27 files
c87be38 verified
Raw
History Blame Contribute Delete
17.8 kB
// 动物系统类
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';
}
});
}
}