连接形状并追踪轮廓
编辑:找到解决方案。 我在问题后添加了它。
我正在为Android设计一款游戏,我正试图想出在渲染阶段减少计算的方法。 目前我已经有了一种方法,可以将所有金属和橡胶块放到关卡中,并将纹理ID存储到int [] []网格中,以便渲染器读取该值,而不是每帧计算每块块平铺纹理。
这工作正常,但现在我正在尝试创建一个关卡和关卡中的关卡和激光块的角落和直片。 水平边界和激光块是使用一组直线激光纹理和角落纹理绘制的。 我不知道如何最好地解决在哪里不要渲染激光,其中块与其他块重叠并且具有水平边缘。 下面的图片展示了我的意思:
画画
在游戏中
在这里您可以看到水平边缘(L形激光路径延伸到图像边缘之外)和三/两个内部激光块(分别针对图像顺序)。 据我所知,我应该在上面创建一个类似的网格,但使用布尔值,所以任何触及(红色突出显示)时触发玩家的正方形都是正确的,安全正方形是错误的。
然后,我首先想到了通过网格中的所有真实(红色)单元,并计算出激光轮廓使用邻近网格单元的样子,但我意识到这可能非常困难,所以我现在确信我使用了假广场找出来。 我确信我可以通过在水平边界的左下方开始工作并遍历网格直到我找到一个错误的方块(除非第一个方块是假的),然后通过网格向右移动直到我到达右边的一个真正的单元格,所以我会左转并继续向上通过网格,直到发现上面的真实向左转,或者在右侧找到假向右转。 我会重复这个过程,直到我到达我的起始假细胞。
我在写这个问题的时候提出了这个问题。 这似乎是最简单的方法,所以我猜我的问题是这是一个很好的方法来做到这一点,我将如何制定激光块相互接触但不触及水平边界,因为上述方法只会追踪最外面的激光路径。
感谢您花时间阅读本文。 我希望我已经解释得很清楚了,我期待着有关这个问题的任何信息。
解:
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上不正确索引的需要。
水平范围映射到网格后,单个单元被更改为真,其中有激光块覆盖。
一旦布尔网格被完全映射,它就会遍历每个网格单元格,当它发现一个单元格是假的时,它会将网格坐标传递给下一个查看12个不同邻居模式的方法,以确定是否应该在该单元格周围渲染任何激光器。 LaserData构造函数采用以下参数(float x,float y,boolean cornerPiece,float length,int direction)
最后一节进行蛮力搜索,以检查是否有任何相邻的直片可以被单个较长的直片代替以保存渲染额外的精灵。
然后,渲染器可以通过laserData列表读取每一帧,并且它具有渲染正确纹理,位置,长度等所需的所有信息。
注意:等级边界的宽度和高度比实际的游戏区域小3个单位,以说明边界外的玩家的宽度。 这就是levelBounds.lowerleft + 5,+2和+ 1.5f等等来自哪里。 这是一个有点哈克我知道,但它是旧的代码,我不敢碰它xD
链接地址: http://www.djcxy.com/p/66569.html上一篇: Joining shapes together and tracing their outline
下一篇: Can I have someone verify my collections for the SCJP Exam