持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第9天,点击查看活动详情
游戏玩法
游戏主要考验玩家的空间感和记忆能力,玩家需要通过开局的3秒内尽可能多的记忆两个空间内相同元素的位置,3秒后将会翻牌把图案盖住,玩家需要点击卡牌来翻转牌面,两张相同图案的卡牌即可保留,游戏计时将在卡牌翻转之后开始,完全翻转所有卡牌则计时结束,我打赌没人能在60秒内通关这个游戏
游戏彩蛋
假如有好事者将鼠标移动到我们的标题看谁翻得快
的时候,会发现这是一个复古魂斗罗标题样式,具体实现依赖的是background-image里的repeating-linear-gradient与-webkit-background-clip
,我们利用伪元素::before
和::after
,来实现复古的重叠文字效果。
- repeating-linear-gradient 重复径向渐变
- -webkit-background-clip 以盒子内的文字作为裁剪区域向外裁剪,文字之外的区域都将被裁剪掉
<div class="title">看谁翻得快</div>
.title {
width: 380px;
position: absolute;
left: 0;
right: 0;
top: 0;
margin: auto;
display: block;
color: #1e80ff;
font-size: 64px;
letter-spacing: 8px;
cursor: pointer;
}
.title::before {
content: "看谁翻得快";
position: absolute;
color: transparent;
background-image: repeating-linear-gradient(
45deg,
transparent 0,
transparent 2px,
white 2px,
white 4px
);
-webkit-background-clip: text;
top: 0px;
left: 0;
z-index: -1;
transition: 1s;
}
.title::after {
content: "看谁翻得快";
position: absolute;
color: transparent;
background-image: repeating-linear-gradient(
135deg,
transparent 0,
transparent 2px,
white 2px,
white 4px
);
-webkit-background-clip: text;
top: 0px;
left: 0px;
transition: 1s;
}
.title:hover:before {
top: 10px;
left: 10px;
}
.title:hover:after {
top: -10px;
left: -10px;
}
核心实现
- 容器 容器是由720x450的盒子拆成的两个350x450的小盒子构成,大盒子通过flex布局水平垂直居中,小盒子也是通过flex布局实现水平拆分。
<div id="box">
<div class="left"></div>
<div class="right"></div>
</div>
#box{
width: 720px;
height: 450px;
display: flex;
justify-content: space-between;
align-items: center;
}
.left,.right{
width: 350px;
height: 450px;
background: #fff;
border-radius: 8px;
overflow: hidden;
display: flex;
justify-content: space-around;
align-items: center;
flex-wrap: wrap;
transform-style: preserve-3d;
}
- 元素,元素样式是100x100的小卡片,背景图随机生成,背景图来源于掘金商城,随机生成算法还是通过标记法去重,图片一共12张,所以我们需要生成不重复的随机顺序的12个数字,从0开始。将生成的数字以 自定义属性
key
记录在对应的dom上, 牌面的翻转覆盖效果通过transition
配合transform
来实现,不管是添加还是移除,都会应用过渡效果,所以看起来像是在翻转一样
// 样式
.left div, .right div{
width: 100px;
height: 100px;
border-radius: 8px;
cursor: pointer;
box-shadow: inset 0 0 15px 3px rgb(12, 133, 215);
background-position: center;
background-size: contain;
background-repeat: no-repeat;
transform: rotateY(180deg);
transition: all ease .5s;
}
#box .shine{
transform: rotateZ(360deg) rotateY(360deg);
}
// 随机算法
// 参数map是标记对象,from是为了将dom正确append, imgSrc比较多,不在这里罗列了
function randomKey (map, from) {
let ket = null
do {
key = Math.floor(Math.random()*len)
} while (map[key])
let div = $('<div>')
div.addClass('item')
div.addClass('shine')
div.attr('key', key)
div.css('background-image', `url(${imgSrc[key]})`)
map[key] = div
$(`.${from}`).append(div)
}
for(let i =0;i<imgSrc.length;i++) {
randomKey(left_Map, 'left')
randomKey(right_Map, 'right')
}
- 倒计时3s翻转卡牌 ,这里采用了定时器的方法,上面讲过,添加移除
transfrom
都会响应过渡,那么我们只需要在倒计时结束时统一为卡牌更换背景图即可
let t =setTimeout(function () {
for(let i in left_Map) {
left_Map[i].removeClass('shine')
left_Map[i].css('background-image', `url(https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/0a4ce25d48b8405cbf5444b6195928d4~tplv-k3u1fbpfcp-no-mark:0:0:0:0.awebp)`)
}
for(let i in right_Map) {
right_Map[i].removeClass('shine')
right_Map[i].css('background-image', `url(https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/0a4ce25d48b8405cbf5444b6195928d4~tplv-k3u1fbpfcp-no-mark:0:0:0:0.awebp)`)
}
},3000)
- 添加点击事件,处理翻牌相同和翻牌不同的情况, 这里,我们需要一个缓存数组cache,将点击获得的属性key缓存在cache里,然后进行判断即可,这里我们只需要判断,cache有长度和cache没长度的情况,有长度则需要进行比较,没长度直接将key缓存在cache内即可,相关注释都在代码里了
$('.item').click(function () {
// 这里判断的是 假如已经翻转了牌面,就不再响应点击事件
if ($(this).hasClass('shine')) {
return false
}
// 获取key,将牌面翻转并设置key对应的背景图
let key = Number($(this).attr('key'))
$(this).addClass('shine')
$(this).css('background-image', `url(${imgSrc[key]})`)
// 判断缓存数组长度
if (cache.length === 1) {
// 判断当前点击Key与缓存的key是否一致
if (cache.find(v => v===key) !== undefined) {
cache = []
// 更新成功翻牌配对次数
findNum++
console.log(findNum)
// 判断翻牌结束条件,停止计时
if (findNum>=12) {
clearInterval(timer)
$('#time').text('游戏结束,用时'+timeText+'秒')
}
return false
} else {
// 加一个人为延时,处理已经翻转但配对不成功的两个牌面,并清空cache缓存
let self = this
let inx = cache[0]
cache = []
let tm = setTimeout(function () {
$(`.item[key=${inx}]`).removeClass('shine')
$(`.item[key=${inx}]`).css('background-image', `url(https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/0a4ce25d48b8405cbf5444b6195928d4~tplv-k3u1fbpfcp-no-mark:0:0:0:0.awebp)`)
$(self).removeClass('shine')
$(self).css('background-image', `url(https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/0a4ce25d48b8405cbf5444b6195928d4~tplv-k3u1fbpfcp-no-mark:0:0:0:0.awebp)`)
}, 500)
}
} else {
// 没长度直接记录缓存
cache.push(key)
}
})
结语 & 码上掘金地址
笔者多次尝试,哪怕作弊,时间也在110秒左右,真的很考验记忆力