h5原生实现飞机大战(完整代码)

先看看效果图

 

 

  github地址:https://github.com/dong432/plane

1、首先准备好需要的素材,己方飞机、敌方飞机、爆炸效果(可以自行寻找素材,一下是该项目所用素材)

             

2、创建好父类-plane.js,(好像没啥用,就保存dom和一些属性)

class plane {
  constructor(options) {
    this.dom = options.dom;
    for (let key in options) {
      this[key] = options[key];
    }
  }
}

3、创建己方飞机类-mine.js

        继承父类plane,给定己方飞机高度宽度和位置,然后给己方飞机绑定拖拽事件

class mine extends plane {
    constructor (options) {
        super({
            name: 'mine',
            left: 0,
            top: 0,
            ...options,
            dom: document.createElement('div')
        })
        this.dom.className = 'mine'
        // 设置飞机在屏幕下方中间
        this.left = bodyWidth / 2 - this.width / 2;
        this.top = bodyHeight - 100;
        // 把飞机放到body里面
        document.body.appendChild(this.dom)
        // 绑定拖拽事件
        this.draggable()
    }
    // 让元素可拖拽
    draggable() {
      this.dom.onmousedown = (e) => {
        let left = e.clientX - this.dom.offsetLeft;
        let top = e.clientY - this.dom.offsetTop;
        document.onmousemove = ({ clientX, clientY }) => {
          this.left =
            clientX - left < 0 - this.width / 2
              ? -this.width / 2
              : clientX - left > bodyWidth - this.width / 2
              ? this.left
              : clientX - left;
          this.top =
            clientY - top < 0
              ? 0
              : clientY - top > bodyHeight - this.height
              ? this.top
              : clientY - top;
          render(this)
        };
        document.onmouseup = (e) => {
          document.onmousemove = null;
          this.dom.onmouseup = null;
        };
      };
    }
}

4、创建子弹类-bullet.js

        子弹为敌人和英雄共用类,所以设置了子弹方向(direction),速度(speed),颜色(color),

给子弹实例一个定时器,让它不停向下或向上移动,当子弹超出屏幕时,删除子弹实例,移除dom元素

class bullet extends plane {
    constructor(options) {
        super({
            ...options,
            name: 'enemy',
            dom: document.createElement('div')
        })
        this.dom.style.backgroundColor = options.color || "#000";
        this.dom.className = 'bullet';
        // 子弹显示停留做个透明度过渡衔接
        this.dom.style.opacity = 0;
        document.body.appendChild(this.dom);
        this.upgo()
    }
    upgo() {
        let clock = setInterval(() => {
            if (this.direction == 'up') this.top -= this.speed;
            else if (this.direction == 'down') this.top += this.speed;
            else {
                clearInterval(clock)
                console.warn('请设置子弹方向')
            }
            this.dom.style.opacity = 1;
            if (this.top <= -this.height && this.direction == 'up') {
                bulletObj[this.index] = null;
                delete bulletObj[this.index]
                clearInterval(clock)
                return this.dom.remove()
            } else if (this.top >= bodyHeight && this.direction == 'down') {
                enemyBulletObj[this.index] = null;
                delete enemyBulletObj[this.index]
                clearInterval(clock)
                return this.dom.remove()
            }
        }, 100);
        this.moveClock = clock
    }
}

5、创建敌机类-enemy.js

        创建一个敌机,left 为屏幕宽度随机位置,top 为负的敌机高度,然后给敌机创建子弹,速度应快于敌机下降速度,当敌机超出屏幕,删除敌机实例,移除dom元素

