vue新春游戏-年兽大作战,欢欢喜喜过大年(可在线体验)

  • @param {*}

  • @return {*}

*/

showBullet () {

// 此处直接设定了10条弹道,也可根据屏幕高度和弹幕高度计算弹道数

let ballisticArr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

// 按随机顺序在所有的弹道添加弹幕

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 }}

再看一下题库中题目的结构

{

“title”: “以下哪位是神舟十三号航天员?”,

“option”: [

{

“key”: “A”,

“value”: “翟志刚”

},

{

“key”: “B”,

“value”: “刘伯明”

},

{

“key”: “C”,

“value”: “聂海胜”

}

],

“answer”: “A”,

“desc”: “神舟十三号航天员是翟志刚、王亚平、叶光富”

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
“刘伯明”

},

{

“key”: “C”,

“value”: “聂海胜”

}

],

“answer”: “A”,

“desc”: “神舟十三号航天员是翟志刚、王亚平、叶光富”

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

[外链图片转存中…(img-edMmH1TA-1715698123735)]

[外链图片转存中…(img-T5rD9TtL-1715698123735)]

[外链图片转存中…(img-PBqMbNbt-1715698123736)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值