纯CSS实现密室逃脱游戏

前端Q

共 3575字,需浏览 8分钟

 ·

2021-08-07 09:26

点击上方 前端Q,关注公众号

回复加群,加入前端Q技术交流群

@alphardex,一个兴趣使然的前端,号称“CSS魔法使”,重度中二病患者,喜欢独自研究CSS的奥秘,口头禅是”我不是无所不知,只是刚好知道而已。”,爱好动漫、日语,平时经常在codepen进行创作。



“密室逃脱”这个词想必大家并不陌生,在以前的flash时代,这是一类很经典的益智游戏之一。玩家常常会被困在一间密室中,而过关的目的就是想法设法逃出这件密室。以下是笔者玩的最早的一个密室逃脱游戏——深红房间,它也可以说是密室逃脱类游戏的先祖。

接下来,笔者要用纯CSS实现一款类似的密室逃脱类游戏。

是的,你没听错,纯CSS,也就意味着完全没有JS的参与。有人就纳闷了:WTF?CSS,一个网页布局的语言,居然还能写游戏?可惜的是,CSS还真能写游戏。接下来随笔者一起进入这个不思议的国度吧。

攻略

每次笔者玩密室逃脱游戏卡关时,总会去搜搜攻略,看完后就能把游戏玩通。因此当我们做密室逃脱类游戏时,首先要考虑的事情就是攻略。以下是笔者为本文密室逃脱游戏所制定的攻略

  • 左转,转动地球仪

  • 右转,发现一根锤子,点击捡起,记住墙上的数字

  • 左转,点击柜子,用锤子砸开它,获得一个圆盘

  • 点击墙上的壁画,壁画移开,看到一圆盘印,嵌入圆盘,获得一个usb

  • 右转2次,将usb插入电脑,电脑开启,输入墙上的密码,获得钥匙

  • 右转,用钥匙打开大门,游戏结束

开关

制定完攻略后,就要开始确定该游戏的核心所在——开关。说到开关,大家觉得HTML里的哪个元素最适合用来做开关?答案是单复选框。

说起单复选框,就不得不提这2个CP——label和兄弟选择符。label负责将该元素与其对应的复选框用for来关联起来,而兄弟选择符则负责与:checked伪类配合好,当某元素被勾选时,其相邻的元素就会受到它的影响。

首先,让我们来看一看一个简单的开关例子

  1. <input type="radio" id="globe" class="globe-trigger" />

  2. <input type="radio" id="hammer" class="hammer-trigger" />

  3. <label for="globe" class="globe">

  4. <img src="https://i.loli.net/2020/10/25/YBnOQ2jVtSTmFkE.png" alt class="w-8" />

  5. </label>

  6. <label for="hammer" class="hammer">

  7. <img src="https://i.loli.net/2020/10/25/KhVp4EaMoYrjlIC.png" alt class="w-6" />

  8. </label>

  1. .hammer {

  2. display: none;

  3. }


  4. .globe-trigger:checked {

  5. & ~ {

  6. .globe {

  7. pointer-events: none;

  8. }


  9. .hammer {

  10. display: inline-block;

  11. }

  12. }

  13. }


  14. .hammer-trigger:checked {

  15. & ~ {

  16. .hammer {

  17. transform: scale(0);

  18. opacity: 0;

  19. }

  20. }

  21. }

可以看到我们用label元素包裹了对应的图片,并关联好了对应的开关。当用户点击地球仪globe时,globe-trigger开关就会被触发,这就是label的关联性

触发开关后,开关旁边对应的元素状态就发生了变化:globe变得无法被点击;hammer元素出现,这就是兄弟选择符的作用

同理,点击锤子hammer时,与其关联的hammer-trigger开关被触发,与此同时旁边的hammer就会消失,代表被用户“捡起”这一动作

理解开关的原理后,我们就可以把开关给隐藏起来啦

  1. input[type="checkbox"],

  2. input[type="radio"] {

  3. display: none;

  4. }

场景切换

假设我们游戏地图分为4块,且可以用导航箭头来切换。

游戏的地图其实是一张长图,如下图所示

  1. <div class="camera">

  2. <!-- 导航 -->

  3. <input type="radio" id="nav-1" name="nav" class="nav-trigger-1" />

  4. <input type="radio" id="nav-2" name="nav" class="nav-trigger-2" />

  5. <input type="radio" id="nav-3" name="nav" class="nav-trigger-3" />

  6. <input type="radio" id="nav-4" name="nav" class="nav-trigger-4" />

  7. <!-- 长图 -->

  8. <form class="stage">

  9. <!-- 开关 -->

  10. <input type="checkbox" id="globe" class="globe-trigger" />...

  11. <!-- 场景 -->

  12. <div class="scene scene-1">

  13. <label for="...">...</label>

  14. <nav class="navs">

  15. <label for="nav-4" class="nav-left"></label>

  16. <label for="nav-2" class="nav-right"></label>

  17. </nav>

  18. </div>

  19. </form>

  20. </div>

首先,设定游戏的固定视角,将多余的部分裁掉

  1. .camera {

  2. --stage-width: 18rem;

  3. --scene-id: 0;


  4. position: relative;

  5. width: var(--stage-width);

  6. height: var(--stage-width);

  7. overflow: hidden;

  8. }

然后,设定导航,根据所选的导航来确定长图的平移距离

  1. @for $i from 1 through 4 {

  2. .nav-trigger-#{$i}:checked {

  3. & ~ .stage {

  4. --scene-id: #{$i - 1};

  5. }

  6. }

  7. }


  8. .stage {

  9. transform: translateY(calc(var(--stage-width) * var(--scene-id) * -1));

  10. }


  11. .scene {

  12. position: relative;

  13. width: var(--stage-width);

  14. height: var(--stage-width);

  15. }

比如在场景1,用户向右走,导航2被触发,长图将上平移一个单位,如下图所示

这样就完成了场景切换这一效果

完成项目

此刻,我们已经具备完成密室逃脱游戏所必须的知识了。根据上面的攻略,一步步定制好所有开关,摆放好所有物件,且能确保场景能自由切换,这样一个纯CSS密室逃脱游戏就成功诞生啦

在线游玩地址:https://codepen.io/alphardex/full/GRqWRyB

关于本文 作者:@alphardex 原文:https://juejin.im/post/6887792725031288839

声明:文章著作权归作者所有,如有侵权,请联系小编删除。




内推社群


我组建了一个氛围特别好的腾讯内推社群,如果你对加入腾讯感兴趣的话(后续有计划也可以),我们可以一起进行面试相关的答疑、聊聊面试的故事、并且在你准备好的时候随时帮你内推。下方加 winty 好友回复「面试」即可。


浏览 40
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报