純CSS實(shí)現(xiàn)密室逃脫游戲
@alphardex,一個(gè)興趣使然的前端,號(hào)稱“CSS魔法使”,重度中二病患者,喜歡獨(dú)自研究CSS的奧秘,口頭禪是”我不是無所不知,只是剛好知道而已。”,愛好動(dòng)漫、日語,平時(shí)經(jīng)常在codepen進(jìn)行創(chuàng)作。
“密室逃脫”這個(gè)詞想必大家并不陌生,在以前的flash時(shí)代,這是一類很經(jīng)典的益智游戲之一。玩家常常會(huì)被困在一間密室中,而過關(guān)的目的就是想法設(shè)法逃出這件密室。以下是筆者玩的最早的一個(gè)密室逃脫游戲——深紅房間,它也可以說是密室逃脫類游戲的先祖。

接下來,筆者要用純CSS實(shí)現(xiàn)一款類似的密室逃脫類游戲。
是的,你沒聽錯(cuò),純CSS,也就意味著完全沒有JS的參與。有人就納悶了:WTF?CSS,一個(gè)網(wǎng)頁布局的語言,居然還能寫游戲?可惜的是,CSS還真能寫游戲。接下來隨筆者一起進(jìn)入這個(gè)不思議的國(guó)度吧。
攻略
每次筆者玩密室逃脫游戲卡關(guān)時(shí),總會(huì)去搜搜攻略,看完后就能把游戲玩通。因此當(dāng)我們做密室逃脫類游戲時(shí),首先要考慮的事情就是攻略。以下是筆者為本文密室逃脫游戲所制定的攻略
左轉(zhuǎn),轉(zhuǎn)動(dòng)地球儀
右轉(zhuǎn),發(fā)現(xiàn)一根錘子,點(diǎn)擊撿起,記住墻上的數(shù)字
左轉(zhuǎn),點(diǎn)擊柜子,用錘子砸開它,獲得一個(gè)圓盤
點(diǎn)擊墻上的壁畫,壁畫移開,看到一圓盤印,嵌入圓盤,獲得一個(gè)usb
右轉(zhuǎn)2次,將usb插入電腦,電腦開啟,輸入墻上的密碼,獲得鑰匙
右轉(zhuǎn),用鑰匙打開大門,游戲結(jié)束
開關(guān)
制定完攻略后,就要開始確定該游戲的核心所在——開關(guān)。說到開關(guān),大家覺得HTML里的哪個(gè)元素最適合用來做開關(guān)?答案是單復(fù)選框。
說起單復(fù)選框,就不得不提這2個(gè)CP——label和兄弟選擇符。label負(fù)責(zé)將該元素與其對(duì)應(yīng)的復(fù)選框用for來關(guān)聯(lián)起來,而兄弟選擇符則負(fù)責(zé)與:checked偽類配合好,當(dāng)某元素被勾選時(shí),其相鄰的元素就會(huì)受到它的影響。
首先,讓我們來看一看一個(gè)簡(jiǎn)單的開關(guān)例子
type="radio" id="globe" class="globe-trigger" />
type="radio" id="hammer" class="hammer-trigger" />
src="https://i.loli.net/2020/10/25/YBnOQ2jVtSTmFkE.png" alt class="w-8" />
src="https://i.loli.net/2020/10/25/KhVp4EaMoYrjlIC.png" alt class="w-6" />
.hammer {
display: none;
}
.globe-trigger:checked {
& ~ {
.globe {
pointer-events: none;
}
.hammer {
display: inline-block;
}
}
}
.hammer-trigger:checked {
& ~ {
.hammer {
transform: scale(0);
opacity: 0;
}
}
}

可以看到我們用label元素包裹了對(duì)應(yīng)的圖片,并關(guān)聯(lián)好了對(duì)應(yīng)的開關(guān)。當(dāng)用戶點(diǎn)擊地球儀globe時(shí),globe-trigger開關(guān)就會(huì)被觸發(fā),這就是label的關(guān)聯(lián)性
觸發(fā)開關(guān)后,開關(guān)旁邊對(duì)應(yīng)的元素狀態(tài)就發(fā)生了變化:globe變得無法被點(diǎn)擊;hammer元素出現(xiàn),這就是兄弟選擇符的作用
同理,點(diǎn)擊錘子hammer時(shí),與其關(guān)聯(lián)的hammer-trigger開關(guān)被觸發(fā),與此同時(shí)旁邊的hammer就會(huì)消失,代表被用戶“撿起”這一動(dòng)作
理解開關(guān)的原理后,我們就可以把開關(guān)給隱藏起來啦
input[type="checkbox"],
input[type="radio"] {
display: none;
}
場(chǎng)景切換
假設(shè)我們游戲地圖分為4塊,且可以用導(dǎo)航箭頭來切換。
游戲的地圖其實(shí)是一張長(zhǎng)圖,如下圖所示

class="camera">
type="radio" id="nav-1" name="nav" class="nav-trigger-1" />
type="radio" id="nav-2" name="nav" class="nav-trigger-2" />
type="radio" id="nav-3" name="nav" class="nav-trigger-3" />
type="radio" id="nav-4" name="nav" class="nav-trigger-4" />
type="checkbox" id="globe" class="globe-trigger" />...
class="scene scene-1">
首先,設(shè)定游戲的固定視角,將多余的部分裁掉
.camera {
--stage-width: 18rem;
--scene-id: 0;
position: relative;
width: var(--stage-width);
height: var(--stage-width);
overflow: hidden;
}
然后,設(shè)定導(dǎo)航,根據(jù)所選的導(dǎo)航來確定長(zhǎng)圖的平移距離
@for $i from 1 through 4 {
.nav-trigger-#{$i}:checked {
& ~ .stage {
--scene-id: #{$i - 1};
}
}
}
.stage {
transform: translateY(calc(var(--stage-width) * var(--scene-id) * -1));
}
.scene {
position: relative;
width: var(--stage-width);
height: var(--stage-width);
}
比如在場(chǎng)景1,用戶向右走,導(dǎo)航2被觸發(fā),長(zhǎng)圖將上平移一個(gè)單位,如下圖所示

這樣就完成了場(chǎng)景切換這一效果
完成項(xiàng)目
此刻,我們已經(jīng)具備完成密室逃脫游戲所必須的知識(shí)了。根據(jù)上面的攻略,一步步定制好所有開關(guān),擺放好所有物件,且能確保場(chǎng)景能自由切換,這樣一個(gè)純CSS密室逃脫游戲就成功誕生啦
在線游玩地址:https://codepen.io/alphardex/full/GRqWRyB

關(guān)于本文 作者:@alphardex 原文:https://juejin.im/post/6887792725031288839
??愛心三連擊 1.看到這里了就點(diǎn)個(gè)在看支持下吧,你的「點(diǎn)贊,在看」是我創(chuàng)作的動(dòng)力。
2.關(guān)注公眾號(hào)
程序員成長(zhǎng)指北,回復(fù)「1」加入Node進(jìn)階交流群!「在這里有好多 Node 開發(fā)者,會(huì)討論 Node 知識(shí),互相學(xué)習(xí)」!3.也可添加微信【ikoala520】,一起成長(zhǎng)。
“在看轉(zhuǎn)發(fā)”是最大的支持
