Web网页开发——水果忍者

时间:2025-02-27 08:57:44
// Game variables const canvas = document.getElementById('gameCanvas'); const ctx = canvas.getContext('2d'); const startScreen = document.getElementById('startScreen'); const gameOverScreen = document.getElementById('gameOverScreen'); const startButton = document.getElementById('startButton'); const restartButton = document.getElementById('restartButton'); const scoreDisplay = document.getElementById('scoreDisplay'); const finalScore = document.getElementById('finalScore'); let score = 0; let gameActive = false; let gameObjects = []; let sliceTrail = []; let sliceActive = false; let lastTimestamp = 0; let spawnTimer = 0; let comboCount = 0; let comboTimer = 0; // Resize canvas function resizeCanvas() { canvas.width = window.innerWidth; canvas.height = window.innerHeight; } // Initialize game function initGame() { resizeCanvas(); score = 0; gameObjects = []; sliceTrail = []; sliceActive = false; scoreDisplay.textContent = score; gameActive = true; lastTimestamp = 0; spawnTimer = 0; // Start animation requestAnimationFrame(gameLoop); } // Game objects classes class GameObject { constructor(x, y, type) { this.x = x; this.y = y; this.type = type; this.sliced = false; this.velocityX = Math.random() * 8 - 4; this.velocityY = -15 - Math.random() * 5; this.gravity = 0.5; this.rotation = 0; this.rotationSpeed = Math.random() * 0.1 - 0.05; this.size = 40 + Math.random() * 20; if (this.type === 'banana') { this.color = '#FFD700'; } else if (this.type === 'bomb') { this.color = '#333'; this.size = 30 + Math.random() * 10; } else if (this.type === 'pomegranate') { this.color = '#FF4500'; this.size = 50 + Math.random() * 10; } else if (this.type === 'watermelon') { this.color = '#32CD32'; this.size = 60 + Math.random() * 10; } else { // Default apple this.color = '#FF0000'; } this.slicedColor1 = this.color; this.slicedColor2 = this.type === 'watermelon' ? '#FF6347' : this.color; // For slice animation this.sliceAngle = 0; this.slicePart1 = { x: 0, y: 0, vx: 0, vy: 0, rotation: 0 }; this.slicePart2 = { x: 0, y: 0, vx: 0, vy: 0, rotation: 0 }; } update() { if (this.sliced) { // Update sliced parts this.slicePart1.x += this.slicePart1.vx; this.slicePart1.y += this.slicePart1.vy; this.slicePart1.vy += this.gravity; this.slicePart1.rotation += 0.05; this.slicePart2.x += this.slicePart2.vx; this.slicePart2.y += this.slicePart2.vy; this.slicePart2.vy += this.gravity; this.slicePart2.rotation += 0.05; return this.slicePart1.y < canvas.height && this.slicePart2.y < canvas.height; } else { // Update normal object this.x += this.velocityX; this.y += this.velocityY; this.velocityY += this.gravity; this.rotation += this.rotationSpeed; return this.y < canvas.height + 100; } } draw() { ctx.save(); if (this.sliced) { // Draw first slice part ctx.save(); ctx.translate(this.slicePart1.x, this.slicePart1.y); ctx.rotate(this.slicePart1.rotation); ctx.beginPath(); ctx.arc(0, 0, this.size / 2, 0, Math.PI, false); ctx.fillStyle = this.slicedColor1; ctx.fill(); if (this.type === 'watermelon') { ctx.beginPath(); ctx.arc(0, 0, this.size / 2 - 5, 0, Math.PI, false); ctx.fillStyle = this.slicedColor2; ctx.fill(); } ctx.restore(); // Draw second slice part ctx.save(); ctx.translate(this.slicePart2.x, this.slicePart2.y); ctx.rotate(this.slicePart2.rotation); ctx.beginPath(); ctx.arc(0, 0, this.size / 2, Math.PI, 2 * Math.PI, false); ctx.fillStyle = this.slicedColor1; ctx.fill(); if (this.type === 'watermelon') { ctx.beginPath(); ctx.arc(0, 0, this.size / 2 - 5, Math.PI, 2 * Math.PI, false); ctx.fillStyle = this.slicedColor2; ctx.fill(); } ctx.restore(); } else { // Draw normal object ctx.translate(this.x, this.y); ctx.rotate(this.rotation); if (this.type === 'bomb') { // Draw bomb ctx.beginPath(); ctx.arc(0, 0, this.size / 2, 0, 2 * Math.PI); ctx.fillStyle = this.color; ctx.fill(); // Draw fuse ctx.beginPath(); ctx.moveTo(0, -this.size / 2); ctx.quadraticCurveTo(10, -this.size / 2 - 15, 20, -this.size / 2 - 10); ctx.lineWidth = 3; ctx.strokeStyle = '#8B4513'; ctx.stroke(); } else if (this.type === 'banana') { // Draw banana ctx.beginPath(); ctx.arc(0, 0, this.size / 2, 0.3 * Math.PI, 1.7 * Math.PI); ctx.lineWidth = this.size / 2; ctx.strokeStyle = this.color; ctx.stroke(); } else if (this.type === 'watermelon') { // Draw watermelon ctx.beginPath(); ctx.arc(0, 0, this.size / 2, 0, 2 * Math.PI); ctx.fillStyle = '#32CD32'; ctx.fill(); // Inner part ctx.beginPath(); ctx.arc(0, 0, this.size / 2 - 5, 0, 2 * Math.PI); ctx.fillStyle = '#FF6347'; ctx.fill(); // Seeds ctx.fillStyle = 'black'; for (let i = 0; i < 8; i++) { const angle = i * (Math.PI / 4); const distance = this.size / 4; ctx.beginPath(); ctx.ellipse( Math.cos(angle) * distance, Math.sin(angle) * distance, 3, 5, angle, 0, 2 * Math.PI ); ctx.fill(); } } else if (this.type === 'pomegranate') { // Draw pomegranate ctx.beginPath(); ctx.arc(0, 0, this.size / 2, 0, 2 * Math.PI); ctx.fillStyle = this.color; ctx.fill(); // Crown ctx.beginPath(); ctx.moveTo(-10, -this.size / 2); ctx.lineTo(10, -this.size / 2); ctx.lineTo(0, -this.size / 2 - 10); ctx.closePath(); ctx.fillStyle = '#8B4513'; ctx.fill(); } else { // Draw apple ctx.beginPath(); ctx.arc(0, 0, this.size / 2, 0, 2 * Math.PI); ctx.fillStyle = this.color; ctx.fill(); // Stem ctx.beginPath(); ctx.moveTo(0, -this.size / 2); ctx.lineTo(0, -this.size / 2 - 7); ctx.lineWidth = 3; ctx.strokeStyle = '#8B4513'; ctx.stroke(); } } ctx.restore(); } checkSlice(slicePath) { if (this.sliced) return false; // Check if the slice path intersects with the object for (let i = 1; i < slicePath.length; i++) { const x1 = slicePath[i-1].x; const y1 = slicePath[i-1].y; const x2 = slicePath[i].x; const y2 = slicePath[i].y; // Calculate distance from line segment to center of object const distance = distToSegment(this.x, this.y, x1, y1, x2, y2); if (distance < this.size / 2) { // Calculate slice angle this.sliceAngle = Math.atan2(y2 - y1, x2 - x1); // Set the slice parts this.slicePart1.x = this.x; this.slicePart1.y = this.y; this.slicePart1.vx = this.velocityX - 1 + Math.random() * 2; this.slicePart1.vy = this.velocityY - 2; this.slicePart2.x =