在網頁上實做isometric迷宮

 Sun, 06 Aug 2006 11:00:32 +0800

isometric迷宮就是一般常見的45度斜角2.5D迷宮。isometic迷宮沒有透視的景深(近大遠小),所以不需要3D的支援就可以實做,但是又可以做出一些近似3D前景遮蓋背景的效果,比起單純的2D迷宮效果更好。

在網頁上實做,碰到的問題跟用其它程式語言實做不一樣。因為執行速度的限制,在用網頁實做isometric迷宮必須用不同的方法。

簡單地說,通常做出isometric迷宮的方式,是計算畫面每一個frame的畫面,然後用double buffer的方式繪出。這在網頁上會碰到幾個困難點,首先就是瀏覽器執行的速度沒辦法讓畫面順利平順地播放。

我解決的方式,是在一個layer(div啦)上繪出整個地圖,前方用另一個layer配合style的clip屬性來限制地圖可視的範圍,移動地圖時就移動整個地圖的layer,這樣就可以做出人物走動的效果,又可以真正平順地移動。(前提還是地圖不能太大,我第一次試作時(好像是在1999年的時候),在IE5可以勉強看到效果(會警告迴圈跑太久),在netscape根本不會動.....當時的電腦速度跟現在的比起來也太慢就是了,不過最近的測試是firefox跑的比ie6快?不知道為甚麼ie變慢了.....)

地圖的計算,有一個很簡單的公式,可以把斜角的座標轉換成螢幕的座標(想像一個順時針轉了四十五度的陣列,左上右下的方向是x軸,右上左下的方向是y軸,構成地圖的單位是一個菱形,寬是w高是h,h=w/2(實際上圖還是一個長方形,只是在菱形範圍外是透明的)):

  1. 假設map[0][0]在螢幕上的座標是X0, Y0
  2. 則map[x][y]在螢幕上的x座標是X0+x*w/2-y*w/2
  3. 而map[x][y]在螢幕上的y座標是Y0+x*h/2+y*h/2

(所以,長寬最好都是偶數....)

另外就是要處理深度的問題。有一個很簡單的計算方式,就是map[x][y]中,x+y相等的地圖區塊就有相同的深度。實做的方式,在DHTML中是給予不同的地圖區塊不同的z-index值,如果用或其他方式實做,一般大概是用依次畫到buffer中的方式達成(後來畫的就會蓋過原來畫的部份,可以達到一樣的效果)。

簡單地應用這幾個公式以及搭配DHTML物件的style.position、style.top、style.left、style.zIndex等等屬性,大致上就可以做出想要的效果。

現在做出這樣效果的網站應該已經不少了,在google上面找isometric跟dhtml關鍵字就可以找到一大堆。

人物的行走是另外一個問題。我是用setTimeout做出分格動畫來做出行走的效果,為了避免發生意外,還用一些變數來lock住一些動作,如果同時跑好幾個timeout/interval,就必須避免racing condition的發生,所以必須小心控制,以免人物走到無法控制的地方。

最簡單的控制人物的方法是用鍵盤,一次走一格。這樣只要顧到人物行走當中按下方向鍵盤不要有反應就可以了。用滑鼠點選控制人物行走就需要做更多的事情.....

用鍵盤控制時,一次只要走一步,用滑鼠控制時,一次就會走好幾步,障礙物怎麼處理(就是怎麼產生行走的路徑)是更為複雜的問題。最簡單的方法,就是只走直線,碰到障礙物就停下來。產生直線路徑只要用Bressenham畫直線的方法就可以了,碰到障礙就停下來,可以避免走到不對的地方。一次走幾個格子需要用到兩層巢狀的timeout/interval,一層控制行走的動畫,一層控制走到不同的格子。這時用一些變數來lock不應發生的動作就更重要,一不小心就會大幅拖慢畫面(我在試作過程中,瀏覽器當掉好幾次)。

更進一步的路徑,需要用A* Algorithm來做,呵呵,我還沒做出來,這裡先不提了。

前一陣子想出來的判別點是否在凸多邊形內的方法,我也拿來用了(有一個潛在的好處,就是可以把現在用javascript寫的東西移植到SDL上做)。

有興趣看實做出來的效果,可以到以下的網址:

http://www.fillano.idv.tw/game.htm

看看,我還在陸續改進中。