2010-04-05 140 views
0

有很多像這樣的話題,但沒有具體的答案。我正在用傳統方式繪製一張瓷磚地圖(兩個for循環),並保持我的播放器居中,除非地圖邊緣到達。我將如何創建碰撞檢測?我需要知道如何將數組中的圖塊位置轉換爲我認爲的屏幕座標。瓷磚地圖碰撞檢測

+0

發佈一些地圖渲染的僞代碼(包括播放器)和哪些對象可以相互碰撞可能會有幫助。 – 2010-04-05 00:27:24

回答

1

這取決於型號。

如果您的模型(數據)是一個網格,那麼當兩個不兼容的對象佔據相同的位置時就會發生碰撞。處理這種類型的碰撞最簡單的方法就是確保您試圖將遊戲實體移動到「可用」位置。如果是,則不會碰撞,並且更新型號。如果它不是免費的,那麼就會發生碰撞。

屏幕只是呈現模型。除了類似於每像素碰撞檢測(認爲原始的旅鼠或蠕蟲)之外,不會將其用於碰撞檢測

屏幕/視圖只是渲染代理。雖然您可以將模型緊緊地綁在屏幕上(例如,您只需更新事物發生變化的部分,例如移動某個部分時),但屏幕並非也不應該被視爲部分的模型。但是,以現代計算速度,您可能簡單地在每一幀重新渲染整個可見模型。

(是的,我知道我重複自己這是故意的。)

現在,爲了回答在標題沒有提到次要的問題:

當你開始渲染,簡單地劃SCREEN_WIDTH/cell_width/2個單元格,玩家右側的screen_width/cell_width/2個單元格(玩家被假定爲1x1)。爲上下做同樣的事情。確保不會導致索引超出範圍異常。只要您在使用它們之前進行鉗制/過濾,您就可以使用越界值運行for循環。如果你只想讓角色在靠近邊緣時「推」邊緣,還要跟蹤當前的模型 - 視圖參考。

2

我會給你我爲點/地圖碰撞檢測寫的代碼。該代碼假定您在(xfrom,yfrom)處有一個點,並且您想將其移動到(xto,yto),並且想要查看是否與tilemap貼圖[Y] [X]中的塊發生衝突。我假設一個方法isSolid(tileId),如果瓦片是實體的,它將返回true。

/** 
* This method returns true if there is a collision between a point and a 2D tilemap map[Y][X]. 
* The isSolid method must be implemented to indicate if a tile is solid or not 
* Assumes the tilemap starts at (0,0) and TILEWIDTH and TILEHEIGHT hold the size of a tile (in pixels) 
* @param xfrom the original x-coordinate of the point 
* @param yfrom the original y-coordinate of the point 
* @param xto the destination x-coordinate of the point 
* @param yto the destination y-coordinate of the point 
* @param outCollisionPoint output the location where the collision occurs 
* @return true if a collision is found 
*/ 
public boolean collisionDetection(int xfrom, int yfrom, int xto, int yto, Point outCollisionPoint){ 
    //Ref: A fast voxel traversal algorithm J.Amanatides, A. Woo 
    float tMaxX, tMaxY, tDeltaX, tDeltaY, collisionLength; 
    int X, Y, stepX, stepY, endX, endY, blkX, blkY; 

    //Calculate direction vector 
    float dirX = (xto - xfrom); 
    float dirY = (yto - yfrom); 

    float length = (float) Math.sqrt(dirX * dirX + dirY * dirY); 

    //Normalize direction vector 
    dirX /= length; 
    dirY /= length; 

    //tDeltaX: distance in terms of vector(dirX,dirY) between two consecutive vertical lines 
    tDeltaX = TILEWIDTH/Math.abs(dirX); 
    tDeltaY = TILEHEIGHT/Math.abs(dirY); 

    //Determine cell where we originally are 
    X = xfrom/TILEWIDTH; 
    Y = yfrom/TILEHEIGHT; 

    endX = xto/TILEWIDTH; 
    endY = yto/TILEHEIGHT; 

    //stepX: Determine in what way do we move between cells 
    //tMaxX: the distance in terms of vector(dirX,dirY) to the next vertical line 
    if (xto > xfrom){ 
     blkX = 0; 
     stepX = 1; 
     tMaxX = ((X+1) * TILEWIDTH - xfrom)/dirX; 
    }else{ 
     blkX = 1; 
     stepX = -1; 
     tMaxX = (X * TILEWIDTH - xfrom)/dirX; 
    } 
    if (yto > yfrom){ 
     blkY = 0; 
     stepY = 1; 
     tMaxY = ((Y+1) * TILEHEIGHT - yfrom)/dirY; 
    }else{ 
     blkY = 1; 
     stepY = -1; 
     tMaxY = (Y * TILEHEIGHT - yfrom)/dirY; 
    } 

    if (isSolid(map[Y][X])) { 
     //point already collides 
     outCollisionPoint = new Point(xfrom, yfrom); 
     return true; 
    } 
    //Scan the cells along the line between 'from' and 'to' 
    while (X != endX || Y !=endY){ 
     if(tMaxX < tMaxY){ 
      tMaxX += tDeltaX; 
      X += stepX; 
      if (isSolid(map[Y][X])) { 
       collisionLength = ((X + blkX) * TILEWIDTH - xfrom)/dirX; 
       outCollisionPoint = new Point((int)(xfrom + dirX * collisionLength), (int)(yfrom + dirY * collisionLength)); 
       return true; 
      } 
     }else{ 
      tMaxY += tDeltaY; 
      Y += stepY; 
      if (isSolid(map[Y][X])) {   
       collisionLength= ((Y + blkY) * TILEHEIGHT - yfrom)/dirY; 
       outCollisionPoint = new Point((int)(xfrom + dirX * collisionLength), (int)(yfrom + dirY * collisionLength)); 
       return true; 
      }     
     } 
    } 
    return false; 
}