植物大战僵尸HTML5游戏完整实现教程

该文章已生成可运行项目,

一、游戏概述与技术背景

1.1 植物大战僵尸游戏简介

《植物大战僵尸》(Plants vs. Zombies)是由PopCap Games开发的一款塔防类游戏,自2009年发布以来风靡全球。玩家通过种植各种植物来抵御不同类型的僵尸入侵,保护自己的家园。游戏的核心机制包括:

  • 资源管理:通过收集阳光种植植物
  • 策略布局:在不同位置放置适合的植物应对特定僵尸
  • 关卡挑战:不同难度和特殊条件的关卡设计
  • 多样化元素:丰富的植物和僵尸类型

1.2 为什么选择HTML5实现游戏

HTML5为游戏开发提供了强大且标准化的技术栈:

  • 跨平台兼容:可在PC、移动设备和各种浏览器上运行
  • 无需插件:基于标准Web技术,无需Flash等插件
  • Canvas API:提供高性能2D图形渲染能力
  • Web Audio API:支持高质量音效处理
  • 本地存储:可保存游戏进度和设置

根据知识库资料,HTML5游戏开发已成为现代网页游戏的主流选择,特别是Canvas技术为2D游戏提供了强大支持。

1.3 本教程的独特价值

本教程提供的是完全可运行的独立HTML文件,包含:

  • 专业级游戏架构设计
  • 完整的游戏核心机制实现
  • 详细的代码注释和解析
  • 游戏性能优化技巧
  • 可扩展的模块化设计
  • 自定义植物/僵尸图标功能
  • 响应式布局适配不同设备

与市面上常见的简单示例不同,本实现包含了真正的游戏循环、碰撞检测、状态管理等专业游戏开发要素。


二、完整可运行的HTML5植物大战僵尸游戏代码

