我目前正在研究为小型2D游戏制作一个简单的阴影投射算法。在使用优化库之前,我想尽可能自己尝试一下。
我觉得我几乎在那里,但由于某种原因,我用来检测来自我的线源和一个线段(障碍物或屏幕边缘的任何一侧)的光线之间的交叉点的方法似乎并不能捕获所有碰撞。
我将错误缩小到此函数,但我找不到错误。我经历过很多次,仍然无法弄清楚为什么它并不总是有效。我所有的光线都伸出屏幕,所以我至少应该检测到与屏幕边缘的碰撞。我还检查了算法循环遍历所有光线和段。
这是检查碰撞的方法:
def check_col(self, ray, source):
'''
segment1 = (self.start,self.end)
segment2 = (source.pos,ray.far_pt)'''
X1,Y1 = self.start #start pt of segment 1
X2,Y2 = self.end #end pt of segment 1
X3,Y3 = source.pos #start pt of segment 2
X4,Y4 = ray.far_pt #end pt of segment 2
'''we are looking to express the segments as:
A*x + b = y '''
'''ensuring mutual abscisse exists'''
if (max(X1,X2) < min(X3,X4)) or (min(X1,X2) > max(X3,X4))\
or (max(Y1,Y2) < min(Y3,Y4)) or (min(Y1,Y2) > max(Y3,Y4)):
return False,0 #no mutual abscisse, 0 added to return a tulpe
'''ensures no division by 0
when calculating the segment
slopes A1 and A2'''
if float(X1-X2) == 0:
X1 +=0.1 #add a small increment to avoid difference to be null
if float(X3-X4) == 0:
X3 += 0.1 #add a small increment to avoid difference to be null
'''calculating segment slopes'''
A1 = (Y1-Y2)/float(X1-X2) # Pay attention to not dividing by zero
A2 = (Y3-Y4)/float(X3-X4) # Pay attention to not dividing by zero
b1 = Y1-A1*X1# = Y2-A1*X2
b2 = Y3-A2*X3# = Y4-A2*X4
'''if slopes are the same, offsets one slightly
to avoid dividing by 0 later on'''
if (A1 == A2):
A1 += 0.0001
'''finding out intersect between the two segments at (Xa,Ya)'''
#A1 * Xa + b1 = A2 * Xa + b2
Xa = int((b2 - b1) / (A1 - A2))# Once again, pay attention to not dividing by zero
Ya = int(A1 * Xa + b1)
#Ya = int(A2 * Xa + b2)
col_pt = (Xa,Ya)
'''make sure intersection is within bounds'''
if max(min(X1,X2),min(X3,X4)) <= Xa <= min(max(X1,X2),max(X3,X4)):
'''calculates distance between the light source and the collision point'''
dist = sqrt((source.pos[0]-col_pt[0])**2+(source.pos[1]-col_pt[1])**2)
return True,col_pt,dist
else:
return False,0 #0 added to return a tulpe
这是一个屏幕截图,显示一些光线在明显应该与蓝色障碍物或墙壁碰撞时不会碰撞:
答案 0 :(得分:1)
您的功能有缺陷 - 像X1 +=0.1
这样的碎片会导致奇怪的行为(垂直段的近端很明显)。使用一些强大的实现,如this simple one
(Alexander Hristov。Java但很容易理解)。
/**
* Computes the intersection between two segments.
* @param x1 Starting point of Segment 1
* @param y1 Starting point of Segment 1
* @param x2 Ending point of Segment 1
* @param y2 Ending point of Segment 1
* @param x3 Starting point of Segment 2
* @param y3 Starting point of Segment 2
* @param x4 Ending point of Segment 2
* @param y4 Ending point of Segment 2
* @return Point where the segments intersect, or null if they don't
*/
public Point intersection(
int x1,int y1,int x2,int y2,
int x3, int y3, int x4,int y4
) {
int d = (x1-x2)*(y3-y4) - (y1-y2)*(x3-x4);
if (d == 0) return null;
int xi = ((x3-x4)*(x1*y2-y1*x2)-(x1-x2)*(x3*y4-y3*x4))/d;
int yi = ((y3-y4)*(x1*y2-y1*x2)-(y1-y2)*(x3*y4-y3*x4))/d;
Point p = new Point(xi,yi);
if (xi < Math.min(x1,x2) || xi > Math.max(x1,x2)) return null;
if (xi < Math.min(x3,x4) || xi > Math.max(x3,x4)) return null;
return p;
}
SO的另一个very long discussion。
注意有一些特殊的(更有效的)方法,用于查找与轴对齐框(Line clipping)边缘的线的交点。我推荐Liang-Barski one。