我正在参加「兔了个兔」创意投稿大赛,详情请看:「兔了个兔」创意投稿大赛”
报!~~~ 兔年到啦! 🎉🎉🎉祝大家兔然暴富,兔然涨薪,代码不会兔然报错ヾ(•ω•`)o 本文将基于vue3,除了基于css与js知识,还用到了一些高中的数学知识(死去的青春兔然攻击我😭)。现在就开始正文部分吧。
游戏构思
本次打算制作一款类似于投篮的小游戏。即让投掷物从固定点通过抛物线的轨迹进行运动,以接触投掷目标作为结束的条件。然后加入计分器,优化下流程,再美化一下效果加上可爱的小兔子即可完成。
抛物线
虽然这是很简单的高中知识,但是现在看来已经忘得一干二净,需要重新学习一下了(想当年我也是...算了,好汉不提当年勇😥)。但是仍然记得并且可以确定的是,抛物线只需要确定顶点和抛物线上的任意一点即可确定抛物线的公式,然后就可以求出抛物线上的所有的点。
顶点式:y=a(x-h)²+b 其中a是常数,是需要我们求出来的数。h和b分别是抛物线顶点的x坐标和y坐标即抛物线顶点为(h,b)。
根据游戏构思,我们从小兔子的位置作为坐标原点和抛物线经过一点,把鼠标点击位置作为抛物线顶点,那么抛物线的公式即可确定,那么与x轴另一个交点也可以确定。
那么用代码怎么实现呢?我们首先需要获取鼠标的当前位置,在vueUse这个库中我们可以通过useMouse很轻松的获取到鼠标当前坐标,我们假设获取到的鼠标坐标为h和b则根据公式可得
a=-b/Math.pow(h, 2)
与抛物线的另一个交点横坐标为x=Math.sqrt(-b / a) + h这个坐标后面将用来确定步长。
有了这些公式后无论我们点击哪里作为抛物线的顶点,抛物线的公式都将确定即小兔子将抛出的元宝轨迹得到确定。现在只需要让元宝动起来即可,首先元宝初始坐标定在原点,当抛物线公式确定后,只需要对抛物线公式中的x进行累加确定y的值即可确定元宝坐标。
坐标确定后我们设置为无论多长的路径都在1000ms内完成动作,我们有两种思路,一是将步长确定,把执行次数进行按比例调整,一种是执行次数确定,按比例调整步长,由于另一焦点变动过大,此我们采用第二张方案。将1000s毫秒拆分成100步后每一步需要执行的距离为另一焦点/100代码如下,效果如图所示。
function shoot() {
if (state.value) {
state.value = false;
time = setInterval(() => {
ball.x += parabola.x / 100;
}, 10);
setTimeout(() => {
reset() //重置位置
}, 1000);
}
}
目标制作
我们接下来需要制作个目标,利用定位制作好位置后有几个问题摆在我们面前。
- 我们需要控制可点击区域为左侧一部分,这样可以避免直接点击目标以击中。
- 我们需要在合适的时机来修改目标位置,同时保证目标不能跑出界面以外。
- 我们需要进行碰撞检测,即元宝是否接触到目标的判断。
一个个来,第一个很简单,我们只需要在左侧添加容器绑定点击事件即可解决。
随机数
第二个问题,我们需要用随机数来确定移动方向和距离,随机数的知识如下 取值区间[min,max]的随机数为
function getrandom(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min
}
我们把最小值最大值分别设为负值和正值即可确定移动方向,同时保证目标在移动时与边缘距离始终无法为0,具体实现为判断目标与边缘距离是否小于移动最值,若小于则方向修改为固定方向。代码如下,加上transition: all 0.01s后效果如图所示。
function resetPosition() {
if (pen.r < 200) {
pen.r += getrandom(0, 200)
}
else if (pen.r > 400) {
pen.r += getrandom(-200, 0)
}
else {
pen.r += getrandom(-200, 200)
}
if (pen.t < 200) {
pen.t += getrandom(0, 200)
} else if (pen.t > 300) {
pen.t += getrandom(-200, 0)
}
else {
pen.t += getrandom(-200, 200)
}
}
碰撞检测
我们需要判断元宝的四个点是否与目标区域重合,判断逻辑如图所示。
点1 横坐标为left 需要满足W-right-w2<left<W-right
纵坐标为bottom+h1 需要满足H-top-w2<bottom+h1<H-top
点2 横坐标为left+w1 需要满足W-right-w2<left+w1<W-right
纵坐标为bottom+h1 需要满足H-top-w2<bottom+h1<H-top
点3 横坐标为left 需要满足W-right-w2<left<W-right
纵坐标为bottom 需要满足H-top-w2<bottom<H-top
点4 横坐标为left+w1 需要满足W-right-w2<left+w1<W-right
纵坐标为bottom 需要满足H-top-w2<bottom<H-top
上述任意一点满足即可判定为接触,我们只需要在累加时进行判断即可检测是否得分。
优化工作
最困难的逻辑完成后,我们需要对一些细节进行优化,比如投掷时的节流处理、添加计分、添加背景、重置元宝位置、清空定制器、超过十分后增加难度等。
下面是码上掘金,建议点击右上角去详情中体验,如大小不合适对浏览器进行缩放即可。
同样,还有很多可以优化的部分,比如这个投掷的行为让我想到了投掷🏀,也让我想到了一位故人(狗头保命),之前的文章已有现成模型,因此下一篇可以考虑换个皮肤。
最后祝大家兔年大吉,都能在兔年获得成长和想要的收获🐱🏍🐱🏍🐱🏍