游戏开发之主角的移动与地图的平滑滚动-卡马克算法

相关资料

雨松MOMO带你走进游戏开发的世界之主角的移动与地图的平滑滚动

http://blog.csdn.net/xys289187120/article/details/6649274

卡马克卷轴算法研究_地图双缓冲

http://wenku.baidu.com/view/a51f0b8ca0116c175f0e48c3.html

矩形相交判断

http://hi.baidu.com/jiyeqian/blog/item/c14e52c24794b4170ff47715.html


实现原理

将地图每次移动时的相交区域作为重复利用资源(缓冲区),如图a1b1c1d1(移动前)和a2b2c2d2(移动后)相交得到的矩形为aabbccdd。


根据判断矩形是否相交公式为:

通过中心点距离判断(中心点距离 X<= 矩形1宽度/2 + 矩形2宽度/2)且(中心点距离 Y<= 矩形1高度/2 + 矩形2高度/2)

获取相交矩形公式为:

如果相交,则相交矩形的左上角坐标为(max(a1.x,a2.x),max(a1.y,a2.y))和右下角坐标(min(d1.x,d2.x),min(d1.y,d2.y))

当每次屏幕移动时,实际是将地图移动在相反的方向移动,移动后根据当前屏幕所在地图中的相对位置,将屏幕中的区域贴砖。在每次移动中实际不同的区域只是非AaBbCcDd相交区域,所以可以在贴砖时增加判断当前贴砖区域是否是在相交区域,如果是则不用贴砖,只把相交区域外的区域进行贴砖即可,实际就是少贴砖,减少CPU的运算量。

注意采用该算法后,占用内寸不会减少,由于卡马克卷轴涉及到很多坐标运算,所以在当前内存消耗中,有时候会多占用一些内存资源。


具体实现代码如下:

