跳至拼图
有一天,我的脑海中突然浮现出童年时的一个小拼图玩具的回忆,这是一个滑块拼图,其中 15 个方形瓷砖以 4 x 4 的单元格排列方式放置在框架中,留下一个可用空间。每块瓷砖和框架边缘上的一组脊和凹槽允许瓷砖彼此滑过,同时将瓷砖固定在框架中。在任何给定时间,与自由空间相邻的任何图块都可以移动到该空间中,否则这些图块将被阻止移动。将一块图块移动到空闲空间中,然后在该图块来自的地方留下一个新的空闲空间,然后另一个图块可以移动到该新空间中。这个想法是通过以这种方式重复滑动图块来将图块排列成某种预定的顺序。
显然这被称为“15 Puzzle”,自 1870 年代以来就一直存在。搜索网络会返回许多用各种编程语言编写的游戏,实际上 dev.to 上有几篇文章,包括 https://dev.to/artydev/let-us-code-a-sliding-puzzle-9n 、https://dev.to/xzanderzone/making-a-slider-puzzle-in-java-script-83m 和 https://dev.to/claurcia/slide-puzzle-5c55 均采用 JavaScript 和 https://dev.to/claurcia/slide-puzzle-5c55 Go 中的 /dev.to/mfbmina/building-a-sliding-puzzle-with-go-3bnj。对于那些学习 JavaScript 的人来说,它也是一个很好的入门挑战。
不过,激起我兴趣的是它应该可以在网络上使用根本不使用编程语言来重新创建的想法!也就是说,仅使用纯 HTML 和 CSS 的实现。所以我在下面介绍一下。我必须做出的一个妥协是,所提供的 10 场比赛具有固定的预先洗牌的起始位置。
为此,预定的顺序是显示完整的图片。
此实现的基本原理是每个图块保留其在帧内位置的状态记录。在 HTML 和 CSS 中更改和保持状态的方法并不多,但最常见的是“复选框黑客”,并且此实现大量使用了它。对于任何不熟悉复选框黑客的人来说,当单击或点击
因此,每个图块都有一对单选按钮组,每个单选按钮组有四个单选按钮。其中一组保留图块在 X 轴上的位置,另一组保留图块在 Y 轴上的位置。 (如果您愿意,也可以分别是水平位置和垂直位置。)这 15 个图块最初通过其单选按钮指定了不同的 X 和 Y 坐标组合,以便每个图块占据帧中的不同单元格。
这些图块最初放置在框架的顶部、左侧单元格中,然后通过 CSS 在框架内移动,通过对单选按钮应用平移变换来测量单选按钮的状态:
/* "X" refers to the X-axis cell positions, "Y" to the Y-axis cell positions. * 0, 1, 2, 3 refers to the position on that axis, * 0 = left and top, 3 = right and bottom respectively. */ .tile:has(.X0:checked~.Y0:checked) { transform: translate(0%, 0%); } .tile:has(.X0:checked~.Y1:checked) { transform: translate(0%, 100%); } .tile:has(.X0:checked~.Y2:checked) { transform: translate(0%, 200%); } .tile:has(.X0:checked~.Y3:checked) { transform: translate(0%, 300%); } .tile:has(.X1:checked~.Y0:checked) { transform: translate(100%, 0%); } /* and so on for the remainder of the sixteen combinations */
该图块还包含八个标签元素,对应于八个单选按钮。每个标签都是绝对定位的,彼此重叠,并且每个标签都完全填充图块。标签是透明的,并且最初设置为不响应单击和点击,方法是在所有标签上设置pointer-events:none。
下一步是 CSS 选择器识别空单元格的位置。这是通过消除来完成的,它是 X、Y 坐标不由 15 个图块中任何一个的单选按钮组对表示的单元格。
例如,如果匹配:
.frame:not(:has(.tile .X0:checked~.Y0:checked)) { .... }
那么空单元格当前必须位于左上角单元格中。对 16 个单元格中的每一个单元格重复此操作,其中恰好有一个单元格将匹配。
一旦完成,就可以识别与空单元格相邻的单元格。如果空单元格位于角落,则正好有两个图块可以移动到该单元格中,否则,如果空单元格靠着框架的一侧,则有三个图块可以移动到该单元格中,否则空单元格可以移动到该单元格中。单元格必须是四个中间单元格之一,并且有四个方块可以移动到它。对于每个图块,图块的八个标签之一将激活将图块移动到空单元格所需的正确单选按钮。通过将其pointer-events 值设置回auto 来启用该标签。举个例子:
/* Top, left corner */ .frame:not(:has(.tile .X0:checked ~ .Y0:checked)) { :is( .tile:has(.X0:checked ~ .Y1:checked) label.Y0, .tile:has(.X1:checked ~ .Y0:checked) label.X0 ) { pointer-events: auto; } } /* right most cell of row two */ .frame:not(:has(.tile .X1:checked ~ .Y3:checked)) { :is( .tile:has(.X1:checked ~ .Y2:checked) label.Y3, .tile:has(.X0:checked ~ .Y3:checked) label.X1, .tile:has(.X2:checked ~ .Y3:checked) label.X1 ) { pointer-events: auto; } } /* second cell from left on row three */ .frame:not(:has(.tile .X2:checked ~ .Y1:checked)) { :is( .tile:has(.X2:checked ~ .Y0:checked) label.Y1, .tile:has(.X2:checked ~ .Y2:checked) label.Y1, .tile:has(.X1:checked ~ .Y1:checked) label.X2, .tile:has(.X3:checked ~ .Y1:checked) label.X2 ) { pointer-events: auto; } }
游戏的最后一步是确定谜题何时被解决。这只是检查 15 个图块是否都将其预期的 X 和 Y 轴单选按钮设置为“已解决”位置的情况。
/* Each tile is assigned a letter "a" to "o". * The puzzle is solved when the tiles are in alphabetical order * reading left to right and top to bottom */ .frame:has(.a .X0:checked ~ .Y0:checked):has(.b .X1:checked ~ .Y0:checked):has( .c .X2:checked ~ .Y0:checked ):has(.d .X3:checked ~ .Y0:checked):has(.e .X0:checked ~ .Y1:checked):has( .f .X1:checked ~ .Y1:checked ):has(.g .X2:checked ~ .Y1:checked):has(.h .X3:checked ~ .Y1:checked):has( .i .X0:checked ~ .Y2:checked ):has(.j .X1:checked ~ .Y2:checked):has(.k .X2:checked ~ .Y2:checked):has( .l .X3:checked ~ .Y2:checked ):has(.m .X0:checked ~ .Y3:checked):has(.n .X1:checked ~ .Y3:checked):has( .o .X2:checked ~ .Y3:checked ) ~ .options .success { display: block; }
剩下的都是装饰性的。滑动是通过上述变换的简单转换来完成的
.tile { transition: 0.5s transform; @media (prefers-reduced-motion) { transition: none; } }
每个图块使用背景大小和背景位置显示游戏图像的一部分
.tile { background-size: 400%; } #board1 .tile { background-image: url("https://alohci.net/image/dev.to/slidergame/mullermarc-k7bQqdUf954-unsplash.webp"); } .a { background-position: 0% 0%; } .b { background-position: 33.333% 0%; } .c { background-position: 66.667% 0%; } .d { background-position: 100% 0%; } .e { background-position: 0% 33.333%; } /* and so on for the remaining tiles */
还有一组单选按钮可以选择玩十个游戏中的哪一个。
要玩游戏,只需点击或点按您想要滑动到空单元格的图块即可。
我还提供了“准系统”模式来显示平铺字母和单选按钮,这可能有助于理解 HTML 和 CSS 的工作原理。
这就是完成的益智游戏。如果您有任何反馈,请告诉我。
免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。
Copyright© 2022 湘ICP备2022001581号-3