自制植物大战僵尸:HTML5与JavaScript实现的简单游戏

news2024/12/24 6:05:14
引言

在本文中,我们将一起探索如何使用HTML5和JavaScript来创建一个简单的植物大战僵尸游戏。这不仅是一项有趣的编程挑战,也是学习游戏开发基础的绝佳机会。

什么是植物大战僵尸?

植物大战僵尸是一款流行的策略塔防游戏,玩家需要种植不同类型的植物来防御进攻的僵尸。我们的目标是复现这款游戏的核心机制,以一个简化的版本呈现。

准备工作

        在开始编码之前,你需要具备基本的HTML、CSS和JavaScript知识。此外,一个代码编辑器(如VS Code或Sublime Text)将帮助你编写和测试代码。

        比如:

HBulider

 

HTML结构

首先,我们创建HTML页面的基本结构,包括<!DOCTYPE html>, <html>, <head>, 和 <body>标签。在<head>部分,我们定义了页面的元数据和标题。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>植物大战僵尸</title>
</head>
<body>
</body>
</html>
CSS样式

接下来,我们添加内联<style>标签来定义游戏的样式。这包括背景、按钮、植物、僵尸和动画等元素的样式。


body {
    * {
            margin: 0;
            padding: 0;
            /* 设置怪异盒子 */
            box-sizing: border-box;
        }
        body{
            background-color:#949489;
        }
        #app {
            margin: 50px auto;
            width: 1400px;
            height: 600px;
            border: 5px solid #010101;
            border-radius: 50px;
            background-image: url(../images/background1.jpg);
            background-repeat: no-repeat;
            background-size: cover;
            position: relative;
        }
        #topui {
            width: 1200px;
            height: 45px;
            position: absolute;
            top: 10px;
            left: 150px;
        }
        /* 能量栏 */
        .vessel{
            width: 100px;
            height: 45px;
            background-image: url(../images/sunback.png);
            background-repeat: no-repeat;
            background-size: 100px;
            font-size: 20px;
            font-weight: 700;
            line-height: 30px;
            padding-left: 15px;
            text-align: center;
            position: absolute;
            top: 0px;
            left: 0px;
            border: 1px solid #000;
            border-color: rgba(0, 0, 0,0);
        }
        .energy{
            width: 50px;
            height: 50px;
            border: 1px solid #000;
            border-color: rgba(0, 0, 0,0);
            border-radius: 20px;
            opacity: 1;
            position: absolute;
            top: 0px;
            left: 0px;
        }
        /* 按钮样式 */
        .button{
            width: 120px;
            height: 45px;
            line-height: 41px;
            border-radius: 5px;
            color: aliceblue;
            background-repeat: no-repeat;
            text-align: center;
            position: absolute;
            top: 0px;
            left: 1080px;
            border: 1px solid #000;
            border-color: rgba(0, 0, 0,0);

        }
        /* 删除植物 */
        .delete{
            width: 45px;
            height: 45px;
            background-image: url(../images/铁锹.png);
            background-repeat: no-repeat;
            background-size: 40px;
            text-align: center;
            position: absolute;
            top: 0px;
            left: 850px;
            border: 1px solid #000;
            border-color: rgba(0, 0, 0,0);
        }
        .delete:hover{
            transform: scale(1.2);
        }
        /* 得分 */
        .grade{
            width: 200px;
            height: 30px;
            text-align: center;
            line-height: 30px;
            font-size: 25px;
            color: #fafcfa;
            position: absolute;
            top: 0;
            left: 400px;
            border: 1px solid #000;
            border-color: rgba(0, 0, 0,0);
            background-color: lightslategrey;
            border-radius: 20px;
        }
        .button:hover{
            color: #09f63c;
        }
        #leftui {
            width: 100px;
            height: 455px;
            position: absolute;
            top: 60px;
            left: 10px;
        }
        /* 植物选择框单元样式 */
        .plantui{
            width: 100px;
            height: 60px;
            font-weight: 700;
            padding-left: 60px;
            padding-top: 40px;
            margin-bottom: 5px;
            border: 1px solid #000;
            border-color: rgba(0, 0, 0,0);
            border-radius: 10px;
        }
        .plantui:hover{
            
            border: 1px solid #09f63c;
        }
        /* 网格坐标样式 */
        .geid{
            width: 80px;
            height: 100px;
            border: 1px solid #000;
            border-color: rgba(0, 0, 0,0);
            border-radius: 20px;
            position: absolute;
            top: 60px;
            left: 250px;
        }
        /* 植物div */
        .plant {
            width: 80px;
            height: 100px;
            text-align: center;
            color: rgb(249, 250, 251);
            border: 1px solid #000000;
            border-color: rgba(0, 0, 0,0);
            border-radius: 20px;
            position: absolute;
            /* opacity: 0.8; */
        }
        /* 植物img */
        .plantimg{
            width: 80%;
            margin-top: 0px;
            margin-left: 10px;
            position: absolute;
            top: 25px;
            left: 0;
        }
        .plantspan{
            position: absolute;
            top: 0;
            left: 25px;
        }
        /* 僵尸div */
        .zombie {
            width: 80px;
            height: 102px;
            text-align: center;
            color: rgb(7, 7, 7);
            border: 1px solid #000;
            border-color: rgba(0, 0, 0,0);
            border-radius: 20px;
            border-radius: 20px;
            position: absolute;
        }
        /* 僵尸img */
        .zombieimg{
            width: 150%;
            margin-top: -12px;
            margin-left: -30px;
        }
        /* 子弹 */
        .bullet{
            width: 10px;
            height: 10px;
            margin-top: 35px;
            margin-left: 60px;
            background-color: #02a0f5;
            border: 1px solid #000;
            border-radius: 50%;
            position: absolute;
        }
        /* 准备游戏样式 */
        #go{
            width: 255px;
            height: 108px;
            position: absolute;
            top: 246px;
            left: 573px;
            background-image: url(../images/loading/loading_0.png);
            animation: xz 1s infinite;
        }
        @keyframes xz{
            0%{
                transform: scale(1);
            }
            50%{
                transform: scale(1.1);
            }
            100%{
                transform: scale(1);
            }
        }
        /* 游戏结束 */
        .end{
            width: 566px;
            height: 470px;
            position: absolute;
            top: 50px;
            left: 400px;
            background-image: url(../images/zombieWon.png);
            border: 1px solid #000;
            border-color: rgba(0, 0, 0,0);
            animation: end 2s infinite;
        }
        @keyframes end {
            0%{
                transform: scale(1);
            }
            50%{
                transform: scale(1.1);
            }
            100%{
                transform: scale(1);
            }
        }
        /* 游戏胜利 */
        .vict{
            width: 566px;
            height: 470px;
            text-align: center;
            padding-top: 308px;
            padding-left: 230px;
            padding-right: 200px;
            font-size: 40px;
            color: white;
            background-image: url(../images/游戏胜利.png);
            background-size: 1000px;
            background-position: left -200px top -50px;
            background-repeat: no-repeat;
            border: 1px solid #000;
            border-color: rgba(0, 0, 0,0);
            position: absolute;
            top: 50px;
            left: 400px;
            animation: vict 2s infinite;
        }
        @keyframes vict {
            0%{
                transform: scale(1);
            }
            50%{
                transform: scale(1.1);
            }
            100%{
                transform: scale(1);
            }
        }
        /* 时钟 */
        .nz{
            width: 100px;
            height: 50px;
            margin: 5px;
            padding-left: 40px;
            padding-top: 10px;
            font-weight: 700;
            color: #fafcfa;
            line-height: 28px;
            text-align: center;
            border-radius: 15px;
            background-image: url(../images/闹钟.png);
            background-size: 50px;
            background-repeat: no-repeat;
            position: absolute;
            top: 60;
            left: 900px;
        }

}
JavaScript逻辑

