2012-11-24 70 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