class enemy extends plane {
    constructor(options) {
        super({
            ...options,
            top: -options.height,
            left: Math.floor(Math.random() * bodyWidth),
            name: 'enemy',
            dom: document.createElement('div')
        })
        this.dom.className = "enemy"
        document.body.appendChild(this.dom)
        this.down()
        this.createBullet()
    }
    // 向下坠
    down() {
        let clock = setInterval(() => {
            this.top += this.speed
            if (this.top >= bodyHeight) {
                clearInterval(clock)
                clearInterval(this.enemyBulletClock)
                enemyObj[this.index] = null
                delete enemyObj[this.index]
                return this.dom.remove()
            }
        }, 100);
        this.moveClock = clock
    }
    // 创建子弹
    createBullet() {
        let enemyBulletClock = setInterval(() => {
            enemyBulletKey++;
            const width = 10, height = 20
            let enemyBullet = new bullet({
                speed: this.speed + 30,
                width,
                height,
                direction: 'down',
                left: this.left + this.width / 2 - width / 2,
                top: this.top + this.height,
                index: enemyBulletKey
            })
            enemyBulletObj[enemyBulletKey] = enemyBullet
        }, 500);
        this.enemyBulletClock = enemyBulletClock
    }
}

6、创建游戏结束类-gameover.js

        游戏结束,创建一个弹窗在屏幕正中间,显示分数和评语,以及重新开始按钮

class gameover extends plane{
    constructor(options) {
        super({
            ...options,
            dom: document.createElement('div')
        })
        this.draggable()
        this.dom.className = 'gameover'
        let title = document.createElement('div')
        title.className = 'title'
        title.innerText = '游戏结束'
        this.dom.appendChild(title)
        let scoreDom = document.createElement('div')
        scoreDom.className = 'score'
        scoreDom.innerText = '分数:' + score
        this.dom.appendChild(scoreDom)
        let time = document.createElement('div')
        time.className = 'time'
        time.innerText = score > 200 ? '超神' : score > 120 ? '666' : score > 50 ? '太棒啦' : '继续努力'
        this.dom.appendChild(time)
        let btn = document.createElement('button')
        btn.className = 'resetGame'
        btn.innerText = '重新开始'
        btn.onclick = () => {
            location.reload()
        }
        this.dom.appendChild(btn)
        document.body.appendChild(this.dom)
    }
}

