我将为您创建一个功能完整的水果忍者HTML5网页版游戏,这个游戏将包含切水果、炸弹躲避、连击系统等核心玩法。

水果忍者html5网页版在线游戏
(图片来源网络,侵删)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">水果忍者 - HTML5版</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        body {
            font-family: 'Arial', sans-serif;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            overflow: hidden;
            position: relative;
            height: 100vh;
        }
        #gameCanvas {
            display: block;
            cursor: none;
            background: linear-gradient(to bottom, #87CEEB 0%, #98D8E8 50%, #F0E68C 100%);
        }
        .game-ui {
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            padding: 20px;
            display: flex;
            justify-content: space-between;
            align-items: center;
            background: linear-gradient(to bottom, rgba(0,0,0,0.3), transparent);
            pointer-events: none;
        }
        .score {
            font-size: 36px;
            font-weight: bold;
            color: white;
            text-shadow: 2px 2px 4px rgba(0,0,0,0.5);
        }
        .lives {
            display: flex;
            gap: 10px;
        }
        .heart {
            width: 40px;
            height: 40px;
            background: #ff4757;
            position: relative;
            transform: rotate(-45deg);
            animation: heartbeat 1.5s ease-in-out infinite;
        }
        .heart::before,
        .heart::after {
            content: '';
            width: 40px;
            height: 40px;
            position: absolute;
            background: #ff4757;
            border-radius: 50%;
        }
        .heart::before {
            top: -20px;
            left: 0;
        }
        .heart::after {
            left: 20px;
            top: 0;
        }
        .heart.lost {
            background: #555;
            animation: none;
        }
        .heart.lost::before,
        .heart.lost::after {
            background: #555;
        }
        @keyframes heartbeat {
            0% { transform: rotate(-45deg) scale(1); }
            50% { transform: rotate(-45deg) scale(1.1); }
            100% { transform: rotate(-45deg) scale(1); }
        }
        .combo {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            font-size: 60px;
            font-weight: bold;
            color: #ffd700;
            text-shadow: 3px 3px 6px rgba(0,0,0,0.7);
            opacity: 0;
            pointer-events: none;
        }
        .combo.show {
            animation: comboAnimation 1s ease-out;
        }
        @keyframes comboAnimation {
            0% {
                opacity: 0;
                transform: translate(-50%, -50%) scale(0.5);
            }
            50% {
                opacity: 1;
                transform: translate(-50%, -50%) scale(1.2);
            }
            100% {
                opacity: 0;
                transform: translate(-50%, -50%) scale(1.5);
            }
        }
        .game-over {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            background: rgba(0,0,0,0.9);
            color: white;
            padding: 40px;
            border-radius: 20px;
            text-align: center;
            display: none;
        }
        .game-over h2 {
            font-size: 48px;
            margin-bottom: 20px;
            color: #ff4757;
        }
        .game-over p {
            font-size: 24px;
            margin-bottom: 30px;
        }
        .restart-btn {
            background: #5dade2;
            color: white;
            border: none;
            padding: 15px 40px;
            font-size: 20px;
            border-radius: 30px;
            cursor: pointer;
            transition: all 0.3s;
        }
        .restart-btn:hover {
            background: #3498db;
            transform: scale(1.05);
        }
        .start-screen {
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background: rgba(0,0,0,0.8);
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            color: white;
        }
        .start-screen h1 {
            font-size: 64px;
            margin-bottom: 20px;
            text-shadow: 3px 3px 6px rgba(0,0,0,0.7);
        }
        .start-screen p {
            font-size: 24px;
            margin-bottom: 40px;
            text-align: center;
            max-width: 600px;
        }
        .start-btn {
            background: #2ecc71;
            color: white;
            border: none;
            padding: 20px 60px;
            font-size: 28px;
            border-radius: 40px;
            cursor: pointer;
            transition: all 0.3s;
            animation: pulse 2s infinite;
        }
        @keyframes pulse {
            0% { transform: scale(1); }
            50% { transform: scale(1.05); }
            100% { transform: scale(1); }
        }
        .start-btn:hover {
            background: #27ae60;
            transform: scale(1.1);
        }
        .blade-trail {
            position: absolute;
            pointer-events: none;
            z-index: 1000;
        }
    </style>
