赞 | 0 |
VIP | 2 |
好人卡 | 27 |
积分 | 1 |
经验 | 26327 |
最后登录 | 2019-10-13 |
在线时间 | 953 小时 |
Lv1.梦旅人
- 梦石
- 0
- 星屑
- 110
- 在线时间
- 953 小时
- 注册时间
- 2007-4-25
- 帖子
- 805
|
本帖最后由 苏小脉 于 2010-12-26 06:07 编辑
在 R2 中检测有两个端点的线段是否与一个矩形碰撞的问题可以被划分为检测线段是否和矩形的任意边相交,或线段的任意端点在矩形内部(包括刚好在边上)。
前者是四次线段相交检测。对于线段相交检测,最明显的途径自然就是求包含这两条线段的直线的交点,然后判断是否在线段范围内。然而,这个方法无法避免浮点运算。为了提高效率,就需要避免浮点运算,只进行整数定点运算。下面的算法,是判断两条线段各自的端点是否分别在包含另一条线段的直线的两端。只有在这种情况下(当且仅当),两条线段才相交。这就涉及到另一个问题——判断两个点是否分别在一条直线的两端。这里可以分别使用两个点按固定的顺序连接线段的两个端点(即直线上的两个点),形成两个凸包(三角形),然后检测凸包的形成是通过顺时针还是逆时针旋转。如果这两个点各自在直线的一端,那么必然有着相反的旋转方向,一个是顺时针,一个是逆时针。- def cw_test(ax, ay, bx, by, cx, cy)
- lhs = (by - ay) * (cx - ax)
- rhs = (cy - ay) * (bx - ax)
- if lhs == rhs then 0
- elsif lhs < rhs then 1
- else 2
- end
- end
- def bound?(x, a, b)
- a <= x && x <= b || a >= x && x >= b
- end
- def bound_inside?(x, y, ax, ay, bx, by)
- bound?(x, ax, bx) && bound?(y, ay, by)
- end
- def seg_intersect?(px1, py1, px2, py2, qx1, qy1, qx2, qy2)
- t1 = cw_test(px1, py1, qx1, qy1, qx2, qy2)
- t2 = cw_test(px2, py2, qx1, qy1, qx2, qy2)
- t3 = cw_test(qx1, qy1, px1, py1, px2, py2)
- t4 = cw_test(qx2, qy2, px1, py1, px2, py2)
- 3 == (t1 | t2) && 3 == (t3 | t4) ||
- 0 == t1 && bound_inside?(px1, py1, qx1, qy1, qx2, qy2) ||
- 0 == t2 && bound_inside?(px2, py2, qx1, qy1, qx2, qy2) ||
- 0 == t3 && bound_inside?(qx1, qy1, px1, py1, px2, py2) ||
- 0 == t4 && bound_inside?(qx2, qy2, px1, py1, px2, py2)
- end
- def point_lies_in?(x, y, ax, ay, bx, by, cx, cy, dx, dy)
- (cw_test(x, y, ax, ay, bx, by) |
- cw_test(x, y, bx, by, cx, cy) |
- cw_test(x, y, cx, cy, dx, dy) |
- cw_test(x, y, dx, dy, ax, ay)) != 3
- end
- def seg_rect_collide?(ax, ay, bx, by, tlx, tly, trx, try, brx, bry, blx, bly)
- point_lies_in?(ax, ay, tlx, tly, trx, try, brx, bry, blx, bly) ||
- point_lies_in?(bx, by, tlx, tly, trx, try, brx, bry, blx, bly) ||
- seg_intersect?(ax, ay, bx, by, tlx, tly, trx, try) ||
- seg_intersect?(ax, ay, bx, by, trx, try, brx, bry) ||
- seg_intersect?(ax, ay, bx, by, brx, bry, blx, bly) ||
- seg_intersect?(ax, ay, bx, by, blx, bly, tlx, tly)
- end
复制代码 seg_rect_collide? 是检测线段 (ax, ay)-(bx, by) 与矩形碰撞的函数。矩形的四个顶点 (tlx, tly), (trx, try), (brx, bry), (blx, bly) 是按时钟顺序排列的,比如“左上、右上、右下、左下”这样的顺序。
详情可参考:
http://szsu.wordpress.com/2010/12/25/seg_rect_collision/
附一段在 RM 中的随机化、可视化测试脚本:
- def init_sprite(sprite, color)
- sprite.ox = sprite.oy = 5
- sprite.bitmap = Bitmap.new(10, 10)
- sprite.bitmap.fill_rect(0, 0, 10, 10, color)
- end
- yellow = Color.new(0xff, 0xff, 0)
- blue = Color.new(0, 0, 0xff)
- init_sprite(a = Sprite.new, yellow)
- init_sprite(b = Sprite.new, yellow)
- init_sprite(tl = Sprite.new, blue)
- init_sprite(tr = Sprite.new, blue)
- init_sprite(br = Sprite.new, blue)
- init_sprite(bl = Sprite.new, blue)
- loop do
- ax = rand(640)
- ay = rand(480)
- bx = rand(640)
- by = rand(480)
- tlx = rand(320)
- tly = rand(240)
- brx = rand(320) + 320
- bry = rand(240) + 240
- a.x = ax
- a.y = ay
- b.x = bx
- b.y = by
- tl.x = tlx
- tl.y = tly
- tr.x = brx
- tr.y = tly
- br.x = brx
- br.y = bry
- bl.x = tlx
- bl.y = bry
- p "(#{ax},#{ay}), (#{bx},#{by})",
- "(#{tlx}, #{tly}), (#{brx}, #{tly}), (#{brx}, #{bry}), (#{tlx}, #{bry})",
- seg_rect_collide?(ax, ay, bx, by, tlx, tly, brx, tly, brx, bry, tlx, bry)
-
- Graphics.update
- end
复制代码 |
评分
-
查看全部评分
|