前言
偶然接觸到CSS的3D屬性, 就萌生了一種做
3D遊戲
的想法。
瞭解過css3D屬性的同學應該都瞭解過、、這個三個屬性值, 它們構成了CSS的3d世界。
同時, 還有屬性來對3D的節點進行平移、縮放、旋轉以及拉伸。
屬性值很簡單, 在我們平時的web開發中也很少用到。
那用這些CSS3D屬性可以做3D遊戲嗎?
當然是可以的。
即使只有沙盒, 也有
我的世界
這種神作。
今天我就來帶大家玩一個從未有過的全新3D體驗。
廢話不多說, 我們先來看下效果:
我們要完成這個
迷宮大作戰
,需要完成以下步驟:
建立一個3D世界
寫一個3D相機的功能
建立一座3D迷宮
建立一個可以自由運動的玩家
在迷宮中找出一條最短路徑提示
我們先來看下一些前置知識。
做一款CSS3D遊戲需要的知識和概念
CSS3D座標系
在css3D中, 首先要明確一個概念,
3D
座標系。
使用
左手座標系
, 伸出我們的左手, 大拇指和食指成
L
狀, 其他手指與食指垂直, 如圖:
大拇指為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這裡就不貼上了, 有興趣的同學可以直接下載原始碼檢視。 介面搭建完成如圖所示:
接下來就是重頭戲了, 我們去寫js程式碼來繼續完成我們的遊戲。
完成一個3D相機功能
相機在3D開發中必不可少, 使用相機功能不僅能檢視3D世界模型, 同時也能實現很多實時的炫酷功能。
一個3d相機需要哪些功能?
最簡單的, 上下左右能夠360度無死角觀察地圖。同時需要拉近拉遠視距。
透過滑鼠互動
滑鼠左右移動可以旋轉檢視地圖; 滑鼠上下移動可以觀察上下地圖; 滑鼠滾輪可以拉近拉遠視距。
✅1。 監聽滑鼠事件
首先, 我們需要透過監聽滑鼠事件來記錄滑鼠位置, 從而判斷相機上下左右檢視。
✅2。 判斷相機上下左右
使用來設定相機的上下視線。
使用來旋轉Z軸檢視左右方向上的360度。
這裡使用了矩陣的方法來旋轉Z軸, 矩陣類是我臨時寫的一個方法類, 就倆方法, 一個設定二維陣列, 一個矩陣相乘。
文末的原始碼地址中有, 這裡就不再贅述了。
✅3。 監聽滾輪拉近拉遠距離
這裡就是根據來設定視距。
注意:
perspective-origin屬性只有X、Y兩個值, 做不到和u3D一樣的相機。
我這裡取巧使用了對地平線的旋轉, 從而達到一樣的效果。
滾輪拉近拉遠視距有點彆扭, 和3D引擎區別還是很大。
完成之後可以看到如下的場景, 已經可以隨時觀察我們的地圖了。
這樣子, 一個3D相機就完成, 大家有興趣的可以自己下去寫一下, 還是很有意思的。
繪製迷宮棋盤
繪製格子地圖最簡單了, 我這裡使用一個15*15的陣列。
「」代表可以透過的路, 「1」代表障礙物。
然後我們去遍歷這個陣列, 得到地圖。
寫一個方法去建立地圖格子, 同時返回格子陣列和節點陣列。
這裡的是在html中建立的一個預製體, 他是一個正方體。
然後透過克隆節點的方式新增進棋盤中。
可以看到, 我們的介面已經變成了這樣。
接下來, 我們需要去控制玩家移動了。
控制玩家移動
透過上下左右鍵來控制玩家移動。
使用來移動和旋轉玩家盒子。
✅監聽鍵盤事件
透過監聽鍵盤事件來判斷值的上下左右。
✅進行位移
在位移中, 使用來平移, Z軸始終正對我們的相機, 所以我們只需要移動X軸和Y軸。
宣告一個變數記錄當前位置。
同時需要記錄上次變換的的值, 這裡我們就不繼續矩陣變換了。
每一個格子都可以看成是二維陣列的下標構成, 每次我們移動一個格子的距離。
到這裡, 我們的玩家盒子已經可以移動了。
注意
在css3D中的平移可以看成是世界座標。
所以我們只需要關心X、Y軸。 而不需要去移動Z軸。 即使我們進行了旋轉。
✅在移動的過程中進行旋轉
在CSS3D中, 3D旋轉和其他3D引擎中不一樣, 一般的諸如u3D、threejs中, 在每次旋轉完成之後都會重新校對成世界座標, 相對來說 就很好計算繞什麼軸旋轉多少度。
然而, 筆者也低估了CSS3D的旋轉。
我以為上下左右滾動一個正方體很簡單。 事實並非如此。
CSS3D的旋轉涉及到四元數和萬向鎖。
比如我們旋轉我們的玩家盒子。 如圖所示:
首先, 第一個格子(0,0)向上繞X軸旋轉90度, 就可以到達(1。0); 向左繞Y軸旋轉90度, 可以到達(0,1); 那我們是不是就可以得到規律如下:
如圖中所示, 單純的向上下, 向左右繞軸旋轉沒有問題, 但是要旋轉到紅色的格子, 兩種不同走法, 到紅色的格子之後旋轉就會出現兩種可能。 從而導致旋轉出錯。
同時這個規律雖然難尋, 但是可以寫出來, 最重要的是,
按照這個規律來旋轉CSS3D中的盒子, 是不對的
那有人就說了, 這不說的屁話嗎?
經過筆者實驗, 倒是發現了一些規律。 我們繼續按照這個規律往下走。
旋轉X軸的時候, 同時看當前Z軸的度數, Z軸為90度的奇數倍, 旋轉Y軸, 否則旋轉X軸。
旋轉Y軸的時候, 同時看當前Z軸的度數, Z軸為90度的奇數倍, 旋轉X軸, 否則旋轉Z軸。
旋轉Z軸的時候, 繼續旋轉Z軸
這樣子我們的旋轉方向就搞定了。
然而, 這還沒有完, 這種方式的旋轉還有個坑, 就是我不知道該旋轉90度還是-90度了。
這裡並不是簡單的上下左右去加減。
旋轉方向對了, 旋轉角度不知該如何計算了.
具體程式碼可以檢視原始碼。
彩蛋時間
⚠️⚠️⚠️ 同時這裡會伴隨著「萬向鎖」的出現, 即是Z軸與X軸重合了。 哈哈哈哈~
⚠️⚠️⚠️ 這裡筆者還沒有解決, 也希望萬能的網友能夠出言幫忙~
⚠️⚠️⚠️ 筆者後續解決了會更新的。 哈哈哈哈, 大坑。
好了, 這裡問題不影響我們的專案。 我們繼續講如何找到最短路徑並給出提示。
最短路徑的計算
在迷宮中, 從一個點到另一個點的最短路徑怎麼計算呢? 這裡筆者使用的是廣度優先遍歷(
BFS
)演算法來計算最短路徑。
我們來思考:
二維陣列中找最短路徑
每一格的最短路徑只有上下左右相鄰的四格
那麼只要遞迴尋找每一格的最短距離直至找到終點
這裡我們需要使用「佇列」先進先出的特點。
我們先來看一張圖:
很清晰的可以得到最短路徑。
注意
使用兩個長度為4的陣列表示上下左右相鄰的格子需要相加的下標偏移量。
每次入隊之前需要判斷是否已經入隊了。
每次出隊時需要判斷是否是終點。
需要記錄當前入隊的目標的父節點, 方便獲取到最短路徑。
我們來看下程式碼:
這樣子我們就可以找到一條最短路徑並得到最短的步數。
然後我們繼續去遍歷我們的原陣列(即棋盤原陣列)。
點選提示點亮路徑。
這樣子, 我們可以得到如圖的提示:
大功告成。 嘿嘿, 是不是很驚豔的感覺~
尾聲
當然, 我這裡的這個小遊戲還有可以完善的地方 比如:
可以增加道具, 拾取可以減少已走步數
可以增加配置關卡
還可以增加跳躍功能
。。。
原來如此, CSS3D能做的事還有很多, 怎麼用全看自己的想象力有多豐富了。
哈哈哈, 真想用CSS3D寫一個「我的世界」玩玩, 效能問題恐怕會有點大。
本文例子均在PC端體驗較好。
試玩地址
https://xdq1553。github。io/-CSS3D-/
原始碼地址
https://github。com/xdq1553/-CSS3D-
作者:起小就些熊
- EOF -