100行代码教你写个卡牌翻翻乐小游戏
Posted 登楼痕
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了100行代码教你写个卡牌翻翻乐小游戏相关的知识,希望对你有一定的参考价值。
卡牌翻翻乐这种小游戏相信大家都玩过,一组卡牌随机翻面平铺在面前,用户点击卡牌翻转,两两配对消除卡牌,游戏的玩法主要是通过玩家自己对卡牌位置的记忆,快速匹配出相同的卡牌予以消除。
那么我们自己来写一个这个小游戏,大致的思路会是什么呢?首先我们先找来卡牌素材,这里取的是12张生肖图案【图片来源于网络侵删】。那么我们就一共要展示24张卡片,布局上我们就按6x4的格子摆放吧。那么接下来主要工作分为:
1、打乱顺序随机摆放卡牌
2、卡牌翻转动画
3、卡牌翻转后的匹配规则,如果未匹配,两张牌自行翻转回去;如果匹配,则消失
思路很清晰,就从第一步开始把!
1、打乱顺序随机摆放卡牌
为了方便图片渲染,我们给12张图片取名为1.png,2.png……12.png。把12x2=24张牌放到一个数组里就是[1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12],这个数组手敲起来眼花还容易写错,用个函数生成吧:
const generateArr = useCallback((): Array<number> =>
let cur = 1;
const initArr = Array(24).fill(1).map((item, index) =>
if (index % 2 === 1)
item = cur - 1;
else
item = cur++;
return item
)
return initArr // 输出[1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12]
, [])
好了,接下来的步骤就是把24张牌通过洗牌算法打乱顺序。之前说展示6x4的布局,会有人想到说把一维数组转成二维数组然后双层for循环打印出来,其实没必要,毕竟6x4的布局我们可以通过css实现。
打乱顺序:
const getRandomNum = (min: number, max: number) =>
return Math.floor(Math.random() * (max - min + 1) + min)
// 洗牌算法
const shuffle = useCallback((array: Array<number>): Array<number> =>
let newArr = array.slice()
for (let i = 0; i < newArr.length; i++)
const j = getRandomNum(0, i)
const temp = newArr[i]
newArr[i] = newArr[j]
newArr[j] = temp
return newArr
, [])
const generateArr = useCallback((): Array<number> =>
let cur = 1;
const initArr = Array(24).fill(1).map((item, index) =>
if (index % 2 === 1)
item = cur - 1;
else
item = cur++;
return item
)
return shuffle(initArr)
, [shuffle])
这样,我们将24张牌通过flex布局,加上flex-wrap:wrap,摆放处6x4的格子:
【图片来源于网络侵删】
2、卡牌翻转动画
然后我们需要将这些卡牌翻转过去,给个封面,在点击的时候将卡牌再翻转过来。
首先通过position:absolute给卡牌加一个同级的div封面,然后将卡牌的img元素rotateY(-180deg),点击卡牌的时候,将容器再次transform: rotateY(180deg)
.....
<div className="card-page">
arr.map((item, index) =>
return (
<div onClick=() => handleClick(item, index) key=index className=`wrap $(currentItem[0]?.item === item && currentItem[0]?.index === index) || (currentItem[1]?.item === item && currentItem[1]?.index === index) ? 'active' : '' $resultItems.includes(item) ? 'hide' : ''`>
<img className="card-img" src=
require(`@/assets/$item.png`)
alt="" />
<div className="cover">
翻翻乐
</div>
</div>
)
)
result ? <span className="result">成功了!</span> : ''
</div>
......
// css部分
.wrap
position: relative;
width: 14%;
margin: 8px;
transition: transform 1s;
transform-style: preserve-3d;
cursor: pointer;
.active
transform: rotateY(180deg);
.hide
opacity: 0;
.card-img
transform-style: preserve-3d;
padding-top: 38px;
background: #256ae5;
z-index: 2;
transform: rotateY(-180deg);
.cover
position: absolute;
width: 100%;
z-index: 1;
height: 100%;
top: 0;
left: 0;
backface-visibility: hidden;
background-color: #7fc5ff;
display: flex;
align-items: center;
justify-content: center;
color: #ffee0c;
box-shadow: inset -5px -5px 10px 1px rgba(107, 126, 135 ,0.2);
3、卡牌翻转后的匹配规则
思路也很清晰,我们用一个长度为2的数组currentItem来临时存放翻转的卡牌,用另一个数组resultItems来存放已消除的卡牌。当两张牌一样时,我们将名字push进resultItems数组;如果不一样,我们清空currentItem数组就行。
根据上面两个数组,我们可以来确定每张卡牌的显示状态:
1、当卡牌在currentItem中,卡牌呈正面显示生肖;
2、当卡牌在resultItems中,卡牌不显示,为已消除的状态;
3、否则,卡牌为背面显示翻翻乐的状态。
所以我们在卡牌的点击事件里维护一下这两数组,再在render里根据数组判断一下每张卡的显示状态就行了:
const handleClick = useCallback((item: number, index: number) =>
if (resultItems.includes(item))
return;
currentItem.push( item: item, index: index )
setCurrentItem([...currentItem])
if (currentItem.length === 2)
if (timeoutID.current)
clearTimeout(timeoutID.current);
if (timeoutID2.current)
clearTimeout(timeoutID2.current);
if (currentItem[1].item !== currentItem[0].item)
timeoutID.current = setTimeout(() => setCurrentItem([]) , 1000)
else
// 命中!
timeoutID2.current = setTimeout(() =>
resultItems.push(item);
setResultItems([...resultItems])
setCurrentItem([])
if (resultItems.length === 12)
setResult(true);
, 1000)
, [currentItem, resultItems])
当resultItems的长度为12,就证明我们消除了所有的卡牌,游戏成功!
以上是关于100行代码教你写个卡牌翻翻乐小游戏的主要内容,如果未能解决你的问题,请参考以下文章