2024年Web前端最新vue新春游戏-年兽大作战,欢欢喜喜过大年(可在线体验),面试总结+解答分享

总结

根据路线图上的重点去进行有针对性的学习,在学习过程中,学会写笔记,做总结。

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

这里分享一些前端学习笔记:

  • html5 / css3 学习笔记

  • JavaScript 学习笔记

  • Vue 学习笔记

let ballisticLaunch = () => {

let randomIndex = Math.floor(Math.random() * ballisticArr.length)

let ballisticIndex = ballisticArr.splice(randomIndex, 1)[0]

this.createBullet(ballisticIndex)

if (ballisticArr.length > 0) {

setTimeout(ballisticLaunch, Math.random() * 1000)

}

}

ballisticLaunch()

// this.createBullet(2)

},

我这里的方法是先设定好弹道数,然后把这些的弹道的序号放进一个数组,开始时直接从这个数组去取编号,往这个弹道放进去一个弹幕,然后循环,直到每一条弹道都被用完为止,那么问题来了,这时候我们每条弹道只有一条弹幕,怎么生成后续弹幕呢,这里的思路是在每一条弹幕移动的时候,判断自己的移动距离,当达到合适的距离时(自身完全出现在屏幕中并且距离屏幕右侧达到了我们设定的两条弹幕间的距离)就调用加载下一条弹幕的方法,并把自身的弹道编码传入,加上我们这里弹幕是匀速的,就不会有重叠的问题了。

/**

  • @description: 添加弹幕

  • @param {*} index 弹道索引

  • @return {*}

*/

createBullet (index) {

let bullet = document.createElement(‘div’)

let bulletHeight = document.documentElement.clientHeight / 10

bullet.className = ‘bullet-chat’

bullet.style.left = this.screenWidth + ‘px’

bullet.style.top = index * bulletHeight + ‘px’

bullet.createNext = false // 是否已创建下一个弹幕

bullet.nextSpace = Math.random() * (this.bulletInterval[1] - this.bulletInterval[0]) + this.bulletInterval[0] // 下一个弹幕间隔

// 从弹幕库随机取弹幕

let dataLength = this.blessingData.length

let randomIndex = Math.floor(Math.random() * dataLength)

let blessing = this.blessingData[randomIndex]

bullet.innerText = blessing.name + “:” + blessing.value

this.$refs.bulletChat.appendChild(bullet)

// 弹幕移动

let bulletMove = () => {

bullet.style.left = bullet.offsetLeft - this.bulletSpeed + ‘px’

if (!bullet.createNext) {

// 如果弹幕距离屏幕右侧距离超出弹幕间隔,则加载下一条弹幕

if (bullet.offsetLeft < (this.screenWidth - bullet.offsetWidth - bullet.nextSpace)) {

this.createBullet(index)

bullet.createNext = true

}

}

// 如果弹幕距离右侧距离大于等于屏幕宽度,则移除弹幕

if (bullet.offsetLeft < (-bullet.offsetWidth)) {

this.$refs.bulletChat.removeChild(bullet)

} else {

requestAnimationFrame(bulletMove)

}

}

bulletMove()

}

这里我们引入了一个弹幕库,每次从中随机取一条,这样就避免旧弹幕无法被看到的问题了,另外大家也都看到了,这里用的定时方法是requestAnimationFrame,这个真的比setinterval要好,本项目基本所有用到动画的地方都用的这个,也建议大家都用这个方法代替setinterval,好处比较多,这里就不占字数了,大家感兴趣自行百度吧。

年兽

image.png

这个可爱的小东西就是我们的年兽了,年兽的组成很简单,一个小图标,加一个血量,然后我们让它来回动起来就可以了。当血量为0时候我们就让它消失。

class=“nianshou”

:style=“‘marginLeft:’ + nianshouLeft + ‘px’”

v-show=“nianshouHP”

HP: {{ nianshouHP }}

nianshouLeft: 0, // 年兽距离左边的距离

nianshouMove () {

// 更新游戏时间

this.gameDuration = new Date().getTime() - this.gameBeginTime

if (this.nianshouLeft + 200 >= this.screenWidth) {

this.nianshouMoveDir = -4

} else if (this.nianshouLeft < 0) {

this.nianshouMoveDir = 4

}

this.nianshouLeft += this.nianshouMoveDir

this.nianshouInterval = requestAnimationFrame(this.nianshouMove)

},

我们的游戏规则是用时越少越厉害,所以我们需要计算游戏用时多少,这里我们以年兽开始移动时为游戏开始时间,另外我们还需要在年兽撞墙的时候往反方向运动,所以这里我们判断了年兽距离屏幕左边和右边的距离,一旦达到界定值的时候,则改变移动方向,也就是改变移动值的正负