[java]  view plain copy
  1. /** 
  2.      * 滚动屏幕(移动距离可以利用onTouchEvent获得) 
  3.      * @param distanceX X方向移动距离 
  4.      * @param distanceY Y方向移动距离  
  5.      */  
  6.     public void scrollMap(float distanceX, float distanceY) {  
  7.         // TODO Auto-generated method stub  
  8.         //触摸位移灵敏度  
  9.         int newScrLeft = screenInMapLoc.x + (int)distanceX/5;  
  10.         int newScrTop = screenInMapLoc.y + (int)distanceY/5;  
  11.           
  12.         int mapWidth = mMapView[0].length * TILE_WIDTH;  
  13.         int mapHeight = mMapView.length * TILE_HEIGHT;  
  14.           
  15.         //设置后则是考虑相交区域  
  16.         lastScrInMapLoc = new Point(screenInMapLoc.x,screenInMapLoc.y);  
  17.   
  18.         if(newScrLeft>0 && newScrLeft + SCREEN_WIDTH<mapWidth){  
  19.             screenInMapLoc.x = newScrLeft;  
  20.         }  
  21.         else if(newScrLeft<=0){  
  22.             screenInMapLoc.x = 0;  
  23.         }  
  24.         else{  
  25.             screenInMapLoc.x = mapWidth - SCREEN_WIDTH;  
  26.         }  
  27.           
  28.         if(newScrTop>0 && newScrTop + SCREEN_HEIGHT<mapHeight){  
  29.             screenInMapLoc.y = newScrTop;  
  30.         }  
  31.         else if(newScrTop<=0){  
  32.             screenInMapLoc.y = 0;  
  33.         }  
  34.         else{  
  35.             screenInMapLoc.y = mapHeight - SCREEN_HEIGHT;  
  36.         }  
  37.           
  38.         Long begin = System.currentTimeMillis();  
  39.         bufferImage = drawBufferImage();  
  40.         Long end = System.currentTimeMillis();  
  41.           
  42.         Log.d("cramack","耗时:" + (end - begin) + "ms");  
  43.     }  
  44.   
  45. private Bitmap drawBufferImage(){  
  46.     //与屏幕大小一致的缓冲图  
  47.     Bitmap _bufferImage = Bitmap.createBitmap(TILE_X_COUNT*TILE_WIDTH,TILE_Y_COUNT*TILE_HEIGHT,Config.RGB_565);  
  48.       
  49.     Rect itscRect = null;  
  50.     Bitmap itscImage = null;  
  51.   
  52.     //当前屏幕左上角所处地图中的网格坐标  
  53.     int startX = screenInMapLoc.x / TILE_WIDTH;  
  54.     int startY = screenInMapLoc.y / TILE_HEIGHT;  
  55.       
  56.     offsetPt.x = -screenInMapLoc.x % TILE_WIDTH;  
  57.     offsetPt.y = -screenInMapLoc.y % TILE_HEIGHT;  
  58.       
  59.     Rect newScrRect = new Rect(screenInMapLoc.x,  
  60.                                screenInMapLoc.y,  
  61.                                screenInMapLoc.x + SCREEN_WIDTH,  
  62.                                screenInMapLoc.y + SCREEN_HEIGHT);  
  63.   
  64.     if(lastScrInMapLoc!=null){  
  65.         Rect lastScrRect = new Rect(lastScrInMapLoc.x,lastScrInMapLoc.y,  
  66.                                    lastScrInMapLoc.x + SCREEN_WIDTH,  
  67.                                    lastScrInMapLoc.y + SCREEN_HEIGHT);  
  68.   
  69.         //两矩形交集  
  70.         itscRect = intersectRect(lastScrRect,newScrRect);  
  71.           
  72.         itscImage = Bitmap.createBitmap(itscRect.width(),  
  73.        itscRect.height(),Config.RGB_565);  
  74.           
  75.         //获取重复区域中上一次缓冲区中的图像  
  76.         Canvas itscCanvas = new Canvas(itscImage);  
  77.           
  78.         itscCanvas.save();  
  79.         itscCanvas.clipRect(new Rect(0,0,itscRect.width(),itscRect.height()));  
  80.         itscCanvas.drawBitmap(bufferImage,  
  81.     lastScrRect.left - itscRect.left,lastScrRect.top-itscRect.top,defaultPaint);  
  82.         itscCanvas.restore();  
  83.     }  
  84.       
  85.     Canvas canvas = new Canvas(_bufferImage);  
  86.       
  87.     defaultPaint.setColor(Color.BLACK);  
  88.     canvas.drawRect(00,  
  89.     _bufferImage.getWidth(),_bufferImage.getHeight(),defaultPaint);  
  90.       
  91.     int rowCount = mMapView.length;  
  92.     int colCount = mMapView[0].length;  
  93.       
  94.     //在缓冲图中贴砖  
  95.     for (int j = 0; j < TILE_X_COUNT; j++) {  
  96.         for (int i = 0; i < TILE_Y_COUNT; i++) {  
  97.             int left = j * TILE_WIDTH + offsetPt.x;  
  98.             int top = i * TILE_HEIGHT + offsetPt.y;  
  99.   
  100.             //剪切显示要贴砖的区域  
  101.             Rect clipRect = new Rect(left,top,left+TILE_WIDTH,top+TILE_HEIGHT);  
  102.               
  103.             //贴砖区域在地图中的区域  
  104.             Rect absClipRect = new Rect(screenInMapLoc.x + left,  
  105.                                         screenInMapLoc.y + top,  
  106.                                         screenInMapLoc.x + left+TILE_WIDTH,  
  107.                                         screenInMapLoc.y + top+TILE_HEIGHT);  
  108.               
  109.             //如果当前要贴砖区域不属于移动的重复区域则贴砖  
  110.             if (!includeRect(itscRect,absClipRect)) {  
  111.                 canvas.save();  
  112.                 canvas.clipRect(clipRect);  
  113.               
  114.                 //将素材图片要贴砖部分左顶点对齐后偏移到缓冲图中的贴钻区域  
  115.                 if(startY+i<rowCount && startX+j<colCount){  
  116.                     Point lay1TilePt = getTilePt(bufferMap,mMapView[startY+i][startX+j]);  
  117.                     canvas.drawBitmap(bufferMap,  
  118.                                       -lay1TilePt.x*TILE_WIDTH + left,  
  119.                                       -lay1TilePt.y*TILE_HEIGHT + top,  
  120.                                       defaultPaint);  
  121.                       
  122.                     Point lay2TilePt = getTilePt(bufferMap,mMapActor[startY+i][startX+j]);  
  123.                       
  124.                     canvas.drawBitmap(bufferMap,  
  125.                                       -lay2TilePt.x*TILE_WIDTH + left,  
  126.                                       -lay2TilePt.y*TILE_HEIGHT + top,  
  127.                                       defaultPaint);  
  128.                 }  
  129.   
  130.                 canvas.restore();  
  131.             }  
  132.         }  
  133.     }  
  134.       
  135.     if (lastScrInMapLoc!=null && itscRect!=null) {  
  136.         //在新坐标下画重复(相交)区域  
  137.         canvas.save();  
  138.         int mLeft = itscRect.left - newScrRect.left;  
  139.         int mTop = itscRect.top - newScrRect.top;  
  140.           
  141.         canvas.clipRect(new Rect(mLeft,mTop,mLeft+itscRect.width(),  
  142.     mTop + itscRect.height()));  
  143.         canvas.drawBitmap(itscImage,mLeft,mTop,defaultPaint);  
  144.         canvas.restore();  
  145.       
  146.         lastScrInMapLoc = new Point(screenInMapLoc.x,screenInMapLoc.y);  
  147.     }  
  148.       
  149.     return _bufferImage;  
  150. }  
  151.   
  152.     /** 
  153.      * 对屏幕进行刷新 
  154.      */  
  155. public void run() {  
  156.         // TODO Auto-generated method stub  
  157.         Paint tipPaint = new Paint();  
  158.         tipPaint.setColor(Color.RED);  
  159.         tipPaint.setTextSize(32);  
  160.           
  161.         while(mIsRunning){  
  162.             synchronized (mSurfaceHolder) {  
  163.                 Canvas canvas = mSurfaceHolder.lockCanvas();  
  164.                   
  165.                 Long begin = System.currentTimeMillis();  
  166.                 drawBackground(canvas);  
  167.                 Long end = System.currentTimeMillis();  
  168.           
  169.                 String tip = "interval:" + (end-begin) + "ms";    
  170.                 canvas.drawText(tip , SCREEN_WIDTH - tipPaint.measureText(tip) , SCREEN_HEIGHT - 40 , tipPaint);  
  171.                   
  172.                 mSurfaceHolder.unlockCanvasAndPost(canvas);  
  173.                   
  174.                 try {  
  175.                     Thread.sleep(100);  
  176.                 } catch (InterruptedException e) {  
  177.                     // TODO Auto-generated catch block  
  178.                     e.printStackTrace();  
  179.                 }  
  180.             }  
  181.         }  
  182.     }  

结论

 在模拟器中未使用卡马克卷轴算法:


在模拟器中使用卡马克卷轴算法:


采用卡马克卷轴算法后,CPU执行耗时有明显减少。


实现代码:

点击下载


  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值