Html飞机大战(十): 消灭敌机

好家伙,本篇是带着遗憾写完的。

很遗憾,我找了很久,找到了bug但并没有成功修复bug

 

 

再上一篇中我们看到

 

子弹射中了敌机,但是敌机并没有消失,所以这篇我们要来完善这个功能

 

按照惯例我们来捋一下思路:

看看表面的物理逻辑:

子弹击中敌机=>敌机爆炸=>敌机消失=>子弹消失

 

敌机爆炸=>敌机消失=>子弹消失

这三步的实现都非常简单

无非就是:

敌机爆炸:改变图片,渲染,

敌机消失:在敌机数组中删除被子弹击中的敌机

子弹消失:在子弹数组中删除击中敌机的子弹

 

我们重点来讲一讲如何判定子弹击中敌机

 

我用到的方法是一个非常粗暴的枚举

 

我们用两个for循环,去遍历所有的敌机和子弹

for (let i = 0; i < enemies.length; i++) {
                //遍历所有的子弹
                for (let j = 0; j < hero.bulletList.length; j++) {
                    //一个检测是否碰撞的方法
             dosomething();
                    //如果碰到了才做某些事情
                    if (dosomething()) {
            //一个删除子弹和敌机的方法             dosomething();
            dosomething();
} } }

在第二个for循环中,我们检测一架敌机是否与所有的子弹中的任意一颗有接触

有接触我们就把这个敌机和子弹删掉

 

大概是这么个思路,碰撞的具体判定方法我们放到下面去说

 

开干

 

1.全局碰撞检测函数

function checkHit() {
            //

            for (let i = 0; i < enemies.length; i++) {
                //遍历所有的子弹
                for (let j = 0; j < hero.bulletList.length; j++) {
                    //用第i架敌机去和第j颗子弹碰撞,返回的是一个布尔类型
                    enemies[i].hit(hero.bulletList[j]);
                    console.log(enemies[i].hit(hero.bulletList[j]));

                    //如果碰到了才做某些事情
                    if (enemies[i].hit(hero.bulletList[j])) {
                        //清除敌机和子弹
                        //导向一个(控制爆炸渲染)变量方法
                        enemies[i].collide();

                        // hero.bulletList[j].collide();

                    }
                }
            }
        }

 

方法调用写上

case RUNNING:
                        sky.judge();
                        sky.paint(context);
                        //加载主角

                        hero.paint(context);
                        hero.shoot();
                        createComponent();
                        //子弹发射
                        judgeComponent();
                        paintComponent();
                        deleteComponent();
                        checkHit();
                        // context.drawImage(hero_frame.live[0], 0, 0);
                        break;

 

2.检测函数hit

我们把这个检测方法hit写在敌机enemy类中,然后我们把子弹当做参数传过去,

这样我们就可以在这个方法中同时处理敌机和子弹了

//检测敌机是否有撞到其他物体(子弹/hero)
            //敌机e
            //子弹o
            hit(o) {
                console.log("hit方法被触发");
                //其他物体的左边
                let ol = o.x;
                //其他物体的右边
                let or = o.x + o.width;
                //其他物体的上边
                let ot = o.y
                //其他物体的下边
                let ob = o.y + o.height;
                //子弹的左边
                let el = this.x;
                //子弹的右边
                let er = this.x + this.width;
                //子弹的上边
                let et = this.y;
                //子弹的下边
                let eb = this.y + this.height;
                //判断是否有碰到
                if (ol > er || or < el || ot > eb || ob < et) {
                    //没有碰到
                    return false;
                } else {
                    //碰到了
                    return true;
                    //转到
                }
            }

 

这里来讲一下碰撞判定的逻辑

理论上来说,我们分别拿到敌机和子弹的上下左右边

随后进行一个判断

如果子弹的左边大于敌机的右边,

       子弹的右边小于敌机的左边,

  如此类推

  如此类推

那么子弹和飞机就没碰撞,

否则两者碰撞碰,碰撞后返回true,使我们在chickHit方法中调用collide()方法

 

3.collide()方法

这个方法被写在敌机enemy类中

collide() {
                //中弹后,减少生命值
                console.log("collide方法被触发");

                this.life--;
                //没血之后,机毁人亡
                if (this.life === 0) {
                    //1.将live标识标记为死亡状态
                    //2.播放死亡东湖
                    //3.播放死亡动画完毕后才有真正的销毁这架飞机
                    this.life = false;
                    console.log(this.life);
                }
            }

我们有一个方法在"监视"life这个属性

当这个属性变为false时,我们开始播放敌机爆炸的动画

 

 

4.move()方法

这个方法被写在enemy类中

由于我们的move方法是一直在被调用的,所以我们可以把"敌机爆炸动画"放在这里

(这里只是改变图片,渲染放到别的方法里面去了,你应该能懂我意思)

并在动画结束后销毁敌机

 move() {
                const currentTime = new Date().getTime();
                //

                if (currentTime - this.lastTime >= this.speed) {
                    //如果飞机活着
                    //this.live由collide
                    if (this.live) {
                        this.img = this.frame.live[0];
                        this.y++;
                        //时间修正
                        this.lastTime = currentTime;
                    } else {
                        //死的时候播放死亡动画 0 1 2 3 
                        //活着 爆炸中 死亡
                        this.img = this.frame.death[this.deathIndex++];
                        //如果死亡动画播放完毕之后就要销毁这家敌机
                        if (this.deathIndex === this.frame.death.length) {
                            this.destory = true;
                            console.log(this.destory);

                        }
                        //修正上一次时间
                        this.lastTime = currentTime;
                    }

                }
            }

在最后我们是destory属性转为true

 

5.全局敌机/子弹删除函数

我们到这一步才真正销毁敌机

//全局函数 来销毁所有的子弹/敌人组件
        function deleteComponent() {
            for(let i =0;i<hero.bulletList.length;i++){
                //删除多余子弹
                if(hero.bulletList[i].y<0){
                    hero.bulletList.splice(i,1);
                }
            }
            console.log("deleteComponent方法被触发");

            for (let i = 0; i < enemies.length; i++) {
                //如果敌机处于一种销毁状态
                if (enemies[i].destory) {
                    //此处才是真正的销毁函数
                    enemies.splice(i, 1);
                    console.log(enemies);

                }
            }
        }

有人会问了:为什么不直接在move()方法后面,在动画结束之后,直接销毁敌机呢?

因为如果直接这样写的话,销毁敌机这一步确实变得方便了,但其实我们还要照顾到子弹的销毁,

所以我们把敌机的销毁放到这个全局方法中,是一个省事的选择

 

大概就是这样了,

但很可惜,有bug,且浏览器没报错,目前查到是判定那块出了问题

接着修bug吧,

 

效果图暂无

 

附上到目前为止,全部的代码

 

 1 //全局函数 来销毁所有的子弹/敌人组件
 2         function deleteComponent() {
 3             for(let i =0;i<hero.bulletList.length;i++){
 4                 //判断有无废除便捷
 5                 if(hero.bulletList[i].y<0){
 6                     hero.bulletList.splice(i,1);
 7                 }
 8             }
 9             console.log("deleteComponent方法被触发");
10 
11             for (let i = 0; i < enemies.length; i++) {
12                 //如果敌机处于一种销毁状态
13                 if (enemies[i].destory) {
14                     //此处才是真正的销毁函数
15                     enemies.splice(i, 1);
16                     console.log(enemies);
17 
18                 }
19             }
20         }
Html飞机大战半成品

 

posted @ 2022-09-04 00:59  养肥胖虎  阅读(69)  评论(0编辑  收藏  举报