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/
This commit is contained in:
Stephen McQuay 2014-01-15 21:48:47 -08:00
parent 72d5a1a64c
commit 7971198c17
4 changed files with 156 additions and 30 deletions

View File

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

View File

@ -62,7 +62,9 @@ func (p *Projectile) Tick(g *game) {
collision, _, pos := v.RectIntersection(obj.Bounds, p.Position, travel) collision, _, pos := v.RectIntersection(obj.Bounds, p.Position, travel)
if collision { if collision {
arrived = true arrived = true
p.Position = pos if pos != nil {
p.Position = *pos
}
obj.Hp -= p.Damage obj.Hp -= p.Damage
// if obj.Hp < 0 { // if obj.Hp < 0 {
// delete(g.obstacles, i) // delete(g.obstacles, i)
@ -70,7 +72,9 @@ func (p *Projectile) Tick(g *game) {
} }
} }
} else { } else {
p.Position = pos if pos != nil {
p.Position = *pos
}
} }
if arrived || hit_player { if arrived || hit_player {

View File

@ -165,17 +165,28 @@ type Instruction struct {
Scan *bool `json:"scan,omitempty"` Scan *bool `json:"scan,omitempty"`
} }
func (r *Robot) checkCollisions(g *game, move_vector v.Vector2d) (bool, v.Point2d, *Robot) { // returns collision, the intersection point, and the robot with whom r has
// collided, if this happened.
func (r *Robot) checkCollisions(g *game, probe v.Vector2d) (bool, *v.Point2d, *Robot) {
finalCollision := false
collision := false collision := false
intersection_point := v.Point2d{X: 0, Y: 0} closest := float32(math.Inf(1))
bot_size := float32(5.0) var intersection *v.Point2d
bot_polygon := v.OrientedSquare(r.Position, r.Heading, bot_size) var finalRobot *Robot
// TODO: this needs moved to the conf?
botSize := float32(5.0)
botPolygon := v.OrientedSquare(r.Position, r.Heading, botSize)
// Check Walls // Check Walls
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}} r_walls := v.AABB2d{A: v.Point2d{X: botSize, Y: botSize}, B: v.Point2d{X: g.width - botSize, Y: g.height - botSize}}
collision, _, pos := v.RectIntersection(r_walls, r.Position, move_vector) collision, _, wallIntersect := v.RectIntersection(r_walls, r.Position, probe)
if collision { if collision && wallIntersect != nil {
return collision, pos, nil finalCollision = collision
if dist := r.Position.Sub(*wallIntersect).Mag(); dist < closest {
intersection = wallIntersect
closest = dist
}
} }
// Check Other Bots // Check Other Bots
@ -184,29 +195,47 @@ func (r *Robot) checkCollisions(g *game, move_vector v.Vector2d) (bool, v.Point2
if bot.Id == r.Id { if bot.Id == r.Id {
continue continue
} }
player_rect := v.OrientedSquare(bot.Position, bot.Heading, bot_size) player_rect := v.OrientedSquare(bot.Position, bot.Heading, botSize)
collision, move_collision, translation := v.PolyPolyIntersection( collision, move_collision, translation := v.PolyPolyIntersection(
bot_polygon, move_vector, player_rect) botPolygon, probe, player_rect)
if collision || move_collision { if collision || move_collision {
return true, r.Position.Add(move_vector).Add(translation.Scale(1.1)), bot finalCollision = collision
p := r.Position.Add(probe).Add(translation.Scale(1.2))
if dist := r.Position.Sub(p).Mag(); dist < closest {
intersection = &p
closest = dist
finalRobot = bot
}
}
}
}
// Check Obstacles
for _, obj := range g.obstacles {
// collision due to motion:
collision, move_collision, translation := v.PolyPolyIntersection(
botPolygon, probe, obj.Bounds.ToPolygon())
if collision || move_collision {
finalCollision = collision
p := r.Position.Add(probe).Add(translation.Scale(1.1))
if dist := r.Position.Sub(p).Mag(); dist < closest {
intersection = &p
closest = dist
}
}
// collision due to probe
collision, _, wallIntersect := v.RectIntersection(obj.Bounds, r.Position, probe)
if collision && wallIntersect != nil {
finalCollision = collision
if dist := r.Position.Sub(*wallIntersect).Mag(); dist < closest {
intersection = wallIntersect
closest = dist
} }
} }
} }
// Check Obstacles return finalCollision, intersection, finalRobot
for _, obj := range g.obstacles {
collision, move_collision, translation := v.PolyPolyIntersection(
bot_polygon, move_vector, obj.Bounds.ToPolygon())
if collision || move_collision {
// log.Printf(" COLLISION: %v %v %v\n", collision, move_collition, translation)
// log.Printf(" DETAILS: %v %v\n", r.Position, move_vector)
// log.Printf(" INPUT: %v %v %v\n", bot_polygon, obj.Bounds.ToPolygon(), obj.Bounds)
return true, r.Position.Add(move_vector).Add(translation.Scale(1.1)), nil
}
}
return collision, intersection_point, nil
} }
func (r *Robot) Tick(g *game) { func (r *Robot) Tick(g *game) {
@ -287,8 +316,8 @@ func (r *Robot) Tick(g *game) {
} }
} }
if r.Position != intersection_point { if r.Position != *intersection_point {
r.Position = intersection_point r.Position = *intersection_point
} }
r.Health -= dmg r.Health -= dmg
@ -343,7 +372,7 @@ func (r *Robot) Tick(g *game) {
probe_vector := r.Probe.Sub(r.Position) probe_vector := r.Probe.Sub(r.Position)
coll, pos, _ := r.checkCollisions(g, probe_vector) coll, pos, _ := r.checkCollisions(g, probe_vector)
if coll { if coll {
r.ProbeResult = &pos r.ProbeResult = pos
} }
} }
} }

91
robot_test.go Normal file
View File

@ -0,0 +1,91 @@
package main
import (
v "bitbucket.org/hackerbots/vector"
"math"
"testing"
)
func TestCollision(t *testing.T) {
tests := []struct {
g game
r Robot
target v.Vector2d
location *v.Point2d
collision bool
}{
// should intersect with first box
{
g: game{
width: 800,
height: 400,
obstacles: []Obstacle{
Obstacle{
Bounds: v.AABB2d{
v.Point2d{200, 100},
v.Point2d{300, 200},
},
},
Obstacle{
Bounds: v.AABB2d{
v.Point2d{400, 200},
v.Point2d{600, 300},
},
},
},
},
r: Robot{
Position: v.Point2d{100, 100},
// Heading: v.Vector2d{1, 1},
},
target: v.Vector2d{900, 350},
location: &v.Point2d{200, 138.88889},
collision: true,
},
// shouldn't intersect at all
{
g: game{
width: 800,
height: 400,
obstacles: []Obstacle{
Obstacle{
Bounds: v.AABB2d{
v.Point2d{200, 100},
v.Point2d{300, 200},
},
},
},
},
r: Robot{
Position: v.Point2d{100, 100},
},
target: v.Vector2d{0, 0},
collision: false,
},
}
for _, test := range tests {
collision, location, _ := test.r.checkCollisions(&test.g, test.target)
if collision != test.collision {
t.Errorf("expected: %t, actual: %t", test.collision, collision)
}
if test.location == nil {
if location != nil {
t.Errorf("expected: %+v, actual: %+v", test.location, location)
}
}
if test.location != nil {
if location == nil {
t.Errorf("expected: %+v, actual: %+v", test.location, location)
} else {
if math.Abs(float64(location.X-test.location.X)) > 1e-4 || math.Abs(float64(location.Y-test.location.Y)) > 1e-4 {
t.Errorf("expected: %+v, actual: %+v", test.location, location)
}
}
}
}
}
// XXX
func TestBotBotCollisions(t *testing.T) {
t.Skip("NYI")
}