这是一个没有套路的前端博主,热衷各种前端向的骚操作,经常想到哪就写到哪,如果有感兴趣的技术和前端效果可以留言~博主看到后会去代替大家踩坑的~接下来的几篇都是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

一. 前言

上一篇中主要实现的是敌机模型的实现,如果我们可以将敌机模型视作为一个JavaScript的类,它这个类上包含了,创建,坐标生成,位移,碰撞检测等等方法,这些方法完整的构成了一个敌机模型,上一篇别的我们都介绍了,唯独位移这个没有细说,那么本篇主要介绍的就是位移的实现以及其实现方法:requestAnimationFrame;

耐心看完,或许你会所有收获~

二. 阅读对象与难度

本文难度属于:中级,主要分享的内容为 模型位移的实现,其实不仅仅是敌机模型,我方控制的飞机,子弹,都是需要位移,通过文本你可以大致了解到一下内容

  • requestAnimationFrame以及其使用方式;
  • 敌机位移的实现;

具体内容可以参考以下的思维导图:

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

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

四. requestAnimationFrame

4.1 介绍

首先来说说什么是 requestAnimationFrame?
Mozilla官方解释:window.requestAnimationFrame() 告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行;这段话怎么理解呢?
首先,我们可以明确:requestAnimationFrame是JavaScript上的原生方法,虽然用的时候可以这么用,如下

requestAnimationFrame();// 实际上的全写
window.requestAnimationFrame()

它是挂载在window对象上的,因此,在没有window对象的环境下,该方法不可使用;

其次,原文说到:你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画,这就是说requestAnimationFrame用于执行动画的,它有点类似于使用 setTimeoutsetInterval,通过无限循环执行实现动画;

最后,原文说到:该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行
意思是它接受一个函数作为参数,这个函数用于执行动画的,比如在函数中修改y轴坐标,那么无限循环下DOM在Y轴上的坐标将不断变化,从而实现了一个动画~

到这里,我们大致知道了 requestAnimationFrame 这是一个啥,简单的说,就是 渲染动画的函数,它接收一个具体执行DOM变化的函数作为参数,通过无限循环执行这个函数达到了动画的效果~

4.2 异步还是同步?

看一个函数首先就是 异步还是同步的问题,requestAnimationFrame 是异步还是同步?做一个实验

setTimeout(() => {console.log('--- setTimeout 1 ---');
});window.requestAnimationFrame(() => {console.log('--- requestAnimationFrame 2 ---');
});async function testAsync() {console.log('--- testAsync 3 ---');await testAsync2();console.log('--- testAsync 4 ---');
}async function testAsync2() {console.log('--- testAsync 5 ---');
}testAsync();new Promise((resolve) => {console.log('--- promise 6 ---');resolve();console.log('--- promise 7 ---');
}).then(() => {console.log('--- promise 8 ---');
});console.log('--- promise 9 ---');

结果如下:

结果很明显,requestAnimationFrame它是一个异步函数

4.3 JS实现动画

在具体聊 requestAnimationFrame 之前,我们先思考一下,假如现在有一个面试题,或者是有一个需求,要求是是使用JS实现一个动画,该怎么做?
正常情况下,我们第一时间可能会想到 setTimeoutsetInterval,假设动画的帧率是60帧,那么我只需要这么写就行

setInterval(()=>{// 具体执行的代码
}, 1000 / 60)

通过setInterval实现了一个循环动画,为什么参数是 1000 / 60,那就说到另外一个原理了,动画的本质其实就是将一张张切片连接起来,当这个连接或者说切换的速度够快时,人眼将无法区分是单独的每一张,从而形成一个不卡顿的连续动画,看起来像是活了一样,动起来了;拿这边举例,当1000毫秒也就是1秒内,连续移动超过60次,那么自然而然人眼看起来就是一副完整的动画;
因此,如果使用setInterval实现了一个简易动画,我们可以这么写

<template><div class="demo" :style="{ left: x + 'px', top: y + 'px' }"> </div>
</template><script lang="ts" setup>import { ref } from 'vue';const x = ref(0);const y = ref(40);setInterval(() => {x.value = x.value + 1;}, 1000 / 60);
</script><style scoped lang="less">.demo {position: absolute;width: 100px;height: 100px;background-color: red;}
</style>

其效果如下:

既然setInterval已经可以实现动画,那么requestAnimationFrame 的意义是什么呢?不着急,继续往下试验;

4.4 requestAnimationFrame 实现动画

依然是上方那个动画,如果使用requestAnimationFrame怎么实现呢,大致如下:

<template><div class="demo" :style="{ left: x + 'px', top: y + 'px' }"> </div>
</template><script lang="ts" setup>import { ref } from 'vue';// setInterval(() => {//     x.value = x.value + 1;//     console.log(x.value);//     // y.value = y.value + 1;// }, 1000 / 60);const move = () => {x.value = x.value + 1;window.requestAnimationFrame(move);};move();
</script><style scoped lang="less">.demo {position: absolute;width: 100px;height: 100px;background-color: red;}
</style>

对应效果图如下:

从效果图上看两者感觉差不多,从用法上看,requestAnimationFrame 的用法貌似更接近setTimeout,而不是setInterval,当然,用法还是既然已经有了setTimeout 和 setInterval了,为什么还要requestAnimationFrame?那当然是为了解决一些瓶颈的问题;

4.5 requestAnimationFrame优点

第一个优点:执行函数的时间更加精准

我们知道 setTimeout 和 setInterval 都是借助于浏览器的定时器线程执行的,因此,当界面上存在大量异步的时候,会堵塞异步代码的执行,在这种情况下setTimeout 和 setInterval 将变得不准时,反映到界面上的效果就是动画执行的过程中会有卡顿,动画整体不再流畅;这是一个硬伤,如果出现的频繁,那么用户体验将变得极差,不可接受;

那requestAnimationFrame 呢?上面我们测试过了,requestAnimationFrame 也是一个异步函数,它会不会也有这种问题,实际上不会,最大的原因是,它执行的时机造成的,requestAnimationFrame 的执行时机是由系统决定的,每一次页面进行刷新时都会执行一次requestAnimationFrame 函数,举个例子吧,可能容易明白点;
比如:我们的电脑刷新率是60Hz,那么这就代表1秒内刷新了60次,刷新的间隔为 1000 / 60 毫秒,每一次进行刷新的时候,浏览器会主动去执行一次 requestAnimationFrame 函数,这将大大的提升精准度,那如果电脑的刷新率是75Hz呢,那刷新间隔是 1000 / 75;
所以,在精准度上,requestAnimationFrame 的效果远好于 setTimeout 和 setInterval,因为它的执行间隔不由代码决定,而由系统决定,适用性更强;

第二个优点:性能更好

这点体现在执行时页面的重绘与回流,我们知道重绘与回流是影响DOM性能最大的因素之一,当使用 setTimeout 和setInterval 等时,就是正常的重绘与回流,但requestAnimationFrame不同,它会把每一帧中需要执行的操作或者说动画步骤都给收集起来,在一次重绘或回流中就完成全部的操作;
除此之外,当网页处于hidden状态时,requestAnimationFrame会被冻结,不再执行,这也会节省电脑的CPU和GPU资源;

五. 敌机模型位移的实现

到这里,我们再回看一下上一篇中关于敌机位移的实现,代码如下:

<script>
export default {props: {data: {type: Object,default: () => {return {};}},},data() {return {moveTimer: null};},methods: {move() {if (this.data.y < 300) {//敌机的加速度let speed = this.data.type === 1 ? 0 : 0.5;this.data.y += this.enemyY + speed;} else {this.remove();}},init() {this.moveTimer = () => {//敌机移动this.move();// 重绘,无限循环requestAnimationFrame(this.moveTimer);};this.moveTimer();},},
};
</script>

一共两个方法:init 和 move ,我们分别看一下
init函数
代码不复杂,通过requestAnimationFrame实现了一个无限循环动画,该动画主要实现的位移逻辑是由this.move()实现的;

move函数
首先是一个if判断,判断当前在y轴上的坐标值是否小于300,如果小于300修改DOM在y轴上的坐标,修改值也可以称作与加速度,其值取决于敌机的类型,敌机的类型如果是小飞机,那么每次加速度是 默认速度+0.5,大飞机则是 默认速度,这也就实现了不同的敌机类型飞行速度不一致的效果;
那么这个300是什么意思?这个300在这里只是一个演示值,正常情况下应该是 屏幕的高度,作用是:当飞机在屏幕的y坐标大于屏幕时,就应该将超出屏幕的飞机移除,毕竟我们不可能让飞机永远存在,当其超出屏幕的情况下,我方飞机依然不可能击毁它,因此我们需要及时销毁;
故以上代码最终能实现的效果图就是如下:

六. 小结

本文主要概述了requestAnimationFrame,通过本文我们知道:

  • requestAnimationFrame这事一个 原生的,帧动画函数,它可以让我们通过它来实现JS动画;
  • 相比 setTimeout 和 setInterval,不管从性能上,还是动画的流程度上requestAnimationFrame都更优,因此,如果是需要使用JS实现动画,可以选择requestAnimationFrame;
  • requestAnimationFrame是 异步函数,它执行的时机在于每次系统帧刷新前;

最后,我们重新回看了一下敌机的位移实现,发现其实并不复杂,就是利用requestAnimationFrame不断改变敌机在y轴上的坐标从而实现了敌机的位移动画效果,当然,至少这个阶段的敌机实现还并不复杂~

《uni-app》一个非canvas的飞机对战小游戏实现-requestAnimationFrame详解相关推荐

  1. 《uni-app》一个非canvas的飞机对战小游戏实现-碰撞检测的实现

    这是一个没有套路的前端博主,热衷各种前端向的骚操作,经常想到哪就写到哪,如果有感兴趣的技术和前端效果可以留言-博主看到后会去代替大家踩坑的-接下来的几篇都是uni-app的小实战,有助于我们更好的去学 ...

  2. 《uni-app》一个非canvas的飞机对战小游戏实现-敌机模型实现

    这是一个没有套路的前端博主,热衷各种前端向的骚操作,经常想到哪就写到哪,如果有感兴趣的技术和前端效果可以留言-博主看到后会去代替大家踩坑的-接下来的几篇都是uni-app的小实战,有助于我们更好的去学 ...

  3. 《uni-app》一个非canvas的飞机对战小游戏实现(一)准备

    这是一个没有套路的前端博主,热衷各种前端向的骚操作,经常想到哪就写到哪,如果有感兴趣的技术和前端效果可以留言-博主看到后会去代替大家踩坑的-接下来的几篇都是uni-app的小实战,有助于我们更好的去学 ...

  4. 《uni-app》一个非canvas的飞机对战小游戏-启动页

    这是一个没有套路的前端博主,热衷各种前端向的骚操作,经常想到哪就写到哪,如果有感兴趣的技术和前端效果可以留言-博主看到后会去代替大家踩坑的-接下来的几篇都是uni-app的小实战,有助于我们更好的去学 ...

  5. 《uni-app》一个非canvas的飞机对战小游戏实现-我方飞机实现

    这是一个没有套路的前端博主,热衷各种前端向的骚操作,经常想到哪就写到哪,如果有感兴趣的技术和前端效果可以留言-博主看到后会去代替大家踩坑的-接下来的几篇都是uni-app的小实战,有助于我们更好的去学 ...

  6. 怎么开发联机小游戏_Q飞机游戏:空战吃鸡大乱斗游戏!好玩的联机Q飞机对战小游戏...

    20000+游戏爱好者已加入我们! 带你发现好游戏! <Q飞机>游戏小程序好玩吗? <Q飞机>小游戏怎么玩? 只有你想不到, 没有我找不到的好游戏! 「良心好游戏推荐」 搜罗了 ...

  7. [ 逻辑锻炼] 用 JavaScript 做一个小游戏 ——2048 (详解版)

    前言 这次使用了 vue 来编写 2048,主要目的是温习一下 vue. 但是好像没有用到太多 vue 的东西,==! 估计可能习惯了不用框架吧 之前由于时间关系没有对实现过程详细讲解,本次会详细讲解 ...

  8. 2048小游戏html制作,[ 逻辑锻炼] 用 JavaScript 做一个小游戏 ——2048 (详解版)

    前言 这次使用了 vue 来编写 2048,主要目的是温习一下 vue. 但是好像没有用到太多 vue 的东西,==! 估计可能习惯了不用框架吧 之前由于时间关系没有对实现过程详细讲解,本次会详细讲解 ...

  9. 【广度优先搜索】一个实例+两张动图彻底理解 BFS | 思路+代码详解 | 用 DFS 自动控制我们的小游戏

    前言: 在 第一篇文章 中,我们讨论了 如何用 pygame 写一个小游戏,并用键盘交互控制 .接下来,我们将分别用 DFS .BFS .DRL 实现自动控制.DFS 已经在 这篇文章 中讨论过,现在 ...

最新文章

  1. vector容器总结.xml
  2. Android导入工程提示Invalid project description
  3. 字符串与byte[]之间的转换
  4. MATLAB 转PDF图片过大导致两边缺失
  5. 机器人学习--有参考意义的视频
  6. 查询DBA_HIST_ACTIVE_SESS_HISTORY缓慢
  7. 真格量化——菜粕策略
  8. PHP错误类型及屏蔽方法
  9. JCL 清理 LOGREC 日志
  10. 85相似标准形06——初等因子、初等因子与不变因子的求法
  11. matlab遗传算法实例crtrp,遗传算法实例参考.ppt
  12. ios微信浏览器, 系统浏览器cookie 丢失问题
  13. Unity说明文档翻译-Time Manager
  14. 怎么卸载VS2013?亲测有效
  15. 践行社会责任 | 华云数据荣登2021新型实体企业百强榜 用创新技术服务实体经济
  16. Swift开发 UIColor分类Hex颜色转换
  17. 从学会用橡皮鸭 debug 的那天,我,走上一条不归之路
  18. 蓝桥杯-振兴中华三种解题方法(C语言)
  19. Keyboard Maestro 9.2 Mac自动化神器
  20. 矩阵的对数运算公式_J.1 对数与分贝(DB)与放大倍数

热门文章

  1. 【送书福利-第十期】清华社 IT BOOK 多得图书活动 ~!
  2. 下周要去女朋友家,第一次去应该给未来老丈人带什么礼物合适,要轻奢、时尚有独特性的,求推荐?
  3. 内网渗透初探(靶场环境搭建+web层面实验+内网基本操作)
  4. 2021年安全员-B证(广西省)考试技巧及安全员-B证(广西省)实操考试视频
  5. 李宏毅ML -lecture 0 机器学习介绍
  6. 坐标系变换下的二阶偏导数求解
  7. Android全面屏适配(系转载自简书的yyBetter)
  8. 数字经济如何引领新增长?岳麓峰会丈量“长沙宽度”
  9. Docker#Docker当做虚拟机使用
  10. 前端网络基础-应用层HTTP协议