7、创建html文件-index.html

        创建维护己方子弹对象

        创建维护敌机对象

        创建维护敌方子弹对象

        用于监听他们之间的碰撞情况,用一个自增key作为他们的属性

        changeCoordinate-更新dom,并监听是否发生碰撞

        render-执行各个元素位置更新

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>飞机大战</title>
    <link rel="stylesheet" href="./index.css" />
  </head>
  <body>
    <div class="scores">得分:0</div>
    <button class="begin">开始游戏</button>
    <script>
      // 创建维护敌机的对象
      let enemyObj = {};
      // 创建维护子弹的对象
      let bulletObj = {};
      // 创建维护敌人子弹的对象
      let enemyBulletObj = {};
      // 创建敌人子弹自增key
      let enemyBulletKey = 0;
      // 创建子弹自增key
      let bulletKey = 0;
      // 创建敌机自增key
      let enemyKey = 0;
      // 游戏是否结束
      let over = false;
      // 分数
      let score = 0;
      // 屏幕宽高
      let bodyWidth =
        document.compatMode == "BackCompat"
          ? document.body.clientWidth
          : document.documentElement.clientWidth;
      let bodyHeight =
        document.compatMode == "BackCompat"
          ? document.body.clientHeight
          : document.documentElement.clientHeight;
      // 更新dom,监听是否碰撞
      function changeCoordinate() {
        if (over) return;
        if (mineExample) {
          this.render(mineExample);
        }
        for (let key in bulletObj) {
          this.render(bulletObj[key]);
        }
        for (let key in enemyObj) {
          this.render(enemyObj[key]);
        }
        for (let key in enemyBulletObj) {
          this.render(enemyBulletObj[key]);
        }
        let l3 = mineExample.dom.offsetLeft;
        let t3 = mineExample.dom.offsetTop;
        let r3 = l3 + mineExample.dom.offsetWidth;
        let b3 = t3 + mineExample.dom.offsetHeight;
        for (let bulletKey in bulletObj) {
          const bulletDom = bulletObj[bulletKey].dom;
          for (let enemyKey in enemyObj) {
            const enemyDom = enemyObj[enemyKey].dom;
            let l1 = bulletDom.offsetLeft;
            let t1 = bulletDom.offsetTop;
            let r1 = l1 + bulletDom.offsetWidth;
            let b1 = t1 + bulletDom.offsetHeight;

            let l2 = enemyDom.offsetLeft;
            let t2 = enemyDom.offsetTop;
            let r2 = l2 + enemyDom.offsetWidth;
            let b2 = t2 + enemyDom.offsetHeight;
            if (r1 > l2 && l1 < r2 && b1 > t2 && t1 < b2 && !enemyDom.bao) {
              enemyDom.bao = true;
              enemyDom.style.backgroundImage = `url(./bao.gif?time=${Math.random()})`;
              bulletObj[bulletKey] = null;
              delete bulletObj[bulletKey];
              // 敌机毁灭,停止发射子弹
              clearInterval(enemyObj[enemyKey].enemyBulletClock);
              clearInterval(enemyObj[enemyKey].moveClock);
              bulletDom.remove();
              score++;
              scoreDom.innerHTML = "得分:" + score;
              setTimeout(() => {
                enemyObj[enemyKey] = null;
                delete enemyObj[enemyKey];
                enemyDom.remove();
              }, 800);
            }
            if (r2 > l3 && l2 < r3 && b2 > t3 && t2 < b3 && !enemyDom.bao) {
              return this.gameOver();
            }
          }
        }
        for (let key in enemyBulletObj) {
          const enemyBulletDom = enemyBulletObj[key].dom;
          let l2 = enemyBulletDom.offsetLeft;
          let t2 = enemyBulletDom.offsetTop;
          let r2 = l2 + enemyBulletDom.offsetWidth;
          let b2 = t2 + enemyBulletDom.offsetHeight;
          if (r2 > l3 && l2 < r3 && b2 > t3 && t2 < b3) {
            return this.gameOver();
          }
        }
      }
      function render(temp) {
        if (over) return;
        temp.dom.style.width = temp.width + "px";
        temp.dom.style.height = temp.height + "px";
        temp.dom.style.left = temp.left + "px";
        temp.dom.style.top = temp.top + "px";
      }
      // 游戏结束
      function gameOver() {
        over = true;
        const width = 400,
          height = 400;
        new gameover({
          width,
          height,
          left: bodyWidth / 2 - width / 2,
          top: bodyHeight / 2 - height / 2,
        });
        for (let key in enemyObj) {
          const item = enemyObj[key];
          clearInterval(item.enemyBulletClock);
          clearInterval(item.clock);
          clearInterval(item.moveClock);
        }
        for (let key in bulletObj) {
          const item = bulletObj[key];
          clearInterval(item.clock);
          clearInterval(item.moveClock);
        }
        for (let key in enemyBulletObj) {
          const item = enemyBulletObj[key];
          clearInterval(item.moveClock);
        }
        mineExample.dom.onmousedown = null;
      }
      const begin = document.querySelector(".begin");
      let scoreDom = null;
      let mineExample = null;
      // 子弹发射频率 - 100毫秒
      const launch = 100;
      begin.onclick = () => {
        begin.style.display = "none";
        // 获取分数dom对象
        scoreDom = document.querySelector(".scores");
        // 创建自己
        /*
            width: number - 自己宽度
            height: number - 自己高度
        */
        mineExample = new mine({
          width: 52,
          height: 26,
        });
        // 循环创建自己的子弹
        let bulletClock = setInterval(() => {
          bulletKey++;
          /*
            speed: number - 子弹速度
            direction: up | down - 子弹方向
            left: number - 坐标x
            top: number - 坐标y
            width: number - 子弹宽度
            height: number - 子弹高度
            color: string - 子弹颜色
        */
          // 生成随机颜色
          const getRandomColor = () => {
            let color = "#";
            const str = "abcdef1234567890";
            const strL = str.length;
            for (let i = 0; i < 6; i++) {
              color += str[Math.floor(Math.random() * strL)];
            }
            return color;
          };
          const width = 4,
            height = 10;
          let biu = new bullet({
            speed: 60,
            direction: "up",
            left: mineExample.left + mineExample.width / 2 - width / 2,
            top: mineExample.top,
            width,
            height,
            color: getRandomColor(),
            index: bulletKey,
            clock: bulletClock,
          });
          bulletObj[bulletKey] = biu;
        }, launch);
        const createEnemyTime = 100;
        // 循环生成敌人
        let enemyClock = setInterval(() => {
          enemyKey++;
          /*
                        speed: number - 敌机速度
                        width: number - 敌机宽度
                        height: number - 敌机高度
                    */
          let di = new enemy({
            width: 50,
            height: 50,
            speed: 20,
            index: enemyKey,
            clock: enemyClock,
          });
          enemyObj[enemyKey] = di;
        }, createEnemyTime);
        setInterval(() => {
          changeCoordinate();
        }, 20);
      };
    </script>
    <script src="./plane.js"></script>
    <script src="./gameover.js"></script>
    <script src="./mine.js"></script>
    <script src="./bullet.js"></script>
    <script src="./enemy.js"></script>
  </body>