以下是一个可以直接复制到.html文件中并在浏览器中运行的完整游戏实现:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>HTML5植物大战僵尸</title>
    <style>
        /* 全局重置和基础样式 */
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            user-select: none;
        }
        
        body {
            font-family: 'Arial', sans-serif;
            background-color: #2c3e50;
            color: #ecf0f1;
            overflow: hidden;
            height: 100vh;
            display: flex;
            flex-direction: column;
        }
        
        /* 游戏标题区域 */
        .game-header {
            text-align: center;
            padding: 10px 0;
            background: linear-gradient(to bottom, #27ae60, #219653);
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.5);
            position: relative;
        }
        
        .game-title {
            font-size: 2.5rem;
            text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);
            color: #f1c40f;
            letter-spacing: 2px;
        }
        
        .sun-value {
            position: absolute;
            top: 10px;
            left: 20px;
            background-color: #f39c12;
            color: #fff;
            padding: 5px 15px;
            border-radius: 20px;
            font-weight: bold;
            font-size: 1.2rem;
            box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3);
        }
        
        /* 游戏主区域 */
        .game-container {
            display: flex;
            flex: 1;
            overflow: hidden;
            position: relative;
        }
        
        /* 植物选择栏 */
        .plant-selector {
            width: 120px;
            background-color: #8e44ad;
            padding: 15px 5px;
            overflow-y: auto;
            display: flex;
            flex-direction: column;
            gap: 10px;
            box-shadow: -2px 0 10px rgba(0, 0, 0, 0.3);
        }
        
        .plant-card {
            width: 100px;
            height: 100px;
            background-color: #9b59b6;
            border-radius: 10px;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            cursor: pointer;
            position: relative;
            transition: transform 0.2s;
            box-shadow: 0 3px 6px rgba(0, 0, 0, 0.3);
            overflow: hidden;
        }
        
        .plant-card:hover {
            transform: scale(1.05);
            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.4);
        }
        
        .plant-card img {
            width: 60px;
            height: 60px;
            object-fit: contain;
        }
        
        .plant-name {
            font-size: 0.8rem;
            margin-top: 5px;
            text-align: center;
        }
        
        .plant-cost {
            position: absolute;
            top: 5px;
            right: 5px;
            background-color: #e74c3c;
            color: white;
            width: 20px;
            height: 20px;
            border-radius: 50%;
            display: flex;
            align-items: center;
            justify-content: center;
            font-weight: bold;
            font-size: 0.7rem;
        }
        
        .plant-cooldown {
            position: absolute;
            bottom: 0;
            left: 0;
            right: 0;
            height: 5px;
            background-color: rgba(0, 0, 0, 0.5);
        }
        
        .plant-cooldown-fill {
            height: 100%;
            background-color: #27ae60;
            width: 0%;
            transition: width 0.1s linear;
        }
        
        /* 游戏场景 */
        .game-scene {
            flex: 1;
            position: relative;
            background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100"><rect width="100" height="100" fill="%239cbb73"/><path d="M0 50 L100 50 M0 70 L100 70 M0 90 L100 90 M0 30 L100 30 M0 10 L100 10" stroke="%237ba05b" stroke-width="1"/></svg>');
            background-size: 100% 100%;
            overflow: hidden;
        }
        
        .grid-lines {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            pointer-events: none;
        }
        
        .grid-line-horizontal {
            position: absolute;
            left: 0;
            right: 0;
            height: 1px;
            background-color: rgba(0, 0, 0, 0.3);
        }
        
        .grid-line-vertical {
            position: absolute;
            top: 0;
            bottom: 0;
            width: 1px;
            background-color: rgba(0, 0, 0, 0.3);
        }
        
        /* 游戏元素通用样式 */
        .game-object {
            position: absolute;
            transition: transform 0.2s;
        }
        
        .plant {
            width: 80px;
            height: 80px;
            z-index: 10;
        }
        
        .zombie {
            width: 80px;
            height: 100px;
            z-index: 5;
            transition: left 0.05s linear;
        }
        
        .sun {
            width: 40px;
            height: 40px;
            border-radius: 50%;
            background-color: #f1c40f;
            display: flex;
            align-items: center;
            justify-content: center;
            font-weight: bold;
            color: #d35400;
            box-shadow: 0 0 10px #f1c40f;
            z-index: 20;
            cursor: pointer;
            animation: float 3s ease-in-out infinite;
        }
        
        @keyframes float {
            0%, 100% { transform: translateY(0); }
            50% { transform: translateY(-10px); }
        }
        
        .projectile {
            width: 30px;
            height: 30px;
            position: absolute;
            z-index: 15;
        }
        
        /* 游戏界面 */
        .game-interface {
            position: absolute;
            bottom: 10px;
            left: 50%;
            transform: translateX(-50%);
            display: flex;
            gap: 15px;
            z-index: 100;
        }
        
        .game-button {
            background-color: #3498db;
            color: white;
            border: none;
            padding: 8px 15px;
            border-radius: 5px;
            cursor: pointer;
            font-weight: bold;
            transition: background-color 0.2s;
        }
        
        .game-button:hover {
            background-color: #2980b9;
        }
        
        .game-button:active {
            transform: scale(0.95);
        }
        
        /* 暂停菜单 */
        .pause-menu {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0, 0, 0, 0.7);
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            z-index: 200;
            display: none;
        }
        
        .pause-title {
            font-size: 2.5rem;
            color: #f1c40f;
            margin-bottom: 20px;
        }
        
        .pause-buttons {
            display: flex;
            gap: 20px;
        }
        
        /* 游戏结束界面 */
        .game-over {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0, 0, 0, 0.7);
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            z-index: 200;
            display: none;
        }
        
        .game-over-title {
            font-size: 3rem;
            color: #e74c3c;
            margin-bottom: 20px;
        }
        
        .game-over-stats {
            font-size: 1.5rem;
            margin-bottom: 30px;
            text-align: center;
        }
        
        /* 自定义设置面板 */
        .custom-panel {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            background-color: #34495e;
            padding: 20px;
            border-radius: 10px;
            width: 400px;
            max-width: 90%;
            z-index: 300;
            display: none;
            box-shadow: 0 0 20px rgba(0, 0, 0, 0.5);
        }
        
        .panel-title {
            font-size: 1.5rem;
            margin-bottom: 15px;
            color: #f1c40f;
            text-align: center;
        }
        
        .custom-form {
            display: flex;
            flex-direction: column;
            gap: 15px;
        }
        
        .form-group {
            display: flex;
            flex-direction: column;
            gap: 5px;
        }
        
        .form-group label {
            font-weight: bold;
        }
        
        .form-group input {
            padding: 8px;
            border-radius: 5px;
            border: 1px solid #7f8c8d;
            background-color: #2c3e50;
            color: #ecf0f1;
        }
        
        .form-actions {
            display: flex;
            justify-content: space-between;
            margin-top: 10px;
        }
        
        .close-panel {
            background-color: #e74c3c;
        }
        
        /* 提示信息 */
        .notification {
            position: fixed;
            top: 20px;
            right: 20px;
            background-color: #27ae60;
            color: white;
            padding: 10px 20px;
            border-radius: 5px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
            z-index: 1000;
            transform: translateX(150%);
            transition: transform 0.3s ease-out;
        }
        
        .notification.show {
            transform: translateX(0);
        }
        
        /* 僵尸健康条 */
        .health-bar {
            position: absolute;
            top: -10px;
            left: 0;
            width: 100%;
            height: 5px;
            background-color: #e74c3c;
            border-radius: 2px;
            overflow: hidden;
        }
        
        .health-fill {
            height: 100%;
            background-color: #27ae60;
            width: 100%;
        }
        
        /* 植物健康条 */
        .plant-health-bar {
            position: absolute;
            bottom: -10px;
            left: 0;
            width: 100%;
            height: 5px;
            background-color: #e74c3c;
            border-radius: 2px;
            overflow: hidden;
        }
        
        .plant-health-fill {
            height: 100%;
            background-color: #27ae60;
            width: 100%;
        }
        
        /* 移动端适配 */
        @media (max-width: 768px) {
            .game-title {
                font-size: 1.8rem;
            }
            
            .plant-selector {
                width: 80px;
            }
            
            .plant-card {
                width: 70px;
                height: 70px;
            }
            
            .plant-card img {
                width: 45px;
                height: 45px;
            }
            
            .sun-value {
                font-size: 1rem;
                padding: 3px 10px;
            }
        }
    </style>