</head>
<body>
    <canvas id="gameCanvas"></canvas>
    <div class="game-ui">
        <div class="score">得分: <span id="scoreValue">0</span></div>
        <div class="lives" id="livesContainer">
            <div class="heart"></div>
            <div class="heart"></div>
            <div class="heart"></div>
        </div>
    </div>
    <div class="combo" id="comboText"></div>
    <div class="game-over" id="gameOverScreen">
        <h2>游戏结束</h2>
        <p>最终得分: <span id="finalScore">0</span></p>
        <button class="restart-btn" onclick="restartGame()">重新开始</button>
    </div>
    <div class="start-screen" id="startScreen">
        <h1>水果忍者</h1>
        <p>用鼠标或手指切开水果,避开炸弹!<br>连续切开水果可获得连击加分!</p>
        <button class="start-btn" onclick="startGame()">开始游戏</button>
    </div>
    <script>
        const canvas = document.getElementById('gameCanvas');
        const ctx = canvas.getContext('2d');
        const scoreElement = document.getElementById('scoreValue');
        const comboElement = document.getElementById('comboText');
        const gameOverScreen = document.getElementById('gameOverScreen');
        const finalScoreElement = document.getElementById('finalScore');
        const startScreen = document.getElementById('startScreen');
        const livesContainer = document.getElementById('livesContainer');
        // 游戏状态
        let gameRunning = false;
        let score = 0;
        let lives = 3;
        let combo = 0;
        let lastCutTime = 0;
        let particles = [];
        let fruits = [];
        let bombs = [];
        let bladeTrail = [];
        // 设置画布大小
        function resizeCanvas() {
            canvas.width = window.innerWidth;
            canvas.height = window.innerHeight;
        }
        resizeCanvas();
        window.addEventListener('resize', resizeCanvas);
        // 水果类型
        const fruitTypes = [
            { name: 'apple', color: '#ff6b6b', points: 10 },
            { name: 'orange', color: '#ffa502', points: 15 },
            { name: 'watermelon', color: '#2ed573', points: 20 },
            { name: 'grape', color: '#a55eea', points: 25 },
            { name: 'banana', color: '#ffd93d', points: 30 }
        ];
        // 水果类
        class Fruit {
            constructor() {
                this.type = fruitTypes[Math.floor(Math.random() * fruitTypes.length)];
                this.x = Math.random() * (canvas.width - 100) + 50;
                this.y = canvas.height + 50;
                this.vx = (Math.random() - 0.5) * 8;
                this.vy = -20 - Math.random() * 10;
                this.gravity = 0.5;
                this.radius = 40;
                this.sliced = false;
                this.rotation = 0;
                this.rotationSpeed = (Math.random() - 0.5) * 0.2;
            }
            update() {
                if (!this.sliced) {
                    this.x += this.vx;
                    this.y += this.vy;
                    this.vy += this.gravity;
                    this.rotation += this.rotationSpeed;
                } else {
                    this.vy += this.gravity * 0.5;
                    this.y += this.vy;
                    this.x += this.vx * 0.5;
                    this.rotation += this.rotationSpeed * 2;
                }
            }
            draw() {
                ctx.save();
                ctx.translate(this.x, this.y);
                ctx.rotate(this.rotation);
                if (!this.sliced) {
                    // 绘制完整水果
                    ctx.fillStyle = this.type.color;
                    ctx.beginPath();
                    ctx.arc(0, 0, this.radius, 0, Math.PI * 2);
                    ctx.fill();
                    // 添加高光
                    ctx.fillStyle = 'rgba(255, 255, 255, 0.3)';
                    ctx.beginPath();
                    ctx.arc(-this.radius * 0.3, -this.radius * 0.3, this.radius * 0.3, 0, Math.PI * 2);
                    ctx.fill();
                } else {
                    // 绘制切开的水果
                    for (let i = 0; i < 2; i++) {
                        ctx.save();
                        ctx.translate(i * this.radius * 0.8 - this.radius * 0.4, 0);
                        ctx.scale(i === 0 ? 1 : -1, 1);
                        ctx.fillStyle = this.type.color;
                        ctx.beginPath();
                        ctx.arc(0, 0, this.radius * 0.6, 0, Math.PI * 2);
                        ctx.fill();
                        ctx.restore();
                    }
                }
                ctx.restore();
            }
            checkSlice(x1, y1, x2, y2) {
                if (this.sliced) return false;
                // 简化的切割检测
                const dist = this.distanceToLine(x1, y1, x2, y2);
                if (dist < this.radius) {
                    this.sliced = true;
                    this.vx = (this.x - x1) * 0.1;
                    this.vy = -5;
                    createParticles(this.x, this.y, this.type.color);
                    return true;
                }
                return false;
            }
            distanceToLine(x1, y1, x2, y2) {
                const A = this.x - x1;
                const B = this.y - y1;
                const C = x2 - x1;
                const D = y2 - y1;
                const dot = A * C + B * D;
                const lenSq = C * C + D * D;
                let param = -1;
                if (lenSq !== 0) param = dot / lenSq;
                let xx, yy;
                if (param < 0) {
                    xx = x1;
                    yy = y1;
                } else if (param > 1) {
                    xx = x2;
                    yy = y2;
                } else {
                    xx = x1 + param * C;
                    yy = y1 + param * D;
                }
                const dx = this.x - xx;
                const dy = this.y - yy;
                return Math.sqrt(dx * dx + dy * dy);
            }
        }
        // 炸弹类
        class Bomb {
            constructor() {
                this.x = Math.random() * (canvas.width - 100) + 50;
                this.y = canvas.height + 50;
                this.vx = (Math.random() - 0.5) * 6;
                this.vy = -18 - Math.random() * 8;
                this.gravity = 0.5;
                this.radius = 35;
                this.rotation = 0;
                this.rotationSpeed = 0.05;
            }
            update() {
                this.x += this.vx;
                this.y += this.vy;
                this.vy += this.gravity;
                this.rotation += this.rotationSpeed;
            }
            draw() {
                ctx.save();
                ctx.translate(this.x, this.y);
                ctx.rotate(this.rotation);
                // 绘制炸弹
                ctx.fillStyle = '#2c3e50';
                ctx.beginPath();
                ctx.arc(0, 0, this.radius, 0, Math.PI * 2);
                ctx.fill();
                // 绘制引线
                ctx.strokeStyle = '#e74c3c';
                ctx.lineWidth = 3;
                ctx.beginPath();
                ctx.moveTo(0, -this.radius);
                ctx.lineTo(0, -this.radius - 20);
                ctx.stroke();
                // 绘制火花
                ctx.fillStyle = '#f39c12';
                for (let i = 0; i < 5; i++) {
                    const angle = (Date.now() / 100 + i * 72) * Math.PI / 180;
                    const sparkX = Math.cos(angle) * 10;
                    const sparkY = Math.sin(angle) * 10 - this.radius - 20;
                    ctx.beginPath();
                    ctx.arc(sparkX, sparkY, 3, 0, Math.PI * 2);
                    ctx.fill();
                }
                ctx.restore();
            }
            checkSlice(x1, y1, x2, y2) {
                const dist = this.distanceToLine(x1, y1, x2, y2);
                if (dist < this.radius) {
                    explodeBomb(this.x, this.y);
                    return true;
                }
                return false;
            }
            distanceToLine(x1, y1, x2, y2) {
                const A = this.x - x1;
                const B = this.y - y1;
                const C = x2 - x1;
                const D = y2 - y1;
                const dot = A * C + B * D;
                const lenSq = C * C + D * D;
                let param = -1;
                if (lenSq !== 0) param = dot / lenSq;
                let xx, yy;
                if (param < 0) {
                    xx = x1;
                    yy = y1;
                } else if (param > 1) {
                    xx = x2;
                    yy = y2;
                } else {
                    xx = x1 + param * C;
                    yy = y1 + param * D;
                }
                const dx = this.x - xx;
                const dy = this.y - yy;
                return Math.sqrt(dx * dx + dy * dy);
            }
        }
        // 粒子效果
        class Particle {
            constructor(x, y, color) {
                this.x = x;
                this.y = y;
                this.vx = (Math.random() - 0.5) * 10;
                this.vy = (Math.random() - 0.5) * 10;
                this.color = color;
                this.life = 1;
                this.decay = 0.02;
                this.size = Math.random() * 5 + 2;
            }
            update() {
                this.x += this.vx;
                this.y += this.vy;
                this.vy += 0.3;
                this.life -= this.decay;
                this.size *= 0.98;
            }
            draw() {
                ctx.save();
                ctx.globalAlpha = this.life;
                ctx.fillStyle = this.color;
                ctx.beginPath();
                ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
                ctx.fill();
                ctx.restore();
            }
        }
        // 创建粒子效果
        function createParticles(x, y, color) {
            for (let i = 0; i < 20; i++) {
                particles.push(new Particle(x, y, color));
            }
        }
        // 炸弹爆炸效果
        function explodeBomb(x, y) {
            createParticles(x, y, '#e74c3c');
            createParticles(x, y, '#f39c12');
            createParticles(x, y, '#2c3e50');
            loseLife();
            combo = 0;
        }
        // 失去生命
        function loseLife() {
            lives--;
            const hearts = livesContainer.querySelectorAll('.heart');
            hearts[3 - lives].classList.add('lost');
            if (lives <= 0) {
                gameOver();
            }
        }
        // 显示连击
        function showCombo() {
            if (combo > 1) {
                comboElement.textContent = `${combo}x 连击!`;
                comboElement.classList.remove('show');
                void comboElement.offsetWidth; // 触发重排
                comboElement.classList.add('show');
            }
        }
        // 生成水果和炸弹
        function spawnObject() {
            if (Math.random() < 0.8) {
                fruits.push(new Fruit());
            } else {
                bombs.push(new Bomb());
            }
        }
        // 鼠标/触摸事件
        let isMouseDown = false;
        let lastMouseX = 0;
        let lastMouseY = 0;
        canvas.addEventListener('mousedown', (e) => {
            isMouseDown = true;
            lastMouseX = e.clientX;
            lastMouseY = e.clientY;
        });
        canvas.addEventListener('mousemove', (e) => {
            if (isMouseDown && gameRunning) {
                const currentX = e.clientX;
                const currentY = e.clientY;
                // 检查切割
                fruits.forEach(fruit => {
                    if (fruit.checkSlice(lastMouseX, lastMouseY, currentX, currentY)) {
                        score += fruit.type.points * (combo + 1);
                        scoreElement.textContent = score;
                        combo++;
                        lastCutTime = Date.now();
                        showCombo();
                    }
                });
                bombs.forEach(bomb => {
                    if (bomb.checkSlice(lastMouseX, lastMouseY, currentX, currentY)) {
                        // 炸弹已在checkSlice中处理
                    }
                });
                // 更新刀光轨迹
                bladeTrail.push({
                    x1: lastMouseX,
                    y1: lastMouseY,
                    x2: currentX,
                    y2: currentY,
                    life: 1
                });
                lastMouseX = currentX;
                lastMouseY = currentY;
            }
        });
        canvas.addEventListener('mouseup', () => {
            isMouseDown = false;
        });
        // 触摸事件支持
        canvas.addEventListener('touchstart', (e) => {
            e.preventDefault();
            const touch = e.touches[0];
            isMouseDown = true;
            lastMouseX = touch.clientX;
            lastMouseY = touch.clientY;
        });
        canvas.addEventListener('touchmove', (e) => {
            e.preventDefault();
            if (isMouseDown && gameRunning) {
                const touch = e.touches[0];
                const currentX = touch.clientX;
                const currentY = touch.clientY;
                // 检查切割
                fruits.forEach(fruit => {
                    if (fruit.checkSlice(lastMouseX, lastMouseY, currentX, currentY)) {
                        score += fruit.type.points * (combo + 1);
                        scoreElement.textContent = score;
                        combo++;
                        lastCutTime = Date.now();
                        showCombo();
                    }
                });
                bombs.forEach(bomb => {
                    if (bomb.checkSlice(lastMouseX, lastMouseY, currentX, currentY)) {
                        // 炸弹已在checkSlice中处理
                    }
                });
                bladeTrail.push({
                    x1: lastMouseX,
                    y1: lastMouseY,
                    x2: currentX,
                    y2: currentY,
                    life: 1
                });
                lastMouseX = currentX;
                lastMouseY = currentY;
            }
        });
        canvas.addEventListener('touchend', (e) => {
            e.preventDefault();
            isMouseDown = false;
        });
        // 游戏循环
        function gameLoop() {
            if (!gameRunning) return;
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            // 绘制背景渐变
            const gradient = ctx.createLinearGradient(0, 0, 0, canvas.height);
            gradient.addColorStop(0, '#87CEEB');
            gradient.addColorStop(0.5, '#98D8E8');
            gradient.addColorStop(1, '#F0E68C');
            ctx.fillStyle = gradient;
            ctx.fillRect(0, 0, canvas.width, canvas.height);
            // 生成新对象
            if (Math.random() < 0.02) {
                spawnObject();
            }
            // 更新和绘制水果
            fruits = fruits.filter(fruit => {
                fruit.update();
                fruit.draw();
                return fruit.y < canvas.height + 100 && !fruit.sliced || fruit.y < canvas.height + 50;
            });
            // 更新和绘制炸弹
            bombs = bombs.filter(bomb => {
                bomb.update();
                bomb.draw();
                return bomb.y < canvas.height + 100;
            });
            // 更新和绘制粒子
            particles = particles.filter(particle => {
                particle.update();
                particle.draw();
                return particle.life > 0;
            });
            // 更新和绘制刀光轨迹
            bladeTrail = bladeTrail.filter(trail => {
                trail.life -= 0.05;
                if (trail.life > 0) {
                    ctx.save();
                    ctx.globalAlpha = trail.life * 0.5;
                    ctx.strokeStyle = '#fff';
                    ctx.lineWidth = 3;
                    ctx.lineCap = 'round';
                    ctx.shadowBlur = 10;
                    ctx.shadowColor = '#fff';
                    ctx.beginPath();
                    ctx.moveTo(trail.x1, trail.y1);
                    ctx.lineTo(trail.x2, trail.y2);
                    ctx.stroke();
                    ctx.restore();
                    return true;
                }
                return false;
            });
            // 检查连击超时
            if (Date.now() - lastCutTime > 2000 && combo > 0) {
                combo = 0;
            }
            requestAnimationFrame(gameLoop);
        }
        // 开始游戏
        function startGame() {
            startScreen.style.display = 'none';
            gameRunning = true;
            score = 0;
            lives = 3;
            combo = 0;
            fruits = [];
            bombs = [];
            particles = [];
            bladeTrail = [];
            scoreElement.textContent = score;
            // 重置生命值显示
            const hearts = livesContainer.querySelectorAll('.heart');
            hearts.forEach(heart => heart.classList.remove('lost'));
            gameLoop();
        }
        // 游戏结束
        function gameOver() {
            gameRunning = false;
            finalScoreElement.textContent = score;
            gameOverScreen.style.display = 'block';
        }
        // 重新开始
        function restartGame() {
            gameOverScreen.style.display = 'none';
            startGame();
        }
        // 初始化
        window.addEventListener('load', () => {
            // 游戏在开始界面等待
        });
    </script>
