游戲中的地圖通常不是由程序員用鍵盤輸入到程序裡然後再在程序中修改然後再修改的狂亂過程,而是一般先由程序員做一個地圖編輯器,在這個地圖編輯器中用鼠標點點點,再保存的過程,或者是從網絡上下載的一些成熟編輯器比如:mappy這樣的工具生成地圖,再用腳本語言為mappy寫一個應該保存成什麼樣格式的程序。通常地圖分為45度角,側視角和俯視角等等,45度角的也有很多種,這種視角相對俯視角和側視叫較復雜,我們主要討論俯視角,其實側視叫和俯視角主要的區別是圖片的表現風格不一樣,比如雷電這樣的空戰就是俯視角,mario這樣的游戲就是側視角,可以用相同的地圖編輯器做出來。綜上,你要知道游戲地圖不是程序員用程序寫出來的,你喜歡寫也可以,修改起來較麻煩,也不能像資源一樣動態管理而是一次性讀入到內存裡,比較不爽。
在這個文章裡面,我們假設我們的2D數組是通過,資源讀取出來的,內容如下:
public static byte[][] B_MAZE_2D_ARRAY = {
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
, {
0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
, {
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
, {
0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
, {
0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}
, {
0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}
, {
0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}
, {
0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0}
, {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0}
, {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0}
, {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
};
這個地圖中一共0,1兩種byte數,0代表一種圖塊,1代表一種圖塊,也可以是動畫圖塊,你繪制的時候區別一下就可以了。因為我們程序裡面想把這整個圖形繪制出來的話有N多種方案,我給出兩個比較合理的方案,當然第二種是比較優化的.我們假設你的主角一直在屏幕中央,當你主角移動的時候,地圖相應的變化,就是說主角為參照物,地圖動.我們知道地圖的大小要超過屏幕的,我們需要設定一個坐標系統,我的方法是,以左上角為0,0也就是和我們常用的Canvas的坐標系統是相同的,我們的圖塊大小為:ELEMENT_WIDTH, ELEMENT_HEIGHT,所以我們整個地圖的面積(絕對面積)是 ELEMENT_WIDTH * 橫坐標的塊數 * ELEMENT_HEIGHT*縱坐標的塊數。因此,我們把這麼大的題圖畫在屏幕上時,需要把需要畫的坐標面積(也就是屏幕面積)從這個地圖中拿出來,其他地方被切除,這就比較的高效了。
方法一:循環整個2維數組,不需要的地方不繪制只繪需要的部分:
int kI = 0;// 表示
int kJ = 0;
//nEleStartedX, nEleStartedY表示從2D Array哪個位置開始繪制地圖
for (int i = nEleStartedY; i < B_MAZE_2D_ARRAY.length; i++) {
kJ = 0;
//是否需要繪制
boolean isDrawed = false;
for (int j = nEleStartedX; j < B_MAZE_2D_ARRAY[i].length; j++) {
//繪制需要的面積,N_MAZE_ELEMENT_WIDTH,N_MAZE_ELEMENT_HEIGHT表示圖塊寬高
int bX = nMapStartedX + j * N_MAZE_ELEMENT_WIDTH;
int bY = nMapStartedY + i * N_MAZE_ELEMENT_HEIGHT;
//SCREEN_WIDTH,SCREEN_HEIGHT屏幕大小
if (bX <= SCREEN_WIDTH
&&
bY <= SCREEN_HEIGHT
&&
bX >= -N_MAZE_ELEMENT_WIDTH
&&
bY >= -N_MAZE_ELEMENT_HEIGHT
) {
g.drawImage(mapImages[B_MAZE_2D_ARRAY[i][j]], bX,
bY,
Graphics.TOP | Graphics.LEFT);//繪制圖塊
isDrawed = true;
kJ++;
// N_MAX_MAZE_ITEM_X , N_MAX_MAZE_ITEM_Y屏幕面積內圖塊的最大值
if (kJ > N_MAX_MAZE_ITEM_X + 2) {
break;
}
}
}
if (isDrawed) {
kI++;
}
if (kI > N_MAX_MAZE_ITEM_Y + 2) {
break;
}
}
方法二:事先找到需要繪制的橫坐標縱坐標的圖塊編號(2DArray的數組下標),循環屏幕面積大小的數組:
// 需要繪制的2DArray左上角位置,nMapStartedX,nMapStartedY在地圖絕對面積上的坐標
int nArrayI = ( -N_MAZE_ELEMENT_HEIGHT - nMapStartedY) /
N_MAZE_ELEMENT_HEIGHT;
int nArrayJ = ( -N_MAZE_ELEMENT_WIDTH - nMapStartedX) /
N_MAZE_ELEMENT_WIDTH;
for (int i = nArrayI;
i < SCREEN_HEIGHT / N_MAZE_ELEMENT_HEIGHT + 2; i++) {
for (int j = nArrayJ;
j < SCREEN_WIDTH / N_MAZE_ELEMENT_WIDTH + 2; j++) {
if (i < 0 || j < 0 || i > B_MAZE_2D_ARRAY.length ||
j > B_MAZE_2D_ARRAY[0].length) {
continue;
}
else {
int bX = nMapStartedX + j * N_MAZE_ELEMENT_WIDTH;
int bY = nMapStartedY + i * N_MAZE_ELEMENT_HEIGHT;
g.drawImage(mapImages[B_MAZE_2D_ARRAY[i][j]], bX,
bY,
Graphics.TOP | Graphics.LEFT);
}
}
}
根據我的測試,方法一的地圖面積越大fps掉的越為厲害,而方法二基本上不會掉fps,強烈推薦方法二.
地圖系統做好了之後,你就可以使用地圖做更多的表現力了,只要改變nMapStartedX,nMapStartedY,就可以繪制出地圖上的相應部分,代碼的復用效率非常的高。RPG, SLG, PUZZLE等游戲類型都可以使用.歡迎跟我探討更多的游戲制作技術,我還將寫一個關於動畫的相關東東,不過最近沒什麼時間.