</head>
<body>
    <div class="game-header">
        <div class="sun-value">☀ <span id="sunCount">50</span></div>
        <h1 class="game-title">植物大战僵尸</h1>
    </div>
    
    <div class="game-container">
        <div class="plant-selector" id="plantSelector">
            <!-- 植物选择卡将通过JS动态生成 -->
        </div>
        
        <div class="game-scene" id="gameScene">
            <div class="grid-lines" id="gridLines"></div>
            <!-- 游戏元素将通过JS动态添加 -->
        </div>
    </div>
    
    <div class="game-interface">
        <button class="game-button" id="pauseButton">暂停</button>
        <button class="game-button" id="customButton">自定义</button>
        <button class="game-button" id="restartButton">重新开始</button>
    </div>
    
    <div class="pause-menu" id="pauseMenu">
        <h2 class="pause-title">游戏暂停</h2>
        <div class="pause-buttons">
            <button class="game-button" id="resumeButton">继续</button>
            <button class="game-button" id="menuButton">主菜单</button>
        </div>
    </div>
    
    <div class="game-over" id="gameOver">
        <h2 class="game-over-title" id="gameResult">游戏结束</h2>
        <div class="game-over-stats">
            <p>获得阳光: <span id="finalSun">0</span></p>
            <p>存活波数: <span id="finalWave">0</span></p>
        </div>
        <div class="pause-buttons">
            <button class="game-button" id="retryButton">再试一次</button>
            <button class="game-button" id="backToMenuButton">主菜单</button>
        </div>
    </div>
    
    <div class="custom-panel" id="customPanel">
        <h2 class="panel-title">自定义游戏元素</h2>
        <div class="custom-form">
            <div class="form-group">
                <label for="sunflowerImg">向日葵图片URL:</label>
                <input type="text" id="sunflowerImg" value="https://i.imgur.com/6XwV0Pm.png">
            </div>
            <div class="form-group">
                <label for="peashooterImg">豌豆射手图片URL:</label>
                <input type="text" id="peashooterImg" value="https://i.imgur.com/4cYcBkX.png">
            </div>
            <div class="form-group">
                <label for="zombieImg">普通僵尸图片URL:</label>
                <input type="text" id="zombieImg" value="https://i.imgur.com/3kQ0c9z.png">
            </div>
            <div class="form-group">
                <label for="coneheadZombieImg">路障僵尸图片URL:</label>
                <input type="text" id="coneheadZombieImg" value="https://i.imgur.com/1GkT9Dk.png">
            </div>
            <div class="form-actions">
                <button class="game-button" id="applyCustom">应用</button>
                <button class="game-button close-panel" id="closeCustom">关闭</button>
            </div>
        </div>
    </div>
    
    <div class="notification" id="notification">通知消息</div>

    <script>
        // ======================
        // 游戏核心引擎
        // ======================
        
        /**
         * 游戏主类 - 管理整个游戏的生命周期和状态
         */
        class PVZGame {
            constructor() {
                // 游戏状态
                this.gameState = 'playing'; // playing, paused, gameOver
                this.sunCount = 50; // 初始阳光数量
                this.currentWave = 1; // 当前波数
                this.zombiesInWave = 5; // 当前波僵尸数量
                this.zombiesRemaining = 5; // 剩余僵尸数量
                this.gridRows = 5; // 网格行数
                this.gridCols = 9; // 网格列数
                this.plants = []; // 植物数组
                this.zombies = []; // 僵尸数组
                this.suns = []; // 阳光数组
                this.projectiles = []; // 投射物数组
                this.selectedPlant = null; // 当前选中的植物
                this.gameLoop = null; // 游戏循环ID
                this.lastSunDropTime = 0; // 上次掉落阳光时间
                this.lastZombieSpawnTime = 0; // 上次生成僵尸时间
                this.zombieSpawnInterval = 3000; // 僵尸生成间隔(ms)
                this.sunDropInterval = 15000; // 阳光掉落间隔(ms)
                this.gridCellWidth = 0; // 网格单元宽度
                this.gridCellHeight = 0; // 网格单元高度
                this.plantCooldowns = {}; // 植物冷却计时
                
                // DOM元素引用
                this.gameScene = document.getElementById('gameScene');
                this.plantSelector = document.getElementById('plantSelector');
                this.sunCountElement = document.getElementById('sunCount');
                this.gridLines = document.getElementById('gridLines');
                this.pauseMenu = document.getElementById('pauseMenu');
                this.gameOver = document.getElementById('gameOver');
                this.gameResult = document.getElementById('gameResult');
                this.finalSun = document.getElementById('finalSun');
                this.finalWave = document.getElementById('finalWave');
                this.notification = document.getElementById('notification');
                this.customPanel = document.getElementById('customPanel');
                
                // 游戏元素配置
                this.plantTypes = [
                    {
                        id: 'sunflower',
                        name: '向日葵',
                        cost: 50,
                        cooldown: 5000,
                        img: 'https://i.imgur.com/6XwV0Pm.png',
                        description: '每24秒生产50阳光'
                    },
                    {
                        id: 'peashooter',
                        name: '豌豆射手',
                        cost: 100,
                        cooldown: 7500,
                        img: 'https://i.imgur.com/4cYcBkX.png',
                        description: '发射豌豆攻击僵尸'
                    },
                    {
                        id: 'wallnut',
                        name: '坚果墙',
                        cost: 50,
                        cooldown: 30000,
                        img: 'https://i.imgur.com/0nT5qQv.png',
                        description: '阻挡僵尸前进'
                    }
                ];
                
                this.zombieTypes = [
                    {
                        id: 'normal',
                        name: '普通僵尸',
                        speed: 0.5,
                        health: 100,
                        damage: 10,
                        img: 'https://i.imgur.com/3kQ0c9z.png'
                    },
                    {
                        id: 'conehead',
                        name: '路障僵尸',
                        speed: 0.4,
                        health: 200,
                        damage: 15,
                        img: 'https://i.imgur.com/1GkT9Dk.png'
                    }
                ];
                
                this.projectileTypes = {
                    'peashooter': {
                        speed: 2,
                        damage: 20,
                        img: 'https://i.imgur.com/8qVxV0P.png'
                    }
                };
                
                // 初始化游戏
                this.init();
            }
            
            /**
             * 初始化游戏
             */
            init() {
                // 创建网格线
                this.createGridLines();
                
                // 创建植物选择卡
                this.createPlantSelector();
                
                // 添加事件监听器
                this.setupEventListeners();
                
                // 启动游戏循环
                this.startGameLoop();
                
                // 显示初始通知
                this.showNotification('游戏开始!种植向日葵获取阳光,种植豌豆射手抵御僵尸!');
            }
            
            /**
             * 创建网格线
             */
            createGridLines() {
                // 移除现有网格线
                while (this.gridLines.firstChild) {
                    this.gridLines.removeChild(this.gridLines.firstChild);
                }
                
                // 计算网格尺寸
                this.gridCellWidth = this.gameScene.clientWidth / this.gridCols;
                this.gridCellHeight = this.gameScene.clientHeight / this.gridRows;
                
                // 创建水平网格线
                for (let i = 1; i < this.gridRows; i++) {
                    const line = document.createElement('div');
                    line.className = 'grid-line-horizontal';
                    line.style.top = (i * this.gridCellHeight) + 'px';
                    this.gridLines.appendChild(line);
                }
                
                // 创建垂直网格线
                for (let i = 1; i < this.gridCols; i++) {
                    const line = document.createElement('div');
                    line.className = 'grid-line-vertical';
                    line.style.left = (i * this.gridCellWidth) + 'px';
                    this.gridLines.appendChild(line);
                }
            }
            
            /**
             * 创建植物选择卡
             */
            createPlantSelector() {
                this.plantSelector.innerHTML = '';
                
                this.plantTypes.forEach(plant => {
                    const plantCard = document.createElement('div');
                    plantCard.className = 'plant-card';
                    plantCard.dataset.plantId = plant.id;
                    
                    plantCard.innerHTML = `
                        <img src="${plant.img}" alt="${plant.name}">
                        <div class="plant-name">${plant.name}</div>
                        <div class="plant-cost">${plant.cost}</div>
                        <div class="plant-cooldown">
                            <div class="plant-cooldown-fill"></div>
                        </div>
                    `;
                    
                    this.plantSelector.appendChild(plantCard);
                    
                    // 设置初始冷却状态
                    this.plantCooldowns[plant.id] = {
                        lastUsed: 0,
                        isCooling: false
                    };
                });
            }
            
            /**
             * 设置事件监听器
             */
            setupEventListeners() {
                // 植物选择卡点击事件
                document.querySelectorAll('.plant-card').forEach(card => {
                    card.addEventListener('click', (e) => {
                        const plantId = e.currentTarget.dataset.plantId;
                        this.selectPlant(plantId);
                    });
                });
                
                // 游戏场景点击事件(放置植物)
                this.gameScene.addEventListener('click', (e) => {
                    if (this.gameState !== 'playing' || !this.selectedPlant) return;
                    
                    // 计算网格位置
                    const rect = this.gameScene.getBoundingClientRect();
                    const x = e.clientX - rect.left;
                    const y = e.clientY - rect.top;
                    
                    const col = Math.floor(x / this.gridCellWidth);
                    const row = Math.floor(y / this.gridCellHeight);
                    
                    // 检查是否在有效网格内
                    if (col >= 0 && col < this.gridCols && row >= 0 && row < this.gridRows) {
                        this.placePlant(row, col);
                    }
                });
                
                // 暂停按钮
                document.getElementById('pauseButton').addEventListener('click', () => {
                    this.togglePause();
                });
                
                // 恢复按钮
                document.getElementById('resumeButton').addEventListener('click', () => {
                    this.togglePause();
                });
                
                // 菜单按钮
                document.getElementById('menuButton').addEventListener('click', () => {
                    this.gameOverScreen('游戏已暂停');
                });
                
                // 重新开始按钮
                document.getElementById('restartButton').addEventListener('click', () => {
                    this.restartGame();
                });
                
                // 自定义按钮
                document.getElementById('customButton').addEventListener('click', () => {
                    this.showCustomPanel();
                });
                
                // 应用自定义设置
                document.getElementById('applyCustom').addEventListener('click', () => {
                    this.applyCustomSettings();
                });
                
                // 关闭自定义面板
                document.getElementById('closeCustom').addEventListener('click', () => {
                    this.hideCustomPanel();
                });
                
                // 重试按钮
                document.getElementById('retryButton').addEventListener('click', () => {
                    this.restartGame();
                });
                
                // 返回主菜单按钮
                document.getElementById('backToMenuButton').addEventListener('click', () => {
                    this.gameOverScreen('游戏已暂停');
                });
                
                // 窗口大小变化事件
                window.addEventListener('resize', () => {
                    this.createGridLines();
                });
                
                // 键盘事件(作弊码支持)
                window.addEventListener('keydown', (e) => {
                    this.handleCheats(e);
                });
            }
            
            /**
             * 处理作弊码
             */
            handleCheats(e) {
                // 暂存输入的字符
                if (!this.cheatBuffer) {
                    this.cheatBuffer = '';
                    this.cheatBufferTimer = setTimeout(() => {
                        this.cheatBuffer = '';
                    }, 2000);
                }
                
                this.cheatBuffer += e.key.toLowerCase();
                
                // 检查作弊码
                if (this.cheatBuffer.includes('sun')) {
                    this.addSun(250);
                    this.showNotification('阳光作弊码激活!+250阳光');
                    this.cheatBuffer = '';
                }
                
                if (this.cheatBuffer.includes('kill')) {
                    this.killAllZombies();
                    this.showNotification('全屏秒杀激活!');
                    this.cheatBuffer = '';
                }
                
                if (this.cheatBuffer.includes('win')) {
                    this.currentWave += 5;
                    this.zombiesInWave += 10;
                    this.showNotification(`波数增加!当前第${this.currentWave}波`);
                    this.cheatBuffer = '';
                }
                
                if (this.cheatBuffer.includes('dance')) {
                    this.makeZombiesDance();
                    this.showNotification('僵尸开始跳舞!');
                    this.cheatBuffer = '';
                }
                
                if (this.cheatBuffer.includes('future')) {
                    this.changeZombieAppearance('future');
                    this.showNotification('僵尸戴上时尚太阳眼镜!');
                    this.cheatBuffer = '';
                }
                
                if (this.cheatBuffer.includes('mustache')) {
                    this.changeZombieAppearance('mustache');
                    this.showNotification('僵尸戴上两撇胡子!');
                    this.cheatBuffer = '';
                }
            }
            
            /**
             * 切换游戏暂停状态
             */
            togglePause() {
                if (this.gameState === 'paused') {
                    this.resumeGame();
                } else {
                    this.pauseGame();
                }
            }
            
            /**
             * 暂停游戏
             */
            pauseGame() {
                this.gameState = 'paused';
                this.pauseMenu.style.display = 'flex';
                if (this.gameLoop) {
                    clearInterval(this.gameLoop);
                    this.gameLoop = null;
                }
            }
            
            /**
             * 恢复游戏
             */
            resumeGame() {
                this.gameState = 'playing';
                this.pauseMenu.style.display = 'none';
                this.startGameLoop();
            }
            
            /**
             * 选择植物
             */
            selectPlant(plantId) {
                if (this.gameState !== 'playing') return;
                
                const plant = this.plantTypes.find(p => p.id === plantId);
                if (!plant) return;
                
                // 检查阳光是否足够
                if (this.sunCount < plant.cost) {
                    this.showNotification(`阳光不足!需要 ${plant.cost} 阳光`);
                    return;
                }
                
                // 检查冷却时间
                const now = Date.now();
                const cooldown = this.plantCooldowns[plantId];
                
                if (cooldown.isCooling && (now - cooldown.lastUsed) < plant.cooldown) {
                    this.showNotification(`${plant.name} 正在冷却中`);
                    return;
                }
                
                this.selectedPlant = plantId;
                document.querySelectorAll('.plant-card').forEach(card => {
                    if (card.dataset.plantId === plantId) {
                        card.style.boxShadow = '0 0 15px #f1c40f';
                    } else {
                        card.style.boxShadow = '';
                    }
                });
                
                this.showNotification(`已选择 ${plant.name},点击草地种植`);
            }
            
            /**
             * 放置植物
             */
            placePlant(row, col) {
                const plant = this.plantTypes.find(p => p.id === this.selectedPlant);
                if (!plant) return;
                
                // 检查该位置是否已有植物
                const existingPlant = this.plants.find(p => p.row === row && p.col === col);
                if (existingPlant) {
                    this.showNotification('该位置已有植物!');
                    return;
                }
                
                // 检查阳光是否足够
                if (this.sunCount < plant.cost) {
                    this.showNotification(`阳光不足!需要 ${plant.cost} 阳光`);
                    return;
                }
                
                // 扣除阳光
                this.sunCount -= plant.cost;
                this.updateSunCount();
                
                // 创建植物元素
                const plantElement = document.createElement('div');
                plantElement.className = 'game-object plant';
                plantElement.style.left = (col * this.gridCellWidth) + 'px';
                plantElement.style.top = (row * this.gridCellHeight) + 'px';
                plantElement.innerHTML = `
                    <img src="${plant.img}" alt="${plant.name}" style="width:100%;height:100%;">
                    <div class="plant-health-bar">
                        <div class="plant-health-fill" style="width:100%"></div>
                    </div>
                `;
                
                this.gameScene.appendChild(plantElement);
                
                // 添加植物到数组
                this.plants.push({
                    id: Date.now(),
                    type: this.selectedPlant,
                    row: row,
                    col: col,
                    element: plantElement,
                    health: 100,
                    lastAction: Date.now()
                });
                
                // 重置选择状态
                this.selectedPlant = null;
                document.querySelectorAll('.plant-card').forEach(card => {
                    card.style.boxShadow = '';
                });
                
                // 开始冷却
                this.startPlantCooldown(plant.id, plant.cooldown);
                
                // 显示通知
                this.showNotification(`成功种植 ${plant.name}!`);
                
                // 特殊植物逻辑
                if (plant.id === 'sunflower') {
                    this.startSunflowerProduction(this.plants[this.plants.length - 1]);
                }
            }
            
            /**
             * 开始植物冷却
             */
            startPlantCooldown(plantId, cooldownTime) {
                const plantCard = document.querySelector(`.plant-card[data-plant-id="${plantId}"]`);
                const cooldownFill = plantCard.querySelector('.plant-cooldown-fill');
                
                this.plantCooldowns[plantId] = {
                    lastUsed: Date.now(),
                    isCooling: true
                };
                
                // 动画冷却效果
                let startTime = Date.now();
                const animate = () => {
                    const elapsed = Date.now() - startTime;
                    const progress = Math.min(elapsed / cooldownTime, 1);
                    cooldownFill.style.width = (progress * 100) + '%';
                    
                    if (progress < 1) {
                        requestAnimationFrame(animate);
                    } else {
                        this.plantCooldowns[plantId].isCooling = false;
                    }
                };
                
                requestAnimationFrame(animate);
            }
            
            /**
             * 开始向日葵生产阳光
             */
            startSunflowerProduction(plant) {
                // 向日葵每24秒生产50阳光
                plant.sunInterval = setInterval(() => {
                    if (this.gameState !== 'playing') return;
                    
                    // 创建阳光元素
                    const sun = document.createElement('div');
                    sun.className = 'game-object sun';
                    sun.textContent = '☀';
                    sun.style.fontSize = '24px';
                    sun.style.left = (plant.col * this.gridCellWidth + 20) + 'px';
                    sun.style.top = (plant.row * this.gridCellHeight + 20) + 'px';
                    
                    this.gameScene.appendChild(sun);
                    this.suns.push({
                        id: Date.now(),
                        element: sun,
                        x: plant.col * this.gridCellWidth + 20,
                        y: plant.row * this.gridCellHeight + 20,
                        targetX: null,
                        targetY: null,
                        collected: false
                    });
                    
                    // 动画:阳光升起
                    let startY = plant.row * this.gridCellHeight + 20;
                    let currentY = startY;
                    const riseHeight = 100;
                    const riseDuration = 1000;
                    const riseStartTime = Date.now();
                    
                    const riseAnimation = () => {
                        const elapsed = Date.now() - riseStartTime;
                        const progress = Math.min(elapsed / rise
本文章已经生成可运行项目
提供国人写的强大的html5植物大战僵尸源码) 写得很棒~占用资源少。 JSPVZ 程序制作进度(2011.1.5) 本程序提供源码HTML5中文网整理打包下载,该下载包可以使用服务器环境运行,也可以在电脑上双击Index.htm直接运行 另外智能手机可以安装OperaMobile10.1及其以上版本,把代码整个拷贝到手机存储卡上,在浏览器中输入形如“E:/jspvz”形式的地址直接本地运行程序,无需联网 转载使用请勿修改LonelyStar署名,pvz.lonelystar.org网址和PopCap公司版权声明 保留对该JS版植物大战僵尸版权所有 2011.1.5 添加了第二大关的第三小关 修正一大波和最后一波字样无法消失的BUG 2010.12.31 添加了“解谜模式” 调整了程序中关卡对于胜利和失败的算法 几个植物僵尸做了调整 修改了几个BUG 2010.12.27 对初始界面稍作修改 2010.12.9 添加了“靠天吃饭”小游戏 给领带僵尸添加两种形象 修正辣椒爆炸图片的问题 咖啡豆0耗的数据修正 2010.12.8 提高了一下僵尸行走的纵坐标 修正了土豆雷和樱桃炸弹爆炸图片在IE下的问题 调整了一大波僵尸和最后一波僵尸出现的图片效果 2010.12.7 添加了第二大关的两小关 添加了“乱葬岗”小游戏 修改了几个BUG 调整了进度显示 2010.12.1 添加了“贫瘠之地”小游戏 调整游戏初始化界面和选择模式界面 修正第十关IE下运行报错的BUG 修正IE下单机运行有部分图片看不到的问题 修正蘑菇植物无睡眠动画而实际却在睡眠的BUG 修正曾哥蘑菇种植在醒着的大喷菇上仍然睡着的BUG 修正僵尸出场界面显示僵尸种类的BUG 修正地刺和地刺王伤害过高的BUG 加大“僵尸快跑!”的难度
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ZTLJQ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值