doodle/pkg/collision/level_test.go

193 lines
4.4 KiB
Go

package collision_test
import (
"fmt"
"testing"
"git.kirsle.net/go/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,
)
}
}
}
}