前言:提前预祝各位开发者、各行各业的工作人员,中秋佳节!国庆节~身体健康,阖家欢乐!!!
前言:马上就到了7+3=8的日子了~中秋节和国庆碰撞在一起。“日升月落,星烁云遮,溪河入海,红旗飘扬,神州大地之上,东方大国重立,皆是顺天而行理当繁荣昌盛。” 在这个日子里,为何不来玩玩有趣又土到掉牙的拼图游戏呢!!!?
在这个拼图游戏中,我们会展示一张月饼图片,然后将它分割成多个小方块。我们需要拖拽这些小方块,使它们重新排列,最终呈现出完整的图片。
话不多说,先看效果!
jcode
框架我们采用的是React,因为也是第一次写拼图小游戏,某些代码有进行Google。其中图片是随便找的一张哈~
简单介绍下,首先,我们需要引入React
、useState
和useCallback
这三个模块,并使用ReactDOM
进行 DOM 渲染。然后,定义一个二维数组data
,存储每个小方块的背景位置信息。声明一个函数组件Test
,在组件内部使用useState
来创建两个状态变量。backgroundPositions
用于保存小方块的背景位置信息,默认值为data
数组。
后面我们定义了一些函数包括handleOneKeyComplete
、handleStartGame
、handleSeeOriginalImage
、handleDragStart
、handleDrop
和handleDragOver
。这些函数分别处理重新排列方块、打乱方块顺序以及拖拽方块等操作。
在组件的返回结果中,使用map
方法遍历backgroundPositions
数组,为每个小方块创建一个div
元素。设置div
元素的背景位置样式为对应的position
,并添加拖拽事件处理函数。最后,我们将组件渲染到id
为app
的 DOM 节点上。
下面我们就开始一一介绍学习如何做出这样的游戏~~~
代码解析:布局
首先映入眼帘的是这个结构。
<div>
<div className="box">
{backgroundPositions.map((position, index) => (
<div
key={index}
className="d1"
style={
{ backgroundPosition: position }}
draggable
onDragStart={(e) => handleDragStart(e, index, position)}
onDrop={(e) => handleDrop(e, index, position)}
onDragOver={handleDragOver}
></div>
))}
</div>
<div id="but">
<button onClick={handleStartGame}>开始游戏</button>
<div style={
{width:'30%'}}>
<img id="yan" src="https://img.zcool.cn/community/0165245d71ad6fa801202f17f3702d.jpg@1280w_1l_2o_100sh.jpg" alt="" />
</div>
</div>
</div>
它由两个主要部分组成:一个包含拼图方块的容器和一个按钮加图片的容器。
拼图方块的容器
使用了一个div
元素,并给它添加了一个box
的类名。在这个容器内部,使用map
方法遍历backgroundPositions
数组,为每个小方块创建一个div
元素。这些小方块的类名为d1
,并且设置了背景位置样式为对应的position
,通过style
属性进行设置。同时,为了实现拖拽功能,给每个小方块添加了draggable
属性,并绑定了相应的拖拽事件处理函数handleDragStart
、handleDrop
和handleDragOver
。这样,用户可以通过拖拽这些小方块来重新排列拼图。
按钮和图片的容器。
使用了一个div
元素,它的id
属性为but
。在这个容器内部,包含一个按钮和一张图片。按钮使用了button
元素,绑定了点击事件处理函数handleStartGame
,用于开始游戏。
代码解析:CSS
其实这段css不用怎么介绍,很简单,直接看代码就可以。如果需要替换图片,可以直接修改d1
里面的background-image
* {
margin: 0;
padding: 0;
}
.box {
width: 312px;
height: 312px;
border: 3px solid #000;
margin: 50px auto 5px;
font-size: 0;
}
.box div {
width: 100px;
height: 100px;
display: inline-block;
border: 2px solid #000;
}
.d1 {
background-image: url('https://img.zcool.cn/community/0165245d71ad6fa801202f17f3702d.jpg@1280w_1l_2o_100sh.jpg');
background-size: 300px 300px;
background-position: 0px 0px;
}
这里我稍作解释下,每个拼图方块小块。设置背景图片为指定的URL,URL指向一张拼图的原始图片,设置背景尺寸为300像素乘以300像素,初始背景位置为0像素左偏移和0像素上偏移。
#but {
border: 1px solid #000 transparent;
width: 300px;
height: 30px;
margin: 0 auto;
}
#but img {
width: 100px;
height: 100px;
float: right;
display: none;
}
button {
margin: 1px auto;
border: 1px solid #000;
}
代码解析:方法
我个人认为,如果不熟悉的新手,难点可能就在拖动上面。
当然,以下是对代码的详细解释和相关代码片段:
const data = [['0 0'], ['-100px 0'], ['-200px 0'], ['0 -100px'], ['-100px -100px'], ['-200px -100px'], ['0 -200px'], ['-100px -200px'], ['-200px -200px']];
这是包含了拼图方块初始位置信息的二维数组。每个元素代表一个方块的位置,格式为[x y]
,其中x
和y
表示方块在CSS中的背景定位。
const [backgroundPositions, setBackgroundPositions] = useState(data);
这是使用React的useState钩子创建了一个名为backgroundPositions
的状态变量,其初始值为上述的data
数组。setBackgroundPositions
是用于更新backgroundPositions
状态的函数。
const handleStartGame = () => {
const arr = [];
let maxTimes = 9;
do {
const num = Math.floor(Math.random() * 9);
if (arr.indexOf(num) === -1) {
arr.push(num);
maxTimes--;
}
} while (maxTimes);
const newBackgroundPositions = arr.map((value, index) => backgroundPositions[value]);
setBackgroundPositions(newBackgroundPositions);
};
handleStartGame
是开始游戏的函数。它首先创建一个空数组arr
和一个最大次数maxTimes
,并使用do-while循环生成一个随机数num
,直到maxTimes
减为0为止。如果arr
数组中没有这个随机数,就将其添加到arr
数组中,并将maxTimes
减1。然后,使用map
方法根据打乱的顺序获取新的背景位置数组newBackgroundPositions
。最后,通过调用setBackgroundPositions
函数将新的背景位置数组设置为更新后的背景位置。
const handleDragStart = (e, id, position) => {
e.dataTransfer.setData('divID', id);
e.dataTransfer.setData('divPosition', position);
};
handleDragStart
这个方法就是用来拖动图片的啦。当拼图方块被拖动时,将该方块的id
和position
存储在dataTransfer
对象中,用于在拖放过程中传递信息。
const handleDrop = (e, id, position) => {
e.preventDefault();
e.stopPropagation();
const droppedDivId = e.dataTransfer.getData('divID');
const droppedDivPosition = e.dataTransfer.getData('divPosition');
const newBackgroundPositions = [...backgroundPositions];
const originalBackgroundPosition = newBackgroundPositions[id];
newBackgroundPositions[id] = droppedDivPosition;
newBackgroundPositions[droppedDivId] = originalBackgroundPosition;
setBackgroundPositions(newBackgroundPositions);
};
handleDrop
这个方法和上面的是联系起来,是用于放置图片,如果拼图方块被释放时,会执行此函数。首先,阻止默认的拖放行为(例如,打开拖放文件时的默认行为)。接着,阻止事件冒泡,以确保不会触发外层元素上的拖放处理程序。
然后,通过dataTransfer
对象获取之前存储的拖拽方块的id
和position
。创建一个新的背景位置数组newBackgroundPositions
,将原本在目标位置上的背景位置替换为拖动方块的position
,同时将原本在拖动方块位置上的背景位置替换为目标位置的position
。最后,通过调用setBackgroundPositions
函数将新的背景位置数组设置为更新后的背景位置。
const handleDragOver = (e) => {
e.preventDefault();
};
这可以处理拖放过程中的拖动目标元素上的事件的函数handleDragOver
。它可以阻止了默认的拖放行为!
最后我们来试试拼一张图片吧~