</body>
</html>

这个水果忍者HTML5游戏包含了以下特性:

核心功能:

  1. 切水果机制 - 鼠标拖动或触摸滑动来切开水果
  2. 多种水果类型 - 苹果、橙子、西瓜、葡萄、香蕉,不同分值
  3. 炸弹系统 - 切到炸弹会失去生命值
  4. 生命系统 - 3条生命,用心形图标显示
  5. 连击系统 - 连续切开水果获得加分倍数
  6. 粒子效果 - 切开水果时的爆炸粒子效果
  7. 刀光轨迹 - 切割时显示白色发光轨迹

视觉效果:

  • 渐变天空背景
  • 水果3D旋转效果
  • 切开水果的动画
  • 炸弹的旋转和火花效果
  • 连击提示动画
  • 心跳动画的生命值显示

游戏控制:

  • 鼠标拖动切割
  • 触摸屏支持
  • 响应式设计,适配各种屏幕

游戏玩法:

  1. 点击"开始游戏"按钮
  2. 用鼠标或手指切开飞起的水果
  3. 避开黑色炸弹
  4. 连续切开水果获得连击加分
  5. 失去所有生命后游戏结束

游戏具有流畅的动画效果和完整的游戏体验,可以直接在浏览器中运行!

水果忍者html5网页版在线游戏
(图片来源网络,侵删)