JavaScript学习之飞机大战小游戏实现

飞机大战-小游戏实现

设计

目前会把整个游戏分成四个类

  • 引擎

  • 飞机

  • 子弹

  • 敌机

  • HTML代码

    <div class="main">
        <ul class="options">
              <li>简单模式</li>
              <li>一般模式</li>
              <li>地狱模式</li>
              <li>春哥附体</li>
        </ul>
    </div>
    <div class="mask"></div>
    
  • CSS代码

    *{
        margin:0;
        padding:0;
    }
    html,body{
        width:100%; 
        height:100%; 
        overflow: hidden;
    }
    .main{
    	margin: auto;
    	height: 100%;
    	background: url(images/bg.jpg) repeat-y;
    	background-position-y: 0px;
    	width: 480px;
    }
    .options{
    	position: absolute;
    	list-style: none;
    	margin: auto;
    	left: 0; right: 0; top: 100px; 
    	width: 200px;
    	height: 300px;
    	
    }
    .options li{
    	border-radius: 5px;
    	box-shadow: 0 0 2px 1px black;
    	float: left;
    	width: 200px;
    	height: 75px;
    	text-align: center;
    	line-height: 75px;
    	margin-bottom: 20px;
    	background: #f40;
    	color: white;
    	font: "微软雅黑";
    	font-size: 28px;
    	cursor: pointer;
    }
    .logo{
    	position: absolute;
    	left: 0; right: 0; top: 25%; 
    	margin: auto;
    	width: 428px; height: 104px;
    	background: url(images/logo.png) no-repeat;	
    }
    .loading{
    	position: absolute;
    	left: 0; right: 0; top: 60%;
    	margin: auto;
    	width: 192px; height: 41px;
    	background: url(images/loading1.png) no-repeat;
    }
    .my-warplane{
    	position: absolute;
    	width: 98px; height: 122px;
    	background: url(images/me.png) no-repeat;
    }
    .bullet{
    	position: absolute;
    	width: 7px; height: 18px;
    	background: url(images/bullet.png) no-repeat;
    }
    .bullet_die{
    	position: absolute;
    	width: 41px; height: 39px;
    	background: url(images/die1.png) no-repeat;
    	margin-left: -17px;
    }
    .enemy-small{
    	position: absolute;
    	width: 59px; height: 36px;
    	background: url(images/plane1.png) no-repeat;
    }
    .enemy-middle{
    	position: absolute;
    	width: 70px; height: 92px;
    	background: url(images/plane2.png) no-repeat;
    }
    .enemy-large{
    	position: absolute;
    	width:165px; height: 256px;
    	background: url(images/plane3.png) no-repeat;
    }
    
    .mask{
    	width: 100%;
    	height: 100%;
    	position: fixed;
    	top: 0;
    	left: 0;
    	z-index: -10;
    }
    .mask.active{
    	z-index: 999;
    	animation:die 0.5s infinite;
    }
    @keyframes die{
    	0%{
    		background-color: rgba(0, 0, 0, 0);
    	}
    	50%{
    		background-color: rgba(0, 0, 0, 0.3);
    	}
    	50%{
    		background-color: rgba(235, 0, 0, 0.3);
    	}
    }
    
  • JavaScript代码

        //引擎类
        class Engine{
            constructor(){
                this.btns = document.querySelectorAll(".options li");
                this.options = document.querySelector(".options");
                this.main = document.querySelector(".main");
                // 这个数据是给plane类用的; 
                this.main_width = this.main.offsetWidth;
                // 选择的游戏难度等级; 
                this.level = null;
                // 保存背景的位移位置; 
                this.bgposition = 0;
                this.bindEvent();
            }
            bindEvent() {
                this.btns.forEach((ele, index) => {
                    ele.onclick = () => {
                        this.level = index;
                        this.showAnimate();
                        
                        setTimeout(() => {
                            this.hideAnimate();
                            this.bgAnaimte();
                            this.gameStart();
                        }, 1000)
                    }
                })
            }
            // 展示开场动画; 
            showAnimate() {
                // 开场动画部分 : 
                // 清场 : 
                this.options.remove();
                // 元素入场 : 
                this.logo = createEle("logo");
                this.loading = createEle("loading");
                
                // 循环执行123的数值;
                // - 我们在javascript之中实现的所有动画效果其实不是对css属性的赋值就是对类名改变; 
                // - 如果多个元素的动作行为组合在一起用定时器执行就是我们需要的动画效果;  
                
                let num = 0;
                this.loading_t = setInterval(() => {
                    this.loading.style.background = `url(images/loading${(++num % 3) + 1}.png) no-repeat`;
                }, 500)
            }
            // 隐藏开场动画; 
            hideAnimate() {
                // 清场 : 
                this.logo.remove();
                this.loading.remove();
                clearInterval(this.loading_t);
            }
            // 背景动画; 
            bgAnaimte() {
                this.bg_t = setInterval(() => {
                    this.bgposition += 40;
                    this.main.style.backgroundPositionY = this.bgposition + "px";
                }, 100)
            }
            // 游戏开启; 
            gameStart() {
                this.plane = new Plane();
                this.createEnemy();
            }
            // 游戏暂停; 
            pause() {
                clearInterval(this.bg_t);   
            }
            // 游戏恢复 ; 
            start() {
                this.bgAnaimte();
            }
            createEnemy() {
                // 小飞机定时器; 
                this.small_enemy_t = setInterval(function () {
                    new Enemy;
                }, 2000)
                //中型飞机定时器
                this.middle_enemy_t = setInterval(function () {
                    new Enemy(1);
                }, 5000)
                //大型飞机定时器
                this.middle_enemy_t = setInterval(function () {
                    new Enemy(2);
                }, 15000)
            }
        }
        
        // 复用的组件我们单独提取并封装;
        function createEle(className) {
            var div = document.createElement("div");
            div.className = className;
            document.body.appendChild(div);
            return div;
        }
        
        function getRandomInt(min, max) {
            return min + Math.round((max - min) * Math.random())
        }
        let engine = new Engine;
        
        //飞机类
        class Plane{
            constructor() {
                this.plane = createEle("my-warplane");
                this.plane_width = this.plane.offsetWidth;
                this.plane_height = this.plane.offsetHeight;
                // 求得飞机x和y的最大最小值; 
                this.min_x = (innerWidth - engine.main_width) / 2;
                this.max_x = this.min_x + engine.main_width - this.plane_width;
                this.x = innerWidth / 2 - this.plane_width / 2;
                this.hp = 100;
                
                this.bullet_list = [];
                
                this.init();
                this.bindEvent();
                this.fire();
            }
            init() {
                this.plane.style.bottom = 0;
                this.plane.style.left = this.x + "px";
            }
            bindEvent() {
                document.addEventListener("mousemove", e => {
                    this.move(e.clientX - this.plane_width / 2)
                });
                window.addEventListener("resize", e => {
                    this.min_x = (innerWidth - engine.main_width) / 2;
                    this.max_x = this.min_x + engine.main_width - this.plane_width;
                })
            }
            move(x) {
                // 边间检测 ; 
                x = x < this.min_x ? this.min_x : x;
                x = x > this.max_x ? this.max_x : x;
                this.plane.style.left = x + "px";
                this.x = x;
            }
            fire() {
                // 1. 发射子弹的频率是engine选择难度之后根据难度数据做出的逻辑; 
                // 2. 每次都创建一个新的子弹对象,让子弹可以直接飞出去; 
                // 3. 记录了当前子弹的实例对象; 
                this.fire_t = setInterval(() => {
                    this.bullet_list.push(new Bullet(this.x, this.plane_height, this.plane_width, this.bullet_list));
                }, engine.level === 3 ? 50 : (engine.level + 1) * 200)
            }
        }
        
        //子弹类
        class Bullet{
            constructor(x, height, width, arr) {
                if (x === null) {
                    return false;
                }
                this.bullet = createEle("bullet");
                this.x = x + width / 2 - 3;
                this.y = innerHeight - height - 30;
                // 存放子弹的数组; 
                this.arr = arr;
                this.init();
                this.move();
            }
            move() {
                this.t = setInterval(() => {
                    this.y -= 18;
                    this.bullet.style.top = this.y + "px";
                    
                    if (this.y <= 0) {
                        this.destory();
                    }
                }, 30)
            }
            destory() {
                this.bullet.className = "bullet_die";
                clearInterval(this.t);
                
                this.arr.splice(this.arr.indexOf(this), 1);
                // 在飞机的数组之中删除掉对应的元素; 
                
                setTimeout(() => {
                    this.bullet.remove();
                }, 200)
            }
        }
        
        //敌机类
            // 敌机创建分成三个类别, 小飞机中飞机大飞机; 
            // - 1. 类名; 
            // - 2. 速度不一样; 
            // - 3. hp差距; 
        class Enemy{
            constructor(type = 0, x) {
                this.mask = document.querySelector(".mask");
                this.list = [
                    {
                        className: "enemy-small",
                        speed: 15,
                        hp: 1,
                        dieList: [
                            "plane1_die1.png",
                            "plane1_die2.png",
                            "plane1_die3.png",
                        ],
                        width: 59,
                        height: 36
                    },
                    {
                        className: "enemy-middle",
                        speed: 8,
                        hp: 5,
                        dieList: [
                            "plane2_die1.png",
                            "plane2_die2.png",
                            "plane2_die3.png",
                            "plane2_die4.png",
                        ],
                        width: 70,
                        height: 92
                    },
                    {
                        className: "enemy-large",
                        speed: 2,
                        hp: 20,
                        dieList: [
                            "plane3_die1.png",
                            "plane3_die2.png",
                            "plane3_die3.png",
                            "plane3_die4.png",
                            "plane3_die5.png",
                            "plane3_die6.png",
                        ],
                        width: 165,
                        height: 256
                    }
                ]
                Object.assign(this, this.list[type])
                this.y = 0;
                this.enemy = createEle(this.className);
                this.min_x = (innerWidth - engine.main_width) / 2;
                this.max_x = this.min_x + engine.main_width - this.enemy.offsetWidth;
                this.x = x || getRandomInt(this.min_x, this.max_x)
                this.init();
                this.move();
            }
            init() {
                this.enemy.style.top = this.y + "px";
                this.enemy.style.left = this.x + "px";
            }
            move() {
                this.enemy_t = setInterval(() => {
                    this.y += this.speed;
                    this.enemy.style.top = this.y + "px";
                    
                    // 碰撞检测; 
                    this.collision()
                    if (this.y >= innerHeight) {
                        this.enemy.remove();
                        clearInterval(this.enemy_t);
                    }
                }, 50)
            }
            destory() {
                clearInterval(this.enemy_t);
                // 动画效果; 
                let die_t = setInterval(() => {
                    var url = this.dieList.shift();
                    this.enemy.style.background = `url(images/${url}) no-repeat`;
                    // 如果死亡动画列表已经播放结束我们就关闭定时器, 同时在100毫秒之后删除当前元素; 
                    if (this.dieList.length === 0) {
                        clearInterval(die_t);
                        setTimeout(() => {
                            this.enemy.remove();
                    }, 100)
                    }
                }, 200)
            }
            // 碰撞检测和边界检测一样; 
            // 找极值 :  left 的极值, top的极值; 
            collision() {
                // this.x , this.y ; 
                let { plane } = engine
                let { bullet_list } = plane;
                bullet_list.forEach(bullet => {
                    // 原理见图片; 
                    if ((bullet.y >= this.y && bullet.y <= this.y + this.height + 20) && (bullet.x >= this.x && bullet.x <= this.x + this.width)) {
                        bullet.destory();
                        // 碰撞之后飞机应该让hp-1; 
                        this.hp--;
                        if (this.hp <= 0) {
                            this.destory();
                        }
                    }
                })
                
                // 判定战机和敌机的状态; 
                // 碰撞检测 ; 
                if (this.y + this.height >= innerHeight - 122) {
                    if (plane.x >= this.x - plane.plane_width && plane.x <= this.x + this.width) {
                        plane.hp--;
                        this.hp--;
                        if (this.hp <= 0) {
                            this.destory();
                        }
                        if (plane.hp <= 0) {
                            alert("游戏结束");
                            location.reload();
                        }
                        this.mask.classList.add("active");
                        clearTimeout(this.collision_t);
                        this.collision_t = setTimeout(() => {
                            this.mask.classList.remove("active");
                        }, 2000)
                    }
                }
            }
        }
    

图片资源链接

原创不易,转载请注明出处。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

山河不识

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

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

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

打赏作者

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

抵扣说明:

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

余额充值