文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Vue实现飞机大战小游戏

2024-04-02 19:55

关注

使用 Vue 开发一个简略版的飞机大战小游戏

如题,假设你为了向更多访问你博客的人展示你的技术,你决定小试身手开发一个飞机大战小游戏。
功能: 开始游戏前用户名必填,玩家可以发射子弹,敌军与行星随机出现,鼠标可操控玩家移动,敌军可发射子弹

一、实现思路

如题所述:

玩家可操控玩家飞机可发射子弹,敌军与行星随机生成;

这意味着我们需要一个单独的玩家飞机dom,以及敌军、行星与子弹 用 vue 循环生成的3个dom。

敌军与行星生成后的dom的位置由数据里的 x 与 y 值决定。

按下空格时产生的子弹由当时按下空格键的时候的飞机的位置来决定。

敌军随机发射的子弹由当时发射子弹的敌军的位置来决定。

游戏开始时用户名必填,那么我们只需要在 Vue 实例里为该 input 绑定一个数据,再为开始游戏按钮绑定点击事件。随后计算用户名的长度只要大于3,就调用游戏开始函数或初始化函数。

玩家鼠标操控移动飞机移动只需要为其父节点绑定鼠标移动事件,然后更改 player 里的 x 与 y 的数据 (x与y的值不能小于0,x与y的值不能大于父节点的宽高) 并且赋予 玩家飞机即可。

击毁敌军只需要拿 子弹与敌军 的 x,y 计算对比即可。

二、所需知识点

1. Vue 事件绑定
2. Vue 监听事件
3. Vue 计算属性
4. Vue Style操作

三、实现步骤

第一步:创建 HTML 与 CSS 文件

HTML

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>Vue 飞机大战</title>
        <link rel="stylesheet" href="css/style.css" >
    </head>
    <body>
        <main>
            -
            <div class="game-plane" 
                @mousemove="touchmove"
                :style="{backgroundPosition:'0px '+ positionY +'px'}" ref='plane'>
                
                <div id="hit">
                    <h2>击毁:{{ hitCount }}</h2>
                    <h2>与敌机相撞:{{ boom }}</h2>
                    <h2>被击中次数:{{ HitTimes }}</h2>
                    <h2>用户名:{{ username }}</h2>
                </div>
                
                <!-- 玩家 -->
                <img src="image/player.png" alt="player" id="p" :style="{top:p.y + 'px',left:p.x+'px'}">
                
                <!-- 星球 -->
                <img v-for="(item,index) of plane.arr" :style="{top:item.y + 'px',left:item.x+'px'}" src="image/plane.png" alt="plane">
                
                <!-- 敌军 -->
                <img v-for="(item,index) of e.arr" :style="{top:item.y + 'px',left:item.x+'px'}" src="image/e.png" class="e" alt="e">
                
                <!-- 子弹 -->
                <img v-for="(item,index) of bullets.arr" class="b"
                 :style="{top:item.y + 'px',left:item.x+'px'}" 
                 :src="item.tag == 'p' ? 'image/p_b.png' : 'image/e_b.png' " 
                 alt="p_b">
                
            </div>
        
            <!-- 开始面板 -->
            <div class="alert" ref="alert">
                <div class="content">
                    <div class="left">
                        <h1>Vue 飞机大战</h1>
                        <p>作者:柴不是柴</p>
                        <img :src="faceChange" class="face">
                    </div>
                    <div class="right">
                        <input type="text" v-model="username" placeholder="请输入你的名字">
                        <input type="submit" @click="startBtnClick"  value="开始游戏">
                    </div>
                </div>
            </div>
        </main>
        
        <script src="js/vue.js"></script>
        <script src="js/data.js"></script>
        <script src="js/app.js"></script>
    </body>
</html>

CSS

* {
    padding: 0;
    margin: 0;
}

main {
    display: flex;
    justify-content: center;
    align-items: center;
    width: 100%;
    height: 100vh;
    background-color: #282828;
}

main .game-plane {
    position: relative;
    width: 1200px;
    max-width: 1200px;
    height: 900px;
    background-image: url(../image/background.png);
    background-size: 100% auto;
    box-shadow: 0 2px 30px rgba(255,255,255,0.5);
    overflow: hidden;
}

main .game-plane img { position: absolute; }

.alert {
    position: absolute;
    top: calc(50% - 100px);
    left: 0;
    width: 100%;
    height: 200px;
    background: #FFF;
    box-shadow: 0 0 0 999em rgba(0, 0, 0, 0.5);
}

.alert .content {
    display: grid;
    grid-template-columns: 4fr 6fr;
    grid-template-rows: 100%;
    gap: 20px;
    margin: 0 auto;
    max-width: 1200px;
    width: 100%;
    height: 100%;
}

.alert .content .left {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
}

.alert .content .left * { margin: 5px 0; }

.alert .content .right {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
}

.alert .content .right input {
    width: 100%;
    display: block;
    box-sizing: border-box;
    padding: 10px;
}

.e { transform: rotate(180deg); }

.b { width: 30px; }#hit {
    position: absolute;
    top: 20px;
    left: 20px;
    color: #FFF;
}

第二步:创建一个全局 data 文件

window.el = document.querySelector(".game-plane");
window.data = {
    p : {// 玩家 Player
        w : document.querySelector("#p").offsetWidth,
        h : document.querySelector("#p").offsetHeight,
        x : el.offsetWidth / 2 - document.querySelector("#p").offsetWidth / 2,
        y : el.offsetHeight - document.querySelector("#p").offsetHeight
    },
    
    e : {// 敌机 enemy plane
        arr : [],
        speed : 6,
    },
    
    plane : { arr : [] },// 星球    
    bullets : { arr : [] },// 子弹
    hitCount : 0,// 击中总数
    boom : 0,// 碰撞次数
    HitTimes : 0,// 被击中次数
    start : false,// 游戏是否开始
    positionY : 0,// 背景 Y 值
    timers : [],// 定时器
    face : "ordinary",// 表情
    username : "" // 玩家名
}