</html>

8、最后加上样式-index.css

* { margin: 0; padding: 0; user-select: none; }
body {
    width: 100vw;
    height: 100vh;
    overflow: hidden;
}
.mine {
    cursor: pointer;
    position: absolute;
    background-color: transparent;
    background-image: url(./mine.png);
    background-repeat: no-repeat;
    background-size: cover;
    background-position: center center;
    border-radius: 3px;
}
.bullet {
    position: absolute;
    border-radius: 3px;
    transition: all .1s linear 0s;
}
.enemy {
    cursor: pointer;
    position: absolute;
    background-color: transparent;
    background-image: url(./enemy.png);
    background-repeat: no-repeat;
    background-size: cover;
    background-position: center center;
    border-radius: 3px;
    transition: all .1s linear 0s;
}
.gameover {
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    z-index: 1;
    width: 400px;
    height: 400px;
    background-color: #eee;
    border-radius: 20px;
    overflow: hidden;
    box-shadow: 0 0 5px 5px #999;
    text-align: center;
}
.gameover .title {
    background-color: brown;
    line-height: 50px;
    color: #fff;
    font-size: 20px;
    font-weight: bold;
}
.gameover .score {
    font-size: 60px;
    color: #0000ae;
    font-family: monospace;
    margin-top: 30px;
}
.gameover .time {
    margin-top: 40px;
    font-size: 30px;
}
.gameover .resetGame {
    width: 50%;
    height: 40px;
    margin-top: 80px;
    cursor: pointer;
    background-color: #ffa500;
    border: none;
    border-radius: 10px;
    font-size: 18px;
    color: #fff;
    box-shadow: 0 0 5px #787878;
}
.gameover .resetGame:active {
    background-color: #ffb938;
}
.scores {
    position: fixed;
    top: 20px;
    left: 50%;
    transform: translateX(-50%);
    font-size: 30px;
    font-weight: bold;
    color: #0000ae;
}
.begin {
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    background-color: #ffa500;
    color: #fff;
    border-radius: 10px;
    border: none;
    width: 200px;
    height: 40px;
    font-size: 20px;
    box-shadow: 0 0 5px #787878;
}
.begin:active {
    background-color: #ffb938;
}
  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

qw.Dong

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

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

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

打赏作者

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

抵扣说明:

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

余额充值