view plain copy to clipboard print ?
//计算单元格起始位置下标
int startIndexX =leftTopY/ MAP_TILE_SIZE;
int startIndexY =leftTopX/ MAP_TILE_SIZE;
//再使用上面得到的数据修改双循环绘制的条件即可,
for (int i = startIndexX; i 1; i++)
for (int j = startIndexY; j 1; j++) //计算单元格起始位置下标 int startIndexX =leftTopY/ MAP_TILE_SIZE; int startIndexY =leftTopX/ MAP_TILE_SIZE; //再使用上面得到的数据修改双循环绘制的条件即可, for (int i = startIndexX; i 卡马克卷轴算法的引入 上面的算法虽然在一定程度上解决了地图绘制的效率问题,但对于某些资源严重不足的手机,或者由于地图块比较小、循环次数过多的情况,仍然会造成画图时屏幕闪烁。因此,在这种情况下,仍然需要对上述算法做进一步的优化。
view plain copy to clipboard print ?
//地图数据
public byte mapData[][];
//移动缓冲区的当前坐标窗口
public int sx,sy;
//地图图片
private Bitmap imgMap;
public GameView m_View;
//常量
public final static int MAP_TILE_SIZE = 24;
/** 缓冲区宽高,命名方式为:Carmack width or height */
private int bufWidth, bufHeight;
/** 缓冲区宽的图块数,与高的图块数*/
private int carTileWidth, carTileHeight;
/** 屏幕宽高命名方式为:screen width or height */
private int scrWidth, scrHeight;
/** 缓冲切割线,命名方式为:Carmack x or y */
private int carx, cary;
/** 地图在缓冲区的X 、Y偏移量,命名方式为:map offset x or y */
private int mapOffx, mapOffy;
/** 缓冲区,命名方式为:Carmack buffer */
public Bitmap carBuffer;
/** 缓冲区画笔,命名方式为:Carmack Graphics */
private Canvas carGp;
/** 缓冲区增大的大小(上下大小是一样的) */
private int buffSize;
/** 图片宽度的所切割的图块数量。 */
private int imageTileWidth;
/** 地图图片 */
private Bitmap mapImage;
Paint paint=new Paint();
/** 地图数组 */
private byte mapArray[][];
/** 图块大小,宽高一致 */
private int tileSize;
/** 图块的宽度数量,与高度数量 */
private int tileW, tileH;
/** 地图的宽高 */
private int mapLastx, mapLasty; //地图数据 public byte mapData[][]; //移动缓冲区的当前坐标窗口 public int sx,sy; //地图图片 private Bitmap imgMap; public GameView m_View; //常量 public final static int MAP_TILE_SIZE = 24; /** 缓冲区宽高,命名方式为:Carmack width or height */ private int bufWidth, bufHeight; /** 缓冲区宽的图块数,与高的图块数*/ private int carTileWidth, carTileHeight; /** 屏幕宽高命名方式为:screen width or height */ private int scrWidth, scrHeight; /** 缓冲切割线,命名方式为:Carmack x or y */ private int carx, cary; /** 地图在缓冲区的X 、Y偏移量,命名方式为:map offset x or y */ private int mapOffx, mapOffy; /** 缓冲区,命名方式为:Carmack buffer */ public Bitmap carBuffer; /** 缓冲区画笔,命名方式为:Carmack Graphics */ private Canvas carGp; /** 缓冲区增大的大小(上下大小是一样的) */ private int buffSize; /** 图片宽度的所切割的图块数量。 */ private int imageTileWidth; /** 地图图片 */ private Bitmap mapImage; Paint paint=new Paint(); /** 地图数组 */ private byte mapArray[][]; /** 图块大小,宽高一致 */ private int tileSize; /** 图块的宽度数量,与高度数量 */ private int tileW, tileH; /** 地图的宽高 */ private int mapLastx, mapLasty;
方法定义
CarMapBuffer(int, int, int, int)构造器
CarMapBuffer(int, int, int)构造器的代理
setMap(Image, byte[][])设置地图参数
initBuffer()初始化绘制地图
scroll(int, int)卷动地图算法
updateBuffer(int, int)绘制缓冲区
getIndexCarX()获得切割线所在的图块索引X
getIndexCarY()获得切割线所在的图块索引Y
getBufferCarX()获得切割线在Buffer中的X位置
getBufferCarY()获得切割线在Buffer中的Y位置
getIndexBuffLastX()获得缓冲区后面的X索引
getIndexBuffLastY()获得缓冲区后面的Y索引
getTitleHeight()获得当前要绘制的图块高度的数量
getTitelWidth()获得当前要绘制的图块宽度的数量
copyBufferX(int, int, int, int, int) 由于x方向卷动造成的重绘
copyBufferY(int, int, int, int, int) 由于y方向卷动造成的重绘
getMapX(int, int) 获得地图图片的X坐标偏移
getMapY(int, int) 获得地图图片的Y坐标偏移
paint(Graphics, int, int)将缓冲区的内容分成4块依次拼合到屏幕上
drawBuffer(Graphics, int, int)绘制缓冲区方法
drawRegion(Graphics, Image, int, int, int, int, int, int, int, int)封装的drawRegion()方法
getGraphics()获得缓冲区画笔
getImage()获得缓冲区Image对象 步骤一的实现
初始化所有地图数据,并且全屏绘制初始的地图,代码如下:
view plain copy to clipboard print ?
/**
* 初始化Buffer,全部地图绘制在此方法中完成
*/
private void initBuffer()
{
int x, y, cx, cy;
for (int i = 0; i
{
for (int j = 0; j
{
x = getMapX(i, j);
y = getMapY(i, j);
cx = j * tileSize;
cy = i * tileSize;
m_View.drawClipImg(cx, cy, tileSize, tileSize, x, y, mapImage, paint, carGp);
}
}
} /** * 初始化Buffer,全部地图绘制在此方法中完成 */ private void initBuffer() { int x, y, cx, cy; for (int i = 0; i 步骤二、三的实现
若人物移动,则调用摄像机算法,修正地图偏移量,若偏移量在[0,maplast]移动范围内移动,则有可能发生重绘
view plain copy to clipboard print ?
/**
* 卷轴滚动 *
* @param x * X轴滚动
* @param y * Y轴滚动
*/
private void scroll(int x, int y)
{
try
{
x += mapOffx;
y += mapOffy;
// *************************************************
// 边界检测
if (x 0 || y 0)
{
return;
}
if (x > mapLastx)
{
mapOffx = mapLastx;
return;
}
if (y > mapLasty)
{
mapOffy = mapLasty;
return;
}
updateBuffer(x, y);
// *************************************************
}
catch (ArrayIndexOutOfBoundsException e)
{
}
}
/** * 卷轴滚动 * * @param x * X轴滚动 * @param y * Y轴滚动 */ private void scroll(int x, int y) { try { x += mapOffx; y += mapOffy; // ************************************************* // 边界检测 if (x mapLastx) { mapOffx = mapLastx; return; } if (y > mapLasty) { mapOffy = mapLasty; return; } updateBuffer(x, y); // ************************************************* } catch (ArrayIndexOutOfBoundsException e) { } }
步骤四的实现 重绘缓冲区,地图的x方向卷动会造成列方向上的重绘(调用copyBufferX()方法),地图的y方向上的卷动会造成行方向上的重绘(调用copyBufferY()方法)。updateBuffer()方法用于针对不同的四个方向上的卷动进行copyBuffer()参数的初始化。 view plain copy to clipboard print ?
/**
* 更新缓冲区 *
* @param x * 缓冲区新的地图X坐标
* @param y * 缓冲区新的地图Y坐标
*/
private void updateBuffer(int x, int y)
{
mapOffx = x;
mapOffy = y;
// 右移
if (x > carx + buffSize)
{
// while (carx
int indexMapLastX = getIndexBuffLastX();
if (indexMapLastX
{
copyBufferX(indexMapLastX, getIndexCarY(), getTileHeight(),
getBufferCarX(), getBufferCarY());
carx += tileSize;
}
// }
}
// 左移
if (x
{
// do {
carx -= tileSize;
copyBufferX(getIndexCarX(), getIndexCarY(), getTileHeight(),
getBufferCarX(), getBufferCarY());
// } while (carx > mapOffx);
}
// 下移
if (y > cary + buffSize)
{
// while (cary
int indexMapLastY = getIndexBuffLastY();
if (indexMapLastY
{
copyBufferY(getIndexCarX(), indexMapLastY, getTitelWidth(),
getBufferCarX(), getBufferCarY());
cary += tileSize;
}
// }
}
// 上移
if (y
{
// do {
cary -= tileSize;
copyBufferY(getIndexCarX(), getIndexCarY(), getTitelWidth(),
getBufferCarX(), getBufferCarY());
// } while (cary > mapOffy);
}
} /** * 更新缓冲区 * * @param x * 缓冲区新的地图X坐标 * @param y * 缓冲区新的地图Y坐标 */ private void updateBuffer(int x, int y) { mapOffx = x; mapOffy = y; // 右移 if (x > carx + buffSize) { // while (carx mapOffx); } // 下移 if (y > cary + buffSize) { // while (cary mapOffy); } }
重绘缓冲区的具体方法,该方法涉及到大量的坐标运算,而且由于卡马克点的存在经常会分成两个区域分两次进行重绘。见下图:
下面以x方向卷动为例举例 view plain copy to clipboard print ?
private void copyBufferX(int indexMapx, int indexMapy, int tileHeight,
int destx, int desty)
{
int mapImagex, mapImagey, vy;
// 拷贝地图上面到缓冲的下面
int timer=0;
for (int j = 0; j
{
mapImagex = getMapX(indexMapy + j, indexMapx);
mapImagey = getMapY(indexMapy + j, indexMapx);
vy = j * tileSize + desty;
m_View.drawClipImg(destx, vy, tileSize, tileSize, mapImagex, mapImagey, mapImage, paint, carGp);
timer++;
}
System.out.println("x:"+timer);
} private void copyBufferX(int indexMapx, int indexMapy, int tileHeight, int destx, int desty) { int mapImagex, mapImagey, vy; // 拷贝地图上面到缓冲的下面 int timer=0; for (int j = 0; j 步骤五的实现
将后台缓冲区的四个子区按照顺序画到屏幕上:
view plain copy to clipboard print ?
public void paint(Canvas g, int x, int y)
{
// 地图在缓冲中的坐标
int tempx = mapOffx % bufWidth;
int tempy = mapOffy % bufHeight;
// 切割线右下角的宽与高
int rightWidth = bufWidth - tempx;
int rightHeight = bufHeight - tempy;
// 画左上
drawRegion(g, carBuffer, tempx, tempy, rightWidth, rightHeight, 0, x, y);
// 画右上
drawRegion(g, carBuffer, 0, tempy, scrWidth - rightWidth, rightHeight, 0, x + rightWidth, y);
// 画左下
drawRegion(g, carBuffer, tempx, 0, rightWidth, scrHeight - rightHeight, 0, x, y + rightHeight);
// 画右下
drawRegion(g, carBuffer, 0, 0, scrWidth - rightWidth, scrHeight
- rightHeight, 0, x + rightWidth, y + rightHeight);
}