最近三個星期利用業餘時間開發了一款J2ME橫向滾軸的2D FPS遊戲,自我感覺項目不是很成功,最主要的原因是圖片太多。但是通過實踐,還是收穫不少。下面就地圖處理髮表一點淺見。
javax.microedition.lcdui.game.TiledLayer是一個保存和繪製地圖的好工具,通過腳本的方式可以將地圖信息轉化爲數字信息保存在TiledLayer對象中(實際上TiledLayer內部採用是數組的方式來保存地圖的數字化信息)。
上面這張地圖中每一個地圖元素的尺寸爲32×32,爲此我們可以對其進行編號:
這樣,一個編號對應的就是一個地圖元,顯然下面這些數字:
00|00|00|00|00|00|00|00|00|00|00|00|00|00|00|00|00|00|00|00
00|00|00|00|00|00|00|00|00|00|00|00|00|00|00|00|00|00|00|00
00|00|00|00|00|00|00|00|00|00|04|05|06|07|00|00|00|00|00|00
00|00|00|00|00|04|05|06|07|00|14|15|16|17|00|00|00|00|00|00
34|35|35|36|00|14|15|16|17|00|00|00|00|00|34|35|35|35|35|36
37|38|38|39|00|00|00|00|00|00|00|00|00|00|37|38|38|38|38|39
對應下面的地圖:
將地圖數字化以後,可以在地圖腳本文件中加入地圖的尺寸信息(長度|寬度),以上面的地圖爲例可以在第一行加入20|6,這樣在讀取第一行之後我們就知道需要分配多大的數組以及用這個尺寸初始化TiledLayer對象。
下面是一個腳本抽象類,所有類型的腳本(地圖、怪物、物品)都繼承自它。
import java.io.*;
public abstract class Script
{
InputStreamReader input;
protected void close()
{
if (input != null)
{
try {input.close();} catch (Exception e) {}
input = null;
}
}
protected String readLine()
{
if (input == null) {return null;}
int temp;
StringBuffer buffer = new StringBuffer();
try
{
while ((temp = input.read()) != 13)
{
if ((int)temp == -1)
{
close();
break;
}
else if ((int)temp != 10)
{
buffer.append((char)temp);
}
}
} catch (Exception e) { close(); }
return buffer.toString();
}
protected String[] readArrayLine(char delimit)
{
String line;
String[] array;
StringBuffer buffer;
int index, count;
char c;
// Count number of items in the array
line = readLine();
if (line.length() == 0)
{
array = new String[1];
array[0] = "";
}
index = 0;
count = 0;
while (index < line.length())
{
if (line.charAt(index++) == delimit) {count++;}
}
// Parse items into the array
array = new String[count+1];
buffer = new StringBuffer();
index = 0;
count = 0;
while (index < line.length())
{
c = line.charAt(index++);
if (c == delimit)
{
array[count++] = buffer.toString();
buffer = new StringBuffer();
}
else
{
buffer = buffer.append(c);
}
}
array[count++] = buffer.toString();
return array;
}
}
下面是專門負責讀取地圖腳本的代碼:
import java.io.*;
public class MapFile extends Script
{
protected int iMapRow;
protected int iMapCol;
public int[] Load(int level)
{
input = new InputStreamReader(getClass().getResourceAsStream("/script/map/level"+level+".map"));
int cnt = 0;
String[] size = readArrayLine('|');
String[] mapline;
if(size.length < 2)
{
System.out.println("map size error!");
return null;
}
iMapCol = Integer.parseInt(size[0]);
iMapRow = Integer.parseInt(size[1]);
int[] map = new int[iMapCol*iMapRow];
while(input != null)
{
mapline = readArrayLine('|');
if(mapline.length < iMapCol)
{
System.out.println("map column error!");
return null;
}
for (int n = 0; n < mapline.length; n++)
map[cnt++] = (Integer.valueOf(mapline[n])).intValue();
}
close();
return map;
}
public int getCol()
{
return iMapCol;
}
public int getRow()
{
return iMapRow;
}
}
最後在遊戲渲染主類中加入載入地圖代碼:
{
Image img = null;
try
{
img = Image.createImage("/res/map/map.png");
}catch(java.io.IOException e) {System.out.println("createMap"+e);}
int[] map = mapfile.Load(level);
TiledLayer tl = new TiledLayer(mapfile.getCol() , mapfile.getRow() , img , 32 , 32);
for(int i = 0;i < map.length;i++)
{
int col = i % mapfile.getCol();
int row = (i - col) / mapfile.getCol();
tl.setCell(col , row , map[i]);
}
return tl;
}
遊戲渲染最好能夠由LayerManager來管理,通過其append方法將TiledLayer對象加入其中,在渲染方法中加入:
LayerManangerObject.paint(GraphicsObject , StartX , StartY);
在setViewWindow中,將玩家的橫座標作爲視口的起始x座標,只要玩家走動,就會有橫向滾軸的效果。