3D魔方


一、3D魔方內容簡介

3D魔方是一款益智類的游戲,是魔方游戲的一個變體,游戲采用了3D的圖形界面,看起來還是非常逼真的。游戲的玩法也和一般性的魔方游戲相同,實現一個網頁版的3D魔方,主要實現的功能是通過鼠標拖拽實現魔方的單層旋轉和整體旋轉。

二、3D立方體的創建

1、先將平面上的6個DIV拼接在一起。形成一張類似於3d立方體圖形展開的平面圖。如圖所示:

                                     圖1

DIV合在一起,將會用到定位的知識,將立方體包起來需要一個大盒子DIV,所以總共需要7個DIV,這七個DIV,將以大盒子為參考點(position:relative),剩下的6個子盒子,每一個都是絕對定位,定位在相應的位置上,定位完成后,就是上面的那個樣子。

2、我們需要將每一個面旋轉到相應的位置上,每一個面的旋轉軸都是不一樣的。上下,左右,分別對應的旋轉軸,以及旋轉角度分別是:bottom(90deg),top(-90deg),right(90deg),left(-90deg)。同時要注意在旋轉后面的時候,旋轉軸為Z軸,並不是上下,左右邊。瀏覽器上面的坐標系是這樣的:Z軸是屏幕里外兩個方向(向外為正,向里為負),X軸的水平方向(向右為正,向左為負),Y軸的豎直方向(向下為正,向上為負)。了解完上面的知識后,就可以實現將后邊的面向里移動啦,通俗來說,就是將“后”面沿着Z軸向里移動整個Div的寬度,大小,CSS3代碼如下:transform:translate3d(-50%,-50%,0px)。完成以上操作后就會得到如下的效果:

                            圖2

3、接下來還有一個關鍵的步驟,就是當變換導致元素在 3D 空間中旋轉時,指定當元素背面朝向觀察者時不可見,具體代碼如下:

   -webkit-backface-visibility: hidden; 

   -moz-backface-visibility: hidden;

   -o-backface-visibility: hidden;

   backface-visibility: hidden;

4、接下來我們要做的就是設置一下所處環境,我們要設置成3D的環境,具體的語法形式如下:transform-style: preserve-3d;

5、然后我們為了讓立方體旋轉起來,以便更好的實現3D效果。首先找到旋轉中心,在3D魔方中,旋轉中心就是立方體的幾何中心。

 

三、魔方整體樣式的創建

1、魔方由6個中心塊、8個角塊、12個棱塊和1個主軸構成,共有27個正方體,其中中心塊有1個顏色、角塊3個顏色、棱塊2個顏色

                                    圖3

2、從cubeletId-0到cubeletId-26共構建了27個正方體模塊,將元素顯示為塊級元素,每個正方體的6個面也要進行設置,以X軸設置左右面,以Y軸設置上下面,以Z軸設置前后面,定義3D旋轉。對於魔方整體,規定所有子元素都在3D空間中呈現,perspective屬性定義3D元素距視圖的距離,該元素允許改變3D元素查看3D元素的視圖。定義3D轉換,使用16個值的4*4矩陣。

3、然后給魔方加上動畫過渡效果,以及旋轉角度和旋轉軸就可以實現流暢的旋轉了。動畫過渡效果是使用TweenJS實現的,TweenJS提供了一個簡單但強大的漸變界面。它支持漸變的數字對象屬性&CSS樣式屬性,並允許鏈接補間動畫和行動結合起來,創造出復雜的序列。它主要包括的參數如圖所示:

                               圖4

四、單層魔方的旋轉

可以通過修改rotation分量的值來指定魔方繞中心點以什么軸旋轉,比如說rotation.x是指當前立方體需要繞中心點以X軸旋轉(從坐標軸正方向朝中心點看)。現在我們只討論魔方的其中一個立方體的旋轉情況,它需要繞Z軸順時針旋轉θ度。這整個過程可以拆分成旋轉和平移。其中立方體的旋轉可以理解為移到中心按順時針旋轉θ度,然后再平移到目標位置。

變換過程可以用下面的公式表示,其中p為旋轉前立方體的中心位置,p' 為旋轉后立方體的中心位置,Rz(θ) 為繞z軸順時針旋轉θ度(即rotation.z),Tp'則是平移矩陣,vv'分別為變換前后的立方體頂點:

 p=p×Rz)p′=p×Rz(θ)

 v=v×Rz)×Tp′ 
    (公式1)

實際上它只會根據rotation來按其中一個軸旋轉。現在我們嘗試給魔方的頂面繞Y軸順時針旋轉,在Rublik::Update方法內部用下述代碼:

 void Rubik::Update(float dt) {

for (int i = 0; i < 3; ++i)

for (int k = 0; k < 3; ++k)

mCubes[i][2][k].rotation.y += XM_PI * dt; }

