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:
parent
72d5a1a64c
commit
7971198c17
2
game.go
2
game.go
@ -1,5 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
|
// delete me
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
"sort"
|
"sort"
|
||||||
|
@ -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 {
|
||||||
|
71
robot.go
71
robot.go
@ -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
|
// Check Obstacles
|
||||||
for _, obj := range g.obstacles {
|
for _, obj := range g.obstacles {
|
||||||
|
// collision due to motion:
|
||||||
collision, move_collision, translation := v.PolyPolyIntersection(
|
collision, move_collision, translation := v.PolyPolyIntersection(
|
||||||
bot_polygon, move_vector, obj.Bounds.ToPolygon())
|
botPolygon, probe, obj.Bounds.ToPolygon())
|
||||||
|
|
||||||
if collision || move_collision {
|
if collision || move_collision {
|
||||||
// log.Printf(" COLLISION: %v %v %v\n", collision, move_collition, translation)
|
finalCollision = collision
|
||||||
// log.Printf(" DETAILS: %v %v\n", r.Position, move_vector)
|
p := r.Position.Add(probe).Add(translation.Scale(1.1))
|
||||||
// log.Printf(" INPUT: %v %v %v\n", bot_polygon, obj.Bounds.ToPolygon(), obj.Bounds)
|
if dist := r.Position.Sub(p).Mag(); dist < closest {
|
||||||
return true, r.Position.Add(move_vector).Add(translation.Scale(1.1)), nil
|
intersection = &p
|
||||||
|
closest = dist
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return collision, intersection_point, nil
|
// 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return finalCollision, intersection, finalRobot
|
||||||
}
|
}
|
||||||
|
|
||||||
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
91
robot_test.go
Normal 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")
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user