愛伊米

前端遊戲鉅製! CSS 居然可以做 3D 遊戲了

前言

偶然接觸到CSS的3D屬性, 就萌生了一種做

3D遊戲

的想法。

瞭解過css3D屬性的同學應該都瞭解過、、這個三個屬性值, 它們構成了CSS的3d世界。

同時, 還有屬性來對3D的節點進行平移、縮放、旋轉以及拉伸。

屬性值很簡單, 在我們平時的web開發中也很少用到。

那用這些CSS3D屬性可以做3D遊戲嗎?

當然是可以的。

即使只有沙盒, 也有

我的世界

這種神作。

今天我就來帶大家玩一個從未有過的全新3D體驗。

廢話不多說, 我們先來看下效果:

我們要完成這個

迷宮大作戰

,需要完成以下步驟:

建立一個3D世界

寫一個3D相機的功能

建立一座3D迷宮

建立一個可以自由運動的玩家

在迷宮中找出一條最短路徑提示

我們先來看下一些前置知識。

做一款CSS3D遊戲需要的知識和概念

CSS3D座標系

在css3D中, 首先要明確一個概念,

3D

座標系。

使用

左手座標系

, 伸出我們的左手, 大拇指和食指成

L

狀, 其他手指與食指垂直, 如圖:

前端遊戲鉅製! CSS 居然可以做 3D 遊戲了

大拇指為X軸, 食指為Y軸, 其他手指為Z軸。

這個就是CSS3D中的座標系。

透視屬性

為css中的透視屬性。

這個屬性是什麼意思呢, 可以把我們的眼睛看作觀察點, 眼睛到目標物體的距離就是視距, 也就是這裡說的透視屬性。

大家都知道,「透視」+「2D」= 「3D」。

3D相機

在3D遊戲開發中, 會有相機的概念, 即是人眼所見皆是相機所見。

在遊戲中場景的移動, 大部分都是移動相機。

例如賽車遊戲中, 相機就是跟隨車子移動, 所以我們才能看到一路的風景。

在這裡, 我們會使用CSS去實現一個偽3d相機。

變換屬性

在CSS3D中我們對3D盒子做平移、旋轉、拉伸、縮放使用屬性。

translateX 平移X軸

translateY 平移Y軸

translateZ 平移Z軸

rotateX 旋轉X軸

rotateY 旋轉Y軸

rotateZ 旋轉Z軸

rotate3d(x,y,z,deg) 旋轉X、Y、Z軸多少度

注意:

這裡「先平移再旋轉」和「先旋轉再平移」是不一樣的

旋轉的角度都是角度值。

矩陣變換

我們完成遊戲的過程中會用到矩陣變換。

在js中, 獲取某個節點的屬性, 會得到一個矩陣, 這裡我列印一下, 他就是長這個樣子:

那麼我們如何使用矩陣去操作transform呢?

線上性變換中, 我們都會去使用矩陣的相乘。

CSS3D中使用4*4的矩陣進行3D變換。

下面的矩陣我均用二維陣列表示。

例如可以用二維陣列表示:

平移即使使用原來狀態的矩陣和以下矩陣相乘, dx, dy, dz分別是移動的方向x, y, z。

繞X軸旋轉, 即是與以下矩陣相乘。

繞Y軸旋轉, 即是與以下矩陣相乘。

繞Z軸旋轉, 即是與以下矩陣相乘。

具體的矩陣的其他知識這裡講了, 大家有興趣可以自行下去學習。

我們這裡只需要很簡單的旋轉應用。

開始建立一個3D世界

我們先來建立UI介面。

相機div

地平線div

棋盤div

玩家div(這裡是一個正方體)

注意

正方體先旋轉在平移, 這種方法應該是最簡單的。

一個平面繞X軸、Y軸旋轉180度、±90度, 都只需要平移Z軸。

這裡大家試過就明白了。

我們先來看下html部分:

很簡單的佈局, 其中、、是我畫的座標軸輔助線。

紅線為X軸, 綠線為Y軸, 藍線為Z軸。 接著我們來看下正方體的主要CSS程式碼。

貼上一大堆CSS程式碼顯得很蠢。

其他CSS這裡就不貼上了, 有興趣的同學可以直接下載原始碼檢視。 介面搭建完成如圖所示:

前端遊戲鉅製! CSS 居然可以做 3D 遊戲了

接下來就是重頭戲了, 我們去寫js程式碼來繼續完成我們的遊戲。

完成一個3D相機功能

相機在3D開發中必不可少, 使用相機功能不僅能檢視3D世界模型, 同時也能實現很多實時的炫酷功能。

一個3d相機需要哪些功能?

最簡單的, 上下左右能夠360度無死角觀察地圖。同時需要拉近拉遠視距。

透過滑鼠互動

滑鼠左右移動可以旋轉檢視地圖; 滑鼠上下移動可以觀察上下地圖; 滑鼠滾輪可以拉近拉遠視距。

✅1。 監聽滑鼠事件

首先, 我們需要透過監聽滑鼠事件來記錄滑鼠位置, 從而判斷相機上下左右檢視。

✅2。 判斷相機上下左右

使用來設定相機的上下視線。

使用來旋轉Z軸檢視左右方向上的360度。

這裡使用了矩陣的方法來旋轉Z軸, 矩陣類是我臨時寫的一個方法類, 就倆方法, 一個設定二維陣列, 一個矩陣相乘。

文末的原始碼地址中有, 這裡就不再贅述了。

✅3。 監聽滾輪拉近拉遠距離

這裡就是根據來設定視距。

注意:

perspective-origin屬性只有X、Y兩個值, 做不到和u3D一樣的相機。

我這裡取巧使用了對地平線的旋轉, 從而達到一樣的效果。

滾輪拉近拉遠視距有點彆扭, 和3D引擎區別還是很大。

完成之後可以看到如下的場景, 已經可以隨時觀察我們的地圖了。

前端遊戲鉅製! CSS 居然可以做 3D 遊戲了

這樣子, 一個3D相機就完成, 大家有興趣的可以自己下去寫一下, 還是很有意思的。

繪製迷宮棋盤

繪製格子地圖最簡單了, 我這裡使用一個15*15的陣列。

「」代表可以透過的路, 「1」代表障礙物。

然後我們去遍歷這個陣列, 得到地圖。

寫一個方法去建立地圖格子, 同時返回格子陣列和節點陣列。

這裡的是在html中建立的一個預製體, 他是一個正方體。

然後透過克隆節點的方式新增進棋盤中。

可以看到, 我們的介面已經變成了這樣。

前端遊戲鉅製! CSS 居然可以做 3D 遊戲了

接下來, 我們需要去控制玩家移動了。

控制玩家移動

透過上下左右鍵來控制玩家移動。

使用來移動和旋轉玩家盒子。

✅監聽鍵盤事件

透過監聽鍵盤事件來判斷值的上下左右。

✅進行位移

在位移中, 使用來平移, Z軸始終正對我們的相機, 所以我們只需要移動X軸和Y軸。

宣告一個變數記錄當前位置。

同時需要記錄上次變換的的值, 這裡我們就不繼續矩陣變換了。

每一個格子都可以看成是二維陣列的下標構成, 每次我們移動一個格子的距離。

到這裡, 我們的玩家盒子已經可以移動了。

注意

在css3D中的平移可以看成是世界座標。

所以我們只需要關心X、Y軸。 而不需要去移動Z軸。 即使我們進行了旋轉。

✅在移動的過程中進行旋轉

在CSS3D中, 3D旋轉和其他3D引擎中不一樣, 一般的諸如u3D、threejs中, 在每次旋轉完成之後都會重新校對成世界座標, 相對來說 就很好計算繞什麼軸旋轉多少度。

然而, 筆者也低估了CSS3D的旋轉。

我以為上下左右滾動一個正方體很簡單。 事實並非如此。

CSS3D的旋轉涉及到四元數和萬向鎖。

比如我們旋轉我們的玩家盒子。 如圖所示:

前端遊戲鉅製! CSS 居然可以做 3D 遊戲了

首先, 第一個格子(0,0)向上繞X軸旋轉90度, 就可以到達(1。0); 向左繞Y軸旋轉90度, 可以到達(0,1); 那我們是不是就可以得到規律如下:

前端遊戲鉅製! CSS 居然可以做 3D 遊戲了

如圖中所示, 單純的向上下, 向左右繞軸旋轉沒有問題, 但是要旋轉到紅色的格子, 兩種不同走法, 到紅色的格子之後旋轉就會出現兩種可能。 從而導致旋轉出錯。

同時這個規律雖然難尋, 但是可以寫出來, 最重要的是,

按照這個規律來旋轉CSS3D中的盒子, 是不對的

那有人就說了, 這不說的屁話嗎?

經過筆者實驗, 倒是發現了一些規律。 我們繼續按照這個規律往下走。

旋轉X軸的時候, 同時看當前Z軸的度數, Z軸為90度的奇數倍, 旋轉Y軸, 否則旋轉X軸。

旋轉Y軸的時候, 同時看當前Z軸的度數, Z軸為90度的奇數倍, 旋轉X軸, 否則旋轉Z軸。

旋轉Z軸的時候, 繼續旋轉Z軸

這樣子我們的旋轉方向就搞定了。

然而, 這還沒有完, 這種方式的旋轉還有個坑, 就是我不知道該旋轉90度還是-90度了。

這裡並不是簡單的上下左右去加減。

旋轉方向對了, 旋轉角度不知該如何計算了.

具體程式碼可以檢視原始碼。

彩蛋時間

⚠️⚠️⚠️ 同時這裡會伴隨著「萬向鎖」的出現, 即是Z軸與X軸重合了。 哈哈哈哈~

⚠️⚠️⚠️ 這裡筆者還沒有解決, 也希望萬能的網友能夠出言幫忙~

⚠️⚠️⚠️ 筆者後續解決了會更新的。 哈哈哈哈, 大坑。

好了, 這裡問題不影響我們的專案。 我們繼續講如何找到最短路徑並給出提示。

最短路徑的計算

在迷宮中, 從一個點到另一個點的最短路徑怎麼計算呢? 這裡筆者使用的是廣度優先遍歷(

BFS

)演算法來計算最短路徑。

我們來思考:

二維陣列中找最短路徑

每一格的最短路徑只有上下左右相鄰的四格

那麼只要遞迴尋找每一格的最短距離直至找到終點

這裡我們需要使用「佇列」先進先出的特點。

我們先來看一張圖:

前端遊戲鉅製! CSS 居然可以做 3D 遊戲了

很清晰的可以得到最短路徑。

注意

使用兩個長度為4的陣列表示上下左右相鄰的格子需要相加的下標偏移量。

每次入隊之前需要判斷是否已經入隊了。

每次出隊時需要判斷是否是終點。

需要記錄當前入隊的目標的父節點, 方便獲取到最短路徑。

我們來看下程式碼:

這樣子我們就可以找到一條最短路徑並得到最短的步數。

然後我們繼續去遍歷我們的原陣列(即棋盤原陣列)。

點選提示點亮路徑。

這樣子, 我們可以得到如圖的提示:

前端遊戲鉅製! CSS 居然可以做 3D 遊戲了

大功告成。 嘿嘿, 是不是很驚豔的感覺~

尾聲

當然, 我這裡的這個小遊戲還有可以完善的地方 比如:

可以增加道具, 拾取可以減少已走步數

可以增加配置關卡

還可以增加跳躍功能

。。。

原來如此, CSS3D能做的事還有很多, 怎麼用全看自己的想象力有多豐富了。

哈哈哈, 真想用CSS3D寫一個「我的世界」玩玩, 效能問題恐怕會有點大。

本文例子均在PC端體驗較好。

試玩地址

https://xdq1553。github。io/-CSS3D-/

原始碼地址

https://github。com/xdq1553/-CSS3D-

作者:起小就些熊

- EOF -