持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第8天,点击查看活动详情
本是无意穿堂风, 偏偏孤踞引山洪
游戏规则
游戏利用了最基本的鼠标mousedown和mouseup来实现,总共分为5个级别,不同级别需要通过的柱子数和搭桥的速度不同,玩家需要控制鼠标精准停在柱子中心且误差不超过4px才算通过,柱子需要依次通过不可跨越,考验的就是眼力和手速,手残党请勿好奇尝试,避免造成财产损失(手动狗头)
游戏实现
游戏采用基本的定位布局实现,随机生成柱子位置,不同难度不同速度通过调节自增的长度单位实现
- 容器 容器就是简单的一个div加上地板组成
<div id="box"></div>
*{
margin: 0;
padding: 0;
list-style: none;
box-sizing: border-box;
}
#box{
width: 100%;
height: 80vh;
background: cyan;
border-bottom: 10vh solid sandybrown;
overflow: hidden;
position: absolute;
top: 0;
bottom: 0;
margin: auto;
}
- 柱子, 柱子采用随机的方式生成,这里依然采用do while 来实现随机不重复left值,
let MAP_INFO = {}
let range = []
// 主要是判断两点 1 重不重复 2 新生成的坐标不能与旧坐标产生的柱子重叠
function randomWall () {
let left = null
do {
left = Math.floor(Math.random()*$('#box').width()-44)
if (left <0) left = 0
} while (MAP_INFO[left] || range.find(v => Math.abs(v-left) <= 44))
range.push(left)
let div = $('<div>')
div.addClass('wall')
div.css('left', left + 'px')
div.html('<div class="point"></div>')
$('#box').append(div)
MAP_INFO[left] = false
}
.wall{
width: 42px;
height: 60vh;
position: absolute;
background: #1e80ff;
bottom: 0;
}
- 添加YoYo
let div = $('<div>')
div.addClass('yoyo')
div.css('left', range[0] + 'px')
$('#box').append(div)
.yoyo{
width: 42px;
height: 42px;
border-radius: 50%;
position: absolute;
bottom: 60vh;
background-image: url('https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/0a4ce25d48b8405cbf5444b6195928d4~tplv-k3u1fbpfcp-no-mark:0:0:0:0.awebp');
background-size: contain;
background-repeat: no-repeat;
background-position: center;
}
- 核心实现: 鼠标按下和抬起事件,以及加分和失败判断,YoYo移动动画。
- 鼠标按下和抬起事件需要注册在开始游戏按钮上,因为不管是选择难度以及开始游戏均会触发事件,所以要在游戏开始后再进行注册
- 加分判断很简单,注意看我们随机生成柱子的部分,我们维护了一个坐标的数组range,在init方法内 我们需要对初始化完成的range进行sort排序,这样他就是一个递增的数组了,通过一个下标inx来取出对应坐标,即可判断我们是否命中,是否跨越柱子
function init () {
// 初始化 得分 重复对象 下标数组以及游标inx
$('.score').html('得分: 0')
$('#box').empty()
MAP_INFO = {}
range = []
score = 0
inx = 1
if (t) {
clearInterval(t)
t = null
$('.btn').show()
}
// 随机生成柱子
for (let i=0;i<level;i++) {
randomWall()
}
对数组排序
range = range.sort((a,b) => a-b)
}
function play () {
// 初始化
init()
$('.btn').hide()
// 这里是为了保证所有的柱子都已经渲染完成,手动写了一个异步队列
setTimeout(function () {
let div = $('<div>')
div.addClass('yoyo')
// 将YoYo放在第一根柱子上
div.css('left', range[0] + 'px')
$('#box').append(div)
line = $('<div>')
line.addClass('line')
line.css('left', range[0]+ 21 + 'px')
$('#box').append(line)
document.body.onmousedown = function () {
// 根据难度来增加桥的长度速度
t = setInterval(function () {
let len = $('.line').width()
len+=level/20
$('.line').width(len+'px')
}, 10)
}
document.body.onmouseup = function () {
if (t) {
clearInterval(t)
}
// 将YoYo移动到桥的终点
$('.yoyo').animate({left: $('.line').width() + $('.line').offset().left - 42 + 'px'}, 500)
// 判断绝对值 桥与柱子的红心点误差是否小于正负4
if (Math.abs(range[inx]-range[inx-1] - $('.line').width()) <=4) {
inx++
score++
$('.score').html(`得分: ${score}`)
// 判断是不是最后一根柱子
if (inx === range.length) {
$('.score').html('恭喜通关,得分: 0')
document.body.onmousedown = null
document.body.onmouseup = null
MAP_INFO = {}
range = []
score = 0
if (t) {
clearInterval(t)
t = null
$('.btn').show()
}
}
} else {
// 失败重置
$('.score').html('游戏结束,得分: 0')
document.body.onmousedown = null
document.body.onmouseup = null
MAP_INFO = {}
range = []
score = 0
if (t) {
clearInterval(t)
t = null
$('.btn').show()
}
}
}
}, 50)
}
- 游戏等级选择 很简单 select即可
<select name="" id="sel">
<option value="3">洒水级</option>
<option value="5">普通级</option>
<option value="7">勇士级</option>
<option value="9">王者级</option>
<option value="20">地狱级</option>
</select>
$('#sel').change(function () {
level = Number($(this).val())
init()
})