游戏的核心逻辑将通过JavaScript实现。我们将创建植物、僵尸、子弹等游戏对象,并定义它们的行为和动画。

游戏初始化和全局变量

首先,代码中定义了游戏容器和一些全局变量,用于跟踪游戏状态:

​
var game = document.getElementById('app');
var gameState = {
    // 游戏状态对象属性
};

植物属性定义

定义了一个包含不同植物属性的对象PlantUte,每个植物都有名称、价格、图像路径、生命值等属性:

var PlantUte = {
     // 向日葵
     SunFlower:{
     name:"向日葵",
     price:50,
     uisrc1:"../images/cards/plants/SunFlower.png",
     uisrc2:"../images/cards/plants/SunFlowerG.png",
     datasrc:"../images/plants/sunflower/idle/idle_0.png",
     url:"../images/plants/sunflower/idle/idle_",
     count:17,
     hp:100,
     attack:0,
     speed:0,
     range:0,
     color:"red"
},

 

 // 初级豌豆射手
Peashooter:{
   name:"初级豌豆射手",
   price:50,
   uisrc1:"../images/cards/plants/Peashooter.png",
   uisrc2:"../images/cards/plants/PeashooterG.png",
   datasrc:"../images/plants/peashooter/attack/attack_0.png",
   url:"../images/plants/peashooter/attack/attack_",
   count:7,
   hp:100,
   attack:5,
   speed:500,
   range:500,
   color:"chartreuse"
},

 

   // 中级豌豆射手
            Repeater:{
                name:"中级豌豆射手",
                price:100,
                uisrc1:"../images/cards/plants/Repeater.png",
                uisrc2:"../images/cards/plants/RepeaterG.png",
                datasrc:"../images/plants/repeater/attack/attack_0.png",
                url:"../images/plants/repeater/attack/attack_",
                count:14,
                hp:100,
                attack:10,
                speed:500,
                range:500,
                color:"chartreuse"
            },
            // 高级豌豆射手
            GatlingPea:{
                name:"高级豌豆射手",
                price:200,
                uisrc1:"../images/cards/plants/GatlingPea.png",
                uisrc2:"../images/cards/plants/GatlingPeaG.png",
                datasrc:"../images/plants/gatlingpea/attack/attack_0.png",
                url:"../images/plants/gatlingpea/attack/attack_",
                count:12,
                hp:100,
                attack:10,
                speed:300,
                range:500,
                color:"chartreuse"
            },
            // 番茄炸弹
            CherryBomb:{
                name:"番茄炸弹",
                price:200,
                uisrc1:"../images/cards/plants/CherryBomb.png",
                uisrc2:"../images/cards/plants/CherryBombG.png",
                datasrc:"../images/plants/cherrybomb/idle/idle_0.png",
                url:"../images/plants/cherrybomb/idle/idle_",
                count:6,
                hp:50,
                attack:100,
                speed:1000,
                range:57,
                color:"rgba(0,0,0,0)"
            },
            // 食人花
            Chomper:{
                name:"食人花",
                price:300,
                uisrc1:"../images/cards/plants/Chomper.png",
                uisrc2:"../images/cards/plants/ChomperG.png",
                datasrc:"../images/plants/chomper/attack/attack_0.png",
                url:"../images/plants/chomper/attack/attack_",
                count:8,
                hp:100,
                attack:20,
                speed:100,
                range:57,
                color:"rgba(0,0,0,0)"
            },
            // 坚果防御
            WallNut:{
                name:"坚果防御",
                price:50,
                uisrc1:"../images/cards/plants/WallNut.png",
                uisrc2:"../images/cards/plants/WallNutG.png",
                datasrc:"../images/plants/wallnut/idleH/idleH_0.png",
                url:"../images/plants/wallnut/idleH/idleH_",
                count:15,
                hp:1000,
                attack:0,
                speed:0,
                range:0,
                color:"red"

UI组件类

定义了多个类来创建游戏的UI组件,例如:

function ToolBar(text,style){
    this.text = text;
    this.element = document.createElement('div');
    this.element.className = style;
    this.element.innerText = this.text;
    topUI.appendChild(this.element); // 添加到游戏选择UI框
    gameState.toolbar.push(this)
}

游戏对象类

定义了游戏中的对象类,例如:

  • Plant:代表一个植物,具有位置、属性和动画。

  • Zombie:代表一个僵尸,具有生命值、攻击能力和移动速度。

  • Bullet:代表从植物发射的子弹。

初始化UI

InitUI函数用于初始化游戏界面元素,包括植物选择框、网格线坐标和顶部UI信息栏:

 var InitUI = function(){
// 初始化网格线坐标
    for(var i=0;i<5;i++){
      for(var j=0;j<9;j++){
        new Geid(parseInt(j*80+240),parseInt(i*100+60))
         }
    }

// 创建顶部UI信息栏对象实例
new ToolBar(500,"vessel");//能量收集
new ToolBar("","delete"); //铲子
new ToolBar(0,"grade"); //销毁僵尸数量
new ToolBar("00:00","nz"); //游戏时间

// 创建UI标签栏对象实例
new Labels(PlantUte.SunFlower); //向日葵
new Labels(PlantUte.Peashooter); //初级豌豆射手
new Labels(PlantUte.Repeater); //中级豌豆射手
new Labels(PlantUte.GatlingPea); //高级豌豆射手
 // new Labels(PlantUte.CherryBomb); //番茄炸弹
new Labels(PlantUte.Chomper); //食人花
new Labels(PlantUte.WallNut); //坚果防御
}

JavaScript完整代码

  <script>

		var game = document.getElementById('app');
         // 获取游戏界面元素
        var leftUI = document.getElementById('leftui');
        // 获取植物选择框
        var topUI = document.getElementById('topui');
        // 获取植物选择框
        var Go = document.getElementById('go');
        // 开始游戏按钮

        // 定义游戏状态
        var gameState = {
            plants: [],// 植物列表
            zombies: [],// 僵尸列表
            energys:[],//能量列表
            bullets: [],// 子弹列表
            toolbar:[],// 顶部UI栏列表
            labels:[],// 植物选择框列表
            geids:[], // 网格坐标列表
            isOver: "",// 游戏是否结束
            occupy:false,  // 选中的植物的对象
            delete:false,//选择要删除的植物
            grade:0,//得分
            startTime1:0,  //游戏运行时间
            startTime2:0,  //游戏运行时间
            pro:0.01

        };

        // 定义植物属性
        var PlantUte = {
            // 向日葵
            SunFlower:{
                name:"向日葵",
                price:50,
                uisrc1:"../images/cards/plants/SunFlower.png",
                uisrc2:"../images/cards/plants/SunFlowerG.png",
                datasrc:"../images/plants/sunflower/idle/idle_0.png",
                url:"../images/plants/sunflower/idle/idle_",
                count:17,
                hp:100,
                attack:0,
                speed:0,
                range:0,
                color:"red"
            },
            // 初级豌豆射手
            Peashooter:{
                name:"初级豌豆射手",
                price:50,
                uisrc1:"../images/cards/plants/Peashooter.png",
                uisrc2:"../images/cards/plants/PeashooterG.png",
                datasrc:"../images/plants/peashooter/attack/attack_0.png",
                url:"../images/plants/peashooter/attack/attack_",
                count:7,
                hp:100,
                attack:5,
                speed:500,
                range:500,
                color:"chartreuse"
            },
            // 中级豌豆射手
            Repeater:{
                name:"中级豌豆射手",
                price:100,
                uisrc1:"../images/cards/plants/Repeater.png",
                uisrc2:"../images/cards/plants/RepeaterG.png",
                datasrc:"../images/plants/repeater/attack/attack_0.png",
                url:"../images/plants/repeater/attack/attack_",
                count:14,
                hp:100,
                attack:10,
                speed:500,
                range:500,
                color:"chartreuse"
            },
            // 高级豌豆射手
            GatlingPea:{
                name:"高级豌豆射手",
                price:200,
                uisrc1:"../images/cards/plants/GatlingPea.png",
                uisrc2:"../images/cards/plants/GatlingPeaG.png",
                datasrc:"../images/plants/gatlingpea/attack/attack_0.png",
                url:"../images/plants/gatlingpea/attack/attack_",
                count:12,
                hp:100,
                attack:10,
                speed:300,
                range:500,
                color:"chartreuse"
            },
            // 番茄炸弹
            CherryBomb:{
                name:"番茄炸弹",
                price:200,
                uisrc1:"../images/cards/plants/CherryBomb.png",
                uisrc2:"../images/cards/plants/CherryBombG.png",
                datasrc:"../images/plants/cherrybomb/idle/idle_0.png",
                url:"../images/plants/cherrybomb/idle/idle_",
                count:6,
                hp:50,
                attack:100,
                speed:1000,
                range:57,
                color:"rgba(0,0,0,0)"
            },
            // 食人花
            Chomper:{
                name:"食人花",
                price:300,
                uisrc1:"../images/cards/plants/Chomper.png",
                uisrc2:"../images/cards/plants/ChomperG.png",
                datasrc:"../images/plants/chomper/attack/attack_0.png",
                url:"../images/plants/chomper/attack/attack_",
                count:8,
                hp:100,
                attack:20,
                speed:100,
                range:57,
                color:"rgba(0,0,0,0)"
            },
            // 坚果防御
            WallNut:{
                name:"坚果防御",
                price:50,
                uisrc1:"../images/cards/plants/WallNut.png",
                uisrc2:"../images/cards/plants/WallNutG.png",
                datasrc:"../images/plants/wallnut/idleH/idleH_0.png",
                url:"../images/plants/wallnut/idleH/idleH_",
                count:15,
                hp:1000,
                attack:0,
                speed:0,
                range:0,
                color:"red"
            }
        }
        
        // 顶部UI类
        function ToolBar(text,style){
            this.text = text;
            this.element = document.createElement('div');
            this.element.className = style;
            this.element.innerText = this.text;
            topUI.appendChild(this.element); // 添加到游戏选择UI框
            gameState.toolbar.push(this)
        }
       
        // 植物选择框类
        function Labels(object){
            this.object = object;
            this.price=object.price;// 价格
            this.uisrc1 = "url("+object.uisrc1+")";// UI图标路径
            this.uisrc2 = "url("+object.uisrc2+")";
            this.occupy = false;//是否选中
            this.element = document.createElement('div'); // 元素节点
            this.element.className = 'plantui'; // 添加样式
            this.element.style.backgroundImage = this.uisrc1;
            this.element.innerText=this.price;// 显示价格
            leftUI.appendChild(this.element); // 添加到游戏选择UI框
            gameState.labels.push(this); // 添加到植物选择框列表
        }

        // 网格坐标类
        function Geid(x,y){
            this.x = x;
            this.y = y;
            this.occupy = false;
            this.element = document.createElement("div");
            this.element.className = "geid";
            this.element.style.top = this.y + 'px'; // 设置位置
            this.element.style.left = this.x + 'px';
            game.appendChild(this.element)
            gameState.geids.push(this)
        }

        // 定义能量类
        function EnErgy(object){
            this.object = object;
            this.x = object.x;
            this.y = object.y+50;
            this.hp = true;
            this.element = document.createElement('img'); // 元素节点
            this.element.src = "../images/sun.gif" ;
            this.element.className = 'energy'; // 添加样式
            this.element.style.top = this.y + "px";
            this.element.style.left = this.x + "px";
            game.appendChild(this.element); // 添加到游戏界面
            gameState.energys.push(this);
        }

        // 定义植物类
        function Plant(x, y,object) {
            this.x = x;
            this.y = y;
            this.object = object;
            this.Animation = {
                src:object.datasrc,
                url:object.url,
                count:object.count,
                num:0,
                animation:false
            }
            this.set = "set"+this.x+this.y
            this.name = object.name;//名字
            this.hp = object.hp; // 血量
            this.attack = object.attack; // 攻击力
            this.speed = object.speed; // 攻击速度
            this.range = object.range; // 射程
            this.color = object.color;//攻击颜色
            this.lastAttackTime = 0; // 上次攻击时间
            this.element = document.createElement('div'); // 元素节点
            this.element.className = 'plant'; // 添加样式
            this.element.style.top = this.y + 'px'; // 设置位置
            this.element.style.left = this.x + 'px';
            
            this.element2 = document.createElement('img'); // 元素节点
            this.element2.className = 'plantimg'; // 添加样式
            this.element2.src = this.Animation.src;
            this.element2.alt = this.name;
            this.element3 = document.createElement('span'); // 元素节点
            this.element3.className = 'plantspan'; // 添加样式
            this.element3.innerText = this.hp;

            game.appendChild(this.element); // 添加到游戏界面
            this.element.appendChild(this.element2); // 添加img标签
            this.element.appendChild(this.element3); // 添加h1标签
            gameState.plants.push(this); // 添加到植物列表

        }

        // 定义僵尸类
        function Zombie(x, y) {
            this.x = x;
            this.y = y;
            // 僵尸动画属性
            this.Animation = {
                src:"../images/zombies/run/run_0.png",
                url:"../images/zombies/run/run_",
                count:30,
                num:0,
                animation:false
            }
            this.hp = 100; // 血量
            this.attack = 1; // 攻击力
            this.speed = 1; // 移动速度
            this.speedG = 50; // 攻击速度
            this.range = 50; // 射程
            this.rice = false;
            this.lastAttackTime = 0; // 上次攻击时间
            this.element = document.createElement('div'); // 元素节点
            this.element.className = 'zombie'; // 添加样式
            this.element.style.top = this.y + 'px'; // 设置位置
            this.element.style.left = this.x + 'px';
            this.element2 = document.createElement('img'); // 元素节点
            this.element2.className = 'zombieimg'; // 添加样式
            this.element2.src = this.Animation.src;
            this.element3 = document.createElement('span'); // 元素节点
            this.element3.className = 'zombiespan'; // 添加样式
            this.element3.innerText = this.hp;
            game.appendChild(this.element); // 添加到游戏界面
            this.element.appendChild(this.element3); // 添加img标签
            this.element.appendChild(this.element2); // 添加img标签
            gameState.zombies.push(this); // 添加到僵尸列表
        }

        // 定义子弹类
        function Bullet(plant, target) {
            this.x = plant.x;
            this.y = plant.y;
            this.speed = 5; // 移动速度
            this.attack = plant.attack;//攻击大小
            this.target = target; // 目标对象
            this.element = document.createElement('div'); // 元素节点
            this.element.className = 'bullet'; // 添加样式
            this.element.style.backgroundColor = plant.color;//子弹颜色
            this.element.style.borderColor = plant.color;
            this.element.style.left = this.x + 'px';// 设置位置
            this.element.style.top = this.y + 'px'; 
            game.appendChild(this.element); // 添加到游戏界面
            gameState.bullets.push(this); // 添加到子弹列表
        }

        // 初始化选择框UI
        var InitUI = function(){

            // 初始化网格线坐标
            for(var i=0;i<5;i++){
                for(var j=0;j<9;j++){
                    new Geid(parseInt(j*80+240),parseInt(i*100+60))
                }
            }

            // 创建顶部UI信息栏对象实例
            new ToolBar(500,"vessel");//能量收集
            new ToolBar("","delete"); //铲子
            new ToolBar(0,"grade"); //销毁僵尸数量
            new ToolBar("00:00","nz"); //游戏时间

            // 创建UI标签栏对象实例
            new Labels(PlantUte.SunFlower); //向日葵
            new Labels(PlantUte.Peashooter); //初级豌豆射手
            new Labels(PlantUte.Repeater); //中级豌豆射手
            new Labels(PlantUte.GatlingPea); //高级豌豆射手
            // new Labels(PlantUte.CherryBomb); //番茄炸弹
            new Labels(PlantUte.Chomper); //食人花
            new Labels(PlantUte.WallNut); //坚果防御
        }

        // 游戏时间
        var Initnz = function(){
            let time = Date.now()-gameState.startTime2;
            var date = new Date(time);
            var m = (date.getMinutes() < 10 ? '0' + (date.getMinutes()) : date.getMinutes()) + ':';
            var s = (date.getSeconds() < 10 ? '0' + (date.getSeconds()) : date.getSeconds());
            var strDate = m+s;
            gameState.toolbar[3].element.innerText = strDate;
        }

        // 开始游戏按钮
        Go.onclick = function(){
            console.log("开始游戏");
            InitUI();
            gameState.startTime1 = Date.now();
            gameState.startTime2 = Date.now();
            
            // 游戏主循环定时器
            var Appset =  setInterval(function(){
                // 游戏时间
                Initnz()
                // 随机生成僵尸
                if (Math.random() < gameState.pro) {
                    console.log("生成僵尸:",gameState.pro)
                    new Zombie(1130, parseInt(Math.random()*5)*100+60);
                }

                // 选择要种植的植物
                gameState.labels.forEach(function(label){
                    if(label.price <= gameState.toolbar[0].element.innerText){
                        label.element.style.backgroundImage = label.uisrc1;
                        label.element.style.color = "black";
                    }else{
                        label.element.style.backgroundImage = label.uisrc2;
                        label.element.style.color = "red";
                    }
                    label.element.onclick = function(){
                        if(gameState.toolbar[0].element.innerText >= label.price){
                            gameState.occupy = label.object;
                            gameState.geids.forEach(function(geid){
                                if(geid.occupy){
                                    geid.element.style.borderColor="rgba(251, 4, 4,0.5)";
                                }else{
                                    geid.element.style.borderColor="rgba(222, 251, 4, 0.759)";
                                }
                            })
                        }
                    }
                })

                // 选择生成植物的网格坐标
                gameState.geids.forEach(function(geid){
                    geid.element.onclick = function(){
                        if(gameState.occupy){
                            geid.occupy = true
                            new Plant(geid.x,geid.y,gameState.occupy);
                            gameState.toolbar[0].element.innerText -=gameState.occupy.price; 
                            gameState.occupy=false;
                            gameState.geids.forEach(function(geid){
                                geid.element.style.borderColor="rgba(0, 0, 0,0)";
                            })
                        }
                        
                    }
                    
                })

                // 僵尸移动
                gameState.zombies.forEach(function(zombie) {
                    if(zombie.x>=170){
                        zombie.x -= zombie.speed;
                        zombie.element.style.left = zombie.x + 'px';
                    }else{
                        gameState.isOver = "挑战失败";
                    }
                });
              
                // 植物攻击僵尸
                gameState.plants.forEach(function(plant) {
                    gameState.zombies.forEach(function(zombie) {
                        if(zombie.y == plant.y){
                            if (zombie.x - plant.x <= plant.range && zombie.x > plant.x) {
                                if (Date.now() - plant.lastAttackTime >= plant.speed) {
                                    new Bullet(plant,zombie);
                                    plant.lastAttackTime = Date.now();
                                    if (zombie.hp <= 0) {
                                        gameState.toolbar[2].element.innerText = ++gameState.grade;
                                        game.removeChild(zombie.element);
                                        gameState.zombies.splice(gameState.zombies.indexOf(zombie), 1);
                                    }
                                }
                            }
                        }
                        
                    });
                });

                // 僵尸攻击植物
                gameState.zombies.forEach(function(zombie) {
                    gameState.plants.forEach(function(plant) {
                        if(zombie.y == plant.y){
                            if(zombie.x-plant.x <= zombie.range && zombie.x > plant.x ){
                                zombie.x = plant.x+zombie.range;
                                zombie.rice = true;
                                if (Date.now() - zombie.lastAttackTime >= zombie.speedG) {
                                    plant.hp-=zombie.attack;
                                    // zombie.rice = true;
                                    plant.element3.innerText = plant.hp;
                                    zombie.lastAttackTime = Date.now();
                                }
                                // zombie.rice = false;
                            }else{
                                zombie.rice = false;
                            }
                        }
                        // zombie.rice = false;
                        
                    });
                });

                // 判断该植物是否死亡,释放网格资源
                gameState.plants.forEach(function(plant){
                    gameState.geids.forEach(function(geid){
                        if(plant.hp<=0){
                            if(geid.x == plant.x && geid.y == plant.y){
                                geid.occupy = false;
                                game.removeChild(plant.element);
                                gameState.plants.splice(gameState.plants.indexOf(plant), 1);
                            }
                        }
                    })
                })

                // 检测子弹是否击中目标
                gameState.bullets.forEach(function(bullet) {
                    if (bullet.target && Math.abs(bullet.x - bullet.target.x) < 60) {
                        bullet.target.hp -= bullet.attack;
                        bullet.target.element3.innerText = bullet.target.hp;
                        game.removeChild(bullet.element);
                        gameState.bullets.splice(gameState.bullets.indexOf(bullet), 1);
                    } else {
                        bullet.x += bullet.speed;
                        bullet.element.style.left = bullet.x + 'px';
                    }
                });

                // 选择要删除的植物
                gameState.toolbar[1].element.onclick = function(){
                    console.log("删除植物");
                    gameState.delete = true;
                    gameState.geids.forEach(function(geid){
                        if(geid.occupy){
                            geid.element.style.borderColor="rgba(222, 251, 4, 0.759)";
                        }else{
                            geid.element.style.borderColor="rgba(251, 4, 4,0.5)";
                        }

                    
                    })

                }

                // 选择删除植物的网格坐标
                gameState.plants.forEach(function(plant){
                    plant.element.ondblclick = function(){
                        gameState.geids.forEach(function(geid){
                            if(gameState.delete){
                                if(geid.x == plant.x && geid.y == plant.y){
                                    geid.occupy = false;
                                    gameState.delete = false;
                                    plant.hp = 0;
                                    game.removeChild(plant.element);
                                    gameState.plants.splice(gameState.plants.indexOf(plant), 1);
                                }
                                gameState.geids.forEach(function(geid){
                                    geid.element.style.borderColor="rgba(0, 0, 0,0)";
                                })
                            }
                        })
                    }

                })

                // 游戏难度,每1分钟提升难度
                if(Date.now()-gameState.startTime1>=60000){
                    gameState.startTime1 = Date.now();
                    gameState.pro = gameState.pro+0.01;
                    console.log("难度升级:",gameState.pro);
                    if(gameState.pro >=0.02){
                        game.style.backgroundImage = "url(../images/background2.jpg)";
                    }
                    if(gameState.pro >=0.04){
                        game.style.backgroundImage = "url(../images/background1.jpg)";
                    }
                    if(gameState.pro >=0.06){
                        game.style.backgroundImage = "url(../images/background2.jpg)";
                    }
                    if(gameState.pro >=0.07){
                        gameState.isOver = "挑战成功";
                    }
                    
                }

                // 植物动画
                gameState.plants.forEach(function(plant){
                    if(!plant.Animation.animation){
                        var plantSet =  setInterval(function(){
                            if(plant.name == "坚果防御" && plant.hp<600 && plant.hp >=300){
                                plant.Animation.src = "../images/plants/wallnut/idleM/idleM_0.png";
                                plant.Animation.url = "../images/plants/wallnut/idleM/idleM_";
                                plant.Animation.count = 10;
                            }
                            if(plant.name == "坚果防御" && plant.hp<300){
                                plant.Animation.src = "../images/plants/wallnut/idleL/idleL_0.png";
                                plant.Animation.url = "../images/plants/wallnut/idleL/idleL_";
                                plant.Animation.count = 14;
                            }
                            if(plant.Animation.num<=plant.Animation.count){
                                plant.element2.src = plant.Animation.url+plant.Animation.num+".png";
                                plant.Animation.num++;
                            }else{
                                plant.Animation.num=0;
                            }
                            if(plant.hp<=0){
                                clearInterval(plantSet);
                            }
                 
                        },100);
                        plant.Animation.animation = !plant.Animation.animation;
                    }
                    
                    
                })

                // 僵尸动画
                gameState.zombies.forEach(function(zombie){
                    if(!zombie.Animation.animation){
                        var zombieSet =  setInterval(function(){
                            if(zombie.hp>20 && zombie.rice){
                                zombie.Animation.src = "../images/zombies/attack_0.png";
                                zombie.Animation.url = "../images/zombies/attack/attack_";
                                zombie.Animation.count = 20;
                            }else{
                                zombie.Animation.src = "../images/zombies/run/run_0.png";
                                zombie.Animation.url = "../images/zombies/run/run_";
                                zombie.Animation.count = 30;
                            }
                            if(zombie.hp<=20){
                                zombie.Animation.src = "../images/zombies/dying/body/body_0.png";
                                zombie.Animation.url = "../images/zombies/dying/body/body_";
                                zombie.Animation.count = 17;
                            }
                            if(zombie.hp<=5){
                                zombie.Animation.src = "../images/zombies/die/die_0.png";
                                zombie.Animation.url = "../images/zombies/die/die_";
                                zombie.Animation.count = 9;
                            }
                            if(zombie.hp<=1){
                                zombie.Animation.src = "../images/zombies/dying/head/head_0.png";
                                zombie.Animation.url = "../images/zombies/dying/head/head_";
                                zombie.Animation.count = 11;
                            }
                            if(zombie.Animation.num<=zombie.Animation.count){
                                zombie.element2.src = zombie.Animation.url+zombie.Animation.num+".png";
                                zombie.Animation.num++;
                            }else{
                                zombie.Animation.num=0;
                            }
                            if(zombie.hp<=0){
                                clearInterval(zombieSet);
                            }

                        },50);
                        zombie.Animation.animation = !zombie.Animation.animation;
                    }
                    
                })

                // 产生小太阳
                gameState.plants.forEach(function(plant){
                    if(plant.name == "向日葵"){
                        plant.name = "向日葵2";
                        var energyset =  setInterval(function(){
                            if(plant.hp>0){
                                new EnErgy(plant);
                            }else{
                                clearInterval(energyset);
                            }
                        },10000)
                    }
                })

                // 销毁小太阳
                gameState.energys.forEach(function(energy){
                    if(energy.hp){
                        energy.hp = false;
                        var energyYD = setInterval(function(){
                            if(energy.y>10){
                                energy.y--;
                                energy.element.style.top = energy.y+"px";
                            }
                            if(energy.x>140){
                                energy.x--;
                                energy.element.style.left = energy.x+"px";
                            }
                            if(energy.x <= 140 && energy.y <=10){
                                clearInterval(energyYD);
                                gameState.toolbar[0].element.innerText =parseInt(gameState.toolbar[0].element.innerText)+10;
                                game.removeChild(energy.element);
                                gameState.energys.splice(gameState.energys.indexOf(energy), 1);

                            }
                        },10)
                    }

                })

                // 如果游戏结束,停止循环
                if (gameState.isOver == "挑战失败") {
                    var End = document.createElement('div'); // 元素节点
                    End.className = "end";
                    game.appendChild(End);
                    clearInterval(Appset);
                    End.ondblclick = function(){
                        game.removeChild(End);
                        location.reload();
                    }
                }

                // 如果游戏通过,停止循环
                if (gameState.isOver == "挑战成功") {
                    var End = document.createElement('div'); // 元素节点
                    End.className = "vict";
                    End.innerText = gameState.grade;
                    game.appendChild(End);
                    clearInterval(Appset);
                    End.ondblclick = function(){
                        game.removeChild(End);
                        location.reload();
                    }
                }

            }, 50);
            setInterval(function(){
                gameState.toolbar[0].element.innerText++;
            }, 1000);
            game.removeChild(Go);
        }

    </script>
游戏初始化

我们将编写一个InitUI函数来初始化游戏界面,包括植物选择框、网格坐标和能量条等。

function InitUI() {
    // 初始化UI元素
}
游戏循环

游戏的主循环将处理僵尸的生成、植物的放置、攻击逻辑和动画更新。

// 游戏主循环示例
   setInterval(function(){
                gameState.toolbar[0].element.innerText++;
            }, 1000);
游戏结束条件

我们将添加逻辑来检测游戏是否结束,并显示相应的胜利或失败界面。

// 如果游戏结束,停止循环
if (gameState.isOver == "挑战失败") {
        var End = document.createElement('div'); // 元素节点
        End.className = "end";
        game.appendChild(End);
        clearInterval(Appset);
        End.ondblclick = function(){
            game.removeChild(End);
            location.reload();
           }
        }

 // 如果游戏通过,停止循环
if (gameState.isOver == "挑战成功") {
         var End = document.createElement('div'); // 元素节点
         End.className = "vict";
         End.innerText = gameState.grade;
         game.appendChild(End);
         clearInterval(Appset);
         End.ondblclick = function(){
         game.removeChild(End);
         location.reload();
         }
 }

        在本文中,我们创建了一个简单的植物大战僵尸游戏。虽然这个版本缺少了原版游戏的许多特性,但它提供了一个很好的起点,你可以在此基础上继续扩展和完善。

进一步学习

     

在本教程中,我们创建了一个基于HTML5和JavaScript的简化版植物大战僵尸游戏。虽然这个项目是一个很好的开始,但游戏开发的世界非常广阔,提供了许多深入学习的机会。以下是一些建议,可以帮助你进一步提高你的技能:

1. 学习游戏开发框架

推荐框架

  • Phaser: 一个非常流行的开源2D游戏框架,提供了丰富的功能,如物理引擎、动画支持和粒子效果。
  • Unity: 一个强大的游戏引擎,支持2D和3D游戏开发,使用C#作为主要编程语言。
  • Unreal Engine: 一个以性能和视觉效果著称的商业游戏引擎,使用C++和蓝图(一种可视化编程系统)。

学习资源

  • 官方文档和教程
  • 在线课程(如Udemy、Coursera)
  • YouTube教程和游戏开发社区
2. 探索高级编程概念

随着你对游戏开发的深入,你将需要掌握更高级的编程概念,如:

  • 面向对象编程(OOP):帮助你构建模块化和可重用的游戏代码。
  • 设计模式:在游戏开发中常用的软件设计模式,如状态模式、观察者模式等。
  • 算法和数据结构:优化游戏性能和AI行为。
3. 理解游戏设计原理

游戏开发不仅仅是编程,还包括游戏设计的各个方面:

  • 关卡设计:学习如何创建有趣且具有挑战性的关卡。
  • 用户体验(UX):理解玩家的需求和期望,设计直观的用户界面。
  • 叙事和角色开发:为你的游戏添加深度和故事性。
4. 参与游戏开发社区

加入游戏开发社区,与其他开发者交流,获取反馈和灵感:

  • 论坛:如GameDev.net、Unity Forum等。
  • 社交媒体群组:如Reddit、Facebook和LinkedIn上的开发者群组。
  • 本地聚会和会议:参加本地的游戏开发聚会和国际游戏开发者大会(GDC)。
5. 实践和构建项目

实践是学习的最佳方式。尝试构建更多的游戏项目,不断挑战自己:

  • 小型项目:从简单的游戏开始,逐步增加项目的复杂度。
  • 参与游戏制作比赛:如Ludum Dare、Global Game Jam等,这些比赛可以激励你在短时间内快速学习和开发。
  • 开源贡献:为开源游戏项目贡献代码,学习团队协作和项目管理。
6. 学习3D图形和动画

如果你对3D游戏开发感兴趣,那么学习3D图形和动画是必不可少的:

  • 3D建模:使用Blender、Maya或3ds Max等工具学习3D建模。
  • 动画:学习关键帧动画和运动捕捉技术。
  • 着色器和材质:为3D模型创建逼真的视觉效果。
7. 掌握音频和音乐制作

音频是游戏中的重要组成部分,学习音频编辑和音乐制作可以极大地增强游戏体验:

  • 音效设计:使用工具如Audacity或FMOD Studio创建和编辑音效。
  • 音乐制作:学习音乐理论,并使用软件如Ableton Live或FL Studio制作背景音乐。
8. 探索虚拟现实(VR)和增强现实(AR)

随着技术的发展,VR和AR为游戏开发提供了新的可能性:

  • VR游戏开发:学习如何在Unity或Unreal Engine中开发沉浸式VR体验。
  • AR应用:使用ARKit(iOS)或ARCore(Android)开发增强现实游戏。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1801097.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C# MemoryCache 缓存应用

摘要 缓存是一种非常常见的性能优化技术&#xff0c;在开发过程中经常会用到。.NET提供了内置的内存缓存类 MemoryCache&#xff0c;它可以很方便地存储数据并在后续的请求中快速读取&#xff0c;从而提高应用程序的响应速度。 正文 通过使用 Microsoft.Extensions.Caching.Me…

Sql-labs的第一关

前言 我们在使用Sql-libs靶场进行Sql注入实验的时候&#xff0c;前提要求我们对mysql数据库结构要有一个大概的了解&#xff0c;因为mysql5.0以上的版本都会自带一个名为information_schema的数据库&#xff0c;这个数据库下面会有columns和tables两个表。 tables这个表的table…

【学习笔记】Windows GDI绘图(十一)Graphics详解(下)

文章目录 Graphics的方法Graphics.FromImageSetClip设置裁切区域IntersectClip更新为相交裁切区域TranslateClip平移裁切区域IsVisible判断点或矩形是否在裁切区域内MeasureCharacterRanges测量字符区域MeasureString测量文本大小MultiplyTransform矩阵变换 Graphics的方法 Gr…

【纯血鸿蒙】——响应式布局如何实现?

前面介绍了自适应布局&#xff0c;但是将窗口尺寸变化较大时&#xff0c;仅仅依靠自适应布局可能出现图片异常放大或页面内容稀疏、留白过多等问题。此时就需要借助响应式布局能力调整页面结构。 响应式布局 响应式布局是指页面内的元素可以根据特定的特征&#xff08;如窗口…

AI降重技术:革新论文查重与修改策略

AIGC降重指南&#xff1a;如何有效使用AI工具降低论文查重率&#xff1f; 论文查重和降重是确保学术成果原创性及学术诚信的关键步骤&#xff0c;直接影响我们的学业成果和毕业资格。传统的论文查重方法主要包括使用查重软件和个人自查&#xff0c;而论文降重通常涉及改写、使…

Docker中搭建likeadmin

一、使用Docker中的docker-compose搭建likeadmin 1.去网址&#xff1a;https://gitee.com/likeadmin/likeadmin_php中下载likeadmin 注册一个giee账号后 点那个克隆下载 按照序号在终端复制粘贴进去。 接着&#xff0c;输入ls 可以发现有一个这个&#xff1a; 里面有一个like…

数据结构复习指导之外部排序

目录 外部排序 复习提示 1.外部排序的基本概念 2.外部排序的方法 2.1对大文件排序时使用的排序算法&#xff08;2016&#xff09; 3.多路平衡归并与败者树 4.置换-选择排序&#xff08;生成初始归并段&#xff09; 4.1置换-选择排序生成初始归并段的实例(2023) 5.最佳…

单链表复习 (C语言版)

目录 一.顺序表与链表的区别 二.链表概念 三.单链表 1.单链表的开始与初始化 2.单链表的打印 3.单链表的尾插 重难点&#xff1a;单链表实现时的指针详解 4.单链表的头插 5.单链表的尾删 6.单链表的头删 小结&#xff1a; 7.单链表的查找 8.在指定位置前插入数据 …

深度学习的舌象诊断:从舌头上了解系统性疾病!

首先 深度学习算法能否解决东方医学中依靠医生经验的诊断问题&#xff1f;而要实现这个目标&#xff0c;需要什么呢&#xff1f; 用舌头诊断被称为口腔健康的指标&#xff0c;但在东方医学中&#xff0c;舌头也被用来评估全身的状况。换句话说&#xff0c;通过分析舌头的图像…

人工智能的统治:会是人类的终结吗?

使用ChatGPT运行/请求一系列提示以探索完全人工智能(AI)控制关键基础设施、自动化工厂 ( Tesla )、社交媒体 ( Meta )、SCADA和其他常见用途 (ModBUS?) 可能产生的后果后&#xff0c;我们进行了分析…… 以下是我们的考虑&#xff1a; 数据、提示和响应应被视为说明性的&…

通过影刀RPA,创建定时任务,自动获取图片验证码登录平台;

1.下载下载影刀客户端-影刀RPA - 影刀官网 2.安装&#xff0c;登录 3.应用创建->PC自动化应用 4.按照流程-创建【可双击或拖动】 5.保存 6.右击【创建的应用】->发版 7.选择触发器->【定时触发器】 根据提示配置 8.完成&#xff0c;每天平台会自动打开&#xff1b;…

算法学习笔记(7.7)-贪心算法(Dijkstra算法-最短路径问题)

目录 1.最短路径问题 2.Dijkstra算法介绍 3.Dijkstra算法演示 4.Dijkstra算法的代码示例 1.最短路径问题 图论中的一个经典问题&#xff0c;通常是指在一个加权图中找到从一个起始顶点到目标顶点的最短路径。 单源最短路径问题&#xff1a;给定一个加权图和一个起始顶点&…

http协议,tomcat的作用

HTTP 概念:Hyper Text Transfer Protocol&#xff0c;超文本传输协议&#xff0c;规定了浏览器和服务器之间数据传输的规则。 特点: 1.基于TCP协议:面向连接&#xff0c;安全 2. 基于请求-响应模型的:一次请求对应一次响应 3HTTP协议是无状态的协议:对于事务处理没有记忆能…

react学习-高阶组件

1.简介 react高阶组件是一个函数&#xff0c;接收一个组件作为参数&#xff0c;返回一个新的组件&#xff0c;可以用来进行组件封装&#xff0c;将一些公共逻辑提取到高阶组件内部。 2.基本实现 以下案例为利用高阶组件来增强props import React, { Component } from "re…

10.dockerfile自动构建镜像

dockerfile自动构建镜像 类似ansible剧本&#xff0c;大小几kb 手动做镜像&#xff1a;大小几百M 首先创建一个dockerfile的路径&#xff0c;便于在路径下存在多个路径每个路径下都是dockerfile命名的脚本 注释&#xff1a;文件必须为&#xff1a;dockerfile或者Dockerfile …

解决linux系统求前N月月份的bug

日常工作中&#xff0c;需要获取某个日期&#xff08;20240531&#xff09;的前N个月&#xff0c;通常会写命令 date -d "20240531 last-month" %Y%m 我期望得到202404 但是很意外&#xff1a; 经过几轮测试&#xff0c;发现只要月内天数超过30天&#xff0c;即所有…

基于Zero-shot实现LLM信息抽取

基于Zero-shot方式实现LLM信息抽取 在当今这个信息爆炸的时代&#xff0c;从海量的文本数据中高效地抽取关键信息显得尤为重要。随着自然语言处理&#xff08;NLP&#xff09;技术的不断进步&#xff0c;信息抽取任务也迎来了新的突破。近年来&#xff0c;基于Zero-shot&#x…

代码随想录——修建二叉搜素树(Leetcode669)

题目链接 递归 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val val; }* TreeNode(int val, TreeNode left, TreeNode right) {* …

【算法每日一练】新月轩就餐

思路&#xff1a; 其实很容易想到是双指针或者双端队列。 我们设置一个type表示当前区间已经有了多少种厨师&#xff0c;同时还需要记录区间中每个元素出现的次数&#xff0c;然后比较棘手的是移动问题了&#xff0c;什么时候移动呢&#xff1f; 我们可以发现当区间当队头元…

AI数据分析:用deepseek根据Excel数据绘制分裂饼形图

工作任务&#xff1a;要绘制下面表格中月活用户占比的分裂饼形图 在deepseek中输入提示词&#xff1a; 你是一个Python编程专家&#xff0c;要完成一个Python脚本编写的任务&#xff0c;具体步骤如下&#xff1a; 读取Excel文件"F:\AI自媒体内容\AI行业数据分析\poetop5…