- 论坛徽章:
- 0
|
第三章. 游戏地图的绘制
在前一章里面,我介绍了我的主角设计思想:只让主角对对应的按键做出相应的动作,但实际上并不发生位移。那么肯定就有朋友会问了:一个RPG里面主角都不能发生位移,那能算是个RPG么?今天咱们就来解决看上去主角没有位移的问题。
在前面我也提到了一个相对移动的概念,所以我在这里不再重复了。今天咱们就来仔细看看游戏地图(背景)的实现,通过移动绘制地图,我们就可以让主角相对移动起来。
首先,我们先将该死的移动绘制地图抛开,考虑一下我们的地图大小吧。在一个RPG里面,主要的组成部分就是庞大的地图,巨大的文字量。也就是说我们的地图可能会以一个大怪物的身份登场,这个大怪物很有可能会将移动设备那可怜的内存一口吃掉,甚至让你的移动设备罢工。同时由于移动设备的屏幕大小是完全固定的,用户能看到的地图范围是固定的,因此我就想是不是只绘制用户所能看到的范围大小,而不是完全绘制地图呢?很明显的,这个思路能够大量地节约内存,并且能够达到尽量高效地输出图象桢的目的。
下边就是我用来绘制可视范围的方法:
- public void setAllCells(int offset_block_columns, int offset_block_rows) {
- int new_block_column, new_block_row;
- for (int i = 0; i < blocks_rows; i++) {
- for (int j = 0; j < blocks_columns; j++) {
- new_block_column = j + offset_block_columns;
- new_block_row = i + offset_block_rows;
- if (
- new_block_column >= 0 && new_block_column < current_map_data[0].length
- && new_block_row >= 0 && new_block_row < current_map_data.length - 1
- ) tiled_layer.setCell(j, i, parseModel(current_map_data[new_block_row][new_block_column]));
- else tiled_layer.setCell(j, i, 0);
- }
- }
- }
- private int parseModel(String block_content) {
- int p = block_content.indexOf("|");
- if (p != -1) return Integer.parseInt(block_content.substring(0, p).trim());
- else return Integer.parseInt(block_content.trim());
- }
复制代码
传递的两个参数分别是当前主角相对启始点的X位移和Y位移,每次按一次向左方向键,这个相对X位移就减1,每次按一次向上方向键,相对Y位移就加1。然后在绘制地图的时候,我首先根据这两个参数找到可视范围的左上角在实际地图数据中的位置(new_block_column 和 new_block_row),然后因为固定移动设备的屏幕大小是固定的,因此就可以根据这些绘制出可视范围内的所有地图元素了。
接着,让我们来想想如果我们的地图不仅仅是一张,比如分为了城市/野外/室内几种,那么我们不可能为每一张地图都写一个绘制方法吧?我们要考虑到方法复用,因此我就生成了一个专用的地图读取绘制类。这个地图读取绘制类的作用就是首先从地图配置文件里面读取数据,然后将这个数据存放在缓冲中供绘制方法使用。
最后看看我的完整的地图绘制类吧:
- // 地图绘制工具
- /* *
- * 地图格式
- *
- * 模型ID|事件描述
- * 地图最后一行为初始地图绝对坐标,如果不传入需要前往的地图绝对坐标,则使用该初始绝对坐标
- * */
- /*
- * 事件格式
- * 事件类型|事件是否自动运行|事件发生地图ID|事件需求类型|事件需求|允许输入|事件完成以后当前任务ID
- * 101|0|切换的目标地图ID|在目标地图的绝对块X坐标|在目标地图的绝对块Y坐标|0|0 切换地图
- * 102|1|NPC ID|0|0|0|0 自动对话。事件需求类型为任务,需求当前任务ID为0,不允许输入。输出的是ID为 NPC ID 的NPC对话
- * 事件类型
- * 事件ID<100则不能移动,即不监听上下左右按键事件
- * 2 对话
- * 101 切换地图
- */
- import javax.microedition.lcdui.*;
- import javax.microedition.lcdui.game.*;
- import java.lang.Math;
- public class BackgroundLayer {
- private int screen_width, screen_height; // 屏幕宽、高度
- public static final int cell_width = 16; // 地图单元格宽度
- public static final int cell_height = 16; // 地图单元格高度
- private TiledLayer tiled_layer;
- private String[][] current_map_data; // 当前地图的数据
- private int current_map_id; // 当前地图ID
- public static int blocks_columns, blocks_rows; // 屏幕最大块列数和行数
- private int start_block_x, start_block_y; // 起始绝对坐标
- // 构造器
- public BackgroundLayer(int screen_width, int screen_height) {
- this.screen_width = screen_width;
- this.screen_height = screen_height;
- blocks_columns = (int)Math.ceil(screen_width / cell_width); // 单元格列数
- blocks_rows = (int)Math.ceil(screen_height / cell_height); // 单元格行数
- }
- // 装载指定地图
- public String[][] loadMapData(int map_id) {
- if (current_map_id != map_id) {
- FileTool file_tool = new FileTool();
- current_map_data = file_tool.readFromTxtFile("/res/maps/" + map_id + ".txt");
- file_tool = null;
- current_map_id = map_id;
- this.start_block_x = Integer.parseInt(current_map_data[current_map_data.length - 1][0]);
- this.start_block_y = Integer.parseInt(current_map_data[current_map_data.length - 1][1]);
- tiled_layer = null;
- System.gc();
- try {
- tiled_layer = new TiledLayer(blocks_columns, blocks_rows, Image.createImage("/res/images/background/" + current_map_data[current_map_data.length - 1][2] + ".png"), cell_width, cell_height);
- }
- catch (Exception e) { }
- }
- return current_map_data;
- }
- // 装载指定地图
- public String[][] loadMapData(int map_id, int start_block_x, int start_block_y) {
- if (current_map_id != map_id) {
- FileTool file_tool = new FileTool();
- current_map_data = file_tool.readFromTxtFile("/res/maps/" + map_id + ".txt");
- file_tool = null;
- current_map_id = map_id;
- this.start_block_x = start_block_x;
- this.start_block_y = start_block_y;
- tiled_layer = null;
- System.gc();
- try {
- tiled_layer = new TiledLayer(blocks_columns, blocks_rows, Image.createImage("/res/images/background/" + current_map_data[current_map_data.length - 1][2] + ".png"), cell_width, cell_height);
- }
- catch (Exception e) { }
- }
- return current_map_data;
- }
- public void paint(Graphics g) {
- tiled_layer.paint(g);
- }
- // 根据地图范围设置显示区域的模型内容
- public void setAllCells(int offset_block_columns, int offset_block_rows) {
- int new_block_column, new_block_row;
- for (int i = 0; i < blocks_rows; i++) {
- for (int j = 0; j < blocks_columns; j++) {
- new_block_column = j + offset_block_columns;
- new_block_row = i + offset_block_rows;
- if (
- new_block_column >= 0 && new_block_column < current_map_data[0].length
- && new_block_row >= 0 && new_block_row < current_map_data.length - 1
- ) tiled_layer.setCell(j, i, parseModel(current_map_data[new_block_row][new_block_column]));
- else tiled_layer.setCell(j, i, 0);
- }
- }
- }
- // 根据地图范围设置显示区域的模型内容
- // default_block_id 缺省的模型ID,超出地图配置文件范围的内容使用该块绘制
- public void setAllCells(int offset_block_columns, int offset_block_rows, int default_block_id) {
- int new_block_column, new_block_row;
- for (int i = 0; i < blocks_rows; i++) {
- for (int j = 0; j < blocks_columns; j++) {
- new_block_column = j + offset_block_columns;
- new_block_row = i + offset_block_rows;
- if (
- new_block_column >= 0 && new_block_column < current_map_data[0].length
- && new_block_row >= 0 && new_block_row < current_map_data.length - 1
- ) tiled_layer.setCell(j, i, parseModel(current_map_data[new_block_row][new_block_column]));
- else tiled_layer.setCell(j, i, default_block_id);
- }
- }
- }
- // 解析地图模型内容
- private int parseModel(String block_content) {
- int p = block_content.indexOf("|");
- if (p != -1) return Integer.parseInt(block_content.substring(0, p).trim());
- else return Integer.parseInt(block_content.trim());
- }
- // 解析英雄所在块数据内容
- // 第一元素为事件类型,小于MainGameCanvas.STATUS_IN_MOVING的事件类型不能移动
- // 其他参考 EventManager中的说明
- public int[] parseBlock(int offset_x, int offset_y) {
- int[] block_info = new int[7];
- int brave_position_x = blocks_columns / 2 + offset_x;
- int brave_position_y = blocks_rows / 2 + offset_y;
- if (
- brave_position_x >= 0 && brave_position_x < current_map_data[0].length
- && brave_position_y >= 0 && brave_position_y < current_map_data.length - 1
- )
- {
- String tmp = current_map_data[brave_position_y][brave_position_x];
- int p = tmp.indexOf("|");
- int i = 0;
- if (p != -1) {
- while ((p = tmp.indexOf("|")) != -1) {
- if (i > 0) block_info[i - 1] = Integer.parseInt(tmp.substring(0, p).trim()); // 跳过地图模型描述字段
- tmp = tmp.substring(p + 1);
- i++;
- }
- block_info[i - 1] = Integer.parseInt(tmp.trim());
- }
- else block_info[0] = MainGameCanvas.STATUS_IN_MOVING;
- }
- else block_info[0] = MainGameCanvas.STATUS_IN_GAMING;
- return block_info;
- }
- public int getStartOffset(boolean is_x) {
- if (is_x) return start_block_x - blocks_columns / 2;
- else return start_block_y - blocks_rows / 2;
- }
- }
复制代码
其中用到了一个我的自定义类 FileTool,这个文件我在下一次再发上来吧~~ |
|