第三步:创建Vue 实例

var Game = new Vue({
    el : "main",
    data,
    
    methods:{
        startBtnClick() {
            if ( this.username.length <= 2 ) return alert("用户名不可少于3位字符哦!");
            this.init();
        },
        
        init() {// 初始化
            let _this = this;
            this.start = true;
            this.$refs.alert.style.display = "none";
            
            this.createE();
            this.createPlane();
            this.timers.push( setInterval( this.bgMove,20 ) )
            this.timers.push( setInterval(function() { _this.move('bullets') }, 20 ) )
        },
        
        bgMove () { // 背景移动 顺带判断玩家是否装上敌军
            this.positionY += 5; 
            if ( this.hit_check(this.p) ) this.boom++;
        },
        
        touchmove(){// 飞机移动
            let touch,x,y;
            if ( !this.start ) return;
            
            if(event.touches) touch = event.touches[0];
            else touch = event;
            
            x = touch.clientX - this.$refs.plane.offsetLeft - this.p.w / 2;
            y = touch.clientY - this.$refs.plane.offsetTop - this.p.h / 2;
            
            y = y < 0 ? 0 : y > (this.$refs.plane.offsetHeight - this.p.h) ? this.$refs.plane.offsetHeight - this.p.h : y;
            x = x < 0 ? 0 : x > (this.$refs.plane.offsetWidth - this.p.w) ? this.$refs.plane.offsetWidth - this.p.w : x;
            
            this.p.x = x;
            this.p.y = y;
        },
        
        createE() { // 创建敌军
            let _this = this,x;
            
            this.timers.push( setInterval( function() {
                x = Math.ceil( Math.random() * ( _this.$refs.plane.offsetWidth - 80 ) );
                _this.build('e',{ x: x, y: 5 })     
            }, 1000 ));
            
            this.timers.push( setInterval( function() { _this.move('e') }, 20 ));
        },
        
        createPlane() {// 创建行星
            let _this = this,x;
            
            this.timers.push( setInterval( function() {
                x = Math.ceil( Math.random() * ( _this.$refs.plane.offsetWidth - 80 ) );
                _this.build('plane',{ x: x, y: 5 }) 
            }, 2000 ));
            
            this.timers.push( setInterval( function() { _this.move('plane') }, 20 ));
        },
        
        createButter(table,e) {// 创建子弹
            if ( !this.start ) return;
            
            let bullter = {
                x:(e.x + (e.w ? e.w : 30) / 2),
                y:e.y - (e.h ? e.h : -30),
                speed : table == "p" ? -6 : 10,
                tag : table
            };
            
            this.build('bullets',bullter);
        },
        
        build(table,data) {// 公共创建
            let _this = this;
            this[table].arr.push( data );
        },
        
        move(table) {// 公共移动
            for( let i = 0; i < this[table].arr.length; i ++ ){
                let e = this[table].arr[i],
                    math = Math.random() * 100,
                    speed = this[table].speed ? this[table].speed : 5;
                
                if ( table == 'bullets' ) speed = e.speed;
                
                e.y += speed;
              
                if ( table !== 'bullets' ) {// 如果不是子弹dom的移动
                    if( e.y > this.$refs.plane.offsetHeight - 55 ) this[table].arr.splice(i,1);
                    
                    if ( table == 'e' && math < 1 ) { this.createButter('e',e); }
                } else {
                    if ( e.tag == 'p' ) {
                        if ( this.hit_check(e) ) this[table].arr.splice(i,1);
                        else if ( e.y < 0 ) this[table].arr.splice(i,1);
                    } else {
                        if ( this.hit(e,this.p) ) {
                            this[table].arr.splice(i,1);
                            this.HitTimes++;
                        }
                        else if ( e.y > this.$refs.plane.offsetHeight - 30 ) this[table].arr.splice(i,1);
                    }
                }
            }
        },
        
        hit_check(b) {// 是否击毁敌军
            for( let i = 0; i < this.e.arr.length; i ++ ){
                if( this.hit(b,this.e.arr[i]) ){ 
                    this.e.arr.splice(i,1);
                    this.hitCount++;
                    return true;
                }
            }
        },
        
        hit(b,e) {// 碰撞
            let d = this.judgeHit( b.x, b.y, e.x, e.y );
            if( d < 35 ) return true;
        },
        
        judgeHit(x1, y1, x2, y2) {// 计算两个点的距离差
            let a = x1 - x2,
                b = y1 - y2,
                result = Math.sqrt( Math.pow( a, 2) + Math.pow( b, 2 ) );
            return Math.round( result );
        },
        
        pause() {// 暂停
            this.start = false;
            this.timers.forEach(element => { clearInterval(element); })
        }
    },
    
    watch: {
        username () {// 监听玩家输入事件
            if ( this.username.length > 2 ) this.face = "shy";
            else this.face = "ordinary";
        }
    },

    mounted(){
        let _this = this;
        document.onkeyup = function(e) {
            ( e.keyCode == 32 ) && _this.createButter("p",_this.p);
            // ( e.keyCode == 80 ) && _this.pause();
        }
    },
    
    computed:{ faceChange() { return "image/"+this.face + ".png"; } }
});

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程网。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-前端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