• 《uni-app》一个非canvas的飞机对战小游戏实现-子弹模型的实现


    在这里插入图片描述

    这是一个没有套路的前端博主,热衷各种前端向的骚操作,经常想到哪就写到哪,如果有感兴趣的技术和前端效果可以留言~博主看到后会去代替大家踩坑的~接下来的几篇都是uni-app的小实战,有助于我们更好的去学习uni-app~
    主页: oliver尹的主页
    格言: 跌倒了爬起来就好~
    准备篇https://oliver.blog.csdn.net/article/details/127185461
    启动页实现https://oliver.blog.csdn.net/article/details/127217681
    敌机模型实现https://oliver.blog.csdn.net/article/details/127332264
    requestAnimationFrame详解https://oliver.blog.csdn.net/article/details/127377916
    我方飞机实现https://oliver.blog.csdn.net/article/details/127477230

    一. 前言

    上一篇中主要分享的是我方飞机这个模型功能的实现,包括了:飞机的样式,飞机的生成,飞机的创建坐标,飞机的位移操作等等,但是,很明显我们这个飞机还是不完善的,最大的功能遗漏就是子弹了,没有子弹,怎么能被称为是飞机大战呢,对不对~
    本文将实现的是
    子弹模型
    相关,当然,我们这个子弹还是属于简单的那一种,后续复杂子弹的实现我们后续再说,耐心看完,或许你会所有收获~

    二. 阅读对象与难度

    本文难度属于:中级,本文中主要实现的我方飞机发射的子弹型相关的操作,包括子弹坐标位置初始化,子弹移动,子弹样式等等,通过文本你可以大致了解到一下内容

    • Vue中的基础知识,包括v-for等常规用法;
    • 子弹的模型的样式,创建,位移等等;

    具体内容可以参考以下的思维导图:
    在这里插入图片描述

    三. 项目地址以及最终效果

    文本代码已上传CSDN上的gitCode,有兴趣的小伙伴可以直接clone,项目地址:https://gitcode.net/zy21131437/planegameuni
    如果有小伙伴愿意点个星,那就非常感谢了~最终效果图如下:
    在这里插入图片描述

    四. 子弹模型的实现

    4.1 分析分析

    根据上面的效果图,我们先分析一下要实现的功能:

    1. 首先要实现的是子弹的样式;
    2. 其次是子弹的初始化坐标,由于我方飞机的位置是不固定的,因此子弹的生成位置也将是不固定的;
    3. 最后时子弹创建后的自适应位移;

    大致上这三个功能在本文这个阶段是最主要的,再来估计一下如果要实现这几个功能可能要用到什么实现逻辑
    第一个,子弹样式
    子弹样式这一块和我方飞机、敌机一样,都是由DOM+CSS实现的,设定好宽高以及背景图即可;
    第二个,创建坐标
    既然是坐标,那坐标肯定是有x和y的,从效果上看,子弹创建的位置位于飞机头部的中间处,并且由于飞机是不固定位置的,因此子弹的位置也是不固定的
    第三个,子弹位移
    老规矩,位移还是靠的requestAnimationFrame实现的;

    4.2 子弹的样式

    先来看看子弹的样式,它的的素材图如下:
    在这里插入图片描述

    就是一个简单的图片,我们只需要将设定其宽高,并且背景图绑定图片即可:

    <template>
    	<view class="bullet">view>
    template>
    
    <style scoped lang="less">
    .bullet {
    	width: 7px;
    	height: 18px;
    	position: fixed;
    	z-index: 2;
    	background: url(@/static/images/bullet.png) no-repeat left top;
    }
    
    .bullet_effect {
    	display: none;
    }
    style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    4.3 子弹创建

    在了解子弹创建之前,我们得明白子弹的创建时机,和我方飞机与敌机不同的是,子弹并不是随时创建的,它必须在我们触发某一个按钮,比如web上的是按下空格键后触发创建,大致流程如下
    在这里插入图片描述
    因此首先,我们需要添加一个事件,一个按下空格键时触发的事件

    initEvent() {
      document.addEventListener('keydown', e => {
        switch (e.keyCode) {
          //空格
          case 32:
            this.launchBullet();
            break;
          //up键
          case 38:
            this.keyTop = true;
            break;
          //down键
          case 40:
            this.keyBottom = true;
            break;
          //left键
          case 37:
            this.keyLeft = true;
            break;
          //right键
          case 39:
            this.keyRight = true;
            break;
          default:
            console.log('无效案件,请使用上、下、左、右控制');
        }
      });
      document.addEventListener('keyup', e => {
        switch (e.keyCode) {
          //up键
          case 38:
            this.keyTop = false;
            break;
          //down键
          case 40:
            this.keyBottom = false;
            break;
          //left键
          case 37:
            this.keyLeft = false;
            break;
          //right键
          case 39:
            this.keyRight = false;
            break;
        }
      });
    },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    找到plane.vue中的按键监听,在 keydown 中额外新增一项,指定值为32时触发发射子弹的函数,这个32是空格键的内部识别码

    launchBullet() {
      const params = {
        width: 7,
        height: 18,
        x: this.data.x + 49,
        y: this.data.y,
        id: `bullet` + new Date().getTime()
      };
      this.$emit('addBullet', params);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    当按下空格键后,会触发这个名为 launchBullet的子弹创建函数,这个函数包括了子弹的宽,高,X轴,Y轴的坐标,以及唯一的标识码,可能有小伙伴问,不是说子弹的坐标不固定吗,为啥这边可以直接写死,并且还是加了一个49?这里解释一下,这里的this.data.x和this.data.y是当前飞机X轴,Y轴的坐标
    在这里插入图片描述

    子弹虽然是不固定的,但相对我方飞机来说,确又是固定的,它生成的位置永远在我方飞机头部中间处的位置,因此,子弹的X轴坐标只需要取得飞机的X轴加上飞机一半的宽度即可,高度就是等同于我方飞机Y轴的高度~
    创建完成后通过emit将参数传递到父组件中,父组件接收参数之后将其push到子弹缓存列表中

    
    <template>
      <Plane @addBullet="addBullet" />
    template>
    
    <script>
    import Bullet from '../view/bullet/bullet.vue';
    export default {
    	data() {
    		return {
    			bulletData: []
    		};
    	},
    	components: {Bullet },
    	onLoad() {
    		this.init();
    	},
    	methods: {
    		addBullet(param) {
    			console.log('--- 触发子弹 ---');
    			this.bulletData.push(param);
    		},
    	}
    };
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    当参数存入缓存数组后,通过v-for循环动态生成子弹

    
    <template v-if="isStart">
      <Bullet v-for="bullet in bulletData" :key="bullet.id" :data="bullet"  />
    template>
    
    • 1
    • 2
    • 3
    • 4

    并通过props将初始位置赋值给子弹模型

    <template>
    	<view 
        class="bullet" 
        :style="{ left: data.x + 'px', top: data.y + 'px' }"
        >view>
    template>
    
    <script>
    export default {
    	props: {
    		data: {
    			type: Object,
    			default: () => {
    				return {};
    			}
    		}
    	},
    };
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    这样,当我们按下空格键的时候,子弹就会被创建在飞机的头部的中间位置,虽然此时的子弹还不会位移
    在这里插入图片描述

    4.4 子弹的位移

    子弹的位移,实现上还是非常简单的,和我方飞机与敌机是相同的实现方式,都是利用的 requestAnimationFrame 实现,先看代码吧

    <script>
    export default {
    	methods: {
    		init() {
    			this.moveTimer = () => {
    				// 移动
    				this.move();
    				// 重绘,无限循环
    				requestAnimationFrame(this.moveTimer);
    			};
    			this.moveTimer();
    		},
    		move() {
    			if (this.data.y > 0) {
    				// 子弹的加速度
    				this.data.y += -5;
    			} else {
    				// this.isExplosion = true;
    				this.remove();
    			}
    		},
    		remove() {
    			this.$emit('removeBullet', this.data.id);
    		}
    	},
    	mounted() {
    		this.init();
    	}
    };
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    当子弹创建后,会执行 mounted 中的init方法,这个方法会通过 requestAnimationFrame 无限重绘子弹位置,重绘的依据则是在 move() 这个函数中实现的;
    接着看move这个函数,分为两段:

    • 第一段当子弹在Y轴上的坐标大于0时,不断改变它在Y轴上的坐标,每次减少5个像素,或者说子弹的加速度是5;
    • 第二段是移除子弹,我们知道子弹的存在并不是无限制的,比如当子弹没有击中敌机,并且子弹在Y轴的位置小于0,这就代表其实子弹已经超出屏幕了,这种情况下那这个子弹就没有存在的意义了,完全可以在DOM中移除掉,节省性能
      在这里插入图片描述
      因此,当子弹在Y轴的坐标小于0时,触发remove函数,通过emit将子弹的ID给传递出去
    this.$emit('removeBullet', this.data.id);
    
    • 1

    在父组件中接收到 removeBullet 这个事件后,遍历子弹缓存数组,移除对应id的子弹即可

    	let index = 0;
    	for (let i = 0; i < array.length; i++) {
    		if (array[i].id === id) {
    			index = i;
    			break;
    		}
    	}
    	array.splice(index, 1);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    五. 阶段性展示

    到这一章节,我们已经实现的效果图如下:
    在这里插入图片描述

    六. 小结

    本文主要概述了子弹模型的实现,主要包含:

    • 子弹样式:其实就是设定好DOM,加入背景图形成了一个子弹的DOM;
    • 子弹生成:按下空格键时,创建好子弹的参数,包括生成的位置坐标,并将参数传递到子弹的模型中;
    • 子弹操作位移:位移通过requestAnimationFrame实现;

    到这里,敌机,我方飞机,子弹模型都已经结束了,接下来就是碰撞检测了,这一块稍微涉及到了一些计算,当然,问题不大~

  • 相关阅读:
    流式结构化数据计算语言的进化与新选择
    jdk+tomcat+mysql+war打包整合成exe文件,Windows下一键安装
    CAS:385437-57-0 DSPE-PEG-Biotin 磷脂-聚乙二醇-生物素 常用生物活性分子
    如何避免游戏设计缺陷优漫教育
    应急响应 >> Windows系统应急
    为什么自动驾驶需要5G?
    记录了解php8-JIT
    Serverless安全揭秘:架构、风险与防护措施
    时序预测 | MATLAB实现CNN-LSTM卷积长短期记忆神经网络时间序列预测(风电功率预测)
    技术分享 | Selenium多浏览器处理
  • 原文地址:https://blog.csdn.net/zy21131437/article/details/127702195