炮竹

image.png

这个小玩意儿就是我们的炮竹了,也相当于我们的武器,我本来想找一个烟花筒来释放烟花的,奈何资源有限,就用这个将就吧。这个小炮竹会不断的发出光束去打年兽,这里关于炮竹,就是鼠标按下的时候添加移动事件,让他左右移动就可以了。

第一步肯定就是炮竹的移动,这个我们不做的太复杂,直接让鼠标拖动进行左右移动就行了,不让上下移动是为了你举着炮竹往年兽脸上怼。

思路,鼠标点击炮竹,给整个区域添加移动事件,不给炮竹添加移动事件时因为鼠标移动过快的话很容易超出炮竹的范围,造成不好的游戏体验,当鼠标抬起时,我们再把这个事件给移除。至于移动,我们需要先定义一个clientx,每次鼠标移动的时候存储鼠标距离屏幕左侧的距离,当鼠标再次移动的时候,我们用当前光标距离左侧的距离建议刚刚存储的,就可以得出鼠标移动的距离,然后我们把这个值的变化赋值给炮竹的margin-left

class=“paozhu”

ref=“paozhu”

@mousedown=“addMove”

:style=“‘marginLeft:’ + paozhuLeft + ‘px’”

clientX: 0, // 鼠标上次的位置

paozhuLeft: 0 // 炮竹距离左边的距离

// 鼠标按下,添加移动事件

addMove (e) {

e = e || window.event

this.clientX = e.clientX

this.clientY = e.clientY

this.$refs.gemeWrap.onmousemove = this.moveFunc

},

// 鼠标拖动,移动炮竹

moveFunc (e) {

e = e || window.event

e.preventDefault()

let movementX = e.clientX - this.clientX

this.paozhuLeft += movementX

this.clientX = e.clientX

},

// 鼠标抬起,移除移动事件

removeMove () {

this.$refs.gemeWrap.onmousemove = null

},

子弹

我们暂且称炮竹发出的光束为子弹吧,子弹的实现原理很简单,定时发射子弹,发射子弹时获取炮竹的横向坐标,再以屏幕高度减去炮竹高度为纵向坐标,生成之后让子弹往上跑就行了,当子弹距离顶部距离小于等于年兽的高度时,判断子弹的横向坐标是否和年兽的横向坐标重合,如果重合就对年兽扣血,播放击中音效,移除子弹,如果未重合,则在子弹跑出屏幕时移除子弹。

这里我们设置了一个子弹飞行速度,如果你玩过了游戏,一定会发现,刚开始不好射中吧,哈哈哈,这也算是增加了难度,当然,如果答对了问题,射速,攻速,伤害都会相应的增加。

image.png

createBulletInterval: null, // 创建子弹的定时器

frequency: 5, // 发射子弹频率

bulletSpeed: 10, // 子弹飞行速度

damage: 2,// 子弹攻击力

lastBulletTime: 0, // 上次发射子弹时间

// 生成子弹

createBullet () {

// 子弹

let now = new Date().getTime()

if (now - this.lastBulletTime > (1000 / this.frequency)) {

let bullet = document.createElement(‘div’)

bullet.className = ‘bullet’

bullet.style.left = this.paozhuLeft + 25 + ‘px’

bullet.style.top = this.screenHeight - 123 + ‘px’

this.$refs.gemeWrap.appendChild(bullet)

this.$store.commit(‘playAudio’, require(‘…/assets/mp3/emit.mp3’))

// 子弹移动

let bulletMove = () => {

bullet.style.top = bullet.offsetTop - this.bulletSpeed + ‘px’

// 如果子弹距离顶部的距离为年兽的高度时,判断子弹和年兽的水平位置是否重合

if (bullet.offsetTop <= 250 && bullet.offsetLeft >= this.nianshouLeft && bullet.offsetLeft <= this.nianshouLeft + 200) {

// 年兽掉血

this.nianshouHP -= this.damage

this.$store.commit(‘playAudio’, require(‘…/assets/mp3/boom.wav’))

if (this.nianshouHP <= 0) {

this.nianshouHP = 0

this.gameOver()

}

// 子弹消失

this.$refs.gemeWrap.removeChild(bullet)

// cancelAnimationFrame(bulletMove)

} else if (bullet.offsetTop <= 0) {

this.$refs.gemeWrap.removeChild(bullet)

// cancelAnimationFrame(bulletMove)

} else {

requestAnimationFrame(bulletMove)

}

}

bulletMove()

this.lastBulletTime = now

}

this.createBulletInterval = requestAnimationFrame(this.createBullet)

}

