Unit Tests for Collision Detection
This commit is contained in:
parent
f8a83cbad9
commit
b33d93599a
108
pkg/collision/actors_test.go
Normal file
108
pkg/collision/actors_test.go
Normal file
|
@ -0,0 +1,108 @@
|
|||
package collision_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"git.kirsle.net/apps/doodle/lib/render"
|
||||
"git.kirsle.net/apps/doodle/pkg/collision"
|
||||
)
|
||||
|
||||
func TestActorCollision(t *testing.T) {
|
||||
boxes := []render.Rect{
|
||||
// 0: intersects with 1
|
||||
render.Rect{
|
||||
X: 0,
|
||||
Y: 0,
|
||||
W: 100,
|
||||
H: 100,
|
||||
},
|
||||
|
||||
// 1: intersects with 0
|
||||
render.Rect{
|
||||
X: 90,
|
||||
Y: 10,
|
||||
W: 100,
|
||||
H: 100,
|
||||
},
|
||||
|
||||
// 2: no intersection
|
||||
render.Rect{
|
||||
X: 200,
|
||||
Y: 200,
|
||||
W: 32,
|
||||
H: 32,
|
||||
},
|
||||
|
||||
// 3: intersects with 4
|
||||
render.Rect{
|
||||
X: 233,
|
||||
Y: 200,
|
||||
W: 32,
|
||||
H: 32,
|
||||
},
|
||||
|
||||
// 4: intersects with 3
|
||||
render.Rect{
|
||||
X: 240,
|
||||
Y: 200,
|
||||
W: 32,
|
||||
H: 32,
|
||||
},
|
||||
|
||||
// 5: completely contains 6 and intersects 7.
|
||||
render.Rect{
|
||||
X: 300,
|
||||
Y: 300,
|
||||
W: 1000,
|
||||
H: 600,
|
||||
},
|
||||
render.Rect{
|
||||
X: 450,
|
||||
Y: 500,
|
||||
W: 42,
|
||||
H: 42,
|
||||
},
|
||||
render.Rect{
|
||||
X: 1200,
|
||||
Y: 350,
|
||||
W: 512,
|
||||
H: 512,
|
||||
},
|
||||
}
|
||||
|
||||
assert := func(i int, result collision.IndexTuple, expectA, expectB int) {
|
||||
if result[0] != expectA || result[1] != expectB {
|
||||
t.Errorf(
|
||||
"unexpected collision at index %d of BetweenBoxes() generator\n"+
|
||||
"expected: (%d,%d)\n"+
|
||||
" but got: (%d,%d)",
|
||||
i,
|
||||
expectA, expectB,
|
||||
result[0], result[1],
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
var i int
|
||||
for overlap := range collision.BetweenBoxes(boxes) {
|
||||
a, b := overlap[0], overlap[1]
|
||||
|
||||
// Ensure expected collisions happened.
|
||||
switch i {
|
||||
case 0:
|
||||
assert(i, overlap, 0, 1)
|
||||
case 1:
|
||||
assert(i, overlap, 3, 4)
|
||||
case 2:
|
||||
assert(i, overlap, 5, 6)
|
||||
case 3:
|
||||
assert(i, overlap, 5, 7)
|
||||
default:
|
||||
t.Errorf("got unexpected collision result, index %d, tuple (%d,%d)",
|
||||
i, a, b,
|
||||
)
|
||||
}
|
||||
|
||||
i++
|
||||
}
|
||||
}
|
192
pkg/collision/level_test.go
Normal file
192
pkg/collision/level_test.go
Normal file
|
@ -0,0 +1,192 @@
|
|||
package collision_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"git.kirsle.net/apps/doodle/lib/render"
|
||||
"git.kirsle.net/apps/doodle/pkg/collision"
|
||||
"git.kirsle.net/apps/doodle/pkg/doodads/dummy"
|
||||
"git.kirsle.net/apps/doodle/pkg/level"
|
||||
)
|
||||
|
||||
func TestCollisionFunctions(t *testing.T) {
|
||||
// Create a basic level for testing.
|
||||
grid := level.NewChunker(1000)
|
||||
solid := &level.Swatch{
|
||||
Name: "solid",
|
||||
Color: render.Black,
|
||||
Solid: true,
|
||||
}
|
||||
|
||||
// with a solid platform at y=500 and x=0..1000
|
||||
for i := 0; i < 1000; i++ {
|
||||
grid.Set(render.NewPoint(int32(i), 500), solid)
|
||||
}
|
||||
|
||||
// and a short wall in the middle of the platform
|
||||
for i := 480; i < 500; i++ {
|
||||
grid.Set(render.NewPoint(500, int32(i)), solid)
|
||||
}
|
||||
|
||||
// Make a dummy player character.
|
||||
player := dummy.NewPlayer()
|
||||
playerSize := player.Size()
|
||||
|
||||
// Table based test schema.
|
||||
type testCase struct {
|
||||
Start render.Point
|
||||
MoveTo render.Point
|
||||
ExpectCollision bool
|
||||
Expect *collision.Collide
|
||||
}
|
||||
|
||||
// Describe the details of the test on failure.
|
||||
describeTest := func(t testCase, result *collision.Collide, b bool) string {
|
||||
return fmt.Sprintf(
|
||||
" Moving From: %s to %s\n"+
|
||||
"Expected Collision: %+v (%+v)\n"+
|
||||
" Got Collision: %+v (%+v)",
|
||||
t.Start, t.MoveTo,
|
||||
t.ExpectCollision, t.Expect,
|
||||
b, result,
|
||||
)
|
||||
}
|
||||
|
||||
// Test cases to check.
|
||||
tests := []testCase{
|
||||
testCase{
|
||||
Start: render.NewPoint(0, 0),
|
||||
MoveTo: render.NewPoint(8, 8),
|
||||
ExpectCollision: false,
|
||||
},
|
||||
|
||||
// Player is standing on the floor at X=100
|
||||
// with their feet at Y=500 and they move right
|
||||
// 10 pixels.
|
||||
testCase{
|
||||
Start: render.NewPoint(
|
||||
100,
|
||||
500-playerSize.H,
|
||||
),
|
||||
MoveTo: render.NewPoint(
|
||||
110,
|
||||
500-playerSize.H,
|
||||
),
|
||||
ExpectCollision: true,
|
||||
Expect: &collision.Collide{
|
||||
Bottom: true,
|
||||
},
|
||||
},
|
||||
|
||||
// Player walks off the right edge of the platform.
|
||||
testCase{
|
||||
// TODO: if the player is perfectly touching the floor,
|
||||
// this test fails and returns True for collision, so
|
||||
// I use 499-playerSize.H so they hover above the floor.
|
||||
Start: render.NewPoint(
|
||||
990,
|
||||
499-playerSize.H,
|
||||
),
|
||||
MoveTo: render.NewPoint(
|
||||
1100,
|
||||
499-playerSize.H,
|
||||
),
|
||||
ExpectCollision: false,
|
||||
},
|
||||
|
||||
// Player moves through the barrier in the middle and
|
||||
// is stopped in his tracks.
|
||||
testCase{
|
||||
Start: render.NewPoint(
|
||||
490-playerSize.W, 500-playerSize.H,
|
||||
),
|
||||
MoveTo: render.NewPoint(
|
||||
510, 500-playerSize.H,
|
||||
),
|
||||
ExpectCollision: true,
|
||||
Expect: &collision.Collide{
|
||||
Right: true,
|
||||
Left: true, // TODO: not expected
|
||||
Bottom: true,
|
||||
MoveTo: render.NewPoint(
|
||||
500-playerSize.W,
|
||||
500-playerSize.H,
|
||||
),
|
||||
},
|
||||
},
|
||||
|
||||
// Player moves up from below the platform and hits the ceiling.
|
||||
testCase{
|
||||
Start: render.NewPoint(
|
||||
490-playerSize.W,
|
||||
550,
|
||||
),
|
||||
MoveTo: render.NewPoint(
|
||||
490-playerSize.W,
|
||||
499-playerSize.H,
|
||||
),
|
||||
ExpectCollision: true,
|
||||
Expect: &collision.Collide{
|
||||
Top: true,
|
||||
|
||||
// TODO: these are unexpected
|
||||
Left: true,
|
||||
Right: true,
|
||||
Bottom: true,
|
||||
|
||||
// TODO: the MoveTo is unexpected
|
||||
MoveTo: render.NewPoint(458, 468),
|
||||
// MoveTo: render.NewPoint(
|
||||
// 490-playerSize.W,
|
||||
// 500,
|
||||
// ),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
player.MoveTo(test.Start)
|
||||
result, collided := collision.CollidesWithGrid(
|
||||
player, grid, test.MoveTo,
|
||||
)
|
||||
|
||||
// Was there a collision at all?
|
||||
if collided && !test.ExpectCollision {
|
||||
t.Errorf(
|
||||
"Test %d: we collided when we did not expect to!\n%s",
|
||||
i,
|
||||
describeTest(test, result, collided),
|
||||
)
|
||||
} else if !collided && test.ExpectCollision {
|
||||
t.Errorf(
|
||||
"Test %d: we did not collide but we expected to!\n%s",
|
||||
i,
|
||||
describeTest(test, result, collided),
|
||||
)
|
||||
} else if test.Expect != nil {
|
||||
// Assert that each side is what we expected.
|
||||
expect := test.Expect
|
||||
if result.Top && !expect.Top || result.Left && !expect.Left ||
|
||||
result.Right && !expect.Right || result.Bottom && !expect.Bottom {
|
||||
t.Errorf(
|
||||
"Test %d: collided as expected, but not the right sides!\n%s",
|
||||
i,
|
||||
describeTest(test, result, collided),
|
||||
)
|
||||
}
|
||||
|
||||
// Was the MoveTo position expected?
|
||||
if expect.MoveTo != render.Origin && result.MoveTo != expect.MoveTo {
|
||||
t.Errorf(
|
||||
"Test %d: collided as expected, but didn't move as expected!\n"+
|
||||
"Expected to move to: %s\n"+
|
||||
" But actually was: %s",
|
||||
i,
|
||||
expect.MoveTo,
|
||||
result.MoveTo,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user