From 6531325c93e7f4b891b49e88b66a1e7155c9cd82 Mon Sep 17 00:00:00 2001 From: tongxiaojun Date: Sat, 18 Jan 2025 21:26:35 +0800 Subject: [PATCH] add little fish --- .../index.html" | 33 + .../script.js" | 837 ++++++++++++++++++ .../styles.css" | 314 +++++++ .../game.js" | 627 +++++++++++++ .../index.html" | 270 ++++++ 5 files changed, 2081 insertions(+) create mode 100644 "\344\272\272\344\275\223\345\244\247\345\206\222\351\231\251/index.html" create mode 100644 "\344\272\272\344\275\223\345\244\247\345\206\222\351\231\251/script.js" create mode 100644 "\344\272\272\344\275\223\345\244\247\345\206\222\351\231\251/styles.css" create mode 100644 "\345\260\217\344\270\221\351\261\274\346\270\270\346\210\217/game.js" create mode 100644 "\345\260\217\344\270\221\351\261\274\346\270\270\346\210\217/index.html" diff --git "a/\344\272\272\344\275\223\345\244\247\345\206\222\351\231\251/index.html" "b/\344\272\272\344\275\223\345\244\247\345\206\222\351\231\251/index.html" new file mode 100644 index 0000000..4a20b23 --- /dev/null +++ "b/\344\272\272\344\275\223\345\244\247\345\206\222\351\231\251/index.html" @@ -0,0 +1,33 @@ + + + + + + 人体大冒险 + + + +
+

人体大冒险

