2012-11-24 90 views
-3

編輯:找到解決方案。我在問題後添加了它。連接形狀並追蹤其輪廓

我正在爲Android設計一款遊戲,我正試圖想出在渲染階段減少計算的方法。目前我已經有了一種方法,可以將所有金屬和橡膠塊放到關卡中,並將紋理ID存儲到int [] []網格中,以便渲染器讀取該值,而不是每幀計算每塊塊平鋪紋理。

這工作得很好,但現在我試圖創建一個角和直接件的水平邊緣和激光塊在關卡的列表。水平邊界和激光塊是使用一組直線激光紋理和角落紋理繪製的。我不知道如何最好地解決在哪裏不要渲染激光,其中塊與其他塊重疊並且具有水平邊緣。下面的照片顯示了我的意思:

drawing

ingame

在這裏可以看到的水平邊緣(延伸超出畫面邊緣將L形激光路徑)和三個/兩個內部激光塊(分別以圖片順序)。據我所知,我應該在上面創建一個類似的網格,但使用布爾值,所以任何觸及(紅色突出顯示)時觸發玩家的正方形都是正確的,安全正方形是錯誤的。

然後我首先想到了通過網格中的所有真實(紅色)單元並計算出激光輪廓使用鄰近網格單元的樣子,但我意識到這可能非常困難,所以我現在確定我用虛假廣場找出它。我確信我可以通過在水平邊界的左下方開始工作並遍歷網格直到我找到一個錯誤的方塊(除非第一個方塊是假的),然後通過網格向右移動直到我到達右邊的一個真正的單元格,所以我會左轉並繼續向上通過網格,直到發現上面的真實向左轉,或者在右側找到假向右轉。我會重複這個過程,直到我到達我的起始假細胞。

我想出了這個問題,而把這個問題寫出來哈哈。這似乎是最簡單的方法,所以我猜我的問題是這是一個很好的方法來做到這一點,我將如何制定激光塊相互接觸但不觸及水平邊界,因爲上述方法只會追蹤最外面的激光路徑。

感謝您花時間閱讀本文。我希望我已經解釋得很清楚了,我期待着有關這個問題的任何信息。

+2

Yawnnnnnnnnnnnnn !!!! –

回答

0

SOLUTION:

public static boolean[][] laserField = new boolean[(int) Static.WORLD_SIZE][(int)Static.WORLD_SIZE]; 
    public static List<LaserData> laserData = new ArrayList<LaserData>(); 
    public static void calcLaserBoundryAreas() { 
     laserField = new boolean[(int) Level.levelBounds.bounds.width+5][(int) Level.levelBounds.bounds.height+5]; 
     for (int i=0;i<laserField.length;i++) { 
      for (int j=0;j<laserField[i].length;j++) { 
       if(i==0 || i==laserField.length-1 || j==0 || j==laserField[i].length-1) 
        laserField[i][j] = true; 
       else 
        laserField[i][j] = false; 
      } 
     } 
     for (LaserBlock lBlock : lBlocks) { 
      int cols = (int)lBlock.bounds.width; 
      int rows = (int)lBlock.bounds.height; 
      float startX = lBlock.position.x - (cols-1f)/2f; 
      float startY = lBlock.position.y - (rows-1f)/2f; 
      for (int i=0;i<cols;i++) { 
       for (int j=0;j<rows;j++) { 
        addLaserCell(startX+i, startY+j); 
       } 
      } 
     } 
     addLaserData(); 
    } 

private static void addLaserCell(float x, float y) { 
    int cellX = (int)(x- Level.levelBounds.bounds.lowerLeft.x+2); 
    int cellY = (int)(y- Level.levelBounds.bounds.lowerLeft.y+2); 
    if (cellX < 0 || cellX > laserField.length-1)   return; 
    if (cellY < 0 || cellY > laserField[cellX].length-1) return; 
    laserField[cellX][cellY] = true; 
} 

private static void addLaserData() { 
    laserData = new ArrayList<LaserData>(); 
    for (int i=1;i<laserField.length-1;i++) { 
     for (int j=1;j<laserField[i].length-1;j++) { 
      if (!laserField[i][j]) { 
       checkNeighbours(i,j); 
      } 
     } 
    } 
    optimiseLaserData(); 
} 

