Class: Pongo::CollisionDetector
- Inherits:
-
Object
- Object
- Pongo::CollisionDetector
- Defined in:
- lib/pongo/collision_detector.rb
Class Attribute Summary collapse
-
.coll_depth ⇒ Object
Returns the value of attribute coll_depth.
-
.coll_normal ⇒ Object
Returns the value of attribute coll_normal.
-
.cpa ⇒ Object
Returns the value of attribute cpa.
-
.cpb ⇒ Object
Returns the value of attribute cpb.
Class Method Summary collapse
-
.closest_vertex_on_obb(point, rect) ⇒ Object
Returns the location of the closest vertex on rect to point.
-
.norm_vs_norm(obj_a, obj_b) ⇒ Object
default test for two non-multisampled particles.
-
.samp_vs_norm(obj_a, obj_b) ⇒ Object
Tests two particles where one is multisampled and the other is not.
-
.samp_vs_samp(obj_a, obj_b) ⇒ Object
Tests two particles where both are of equal multisample rate.
-
.test(obj_a, obj_b) ⇒ Object
Tests the collision between two objects.
-
.test_circle_vs_circle(cir_a, cir_b) ⇒ Object
Tests the collision between two CircleParticles.
-
.test_intervals(interval_a, interval_b) ⇒ Object
Returns 0 if intervals do not overlap.
-
.test_obb_vs_circle(rect_a, cir_a) ⇒ Object
Tests the collision between a RectangleParticle (aka an OBB) and a CircleParticle.
-
.test_obb_vs_obb(rect_a, rect_b) ⇒ Object
Tests the collision between two RectangleParticles (aka OBBs).
-
.test_types(obj_a, obj_b) ⇒ Object
Tests collision based on primitive type.
Class Attribute Details
.coll_depth ⇒ Object
Returns the value of attribute coll_depth.
5 6 7 |
# File 'lib/pongo/collision_detector.rb', line 5 def coll_depth @coll_depth end |
.coll_normal ⇒ Object
Returns the value of attribute coll_normal.
5 6 7 |
# File 'lib/pongo/collision_detector.rb', line 5 def coll_normal @coll_normal end |
.cpa ⇒ Object
Returns the value of attribute cpa.
5 6 7 |
# File 'lib/pongo/collision_detector.rb', line 5 def cpa @cpa end |
.cpb ⇒ Object
Returns the value of attribute cpb.
5 6 7 |
# File 'lib/pongo/collision_detector.rb', line 5 def cpb @cpb end |
Class Method Details
.closest_vertex_on_obb(point, rect) ⇒ Object
Returns the location of the closest vertex on rect to point
206 207 208 209 210 211 212 213 214 215 216 217 218 219 |
# File 'lib/pongo/collision_detector.rb', line 206 def closest_vertex_on_obb(point, rect) d = point - rect.samp q = rect.samp.dup 2.times do |i| dist = d.dot(rect.axes[i]) if dist >= 0; dist = rect.extents[i] elsif dist < 0; dist = -rect.extents[i] end q.plus!(rect.axes[i] * dist) end q end |
.norm_vs_norm(obj_a, obj_b) ⇒ Object
default test for two non-multisampled particles
27 28 29 30 31 32 33 34 35 36 37 |
# File 'lib/pongo/collision_detector.rb', line 27 def norm_vs_norm(obj_a, obj_b) obj_a.samp.copy(obj_a.curr) obj_b.samp.copy(obj_b.curr) if test_types(obj_a, obj_b) CollisionResolver.resolve(@cpa, @cpb, @coll_normal, @coll_depth) true else false end end |
.samp_vs_norm(obj_a, obj_b) ⇒ Object
Tests two particles where one is multisampled and the other is not. Let objectA be the multisampled particle.
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
# File 'lib/pongo/collision_detector.rb', line 41 def samp_vs_norm(obj_a, obj_b) return if norm_vs_norm(obj_a, obj_b) s = 1 / (obj_a.multisample + 1) t = s obj_a.multisample.times do obj_a.samp.set_to( obj_a.prev.x + t * (obj_a.curr.x - obj_a.prev.x), obj_a.prev.y + t * (obj_a.curr.y - obj_a.prev.y) ) if test_types(obj_a, obj_b) CollisionResolver.resolve(@cpa, @cpb, @coll_normal, @coll_depth) return end t += s end end |
.samp_vs_samp(obj_a, obj_b) ⇒ Object
Tests two particles where both are of equal multisample rate
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
# File 'lib/pongo/collision_detector.rb', line 60 def samp_vs_samp(obj_a, obj_b) return if norm_vs_norm(obj_a, obj_b) s = 1 / (obj_a.multisample + 1) t = s obj_a.multisample.times do obj_a.samp.set_to( obj_a.prev.x + t * (obj_a.curr.x - obj_a.prev.x), obj_a.prev.y + t * (obj_a.curr.y - obj_a.prev.y) ) obj_b.samp.set_to( obj_b.prev.x + t * (obj_b.curr.x - obj_b.prev.x), obj_b.prev.y + t * (obj_b.curr.y - obj_b.prev.y) ) if test_types(obj_a, obj_b) CollisionResolver.resolve(@cpa, @cpb, @coll_normal, @coll_depth) return end t += s end end |
.test(obj_a, obj_b) ⇒ Object
Tests the collision between two objects. This initial test determines the multisampling state of the two particles.
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
# File 'lib/pongo/collision_detector.rb', line 9 def test(obj_a, obj_b) return if obj_a == obj_b # TODO: added by ando return if obj_a.fixed? and obj_b.fixed? if obj_a.multisample == 0 and obj_b.multisample == 0 norm_vs_norm(obj_a, obj_b) elsif obj_a.multisample > 0 and obj_b.multisample == 0 samp_vs_norm(obj_a, obj_b) elsif obj_b.multisample > 0 and obj_a.multisample == 0 samp_vs_norm(obj_b, obj_a) elsif obj_a.multisample == obj_b.multisample samp_vs_samp(obj_a, obj_b) else norm_vs_norm(obj_a, obj_b) end end |
.test_circle_vs_circle(cir_a, cir_b) ⇒ Object
Tests the collision between two CircleParticles. If there is a collision it determines its axis and depth, and then passes it off to the CollisionResolver for handling.
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 |
# File 'lib/pongo/collision_detector.rb', line 173 def test_circle_vs_circle(cir_a, cir_b) depth_x = test_intervals(cir_a.interval_x, cir_b.interval_x) return false if depth_x == 0 depth_y = test_intervals(cir_a.interval_y, cir_b.interval_y) return false if depth_y == 0 @coll_normal = cir_a.samp - cir_b.samp mag = @coll_normal.magnitude @coll_depth = cir_a.radius + cir_b.radius - mag if @coll_depth > 0 @coll_normal.div!(mag) @cpa = cir_a @cpb = cir_b true else false end end |
.test_intervals(interval_a, interval_b) ⇒ Object
Returns 0 if intervals do not overlap. Returns smallest depth if they do.
195 196 197 198 199 200 201 202 203 |
# File 'lib/pongo/collision_detector.rb', line 195 def test_intervals(interval_a, interval_b) return 0 if interval_a.max < interval_b.min return 0 if interval_b.max < interval_a.min len_a = interval_b.max - interval_a.min len_b = interval_b.min - interval_a.max len_a.abs < len_b.abs ? len_a : len_b end |
.test_obb_vs_circle(rect_a, cir_a) ⇒ Object
Tests the collision between a RectangleParticle (aka an OBB) and a CircleParticle. If there is a collision it determines its axis and depth, and then passes it off to the CollisionResolver.
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
# File 'lib/pongo/collision_detector.rb', line 130 def test_obb_vs_circle(rect_a, cir_a) @coll_depth = Numeric::POSITIVE_INFINITY depths = [] # first go through the axes of the rectangle 2.times do |i| box_axis = rect_a.axes[i] depth = test_intervals(rect_a.projection(box_axis), cir_a.projection(box_axis)) return false if depth == 0 if depth.abs < @coll_depth.abs @coll_normal = box_axis @coll_depth = depth end depths[i] = depth end # determine if the circle's center is in a vertex region r = cir_a.radius if depths[0].abs < r and depths[1].abs < r vertex = closest_vertex_on_obb(cir_a.samp, rect_a) # get the distance from the closest vertex on rect to circle center @coll_normal = vertex - cir_a.samp mag = @coll_normal.magnitude @coll_depth = r - mag if @coll_depth > 0 # there is a collision in one of the vertex regions @coll_normal.div!(mag) else # rect_a is in vertex region, but is not colliding return false end end @cpa = rect_a @cpb = cir_a true end |
.test_obb_vs_obb(rect_a, rect_b) ⇒ Object
Tests the collision between two RectangleParticles (aka OBBs). If there is a collision it determines its axis and depth, and then passes it off to the CollisionResolver for handling.
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
# File 'lib/pongo/collision_detector.rb', line 101 def test_obb_vs_obb(rect_a, rect_b) @coll_depth = Numeric::POSITIVE_INFINITY 2.times do |i| axis_a = rect_a.axes[i] depth_a = test_intervals(rect_a.projection(axis_a), rect_b.projection(axis_a)) return false if depth_a == 0 axis_b = rect_b.axes[i] depth_b = test_intervals(rect_a.projection(axis_b), rect_b.projection(axis_b)) return false if depth_b == 0 abs_a = depth_a.abs abs_b = depth_b.abs if abs_a < @coll_depth.abs or abs_b < @coll_depth.abs altb = abs_a < abs_b @coll_normal = altb ? axis_a : axis_b @coll_depth = altb ? depth_a : depth_b end end @cpa = rect_a @cpb = rect_b true end |
.test_types(obj_a, obj_b) ⇒ Object
Tests collision based on primitive type.
84 85 86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/pongo/collision_detector.rb', line 84 def test_types(obj_a, obj_b) if obj_a.is_a?(RectangleParticle) and obj_b.is_a?(RectangleParticle) test_obb_vs_obb(obj_a, obj_b) elsif obj_a.is_a?(CircleParticle) and obj_b.is_a?(CircleParticle) test_circle_vs_circle(obj_a, obj_b) elsif obj_a.is_a?(RectangleParticle) and obj_b.is_a?(CircleParticle) test_obb_vs_circle(obj_a, obj_b) elsif obj_a.is_a?(CircleParticle) and obj_b.is_a?(RectangleParticle) test_obb_vs_circle(obj_b, obj_a) else false end end |