+
+ + + +
+
+
+
+
+
+
+
+ +
分数: 0
+
健康值: 100
+
+
+
+
+ + + diff --git "a/\344\272\272\344\275\223\345\244\247\345\206\222\351\231\251/script.js" "b/\344\272\272\344\275\223\345\244\247\345\206\222\351\231\251/script.js" new file mode 100644 index 0000000..8ee998c --- /dev/null +++ "b/\344\272\272\344\275\223\345\244\247\345\206\222\351\231\251/script.js" @@ -0,0 +1,837 @@ +class Game { + constructor() { + this.score = 0; + this.health = 100; + this.isPlaying = false; + this.foodParticle = document.getElementById('food'); + this.scoreElement = document.getElementById('score'); + this.healthElement = document.getElementById('health'); + this.currentPathIndex = 0; + + // 定义食物类型 + this.foodTypes = { + vegetable: { color: '#4CAF50', points: 10, health: 5, speed: 1 }, + fruit: { color: '#FF9800', points: 15, health: 8, speed: 1.2 }, + meat: { color: '#F44336', points: 20, health: 10, speed: 0.8 }, + junkFood: { color: '#9C27B0', points: 5, health: -5, speed: 1.5 } + }; + + // 定义病毒类型 + this.virusTypes = { + common: { color: '#ff0000', damage: 5, speed: 1, points: 5 }, + fast: { color: '#ff00ff', damage: 3, speed: 2, points: 10 }, + strong: { color: '#800000', damage: 10, speed: 0.5, points: 15 } + }; + + // 消化路径 + this.digestivePath = [ + { organ: 'mouth', y: 80, action: this.digestInMouth.bind(this) }, + { organ: 'stomach', y: 200, action: this.digestInStomach.bind(this) }, + { organ: 'liver', y: 250, action: this.processInLiver.bind(this) }, + { organ: 'small-intestine', y: 350, action: this.absorbNutrients.bind(this) }, + { organ: 'large-intestine', y: 450, action: this.finalProcess.bind(this) }, + { organ: 'exit', y: 550 } + ]; + + // 添加器官描述 + this.organDescriptions = { + '心脏': '心脏是人体的血液泵,负责将血液输送到全身', + '肺部': '肺部负责呼吸,为血液提供氧气并排出二氧化碳', + '肝脏': '肝脏负责解毒和产生胆汁,帮助消化脂肪', + '胃': '胃负责消化食物,分泌胃酸帮助分解食物', + '小肠': '小肠是主要的营养吸收场所,将食物转化为身体可用的营养', + '大肠': '大肠负责吸收水分,处理食物残渣' + }; + + // 初始化音频上下文 + this.audioContext = new (window.AudioContext || window.webkitAudioContext)(); + + // 创建不同类型的音效 + this.sounds = { + click: this.createClickSound(), + digest: this.createDigestSound(), + virus: this.createVirusSound(), + gameOver: this.createGameOverSound() + }; + + this.setupOrganHighlighting(); + + // 创建战斗机元素 + this.createFighter(); + + // 添加鼠标移动监听 + document.addEventListener('mousemove', this.moveFighter.bind(this)); + + // 添加器官音符频率 + this.organNotes = { + '心脏': 523.25, // C5 + '肺部': 587.33, // D5 + '肝脏': 659.25, // E5 + '胃': 698.46, // F5 + '小肠': 783.99, // G5 + '大肠': 880.00 // A5 + }; + } + + setupGameControls() { + const foodButtons = document.createElement('div'); + foodButtons.className = 'food-buttons'; + Object.keys(this.foodTypes).forEach(type => { + const btn = document.createElement('button'); + btn.textContent = this.getFoodName(type); + btn.style.backgroundColor = this.foodTypes[type].color; + btn.onclick = () => { + if (this.isPlaying) { + this.startDigestion(type); + } + }; + foodButtons.appendChild(btn); + }); + document.querySelector('.game-controls').appendChild(foodButtons); + } + + getFoodName(type) { + const names = { + vegetable: '蔬菜', + fruit: '水果', + meat: '肉类', + junkFood: '垃圾食品' + }; + return names[type]; + } + + start() { + this.isPlaying = true; + this.score = 0; + this.health = 100; + this.updateUI(); + // 清除之前的食物按钮 + const oldFoodButtons = document.querySelector('.food-buttons'); + if (oldFoodButtons) { + oldFoodButtons.remove(); + } + // 初始化食物按钮 + this.setupGameControls(); + this.spawnVirus(); + } + + updateUI() { + this.scoreElement.textContent = this.score; + this.healthElement.textContent = this.health; + + // 根据健康值改变显示效果 + if (this.health < 30) { + this.healthElement.style.color = '#ff0000'; + } else if (this.health < 60) { + this.healthElement.style.color = '#ffa500'; + } else { + this.healthElement.style.color = '#4CAF50'; + } + } + + startDigestion(foodType) { + if (!this.isPlaying || this.foodParticle.style.display === 'block') { + return; // 如果已经有食物在消化,则不允许新的食物进入 + } + + this.currentFood = this.foodTypes[foodType]; + this.currentPathIndex = 0; + this.foodParticle.style.display = 'block'; + this.foodParticle.style.backgroundColor = this.currentFood.color; + this.foodParticle.style.top = '80px'; + this.foodParticle.style.left = '150px'; + this.moveFood(); + } + + moveFood() { + if (!this.isPlaying) return; + + const currentPosition = this.digestivePath[this.currentPathIndex]; + this.foodParticle.style.top = currentPosition.y + 'px'; + + // 执行当前器官的消化动作 + if (currentPosition.action) { + currentPosition.action(this.currentFood); + } + + this.currentPathIndex++; + if (this.currentPathIndex >= this.digestivePath.length) { + this.finishDigestion(); + } else { + setTimeout(() => this.moveFood(), 1000 / this.currentFood.speed); + } + } + + // 各个器官的消化过程 + digestInMouth(food) { + // 咀嚼动画效果 + this.foodParticle.style.animation = 'chew 0.5s ease-in-out'; + } + + digestInStomach(food) { + this.sounds.digest(); + const stomach = document.querySelector('.stomach'); + stomach.classList.add('digesting'); + setTimeout(() => stomach.classList.remove('digesting'), 1000); + } + + processInLiver(food) { + // 如果是垃圾食品,会损失健康值 + if (food === this.foodTypes.junkFood) { + this.health = Math.max(0, this.health - 5); + this.updateUI(); + } + } + + absorbNutrients(food) { + // 增加分数和健康值 + this.score += food.points; + this.health = Math.min(100, this.health + food.health); + this.updateUI(); + } + + finalProcess(food) { + // 最终处理 + if (this.health < 30) { + this.gameOver(); + } + } + + spawnVirus() { + if (!this.isPlaying) return; + + const virusType = this.getRandomVirusType(); + const virus = this.createVirus(virusType); + document.querySelector('.virus-container').appendChild(virus); + + // 病毒移动 + this.moveVirus(virus, virusType); + + setTimeout(() => this.spawnVirus(), 2000); + } + + getRandomVirusType() { + const types = Object.keys(this.virusTypes); + return this.virusTypes[types[Math.floor(Math.random() * types.length)]]; + } + + createVirus(virusType) { + const virus = document.createElement('div'); + virus.className = 'virus'; + virus.style.backgroundColor = virusType.color; + + // 设置病毒初始位置 + const organs = [ + {top: 80, left: 150}, // 头部 + {top: 200, left: 150}, // 胃 + {top: 250, left: 150}, // 肝脏 + {top: 350, left: 150}, // 小肠 + {top: 450, left: 150} // 大肠 + ]; + + const position = organs[Math.floor(Math.random() * organs.length)]; + virus.style.left = (position.left + (Math.random() * 60 - 30)) + 'px'; + virus.style.top = (position.top + (Math.random() * 60 - 30)) + 'px'; + + virus.onclick = () => this.destroyVirus(virus, virusType); + + return virus; + } + + moveVirus(virus, virusType) { + const speed = virusType.speed; + const angle = Math.random() * Math.PI * 2; + const vx = Math.cos(angle) * speed; + const vy = Math.sin(angle) * speed; + + const interval = setInterval(() => { + if (!this.isPlaying) { + clearInterval(interval); + return; + } + + const left = parseFloat(virus.style.left); + const top = parseFloat(virus.style.top); + + virus.style.left = (left + vx) + 'px'; + virus.style.top = (top + vy) + 'px'; + + // 检查是否击中器官 + this.checkVirusCollision(virus, virusType); + }, 50); + } + + checkVirusCollision(virus, virusType) { + // 如果病毒接触到器官,扣除健康值 + const organs = document.querySelectorAll('.organ'); + organs.forEach(organ => { + if (this.isColliding(virus, organ)) { + this.health = Math.max(0, this.health - virusType.damage); + this.updateUI(); + this.destroyVirus(virus, virusType); + + if (this.health <= 0) { + this.gameOver(); + } + } + }); + } + + isColliding(virus, organ) { + const virusRect = virus.getBoundingClientRect(); + const organRect = organ.getBoundingClientRect(); + + return !(virusRect.right < organRect.left || + virusRect.left > organRect.right || + virusRect.bottom < organRect.top || + virusRect.top > organRect.bottom); + } + + destroyVirus(virus, virusType) { + this.sounds.virus(); + this.score += virusType.points; + this.updateUI(); + this.createVirusDestroyEffect(virus); + virus.remove(); + } + + gameOver() { + this.sounds.gameOver(); + this.isPlaying = false; + alert(`游戏结束!\n最终得分:${this.score}`); + document.getElementById('start-game').textContent = '重新开始'; + } + + setupOrganHighlighting() { + const organs = document.querySelectorAll('[data-organ]'); + organs.forEach(organ => { + // 为每个器官设置基础颜色 + const baseColor = this.getOrganBaseColor(organ.getAttribute('data-organ')); + organ.style.backgroundColor = baseColor; + + organ.addEventListener('click', () => { + const organName = organ.getAttribute('data-organ'); + // 播放对应器官的音符 + const woodfishSound = this.createWoodfishSound(organName); + woodfishSound(); + + // 添加木鱼敲击效果和颜色变化 + organ.classList.add('organ-hit'); + organ.style.backgroundColor = this.getOrganActiveColor(organ.getAttribute('data-organ')); + + // 添加发光效果 + organ.style.boxShadow = '0 0 20px ' + this.getOrganGlowColor(organ.getAttribute('data-organ')); + + // 恢复原始状态 + setTimeout(() => { + organ.classList.remove('organ-hit'); + organ.style.backgroundColor = baseColor; + organ.style.boxShadow = 'none'; + }, 200); + + // 显示器官信息 + const description = this.organDescriptions[organName]; + + // 创建或更新提示框 + let tooltip = document.getElementById('organ-tooltip'); + if (!tooltip) { + tooltip = document.createElement('div'); + tooltip.id = 'organ-tooltip'; + document.body.appendChild(tooltip); + } + + tooltip.textContent = `${organName}: ${description}`; + tooltip.style.display = 'block'; + + // 定位提示框 + const rect = organ.getBoundingClientRect(); + tooltip.style.left = `${rect.left}px`; + tooltip.style.top = `${rect.top - tooltip.offsetHeight - 10}px`; + + // 3秒后隐藏提示框 + setTimeout(() => { + tooltip.style.display = 'none'; + }, 3000); + }); + }); + } + + // 添加器官基础颜色 + getOrganBaseColor(organName) { + const colors = { + '心脏': '#ff6b6b', + '肺部': '#ffa07a', + '肝脏': '#8b4513', + '胃': '#ff9f7f', + '小肠': '#ffd700', + '大肠': '#deb887' + }; + return colors[organName] || '#ff9f7f'; + } + + // 添加器官激活时的颜色 + getOrganActiveColor(organName) { + const colors = { + '心脏': '#ff4444', + '肺部': '#ff8855', + '肝脏': '#a52a2a', + '胃': '#ff7744', + '小肠': '#ffc125', + '大肠': '#cd853f' + }; + return colors[organName] || '#ff7744'; + } + + // 添加器官发光颜色 + getOrganGlowColor(organName) { + const colors = { + '心脏': 'rgba(255, 105, 105, 0.6)', + '肺部': 'rgba(255, 160, 122, 0.6)', + '肝脏': 'rgba(139, 69, 19, 0.6)', + '胃': 'rgba(255, 159, 127, 0.6)', + '小肠': 'rgba(255, 215, 0, 0.6)', + '大肠': 'rgba(222, 184, 135, 0.6)' + }; + return colors[organName] || 'rgba(255, 159, 127, 0.6)'; + } + + finishDigestion() { + // 完成一次消化过程 + this.score += this.currentFood.points; + this.updateUI(); + this.foodParticle.style.display = 'none'; + } + + createVirusDestroyEffect(virus) { + const effect = document.createElement('div'); + effect.style.position = 'absolute'; + effect.style.left = virus.style.left; + effect.style.top = virus.style.top; + effect.style.width = '30px'; + effect.style.height = '30px'; + effect.style.background = 'radial-gradient(circle, rgba(255,255,255,0.8) 0%, rgba(255,0,0,0) 70%)'; + effect.style.animation = 'explode 0.5s ease-out forwards'; + document.querySelector('.virus-container').appendChild(effect); + + setTimeout(() => effect.remove(), 500); + } + + // 创建点击音效 + createClickSound() { + return () => { + const oscillator = this.audioContext.createOscillator(); + const gainNode = this.audioContext.createGain(); + + oscillator.connect(gainNode); + gainNode.connect(this.audioContext.destination); + + oscillator.type = 'sine'; + oscillator.frequency.setValueAtTime(800, this.audioContext.currentTime); + gainNode.gain.setValueAtTime(0.3, this.audioContext.currentTime); + gainNode.gain.exponentialRampToValueAtTime(0.01, this.audioContext.currentTime + 0.1); + + oscillator.start(); + oscillator.stop(this.audioContext.currentTime + 0.1); + }; + } + + // 创建消化音效 + createDigestSound() { + return () => { + const oscillator = this.audioContext.createOscillator(); + const gainNode = this.audioContext.createGain(); + + oscillator.connect(gainNode); + gainNode.connect(this.audioContext.destination); + + oscillator.type = 'triangle'; + oscillator.frequency.setValueAtTime(200, this.audioContext.currentTime); + oscillator.frequency.linearRampToValueAtTime(100, this.audioContext.currentTime + 0.2); + + gainNode.gain.setValueAtTime(0.2, this.audioContext.currentTime); + gainNode.gain.exponentialRampToValueAtTime(0.01, this.audioContext.currentTime + 0.2); + + oscillator.start(); + oscillator.stop(this.audioContext.currentTime + 0.2); + }; + } + + // 创建病毒消灭音效 + createVirusSound() { + return () => { + const oscillator = this.audioContext.createOscillator(); + const gainNode = this.audioContext.createGain(); + + oscillator.connect(gainNode); + gainNode.connect(this.audioContext.destination); + + oscillator.type = 'square'; + oscillator.frequency.setValueAtTime(600, this.audioContext.currentTime); + oscillator.frequency.exponentialRampToValueAtTime(200, this.audioContext.currentTime + 0.1); + + gainNode.gain.setValueAtTime(0.2, this.audioContext.currentTime); + gainNode.gain.exponentialRampToValueAtTime(0.01, this.audioContext.currentTime + 0.1); + + oscillator.start(); + oscillator.stop(this.audioContext.currentTime + 0.1); + }; + } + + // 创建游戏结束音效 + createGameOverSound() { + return () => { + const oscillator = this.audioContext.createOscillator(); + const gainNode = this.audioContext.createGain(); + + oscillator.connect(gainNode); + gainNode.connect(this.audioContext.destination); + + oscillator.type = 'sawtooth'; + oscillator.frequency.setValueAtTime(400, this.audioContext.currentTime); + oscillator.frequency.exponentialRampToValueAtTime(100, this.audioContext.currentTime + 0.5); + + gainNode.gain.setValueAtTime(0.3, this.audioContext.currentTime); + gainNode.gain.exponentialRampToValueAtTime(0.01, this.audioContext.currentTime + 0.5); + + oscillator.start(); + oscillator.stop(this.audioContext.currentTime + 0.5); + }; + } + + createFighter() { + const fighter = document.createElement('div'); + fighter.className = 'fighter'; + fighter.innerHTML = ` + + + + + + + + + + + + + `; + document.body.appendChild(fighter); + this.fighter = fighter; + + // 隐藏默认光标 + document.body.style.cursor = 'none'; + } + + moveFighter(e) { + if (this.fighter) { + this.fighter.style.left = (e.clientX - 20) + 'px'; + this.fighter.style.top = (e.clientY - 20) + 'px'; + + // 当点击时添加敲击动画 + document.addEventListener('mousedown', () => { + this.fighter.classList.add('hitting'); + }); + + document.addEventListener('mouseup', () => { + this.fighter.classList.remove('hitting'); + }); + } + } + + // 添加木鱼音效 + createWoodfishSound(organName) { + return () => { + const frequency = this.organNotes[organName] || 523.25; // 默认 C5 + const oscillator = this.audioContext.createOscillator(); + const gainNode = this.audioContext.createGain(); + + oscillator.connect(gainNode); + gainNode.connect(this.audioContext.destination); + + // 木鱼的音色 + oscillator.type = 'triangle'; + oscillator.frequency.setValueAtTime(frequency, this.audioContext.currentTime); + + // 音量包络 + gainNode.gain.setValueAtTime(0, this.audioContext.currentTime); + gainNode.gain.linearRampToValueAtTime(0.5, this.audioContext.currentTime + 0.01); + gainNode.gain.exponentialRampToValueAtTime(0.01, this.audioContext.currentTime + 0.3); + + oscillator.start(); + oscillator.stop(this.audioContext.currentTime + 0.3); + + // 添加泛音 + this.addHarmonics(frequency); + }; + } + + // 添加泛音来模拟木鱼的谐波 + addHarmonics(fundamental) { + const harmonics = [2, 3, 4]; // 泛音序列 + harmonics.forEach((harmonic, index) => { + const oscillator = this.audioContext.createOscillator(); + const gainNode = this.audioContext.createGain(); + + oscillator.connect(gainNode); + gainNode.connect(this.audioContext.destination); + + oscillator.type = 'triangle'; + oscillator.frequency.setValueAtTime(fundamental * harmonic, this.audioContext.currentTime); + + // 泛音音量递减 + const volume = 0.2 / (index + 2); + gainNode.gain.setValueAtTime(0, this.audioContext.currentTime); + gainNode.gain.linearRampToValueAtTime(volume, this.audioContext.currentTime + 0.01); + gainNode.gain.exponentialRampToValueAtTime(0.01, this.audioContext.currentTime + 0.2); + + oscillator.start(); + oscillator.stop(this.audioContext.currentTime + 0.2); + }); + } +} + +class HumanBodyDrawer { + constructor() { + this.bodyCanvas = document.getElementById('bodyCanvas'); + this.skeletonCanvas = document.getElementById('skeletonCanvas'); + this.organsCanvas = document.getElementById('organsCanvas'); + + this.canvases = [this.bodyCanvas, this.skeletonCanvas, this.organsCanvas]; + this.canvases.forEach(canvas => { + canvas.width = 300; + canvas.height = 600; + }); + + this.bodyCtx = this.bodyCanvas.getContext('2d'); + this.skeletonCtx = this.skeletonCanvas.getContext('2d'); + this.organsCtx = this.organsCanvas.getContext('2d'); + + this.drawAll(); + } + + drawBody() { + const ctx = this.bodyCtx; + ctx.fillStyle = '#ffdbac'; + + // 头部 + ctx.beginPath(); + ctx.arc(150, 50, 30, 0, Math.PI * 2); + ctx.fill(); + + // 颈部 + ctx.beginPath(); + ctx.moveTo(140, 75); + ctx.lineTo(160, 75); + ctx.lineTo(157, 95); + ctx.lineTo(143, 95); + ctx.closePath(); + ctx.fill(); + + // 躯干 + ctx.beginPath(); + ctx.moveTo(130, 95); // 肩部起点 + ctx.lineTo(170, 95); // 肩部宽度 + ctx.lineTo(175, 280); // 腰部 + ctx.lineTo(165, 400); // 臀部 + ctx.lineTo(135, 400); + ctx.lineTo(125, 280); + ctx.closePath(); + ctx.fill(); + + // 左手臂 + ctx.beginPath(); + ctx.moveTo(130, 95); // 肩部连接点 + ctx.lineTo(110, 200); // 上臂 + ctx.lineTo(105, 300); // 前臂 + ctx.lineTo(115, 300); + ctx.lineTo(120, 200); + ctx.closePath(); + ctx.fill(); + + // 右手臂 + ctx.beginPath(); + ctx.moveTo(170, 95); // 肩部连接点 + ctx.lineTo(190, 200); // 上臂 + ctx.lineTo(195, 300); // 前臂 + ctx.lineTo(185, 300); + ctx.lineTo(180, 200); + ctx.closePath(); + ctx.fill(); + + // 左腿 + ctx.beginPath(); + ctx.moveTo(135, 400); + ctx.lineTo(125, 500); + ctx.lineTo(130, 580); + ctx.lineTo(145, 580); + ctx.lineTo(150, 500); + ctx.closePath(); + ctx.fill(); + + // 右腿 + ctx.beginPath(); + ctx.moveTo(165, 400); + ctx.lineTo(175, 500); + ctx.lineTo(170, 580); + ctx.lineTo(155, 580); + ctx.lineTo(150, 500); + ctx.closePath(); + ctx.fill(); + } + + drawSkeleton() { + const ctx = this.skeletonCtx; + ctx.strokeStyle = '#e0e0e0'; + ctx.lineWidth = 2; + + // 头骨 + ctx.beginPath(); + ctx.arc(150, 50, 25, 0, Math.PI * 2); + ctx.stroke(); + + // 颈椎 + ctx.beginPath(); + ctx.moveTo(150, 75); + ctx.lineTo(150, 95); + ctx.stroke(); + + // 脊椎 + ctx.beginPath(); + ctx.moveTo(150, 95); + for(let y = 95; y < 400; y += 15) { + ctx.lineTo(150, y + 7); + ctx.moveTo(150, y + 15); + } + ctx.stroke(); + + // 肋骨(更自然的弧度) + for(let y = 120; y < 250; y += 25) { + ctx.beginPath(); + // 左侧肋骨 + ctx.moveTo(150, y); + ctx.bezierCurveTo(130, y-5, 120, y, 115, y+5); + // 右侧肋骨 + ctx.moveTo(150, y); + ctx.bezierCurveTo(170, y-5, 180, y, 185, y+5); + ctx.stroke(); + } + + // 锁骨 + ctx.beginPath(); + ctx.moveTo(130, 95); + ctx.quadraticCurveTo(150, 85, 170, 95); + ctx.stroke(); + + // 骨盆 + ctx.beginPath(); + ctx.moveTo(125, 380); + ctx.bezierCurveTo(150, 400, 150, 390, 175, 380); + ctx.stroke(); + + // 手臂骨骼 + this.drawLimb(ctx, 130, 95, 110, 200, 105, 300); // 左臂 + this.drawLimb(ctx, 170, 95, 190, 200, 195, 300); // 右臂 + + // 腿部骨骼 + this.drawLimb(ctx, 135, 400, 125, 500, 130, 580); // 左腿 + this.drawLimb(ctx, 165, 400, 175, 500, 170, 580); // 右腿 + } + + drawLimb(ctx, x1, y1, x2, y2, x3, y3) { + ctx.beginPath(); + ctx.moveTo(x1, y1); + ctx.lineTo(x2, y2); + ctx.lineTo(x3, y3); + ctx.stroke(); + } + + drawOrgans() { + const ctx = this.organsCtx; + + // 心脏(更自然的形状) + ctx.fillStyle = '#ff6b6b'; + ctx.beginPath(); + ctx.moveTo(150, 160); + ctx.bezierCurveTo(170, 140, 170, 180, 150, 200); + ctx.bezierCurveTo(130, 180, 130, 140, 150, 160); + ctx.fill(); + + // 肺部(更自然的形状) + ctx.fillStyle = '#ffa07a'; + // 左肺 + ctx.beginPath(); + ctx.moveTo(120, 150); + ctx.bezierCurveTo(100, 170, 100, 220, 120, 240); + ctx.bezierCurveTo(130, 220, 130, 170, 120, 150); + ctx.fill(); + // 右肺 + ctx.beginPath(); + ctx.moveTo(180, 150); + ctx.bezierCurveTo(200, 170, 200, 220, 180, 240); + ctx.bezierCurveTo(170, 220, 170, 170, 180, 150); + ctx.fill(); + + // 肝脏 + ctx.fillStyle = '#8b4513'; + ctx.beginPath(); + ctx.moveTo(130, 250); + ctx.bezierCurveTo(170, 240, 190, 260, 170, 280); + ctx.bezierCurveTo(150, 290, 130, 280, 130, 250); + ctx.fill(); + + // 胃 + ctx.fillStyle = '#ff9f7f'; + ctx.beginPath(); + ctx.moveTo(140, 290); + ctx.bezierCurveTo(160, 280, 170, 310, 160, 330); + ctx.bezierCurveTo(140, 340, 130, 310, 140, 290); + ctx.fill(); + + // 小肠(更自然的蜿蜒形状) + ctx.fillStyle = '#ffd700'; + this.drawIntestine(ctx, 150, 350, 35, 8, 0.15); + + // 大肠 + ctx.fillStyle = '#deb887'; + this.drawIntestine(ctx, 150, 420, 45, 3, 0.25); + } + + drawIntestine(ctx, x, y, radius, loops, wavelength) { + ctx.beginPath(); + for(let i = 0; i < Math.PI * 2 * loops; i += 0.1) { + const dx = Math.cos(i) * radius + Math.sin(i * 8) * wavelength; + const dy = Math.sin(i) * radius + Math.cos(i * 8) * wavelength; + if(i === 0) { + ctx.moveTo(x + dx, y + dy); + } else { + ctx.lineTo(x + dx, y + dy); + } + } + ctx.fill(); + } + + drawAll() { + this.drawBody(); + this.drawSkeleton(); + this.drawOrgans(); + } +} + +// 初始化游戏和人体绘制 +document.addEventListener('DOMContentLoaded', () => { + const humanBodyDrawer = new HumanBodyDrawer(); + const game = new Game(); + + document.getElementById('start-game').addEventListener('click', () => { + game.start(); + }); +}); + +const style = document.createElement('style'); +style.textContent = ` + @keyframes explode { + 0% { transform: scale(0.3); opacity: 1; } + 100% { transform: scale(2); opacity: 0; } + } +`; +document.head.appendChild(style); \ No newline at end of file diff --git "a/\344\272\272\344\275\223\345\244\247\345\206\222\351\231\251/styles.css" "b/\344\272\272\344\275\223\345\244\247\345\206\222\351\231\251/styles.css" new file mode 100644 index 0000000..708e0ff --- /dev/null +++ "b/\344\272\272\344\275\223\345\244\247\345\206\222\351\231\251/styles.css" @@ -0,0 +1,314 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; + cursor: none !important; +} + +.game-container { + width: 100%; + height: 100vh; + display: flex; + flex-direction: column; + align-items: center; + background: #f0f0f0; + padding: 20px; +} + +.human-body { + position: relative; + width: 300px; + height: 600px; + background: transparent; +} + +.body-base { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + object-fit: contain; +} + +.body-layer { + position: absolute; + top: 0; + left: 0; + width: 300px; + height: 600px; + transition: opacity 0.3s; +} + +.skeleton { + opacity: 0.7; +} + +.organs { + opacity: 0.9; +} + +.organ { + position: absolute; + background: transparent; + cursor: pointer; + transition: all 0.2s ease-out; + width: 40px; + height: 40px; + position: absolute; + cursor: pointer; + transition: filter 0.3s; + transform-style: preserve-3d; + perspective: 1000px; + border-radius: 50%; + background-color: transparent; +} + +.organ:hover { + filter: brightness(1.2); + box-shadow: 0 0 10px rgba(255, 255, 255, 0.3); +} + +.organ:active { + transform: scale(0.95); + filter: brightness(1.4); +} + +.food-particle { + position: absolute; + width: 20px; + height: 20px; + background: #4CAF50; + border-radius: 50%; + display: none; + z-index: 10; +} + +.virus { + position: absolute; + width: 15px; + height: 15px; + background: #ff0000; + border-radius: 50%; + cursor: pointer; + z-index: 10; + animation: pulse 1s infinite; +} + +@keyframes pulse { + 0% { transform: scale(1); } + 50% { transform: scale(1.2); } + 100% { transform: scale(1); } +} + +.game-controls { + margin-top: 20px; + text-align: center; +} + +button { + padding: 10px 20px; + font-size: 16px; + background: #4CAF50; + color: white; + border: none; + border-radius: 5px; + cursor: pointer; + transition: background 0.3s; +} + +button:hover { + background: #45a049; + transform: scale(1.05); +} + +.score { + margin-top: 10px; + font-size: 18px; + color: #333; +} + +[data-organ]:hover::after { + content: attr(data-organ); + position: absolute; + background: rgba(0, 0, 0, 0.8); + color: white; + padding: 5px 10px; + border-radius: 5px; + font-size: 14px; + top: -25px; + left: 50%; + transform: translateX(-50%); + white-space: nowrap; + z-index: 11; +} + +@keyframes digest { + 0% { transform: scale(1); } + 50% { transform: scale(1.1); } + 100% { transform: scale(1); } +} + +.digesting { + animation: digest 1s ease-in-out; +} + +.food-buttons { + margin-top: 10px; + display: flex; + gap: 10px; + flex-wrap: wrap; + justify-content: center; +} + +.food-buttons button { + padding: 8px 15px; + border: none; + border-radius: 5px; + color: white; + cursor: pointer; + transition: transform 0.2s; +} + +.food-buttons button:hover { + transform: scale(1.1); +} + +.health { + margin-top: 10px; + font-size: 18px; + color: #4CAF50; +} + +@keyframes chew { + 0% { transform: scale(1); } + 50% { transform: scale(1.2) rotate(45deg); } + 100% { transform: scale(1); } +} + +.heart { + top: 160px; + left: 130px; +} + +.lungs { + top: 140px; + left: 110px; + width: 80px; +} + +.liver { + top: 250px; + left: 130px; +} + +.stomach { + top: 200px; + left: 140px; +} + +.small-intestine { + top: 350px; + left: 130px; + width: 60px; +} + +.large-intestine { + top: 450px; + left: 120px; + width: 80px; +} + +#organ-tooltip { + position: fixed; + background: rgba(0, 0, 0, 0.8); + color: white; + padding: 10px; + border-radius: 5px; + font-size: 14px; + max-width: 200px; + z-index: 1000; + display: none; + pointer-events: none; + animation: fadeIn 0.3s ease-in-out; +} + +@keyframes fadeIn { + from { opacity: 0; transform: translateY(10px); } + to { opacity: 1; transform: translateY(0); } +} + +.organ { + cursor: pointer; + transition: filter 0.3s; +} + +.organ:hover { + filter: brightness(1.2); +} + +.organ:active { + filter: brightness(1.4); + transform: scale(0.95); +} + +/* 木鱼和木槌样式 */ +.fighter { + position: fixed; + width: 40px; + height: 40px; + pointer-events: none; + z-index: 9999; + transform-origin: 20px 20px; +} + +.fighter svg { + width: 100%; + height: 100%; + filter: drop-shadow(0 2px 2px rgba(0,0,0,0.2)); +} + +/* 敲击动画 */ +.fighter.hitting .mallet { + animation: hit 0.1s ease-in-out; + transform-origin: 18px 22px; +} + +@keyframes hit { + 0% { transform: rotate(0deg); } + 50% { transform: rotate(-30deg); } + 100% { transform: rotate(0deg); } +} + +/* 木鱼震动效果 */ +.fighter.hitting .woodfish { + animation: shake 0.1s ease-in-out; +} + +@keyframes shake { + 0% { transform: translateX(0); } + 25% { transform: translateX(-2px); } + 75% { transform: translateX(2px); } + 100% { transform: translateX(0); } +} + +/* 木鱼敲击效果 */ +@keyframes organHit { + 0% { + transform: scale(1); + filter: brightness(1); + } + 50% { + transform: scale(1.2); + filter: brightness(1.5); + } + 100% { + transform: scale(1); + filter: brightness(1); + } +} + +.organ-hit { + animation: organHit 0.2s cubic-bezier(.36,.07,.19,.97) both; + transform-origin: center; +} \ No newline at end of file diff --git "a/\345\260\217\344\270\221\351\261\274\346\270\270\346\210\217/game.js" "b/\345\260\217\344\270\221\351\261\274\346\270\270\346\210\217/game.js" new file mode 100644 index 0000000..b1540b5 --- /dev/null +++ "b/\345\260\217\344\270\221\351\261\274\346\270\270\346\210\217/game.js" @@ -0,0 +1,627 @@ +// 游戏对象 +class Game { + constructor() { + this.canvas = document.getElementById('gameCanvas'); + this.ctx = this.canvas.getContext('2d'); + this.width = this.canvas.width; + this.height = this.canvas.height; + + // 初始化游戏元素 + this.fishingRod = { + x: this.width / 2, + y: 50, + lineLength: 100, // 增加初始长度 + maxLength: 500, // 增加最大长度 + hookSize: 8, + isFishing: false, + speed: 8 // 增加放线速度 + }; + + // 获取游戏容器 + this.container = document.querySelector('.game-container'); + + // 定义鱼的类型 + this.fishTypes = [ + { + color: '#800080', // 紫色 - 章鱼 + finColor: '#9932CC', + score: 10, // 章鱼分值最高 + size: 1.5, // 章鱼最大 + isOctopus: true // 标记为章鱼 + }, + { + color: '#FF4D4D', // 红色 - 核心组件 + finColor: '#FF8080', + score: 1, + size: 1.4 // 核心组件最大 + }, + { + color: '#FFD700', // 金色 - 数据处理 + finColor: '#FFF0B3', + score: 2, + size: 1.2 // 数据处理较大 + }, + { + color: '#4D4DFF', // 蓝色 - 数据存储 + finColor: '#8080FF', + score: 3, + size: 1.1 // 数据存储中等 + }, + { + color: '#00FF00', // 绿色 - 工具组件 + finColor: '#80FF80', + score: 4, + size: 1.0 // 工具组件标准大小 + } + ]; + + // 添加英语单词库 + this.words = [ + // 核心组件 + { word: 'Hadoop', meaning: '分布式计算平台' }, + { word: 'HDFS', meaning: '分布式文件系统' }, + { word: 'YARN', meaning: '集群资源管理系统' }, + { word: 'MapReduce', meaning: '分布式计算框架' }, + + // 数据处理 + { word: 'Spark', meaning: '内存计算引擎' }, + { word: 'Flink', meaning: '流处理框架' }, + { word: 'Storm', meaning: '实时计算系统' }, + { word: 'Pig', meaning: '数据流处理语言' }, + + // 数据存储 + { word: 'HBase', meaning: '分布式列式数据库' }, + { word: 'Cassandra', meaning: '分布式NoSQL数据库' }, + { word: 'Hive', meaning: '数据仓库工具' }, + { word: 'Phoenix', meaning: 'SQL层for HBase' }, + + // 工具组件 + { word: 'ZooKeeper', meaning: '分布式协调服务' }, + { word: 'Sqoop', meaning: '数据导入导出工具' }, + { word: 'Flume', meaning: '日志收集系统' }, + { word: 'Ambari', meaning: '集群管理工具' }, + { word: 'Oozie', meaning: '工作流调度系统' }, + { word: 'Kafka', meaning: '分布式消息系统' } + ]; + + // 分开存储鱼和装饰物 + this.fishes = []; + this.decorations = { + seaweeds: [], + starfish: [] + }; + + // 先创建装饰物 + this.createSeaweed(); + this.createStarfish(); + + // 再创建可钓的鱼 + this.createFishes(); + this.createOctopus(); + + // 绑定事件监听 + this.canvas.addEventListener('mousemove', (e) => this.handleMouseMove(e)); + + // 添加键盘事件监听 + document.addEventListener('keydown', (e) => this.handleKeyDown(e)); + document.addEventListener('keyup', (e) => this.handleKeyUp(e)); + + // 添加分数 + this.score = 0; + + // 创建音频上下文 + this.audioContext = new (window.AudioContext || window.webkitAudioContext)(); + + // 创建音效生成器 + this.createSoundEffects(); + + // 添加正在钓鱼的状态 + this.hasCaughtFish = false; + + // 开始游戏循环 + this.gameLoop(); + } + + handleMouseMove(e) { + const rect = this.canvas.getBoundingClientRect(); + this.fishingRod.x = e.clientX - rect.left; + } + + // 处理按键按下 + handleKeyDown(e) { + if (e.code === 'Space' && !this.fishingRod.isFishing) { + this.fishingRod.isFishing = true; + this.startFishing(); + } + } + + // 处理按键释放 + handleKeyUp(e) { + if (e.code === 'Space') { + this.fishingRod.isFishing = false; + this.pullUp(); + } + } + + // 创建音效 + createSoundEffects() { + // 下降音效生成器 + this.createDropSound = () => { + const oscillator = this.audioContext.createOscillator(); + const gainNode = this.audioContext.createGain(); + + oscillator.type = 'sine'; + oscillator.frequency.setValueAtTime(200, this.audioContext.currentTime); + + gainNode.gain.setValueAtTime(0.1, this.audioContext.currentTime); + + oscillator.connect(gainNode); + gainNode.connect(this.audioContext.destination); + + return { oscillator, gainNode }; + }; + + // 捕获音效 + this.playCatchSound = () => { + const oscillator = this.audioContext.createOscillator(); + const gainNode = this.audioContext.createGain(); + + oscillator.type = 'sine'; + oscillator.frequency.setValueAtTime(800, this.audioContext.currentTime); + oscillator.frequency.exponentialRampToValueAtTime(400, this.audioContext.currentTime + 0.1); + + gainNode.gain.setValueAtTime(0.1, this.audioContext.currentTime); + gainNode.gain.exponentialRampToValueAtTime(0.01, this.audioContext.currentTime + 0.1); + + oscillator.connect(gainNode); + gainNode.connect(this.audioContext.destination); + + oscillator.start(); + oscillator.stop(this.audioContext.currentTime + 0.1); + }; + } + + // 开始钓鱼 + startFishing() { + // 开始播放下降音效 + this.dropSound = this.createDropSound(); + this.dropSound.oscillator.start(); + } + + // 收竿 + pullUp() { + // 停止下降音效 + if (this.dropSound) { + this.dropSound.oscillator.stop(); + this.dropSound = null; + } + } + + update() { + // 更新鱼线长度 + if (this.fishingRod.isFishing && this.fishingRod.lineLength < this.fishingRod.maxLength) { + // 放线 + this.fishingRod.lineLength += this.fishingRod.speed; + + // 更新下降音效频率 + if (this.dropSound) { + const freq = 200 + (this.fishingRod.lineLength / this.fishingRod.maxLength) * 100; + this.dropSound.oscillator.frequency.setValueAtTime(freq, this.audioContext.currentTime); + } + } else if (!this.fishingRod.isFishing && this.fishingRod.lineLength > 50) { + // 收线 + this.fishingRod.lineLength -= this.fishingRod.speed; + + // 停止下降音效 + if (this.dropSound) { + this.dropSound.oscillator.stop(); + this.dropSound = null; + } + + // 检查是否有鱼被钓上来 + this.fishes.forEach(fish => { + if (fish.caught) { + fish.y = this.fishingRod.y + this.fishingRod.lineLength; + } + }); + } + + // 检测碰撞 + if (this.fishingRod.isFishing && !this.hasCaughtFish) { + const hookX = this.fishingRod.x; + const hookY = this.fishingRod.y + this.fishingRod.lineLength; + + for (let fish of this.fishes) { + if (!fish.caught && this.checkCollision(hookX, hookY, fish)) { + fish.caught = true; + this.hasCaughtFish = true; + this.playCatchSound(); + break; + } + } + } + + // 只更新鱼的位置 + this.fishes.forEach(fish => { + if (fish.caught) { + const hookY = this.fishingRod.y + this.fishingRod.lineLength; + fish.x = this.fishingRod.x - fish.width / 2; + fish.y = hookY; + + // 如果鱼被拉到顶部,重置 + if (fish.y <= 100) { + this.addScore(fish); + this.resetFish(fish); + this.hasCaughtFish = false; // 重置钓鱼状态 + } + } else { + fish.x += fish.speed * fish.direction; + + if (fish.x <= 0 || fish.x >= this.width) { + fish.direction *= -1; + } + } + + // 更新DOM元素位置 + if (fish.isOctopus) { + // 章鱼的特殊处理 + fish.element.style.transform = `translate(${fish.x}px, ${fish.y}px)`; + if (fish.direction < 0) { + fish.element.style.transform += ' scaleX(-1)'; + } + } else { + // 普通鱼的处理 + fish.element.style.transform = `translate(${fish.x}px, ${fish.y}px)`; + const body = fish.element.querySelector('.fish-body'); + const tail = fish.element.querySelector('.fish-tail'); + const fin = fish.element.querySelector('.fish-fin'); + + if (fish.direction < 0) { + body.style.transform = 'scaleX(-1)'; + tail.style.transform = 'scaleX(-1)'; + fin.style.transform = 'scaleX(-1)'; + } else { + body.style.transform = 'scaleX(1)'; + tail.style.transform = 'scaleX(1)'; + fin.style.transform = 'scaleX(1)'; + } + } + }); + } + + checkCollision(x, y, fish) { + const tolerance = 10; + return x > fish.x - tolerance && + x < fish.x + fish.width + tolerance && + y > fish.y - tolerance && + y < fish.y + fish.height + tolerance; + } + + resetFish(fish) { + if (fish.isOctopus) { + // 章鱼重置到随机位置 + fish.x = Math.random() * this.width; + fish.y = 400 + Math.random() * 100; + fish.caught = false; + fish.direction = Math.random() < 0.5 ? 1 : -1; + return; + } + + const fishType = this.fishTypes[Math.floor(Math.random() * this.fishTypes.length)]; + const wordObj = this.words[Math.floor(Math.random() * this.words.length)]; + + // 更新鱼的大小 + const baseWidth = 50; + const baseHeight = 30; + const scale = fishType.size; + + fish.element.style.width = `${baseWidth * scale}px`; + fish.element.style.height = `${baseHeight * scale}px`; + fish.width = baseWidth * scale; + fish.height = baseHeight * scale; + + fish.x = Math.random() * this.width; + fish.y = 300 + Math.random() * 200; + fish.caught = false; + fish.direction = Math.random() < 0.5 ? 1 : -1; + fish.speed = 1 + Math.random() * 2; + fish.type = fishType; + + // 更新鱼的颜色 + const body = fish.element.querySelector('.fish-body'); + const tail = fish.element.querySelector('.fish-tail'); + const fin = fish.element.querySelector('.fish-fin'); + + body.style.backgroundColor = fishType.color; + tail.style.backgroundColor = fishType.color; + fin.style.backgroundColor = fishType.finColor; + + // 更新单词 + fish.word = wordObj; + const wordDiv = fish.element.querySelector('.fish-word'); + wordDiv.textContent = wordObj.word; + } + + draw() { + this.ctx.clearRect(0, 0, this.width, this.height); + + // 绘制鱼线 + this.ctx.beginPath(); + this.ctx.moveTo(this.fishingRod.x, 0); + this.ctx.lineTo(this.fishingRod.x, this.fishingRod.y + this.fishingRod.lineLength); + this.ctx.strokeStyle = '#FFFFFF'; + this.ctx.lineWidth = 2; // 增加线的宽度使其更明显 + this.ctx.stroke(); + + // 绘制鱼钩 + const hookY = this.fishingRod.y + this.fishingRod.lineLength; + this.ctx.beginPath(); + this.ctx.arc( + this.fishingRod.x, + hookY, + this.fishingRod.hookSize, + 0, + Math.PI * 1.5, + false + ); + this.ctx.strokeStyle = '#FFFFFF'; + this.ctx.lineWidth = 2; + this.ctx.stroke(); + + // 绘制分数 + this.ctx.fillStyle = '#FFFFFF'; + this.ctx.font = 'bold 24px Arial'; + this.ctx.fillText(`总分: ${this.score}`, 10, 60); + + // 绘制鱼的说明 + this.ctx.font = '16px Arial'; + this.fishTypes.forEach((type, index) => { + this.ctx.fillStyle = type.color; + let category; + switch(index) { + case 0: category = '章鱼'; break; + case 1: category = '核心组件 (大)'; break; + case 2: category = '数据处理 (中大)'; break; + case 3: category = '数据存储 (中)'; break; + case 4: category = '工具组件 (小)'; break; + } + this.ctx.fillText(`${category}: ${type.score}分`, 10, 90 + index * 25); + }); + + // 绘制操作提示 + this.ctx.font = '20px Arial'; + this.ctx.fillText('按住空格键放线,松开收线', 10, 30); + + // 添加章鱼说明 + this.ctx.fillStyle = '#800080'; + this.ctx.fillText('章鱼: 10分 (特殊奖励)', 10, 90 + this.fishTypes.length * 25); + } + + gameLoop() { + this.update(); + this.draw(); + requestAnimationFrame(() => this.gameLoop()); + } + + // 添加分数 + addScore(fish) { + this.score += fish.type.score; + this.playCatchSound(); + + // 创建得分动画 + const scoreDiv = document.createElement('div'); + scoreDiv.className = 'score-popup'; + + // 先只显示分数和软件名 + scoreDiv.innerHTML = ` +
+${fish.type.score}
+
+
${fish.word.word}
+
+ `; + scoreDiv.style.left = `${this.fishingRod.x}px`; + scoreDiv.style.top = '100px'; + scoreDiv.style.color = fish.type.color; + this.container.appendChild(scoreDiv); + + // 延迟1秒显示中文含义 + setTimeout(() => { + const meaningDiv = document.createElement('div'); + meaningDiv.className = 'meaning'; + meaningDiv.textContent = fish.word.meaning; + scoreDiv.querySelector('.word-popup').appendChild(meaningDiv); + }, 1000); + + // 6秒后开始淡出动画 + setTimeout(() => { + // 英文先淡出 + scoreDiv.querySelector('.score-text').style.animation = 'fadeOut 1s ease-out'; + scoreDiv.querySelector('.english-word').style.animation = 'fadeOut 1s ease-out'; + + // 2秒后中文再淡出 + setTimeout(() => { + scoreDiv.querySelector('.meaning').style.animation = 'fadeOut 1s ease-out'; + + // 等待中文淡出完成后移除元素 + setTimeout(() => { + this.container.removeChild(scoreDiv); + }, 1000); + }, 2000); + }, 6000); + } + + // 创建海草 + createSeaweed() { + // 创建多株海草 + for (let i = 0; i < 8; i++) { + const seaweed = document.createElement('div'); + seaweed.className = 'seaweed'; + + // 每株海草有3片叶子 + for (let j = 0; j < 3; j++) { + const leaf = document.createElement('div'); + leaf.className = 'seaweed-leaf'; + leaf.style.bottom = `${j * 30}px`; + // 随机调整动画延迟,使得摆动不同步 + leaf.style.animationDelay = `${Math.random() * 2}s`; + seaweed.appendChild(leaf); + } + + // 随机位置 + seaweed.style.left = `${50 + (i * 100) + Math.random() * 30}px`; + // 随机高度 + seaweed.style.height = `${80 + Math.random() * 40}px`; + + this.container.appendChild(seaweed); + } + } + + // 创建海星 + createStarfish() { + // 创建多个海星 + for (let i = 0; i < 5; i++) { + const starfish = document.createElement('div'); + starfish.className = 'starfish'; + + // 固定位置在底部 + starfish.style.left = `${100 + (i * 150) + Math.random() * 50}px`; + starfish.style.bottom = '20px'; // 使用 bottom 而不是 transform + // 随机旋转 + starfish.style.transform = `rotate(${Math.random() * 360}deg)`; + // 随机动画延迟 + starfish.style.animationDelay = `${Math.random() * 2}s`; + + this.container.appendChild(starfish); + this.decorations.starfish.push(starfish); + } + } + + // 创建章鱼 + createOctopus() { + const octopus = document.createElement('div'); + octopus.className = 'octopus'; + + // 创建章鱼头部 + const head = document.createElement('div'); + head.className = 'octopus-head'; + + // 创建眼睛 + const leftEye = document.createElement('div'); + leftEye.className = 'octopus-eye left'; + const rightEye = document.createElement('div'); + rightEye.className = 'octopus-eye right'; + + head.appendChild(leftEye); + head.appendChild(rightEye); + octopus.appendChild(head); + + // 创建触手 + for (let i = 0; i < 8; i++) { + const tentacle = document.createElement('div'); + tentacle.className = 'octopus-tentacle'; + tentacle.style.left = `${i * 9}px`; + tentacle.style.animationDelay = `${i * 0.2}s`; + octopus.appendChild(tentacle); + } + + // 添加单词显示 + const wordDiv = document.createElement('div'); + wordDiv.className = 'fish-word'; + const wordObj = { word: 'Octopus', meaning: '章鱼 - 特殊奖励(+10分)' }; + const wordSpan = document.createElement('span'); + wordSpan.className = 'word-text'; + wordSpan.textContent = wordObj.word; + wordDiv.appendChild(wordSpan); + octopus.appendChild(wordDiv); + + this.container.appendChild(octopus); + + // 添加到鱼群中 + this.fishes.push({ + element: octopus, + x: Math.random() * this.width, + y: 400 + Math.random() * 100, + width: 70, + height: 70, + speed: 0.5 + Math.random() * 1, // 章鱼移动较慢 + direction: Math.random() < 0.5 ? 1 : -1, + caught: false, + type: this.fishTypes[0], // 使用章鱼类型 + word: wordObj, + isOctopus: true + }); + } + + // 添加创建普通鱼的方法 + createFishes() { + // 创建10条普通鱼 + for (let i = 0; i < 10; i++) { + // 跳过章鱼类型 + const fishTypeIndex = 1 + Math.floor(Math.random() * (this.fishTypes.length - 1)); + const fishType = this.fishTypes[fishTypeIndex]; + const fishDiv = document.createElement('div'); + fishDiv.className = 'fish'; + + // 设置鱼的基础大小 + const baseWidth = 50; + const baseHeight = 30; + const scale = fishType.size; + + fishDiv.style.width = `${baseWidth * scale}px`; + fishDiv.style.height = `${baseHeight * scale}px`; + + // 创建鱼的身体部分 + const body = document.createElement('div'); + body.className = 'fish-body'; + body.style.backgroundColor = fishType.color; + fishDiv.appendChild(body); + + // 创建鱼尾 + const tail = document.createElement('div'); + tail.className = 'fish-tail'; + tail.style.backgroundColor = fishType.color; + fishDiv.appendChild(tail); + + // 创建鱼眼 + const eye = document.createElement('div'); + eye.className = 'fish-eye'; + fishDiv.appendChild(eye); + + // 创建鱼鳍 + const fin = document.createElement('div'); + fin.className = 'fish-fin'; + fin.style.backgroundColor = fishType.finColor; + fishDiv.appendChild(fin); + + // 添加单词显示 + const wordDiv = document.createElement('div'); + wordDiv.className = 'fish-word'; + const wordObj = this.words[Math.floor(Math.random() * this.words.length)]; + const wordSpan = document.createElement('span'); + wordSpan.className = 'word-text'; + wordSpan.textContent = wordObj.word; + wordDiv.appendChild(wordSpan); + fishDiv.appendChild(wordDiv); + + this.container.appendChild(fishDiv); + + this.fishes.push({ + element: fishDiv, + x: Math.random() * this.width, + y: 300 + Math.random() * 200, + width: baseWidth * scale, + height: baseHeight * scale, + speed: 1 + Math.random() * 2, + direction: Math.random() < 0.5 ? 1 : -1, + caught: false, + type: fishType, + word: wordObj + }); + } + } +} + +// 初始化游戏 +window.onload = () => { + new Game(); +}; \ No newline at end of file diff --git "a/\345\260\217\344\270\221\351\261\274\346\270\270\346\210\217/index.html" "b/\345\260\217\344\270\221\351\261\274\346\270\270\346\210\217/index.html" new file mode 100644 index 0000000..db06c8e --- /dev/null +++ "b/\345\260\217\344\270\221\351\261\274\346\270\270\346\210\217/index.html" @@ -0,0 +1,270 @@ + + + + + 抓金鱼游戏 + + + +
+ +
+ + + \ No newline at end of file