private static void checkNeighbours(int x, int y) { 
    boolean u = laserField[x][y+1]; 
    boolean ul = laserField[x-1][y+1]; 
    boolean l = laserField[x-1][y]; 
    boolean bl = laserField[x-1][y-1]; 
    boolean b = laserField[x][y-1]; 
    boolean br = laserField[x+1][y-1]; 
    boolean r = laserField[x+1][y]; 
    boolean ur = laserField[x+1][y+1]; 

    /* 
    * TOP LEFT CORNER 
    */ 
    float posX, posY; 
    posX = Level.levelBounds.bounds.lowerLeft.x+x-2.5f; 
    posY = Level.levelBounds.bounds.lowerLeft.y+y-1.5f; 
    if(u && ul && l) 
     laserData.add(new LaserData(posX, posY, true, 0, 0)); 
    else if(!u && ul && l) 
     laserData.add(new LaserData(posX, posY, false, 1, 0)); 
    else if(!u && ul && !l) 
     laserData.add(new LaserData(posX, posY, true, 0, 2)); 

    /* 
    * BOTTOM LEFT CORNER 
    */ 
    posX = Level.levelBounds.bounds.lowerLeft.x+x-2.5f; 
    posY = Level.levelBounds.bounds.lowerLeft.y+y-2.5f; 
    if(l && bl && b) 
     laserData.add(new LaserData(posX, posY, true, 0, 1)); 
    else if(!l && bl && b) 
     laserData.add(new LaserData(posX, posY, false, 1, 1)); 
    else if(!l && bl && !b) 
     laserData.add(new LaserData(posX, posY, true, 0, 3)); 

    /* 
    * BOTTOM RIGHT CORNER 
    */ 
    posX = Level.levelBounds.bounds.lowerLeft.x+x-1.5f; 
    posY = Level.levelBounds.bounds.lowerLeft.y+y-2.5f; 
    if(b && br && r) 
     laserData.add(new LaserData(posX, posY, true, 0, 2)); 
    else if(!b && br && r) 
     laserData.add(new LaserData(posX, posY, false, 1, 2)); 
    else if(!b && br && !r) 
     laserData.add(new LaserData(posX, posY, true, 0, 0)); 

    /* 
    * TOP RIGHT CORNER 
    */ 
    posX = Level.levelBounds.bounds.lowerLeft.x+x-1.5f; 
    posY = Level.levelBounds.bounds.lowerLeft.y+y-1.5f; 
    if(r && ur && u) 
     laserData.add(new LaserData(posX, posY, true, 0, 3)); 
    else if(!r && ur && u) 
     laserData.add(new LaserData(posX, posY, false, 1, 3)); 
    else if(!r && ur && !u) 
     laserData.add(new LaserData(posX, posY, true, 0, 1)); 

} 

private static void optimiseLaserData() { 
    List<LaserData> optiLaserData = new ArrayList<LaserData>(); 
    for(LaserData ld : laserData) { 
     if(ld.cornerPiece) 
      optiLaserData.add(ld); 
     else if(ld.dir == 0 || ld.dir == 2){ 
      float x = ld.x; 
      float bottomY = ld.y; 
      float topY = ld.y; 
      float count = 1; 
      while (searchStraightLaserData(laserData, x, topY+1, ld.dir)) { 
       count++; 
       topY++; 
      } 
      while (searchStraightLaserData(laserData, x, bottomY-1, ld.dir)) { 
       count++; 
       bottomY--; 
      } 
      float centerY = bottomY + (topY-bottomY)/2; 
      if(!searchStraightLaserData(optiLaserData, x, centerY, ld.dir)) 
       optiLaserData.add(new LaserData(x, centerY, false, count, ld.dir)); 
     } else { 
      float y = ld.y; 
      float leftX = ld.x; 
      float rightX = ld.x; 
      float count = 1; 
      while (searchStraightLaserData(laserData, rightX+1, y, ld.dir)) { 
       count++; 
       rightX++; 
      } 
      while (searchStraightLaserData(laserData, leftX-1, y, ld.dir)) { 
       count++; 
       leftX--; 
      } 
      float centerX = leftX + (rightX-leftX)/2; 
      if(!searchStraightLaserData(optiLaserData, centerX, y, ld.dir)) 
       optiLaserData.add(new LaserData(centerX, y, false, count, ld.dir)); 
     } 
    } 
    laserData = optiLaserData; 
} 

private static boolean searchStraightLaserData(List<LaserData> data, float x, float y, int dir) { 
    for(LaserData ld : data) 
     if(ld.x == x && ld.y == y && ld.dir == dir && !ld.cornerPiece) 
      return true; 
    return false; 
} 

這些方法首先創建一個布爾網格的水平邊緣界限在每一側一個1個平方額外邊緣的大小。這被初始化爲假來代表安全區域,並且額外的邊緣被設置爲真,以便我們有一種空心的盒子。額外的邊緣有助於稍後消除檢查laserField上不正確索引的需要。

將等級範圍映射到網格後,將單個單元格更改爲真,其中激光塊覆蓋以前的任何單元格。

一旦布爾網格被完全映射,它就會遍歷每個網格單元,當它發現一個單元格爲false時,它會將網格座標傳遞給下一個方法,該方法將查看12個不同的鄰近模式,以確定是否有激光器應該在這個單元周圍呈現。LaserData構造函數採用以下參數(float x,float y,布爾cornerPiece,float長度,int方向)

最後一節進行蠻力搜索以檢查是否有任何相鄰的直片可以被單個較長的直線以節省渲染額外的精靈。

渲染器就可以只通過laserData列表讀取每個幀,它有它需要的所有渲染正確的質地,它的位置,長度等信息......

注:的寬度和高度爲了說明邊界外的玩家的寬度,等級邊界比實際遊戲區域小3個單位。這就是levelBounds.lowerleft + 5,+2和+ 1.5f等等來自哪裏。這是一個有點哈克我知道,但它是舊代碼,我不敢碰它xD