| ___遊戲中的地圖____ |
|
|
| 未知 gameres 2006-08-22 |
|
|
關于地圖:
《仙劍奇俠傳》地圖圖塊(Tile)的大小為32X16(以象素為單位)。 實際每個圖塊的大小為32x15(以像素為單位),通過拼接剛好天衣無縫。 地圖大小為128x128(以圖塊為單位)。
排列方式如下: 0 2 4 6 8…… // 第0行 1 3 5 7 9…… 0 2 4 6 8…… // 第1行 1 3 5 7 9……
採用這種方式的好處是很容易確定那些圖塊在屏幕可見範圍內,每次只畫可見部分。
地圖分為底層和表層共兩層。每個圖塊屬性佔4個字節(底層和表層各2字節)。 所以整個地圖的大小為:128x128x4=64K字節。(太巧了,不是嗎?DOS下內存一個段就這麼大)
每個圖塊的屬性格式如下:
typedef struct { unsigned No:8; // 圖塊序號 unsigned Height:4; // 圖塊高度 unsigned Add:1; // 圖塊序號高位 unsigned Block:1; // 障礙標志(這兒不能走,比如說牆根) unsigned Actor:1; // 人物標志(有人站在這兒NPC) unsigned Switch:1; // 地圖切換標志(人物走到這裡要切換到另一個場景) } TCell;
注釋: 1、設GroundNo = 4,如果GroundAdd = 1,那麼實際的GroundNo += 256,即GroundNo = 300。 2、每個地圖最多由2的(8+1)次方即512種不同的圖塊拚成。實際應用中大約每個地圖用到300種圖塊。 3、人物大約是3個圖塊高,所以4位Height足夠處理人物與場景的遮擋效果。
關于人物: 人物處在底層和表層之間,通過圖塊的高度處理人物與場景之間的遮掩關系。
但是人物之間也有前後關系,怎麼處理呢? 我的方法是建立一個人物鏈表,利用畫家算法。 人物的先後關系很容易計算:先比較Y,再比較X,小的先畫。
可是,可能出現這樣的情況(實際遊戲中可能更復雜,這裡只是一個簡要的舉例): 魔法師站在骷髏的屍體上,正在釋放圓形閃電魔法,又被敵人釋放的四處亂跑的火人擊中。 所以,在同一個圖塊上,同時存在幾個精靈:骷髏、閃電上部、魔法師、閃電下部,火人。
解決的方法是每個精靈有一個屬性字段:BYTE Level;表明它所處的層。 層可以如下定義:(僅僅是個例子,不是真的這樣做的)
const // Sprite Level slDeadBody = 1, // 屍體層 slSpellUnder = 2, // 下層釋放魔法層 slSprite = 3, // 精靈層 slSpellAbove = 4, // 上層釋放魔法層 slSpellHit = 5, // 攻擊魔法層 slFree = 6, // 自由層(天空中飛鳥、蝴蝶等) ……
綜合起來,精靈的先後順序通過3個數即可確定:Y, X, Level。
動態場景:
多數遊戲的場景都比較死,缺乏生氣。即使象Diablo這樣的遊戲,村中的小河和噴泉水池也不會流動,樹也不會隨風搖擺。因為動態確實有難度。
在256色遊戲中最常見的做法是調色板動畫。即通過動態改變256色調色板中某些色彩的值(通常是輪流替換),來實現水波蕩漾的效果。
還有一種方式是通過標準的(通常是正方形)多幀動畫(如水波)結合地圖掩碼做剪裁,遊戲運行時以固定的頻率順次貼動態地表的各幀,從而實現動態地表的效果。最成功的例子我認為是Commandos。 詳細內容參閱: 雲風工作室──斜視角圖形引擎的設計──動態地表的實現http://www.netease.com/~cloudwu/
在16位色彩模式中第一種方法失效,需要加以變通。比如使用多調色板,每個圖像依然以256色模式保存,運行時實時查表。第二種方法依然有效。
在吸收這幾種方法的優點的基礎上,我設想了另一種方法。 地圖數據實際上有兩部分:一個二維矩陣,描述每個圖塊的屬性;一個一維數組,保存各種不同圖塊的圖像數據。如果我們把一維圖像數組比作256色模式下的調色板,就可以發現,使用與調色板的動態技術同樣可以用于地圖地表的動態效果。詳細方法就不羅嗦了。
在實際應用中,我們通常都會對標準的方法加以變通,根據自己的需要有取有舍。 在程序設計裡沒有必須這樣或必須那樣的鐵律。即使是同一個算法,同一個數據結構,每個 程序員的具體實現都可能不盡相同。
我的遊戲引擎(不好意思,很久沒更新了)就不是按上面提到的格式做的。不過原理大同小異。
| | | |
|
|
|
|
 |
|
|
 |
|
|
|
|