然后再調用這個函數,魔方的一層就能旋轉起來了,如下圖所示:

                      圖5

五、鼠標拖拽魔方旋轉

1、鼠標實現拖拽主要的就是有監聽鼠標事件,計算鼠標滑動距離,改變魔方的rotateX、rotateY。鼠標按下時,記錄鼠標當前所處位置,移動時又可以獲取實時位置,用移動時獲取的實時位置減去鼠標按下時的位置,就可以得到鼠標移動的相對位置。鼠標松開,可以結束計算。

         * 獲取鼠標實時移動的坐標;m_move_x,m_move_y

         * 鼠標按下時的坐標;m_down_x,m_down_y

         * div的坐標;dx,dy

         * 鼠標按下時,鼠標與div的偏移量;md_x,md_y

         * div的新坐標;ndx,ndy

代碼實現:

//鼠標按下
function down(){
move_div = document.getElementById("move_div");
isDown = true;

//獲取鼠標按下時坐標
m_down_x = event.pageX;
m_down_y = event.pageY;

//獲取div坐標
dx = move_div.offsetLeft;
dy = move_div.offsetTop;

//獲取鼠標與div偏移量
md_x = m_down_x - dx;
md_y = m_down_y - dy;
}

//鼠標移動
function move(){
move_div = document.getElementById("move_div");

//實時更新div的坐標
dx = move_div.offsetLeft;
dy = move_div.offsetTop;

//獲取鼠標移動實時坐標
m_move_x = event.pageX;
m_move_y = event.pageY;

//鼠標按下時移動才觸發
if(isDown){

//獲取新div坐標,鼠標實時坐標 - 鼠標與div的偏移量
ndx = m_move_x - md_x;
ndy = m_move_y - md_y;

//把新div坐標值賦給div對象
move_div.style.left = ndx+"px";
move_div.style.top = ndy+"px";

}

}

//鼠標釋放
function up(){
isDown = false;
}

 

 2、給魔方的8個角點定位,以方便魔方旋轉后的位置記錄,重新設置立方體邊界。

                                                         圖6

                  圖7

3、根據拖拽方向判斷旋轉軸

我們可以看到魔方的面有+X面,+Y面和-Z面。

在我們拾取到立方體后,我們還要根據這兩個信息來確定旋轉軸:

(1)當前具體是拾取到立方體的哪個面

(2)當前鼠標的拖動方向

當我們的鼠標點擊到一個小立方體上時,我們怎么知道點擊選中的是X.Y.Z中的哪個面呢?

Rubik::HitCube函數不僅返回了拾取到的立方體索引,還有射線擊中立方體表面的最短距離。我們知道-Z面的所有頂點的z值在不產生旋轉的情況下都會為-3,因此我們只需要將得到的t值帶入射線方程 p=e+tdp=e+td 中,判斷求得的 pp 其中的z分量是否為3,如果是,那說明當前鼠標拾取的是該立方體的-Z面。

接下來就是要討論用鼠標拖動魔方會產生怎么樣的旋轉問題了。我們還需要確定當前的拖動會讓哪一層魔方旋轉(或者說繞什么軸旋轉)。以下圖為例:

                         圖8

上圖的X軸和Y軸對應的是屏幕坐標系,坐標軸的原點為鼠標剛點擊時的落點,通過兩條虛線,可以將鼠標的拖動方向划分為四個部分,對應魔方旋轉的四種情況。其中屏幕坐標系的主+X(-X)拖動方向會使得魔方的+Y面做逆(順)時針旋轉,而屏幕坐標系的主+Y(-Y)拖動方向會使得魔方的+X面做逆(順)時針旋轉。

我們可以將這些情況進行簡單歸類,即當X方向的瞬時位移量比Y方向的大時,魔方的+Y面就會繞Y軸進行旋轉,反之則是魔方的+X面繞X軸進行旋轉。

 、魔方開場效果

我們使用一個棧來記錄用戶的操作,這個棧不僅可以用來記錄用戶操作記錄,還可以用來存儲打亂魔方的操作。即游戲剛開始先給這個棧塞入一堆隨機操作,然后每執行一個操作就退棧一次,直到棧空時打亂操作完成,用戶可以開始對魔方進行操作,同時這個棧也開始記錄用戶操作。

同時在開始的時候,有一個鏡頭住鍵推進的效果,這是一個簡單的攝像機移動過程,包含的繞Y軸的旋轉和鏡頭的推進。這個動畫過程需要根據幀時間間隔做更新。

七、成品效果展示

 成果展示鏈接

鏈接:https://pan.baidu.com/s/1esGlcR4N1aX3lTZdEy_HMg
提取碼:i9g5

小組成員:許夢  將安然  王嘉慧  彭欣欣

 

   


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM