137 lines
3.2 KiB
Go
137 lines
3.2 KiB
Go
package world
|
|
|
|
import (
|
|
"slices"
|
|
"testing"
|
|
)
|
|
|
|
func countKind(evs []ContactEvent, k EventKind) int {
|
|
n := 0
|
|
for _, e := range evs {
|
|
if e.Kind == k {
|
|
n++
|
|
}
|
|
}
|
|
return n
|
|
}
|
|
|
|
func dropBox(t *testing.T) (*World, BodyHandle, ShapeHandle, int) {
|
|
w := newTestWorld(t, nil)
|
|
groundBox(t, w, nil)
|
|
b, s := addDynamic(t, w, Vec2{Y: -2}, 0, Box{Half: Vec2{X: 0.5, Y: 0.5}}, nil)
|
|
begins := 0
|
|
for i := 0; i < 120; i++ {
|
|
w.Step(dt)
|
|
evs := w.Events().Contacts
|
|
begins += countKind(evs, BeginContact)
|
|
if countKind(evs, EndContact) > 0 {
|
|
t.Fatalf("step %d: unexpected end", i)
|
|
}
|
|
}
|
|
return w, b, s, begins
|
|
}
|
|
|
|
func TestBeginOncePerPair(t *testing.T) {
|
|
_, _, _, begins := dropBox(t)
|
|
if begins != 1 {
|
|
t.Fatalf("got %d begin events", begins)
|
|
}
|
|
}
|
|
|
|
func TestEndOnSeparation(t *testing.T) {
|
|
w, b, _, _ := dropBox(t)
|
|
noErr(t, w.SetBodyTransform(b, Vec2{Y: -20}, 0))
|
|
w.Step(dt)
|
|
if countKind(w.Events().Contacts, EndContact) != 1 {
|
|
t.Fatalf("events %+v", w.Events().Contacts)
|
|
}
|
|
}
|
|
|
|
func TestEndOnRemoveShapeSameStep(t *testing.T) {
|
|
w, _, s, _ := dropBox(t)
|
|
noErr(t, w.RemoveShape(s))
|
|
if w.Alive(s) {
|
|
t.Fatal("removed shape is alive")
|
|
}
|
|
w.Step(dt)
|
|
evs := w.Events().Contacts
|
|
if countKind(evs, EndContact) != 1 || (evs[0].ShapeA != s && evs[0].ShapeB != s) {
|
|
t.Fatalf("events %+v", evs)
|
|
}
|
|
if w.Alive(s) {
|
|
t.Fatal("removed shape came back")
|
|
}
|
|
}
|
|
|
|
func TestEndOnDestroyBody(t *testing.T) {
|
|
w, b, _, _ := dropBox(t)
|
|
noErr(t, w.DestroyBody(b))
|
|
w.Step(dt)
|
|
if countKind(w.Events().Contacts, EndContact) != 1 {
|
|
t.Fatalf("events %+v", w.Events().Contacts)
|
|
}
|
|
}
|
|
|
|
func TestEndOnTriggerChange(t *testing.T) {
|
|
w, _, s, _ := dropBox(t)
|
|
sd := DefaultShapeDef(Box{Half: Vec2{X: 0.5, Y: 0.5}})
|
|
sd.IsTrigger = true
|
|
noErr(t, w.SetShape(s, sd))
|
|
w.Step(dt)
|
|
evs := w.Events().Contacts
|
|
if countKind(evs, EndContact) != 1 {
|
|
t.Fatalf("events %+v", evs)
|
|
}
|
|
}
|
|
|
|
func TestEndOnFilterChange(t *testing.T) {
|
|
w, b, _, _ := dropBox(t)
|
|
noErr(t, w.SetBodyFilter(b, 0, 0))
|
|
w.Step(dt)
|
|
if countKind(w.Events().Contacts, EndContact) != 1 {
|
|
t.Fatalf("events %+v", w.Events().Contacts)
|
|
}
|
|
}
|
|
|
|
func TestTriggersDoNotCollide(t *testing.T) {
|
|
w := newTestWorld(t, nil)
|
|
zone := addStatic(t, w, Vec2{Y: -5}, 0, Box{Half: Vec2{X: 2, Y: 0.5}}, func(s *ShapeDef) { s.IsTrigger = true })
|
|
ball, _ := addDynamic(t, w, Vec2{Y: -8}, 0, Circle{R: 0.3}, nil)
|
|
var kinds []EventKind
|
|
for i := 0; i < 120; i++ {
|
|
w.Step(dt)
|
|
for _, e := range w.Events().Contacts {
|
|
if e.BodyA == zone || e.BodyB == zone {
|
|
kinds = append(kinds, e.Kind)
|
|
}
|
|
}
|
|
}
|
|
if !slices.Equal(kinds, []EventKind{BeginTrigger, EndTrigger}) {
|
|
t.Fatalf("trigger events %v", kinds)
|
|
}
|
|
if p := posOf(w, ball); p.Y < -4 {
|
|
t.Fatalf("ball stopped at %v", p)
|
|
}
|
|
}
|
|
|
|
func eventLog(t *testing.T) []ContactEvent {
|
|
w := newTestWorld(t, nil)
|
|
groundBox(t, w, nil)
|
|
for i := 0; i < 20; i++ {
|
|
addDynamic(t, w, Vec2{X: float32(i%5) * 0.6, Y: -1 - float32(i)}, float32(i)*0.1, Box{Half: Vec2{X: 0.25, Y: 0.25}}, nil)
|
|
}
|
|
var out []ContactEvent
|
|
for i := 0; i < 240; i++ {
|
|
w.Step(dt)
|
|
out = append(out, w.Events().Contacts...)
|
|
}
|
|
return out
|
|
}
|
|
|
|
func TestEventOrderIsDeterministic(t *testing.T) {
|
|
a, b := eventLog(t), eventLog(t)
|
|
if len(a) == 0 || !slices.Equal(a, b) {
|
|
t.Fatalf("event logs differ: %d vs %d", len(a), len(b))
|
|
}
|
|
}
|