Browse Source

Fixed collision detection in probes

This was a problem before when the probe hit an object that was further than
another object first. Now we traverse all objects all the time to find the
closest one. \o/
Stephen McQuay 5 years ago
parent
commit
7971198c17
4 changed files with 149 additions and 23 deletions
  1. 2
    0
      game.go
  2. 6
    2
      projectile.go
  3. 50
    21
      robot.go
  4. 91
    0
      robot_test.go

+ 2
- 0
game.go View File

@@ -1,5 +1,7 @@
1 1
 package main
2 2
 
3
+// delete me
4
+
3 5
 import (
4 6
 	"log"
5 7
 	"sort"

+ 6
- 2
projectile.go View File

@@ -62,7 +62,9 @@ func (p *Projectile) Tick(g *game) {
62 62
 			collision, _, pos := v.RectIntersection(obj.Bounds, p.Position, travel)
63 63
 			if collision {
64 64
 				arrived = true
65
-				p.Position = pos
65
+				if pos != nil {
66
+					p.Position = *pos
67
+				}
66 68
 				obj.Hp -= p.Damage
67 69
 				// if obj.Hp < 0 {
68 70
 				// 	delete(g.obstacles, i)
@@ -70,7 +72,9 @@ func (p *Projectile) Tick(g *game) {
70 72
 			}
71 73
 		}
72 74
 	} else {
73
-		p.Position = pos
75
+		if pos != nil {
76
+			p.Position = *pos
77
+		}
74 78
 	}
75 79
 
76 80
 	if arrived || hit_player {

+ 50
- 21
robot.go View File

@@ -165,17 +165,28 @@ type Instruction struct {
165 165
 	Scan        *bool       `json:"scan,omitempty"`
166 166
 }
167 167
 
168
-func (r *Robot) checkCollisions(g *game, move_vector v.Vector2d) (bool, v.Point2d, *Robot) {
168
+// returns collision, the intersection point, and the robot with whom r has
169
+// collided, if this happened.
170
+func (r *Robot) checkCollisions(g *game, probe v.Vector2d) (bool, *v.Point2d, *Robot) {
171
+	finalCollision := false
169 172
 	collision := false
170
-	intersection_point := v.Point2d{X: 0, Y: 0}
171
-	bot_size := float32(5.0)
172
-	bot_polygon := v.OrientedSquare(r.Position, r.Heading, bot_size)
173
+	closest := float32(math.Inf(1))
174
+	var intersection *v.Point2d
175
+	var finalRobot *Robot
176
+
177
+	// TODO: this needs moved to the conf?
178
+	botSize := float32(5.0)
179
+	botPolygon := v.OrientedSquare(r.Position, r.Heading, botSize)
173 180
 
174 181
 	// Check Walls
175
-	r_walls := v.AABB2d{A: v.Point2d{X: bot_size, Y: bot_size}, B: v.Point2d{X: g.width - bot_size, Y: g.height - bot_size}}
176
-	collision, _, pos := v.RectIntersection(r_walls, r.Position, move_vector)
177
-	if collision {
178
-		return collision, pos, nil
182
+	r_walls := v.AABB2d{A: v.Point2d{X: botSize, Y: botSize}, B: v.Point2d{X: g.width - botSize, Y: g.height - botSize}}
183
+	collision, _, wallIntersect := v.RectIntersection(r_walls, r.Position, probe)
184
+	if collision && wallIntersect != nil {
185
+		finalCollision = collision
186
+		if dist := r.Position.Sub(*wallIntersect).Mag(); dist < closest {
187
+			intersection = wallIntersect
188
+			closest = dist
189
+		}
179 190
 	}
180 191
 
181 192
 	// Check Other Bots
@@ -184,29 +195,47 @@ func (r *Robot) checkCollisions(g *game, move_vector v.Vector2d) (bool, v.Point2
184 195
 			if bot.Id == r.Id {
185 196
 				continue
186 197
 			}
187
-			player_rect := v.OrientedSquare(bot.Position, bot.Heading, bot_size)
198
+			player_rect := v.OrientedSquare(bot.Position, bot.Heading, botSize)
188 199
 			collision, move_collision, translation := v.PolyPolyIntersection(
189
-				bot_polygon, move_vector, player_rect)
200
+				botPolygon, probe, player_rect)
190 201
 			if collision || move_collision {
191
-				return true, r.Position.Add(move_vector).Add(translation.Scale(1.1)), bot
202
+				finalCollision = collision
203
+				p := r.Position.Add(probe).Add(translation.Scale(1.2))
204
+				if dist := r.Position.Sub(p).Mag(); dist < closest {
205
+					intersection = &p
206
+					closest = dist
207
+					finalRobot = bot
208
+				}
192 209
 			}
193 210
 		}
194 211
 	}
195
-
196 212
 	// Check Obstacles
197 213
 	for _, obj := range g.obstacles {
214
+		// collision due to motion:
198 215
 		collision, move_collision, translation := v.PolyPolyIntersection(
199
-			bot_polygon, move_vector, obj.Bounds.ToPolygon())
216
+			botPolygon, probe, obj.Bounds.ToPolygon())
200 217
 
201 218
 		if collision || move_collision {
202
-			// log.Printf(" COLLISION: %v %v %v\n", collision, move_collition, translation)
203
-			// log.Printf(" DETAILS: %v %v\n", r.Position, move_vector)
204
-			// log.Printf(" INPUT: %v %v %v\n", bot_polygon, obj.Bounds.ToPolygon(), obj.Bounds)
205
-			return true, r.Position.Add(move_vector).Add(translation.Scale(1.1)), nil
219
+			finalCollision = collision
220
+			p := r.Position.Add(probe).Add(translation.Scale(1.1))
221
+			if dist := r.Position.Sub(p).Mag(); dist < closest {
222
+				intersection = &p
223
+				closest = dist
224
+			}
225
+		}
226
+
227
+		// collision due to probe
228
+		collision, _, wallIntersect := v.RectIntersection(obj.Bounds, r.Position, probe)
229
+		if collision && wallIntersect != nil {
230
+			finalCollision = collision
231
+			if dist := r.Position.Sub(*wallIntersect).Mag(); dist < closest {
232
+				intersection = wallIntersect
233
+				closest = dist
234
+			}
206 235
 		}
207 236
 	}
208 237
 
209
-	return collision, intersection_point, nil
238
+	return finalCollision, intersection, finalRobot
210 239
 }
211 240
 
212 241
 func (r *Robot) Tick(g *game) {
@@ -287,8 +316,8 @@ func (r *Robot) Tick(g *game) {
287 316
 				}
288 317
 			}
289 318
 
290
-			if r.Position != intersection_point {
291
-				r.Position = intersection_point
319
+			if r.Position != *intersection_point {
320
+				r.Position = *intersection_point
292 321
 			}
293 322
 
294 323
 			r.Health -= dmg
@@ -343,7 +372,7 @@ func (r *Robot) Tick(g *game) {
343 372
 		probe_vector := r.Probe.Sub(r.Position)
344 373
 		coll, pos, _ := r.checkCollisions(g, probe_vector)
345 374
 		if coll {
346
-			r.ProbeResult = &pos
375
+			r.ProbeResult = pos
347 376
 		}
348 377
 	}
349 378
 }

+ 91
- 0
robot_test.go View File

@@ -0,0 +1,91 @@
1
+package main
2
+
3
+import (
4
+	v "bitbucket.org/hackerbots/vector"
5
+	"math"
6
+	"testing"
7
+)
8
+
9
+func TestCollision(t *testing.T) {
10
+	tests := []struct {
11
+		g         game
12
+		r         Robot
13
+		target    v.Vector2d
14
+		location  *v.Point2d
15
+		collision bool
16
+	}{
17
+		// should intersect with first box
18
+		{
19
+			g: game{
20
+				width:  800,
21
+				height: 400,
22
+				obstacles: []Obstacle{
23
+					Obstacle{
24
+						Bounds: v.AABB2d{
25
+							v.Point2d{200, 100},
26
+							v.Point2d{300, 200},
27
+						},
28
+					},
29
+					Obstacle{
30
+						Bounds: v.AABB2d{
31
+							v.Point2d{400, 200},
32
+							v.Point2d{600, 300},
33
+						},
34
+					},
35
+				},
36
+			},
37
+			r: Robot{
38
+				Position: v.Point2d{100, 100},
39
+				// Heading:  v.Vector2d{1, 1},
40
+			},
41
+			target:    v.Vector2d{900, 350},
42
+			location:  &v.Point2d{200, 138.88889},
43
+			collision: true,
44
+		},
45
+		// shouldn't intersect at all
46
+		{
47
+			g: game{
48
+				width:  800,
49
+				height: 400,
50
+				obstacles: []Obstacle{
51
+					Obstacle{
52
+						Bounds: v.AABB2d{
53
+							v.Point2d{200, 100},
54
+							v.Point2d{300, 200},
55
+						},
56
+					},
57
+				},
58
+			},
59
+			r: Robot{
60
+				Position: v.Point2d{100, 100},
61
+			},
62
+			target:    v.Vector2d{0, 0},
63
+			collision: false,
64
+		},
65
+	}
66
+	for _, test := range tests {
67
+		collision, location, _ := test.r.checkCollisions(&test.g, test.target)
68
+		if collision != test.collision {
69
+			t.Errorf("expected: %t, actual: %t", test.collision, collision)
70
+		}
71
+		if test.location == nil {
72
+			if location != nil {
73
+				t.Errorf("expected: %+v, actual: %+v", test.location, location)
74
+			}
75
+		}
76
+		if test.location != nil {
77
+			if location == nil {
78
+				t.Errorf("expected: %+v, actual: %+v", test.location, location)
79
+			} else {
80
+				if math.Abs(float64(location.X-test.location.X)) > 1e-4 || math.Abs(float64(location.Y-test.location.Y)) > 1e-4 {
81
+					t.Errorf("expected: %+v, actual: %+v", test.location, location)
82
+				}
83
+			}
84
+		}
85
+	}
86
+}
87
+
88
+// XXX
89
+func TestBotBotCollisions(t *testing.T) {
90
+	t.Skip("NYI")
91
+}

Loading…
Cancel
Save