最近三个星期利用业余时间开发了一款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坐标,只要玩家走动,就会有横向滚轴的效果。