由于requestAnimationFrame不能设置间隔时间,所以这里我们就在生成子弹的时候记录下生成子弹的时间,在requestAnimationFrame下一次运行的时候,判断时间间隔是否满足我们对子弹频率的要求,如果满足则往下执行,如果不满足跳过本次执行。

问题

本游戏的一大特色,就是加入了答题系统,否则一直在那biubiubiu的打怪兽有啥意思呢,年兽的血量为2021,靠初始攻速和伤害得打半天,如果答对问题,则会增加buff,打年兽能力蹭蹭的往上涨。

首先来分析一下问题的需求

  • 每道题的答题时间是8秒钟,无论是否提前选择均展示8秒

  • 答对题目则增加buff

  • 答错或者在倒计时结束未选择答案将展示正确答案

  • 每道题的间隔时间是5秒钟

  • 每次出题从题库随机取题,出现过的题目不会第二次抽取

先从最简单的开始,从题库抽取题目

questionJson: require(‘@/assets/data/question.json’), //问题源数据

questionData: [], // 本轮游戏题库

questionList: [],// 问题列表

let dataLength = this.questionData.length

let randomIndex = Math.floor(Math.random() * dataLength)

let question = this.questionData.splice(randomIndex, 1)[0]

很简单,接下来就是添加倒计时,先加的是题目间隔倒计时,在一道题目被添加时候,展示5秒钟倒计时,然后展示题目并开始答题倒计时

image.png

// 添加展示倒计时

let showCountDown = () => {

data.showTime–

if (data.showTime > 0) {

setTimeout(showCountDown, 1000)

} else {

// 倒计时结束,展示问题并开始答题倒计时

answerCountDown()

}

}

接下来是答题倒计时,游戏设置的题目是5道,每道题结束会先判断用户是否作答,如果没有作答,自动将结果设置为错误答案,之后再判断题目是否达到5道,如果没有达到则继续添加,直到够5道为止。

image.png

// 添加回答倒计时

let answerCountDown = () => {

data.answerTime–

if (data.answerTime > 0) {

setTimeout(() => {

showCountDown()

}, 1000)

} else {

// 倒计时结束,如果没有选择正确答案,则添加一道错误答案

if (!data.result) {

data.result = ‘2021’

}

// 如果问题不足5道,则添加一道问题

if (this.questionList.length < 5) {

this.addQuestion()

}

}

}

在接下来就是答题了,先来看一下问题面板的dom结构

class=“question-panel panel-item”

:class=“{ clientCenter: question.answerTime > 0 }”

v-for=“(question, index) in questionList”

:key=“index”

{{ question.showTime }}

请在{{ question.answerTime }}秒内点击正确答案

问题 {{ index + 1 }}
{{ question.question.title }}

class=“answer-item”

v-for=“item in question.question.option”

:key=“item.key”

@mouseover=“$store.commit(‘playAudio’, hoverMusic)”

@click=“answerQuestion(item.key, question)”

{{ item.key }}:{{ item.value }}

class=“answer-item”

v-for=“item in question.question.option”

:key=“item.key”

:class="{

result: question.question.answer === item.key,

}"

{{ item.key }}:{{ item.value }}

class=“buff”

v-if=“question.result === question.question.answer”

攻速+1 射速+1 伤害+1

class=“desc”

v-if="

question.result && question.result !== question.question.answer

"

{{ question.question.desc }}

文末

如果30岁以前,可以还不知道自己想去做什么的话,那30岁之后,真的觉得时间非常的宝贵,不能再浪费时间在一些碎片化的事情上,比如说看综艺,电视剧。一个人的黄金时间也就二,三十年,不能过得浑浑噩噩。所以花了基本上休息的时间,去不断的完善自己的知识体系,希望可以成为一个领域内的TOP。

同样是干到30岁,普通人写业务代码划水,榜样们深度学习拓宽视野晋升管理。

这也是为什么大家都说30岁是程序员的门槛,很多人迈不过去,其实各行各业都是这样都会有个坎,公司永远都缺的高级人才,只用这样才能在大风大浪过后,依然闪耀不被公司淘汰不被社会淘汰。

269页《前端大厂面试宝典》

包含了腾讯、字节跳动、小米、阿里、滴滴、美团、58、拼多多、360、新浪、搜狐等一线互联网公司面试被问到的题目,涵盖了初中级前端技术点。

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

前端面试题汇总

JavaScript

  • 8
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值