You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
108 lines
2.6 KiB
108 lines
2.6 KiB
package gohan |
|
|
|
import ( |
|
"math" |
|
"testing" |
|
|
|
"github.com/hajimehoshi/ebiten/v2" |
|
) |
|
|
|
type movementSystem struct { |
|
positionComponentID ComponentID |
|
velocityComponentID ComponentID |
|
} |
|
|
|
func (s *movementSystem) Components() []ComponentID { |
|
return []ComponentID{ |
|
s.positionComponentID, |
|
s.velocityComponentID, |
|
} |
|
} |
|
|
|
func (s *movementSystem) Update(ctx *Context) error { |
|
position := ctx.Component(s.positionComponentID).(*positionComponent) |
|
velocity := ctx.Component(s.velocityComponentID).(*velocityComponent) |
|
|
|
position.X, position.Y = position.X+velocity.X, position.Y+velocity.Y |
|
return nil |
|
} |
|
|
|
func (s *movementSystem) Draw(ctx *Context, screen *ebiten.Image) error { |
|
return nil |
|
} |
|
|
|
func TestWorld(t *testing.T) { |
|
const iterations = 1024 |
|
|
|
w, e, positionComponentID, velocityComponentID := newTestWorld() |
|
|
|
position := w.Component(e, positionComponentID).(*positionComponent) |
|
velocity := w.Component(e, velocityComponentID).(*velocityComponent) |
|
|
|
expectedX, expectedY := position.X+(velocity.X*iterations), position.Y+(velocity.Y*iterations) |
|
|
|
for i := 0; i < iterations; i++ { |
|
err := w.Update() |
|
if err != nil { |
|
t.Fatal(err) |
|
} |
|
} |
|
|
|
// Fetch component again to ensure consistency. |
|
position = w.Component(e, positionComponentID).(*positionComponent) |
|
if round(position.X) != round(expectedX) || round(position.Y) != round(expectedY) { |
|
t.Errorf("failed to update system: expected position (%f,%f), got (%f,%f)", expectedX, expectedY, position.X, position.Y) |
|
} |
|
} |
|
|
|
func BenchmarkUpdateWorld(b *testing.B) { |
|
w, _, _, _ := newTestWorld() |
|
|
|
b.StopTimer() |
|
b.ResetTimer() |
|
b.ReportAllocs() |
|
b.StartTimer() |
|
|
|
for i := 0; i < b.N; i++ { |
|
err := w.Update() |
|
if err != nil { |
|
b.Fatal(err) |
|
} |
|
} |
|
} |
|
|
|
func newTestWorld() (w *World, e Entity, positionComponentID ComponentID, velocityComponentID ComponentID) { |
|
w = NewWorld() |
|
|
|
e = w.NewEntity() |
|
|
|
positionComponentID = w.NewComponentID() |
|
position := &positionComponent{ |
|
componentID: positionComponentID, |
|
X: 108, |
|
Y: 0, |
|
} |
|
w.AddComponent(e, position) |
|
|
|
velocityComponentID = w.NewComponentID() |
|
velocity := &velocityComponent{ |
|
componentID: velocityComponentID, |
|
X: -0.1, |
|
Y: 0.2, |
|
} |
|
w.AddComponent(e, velocity) |
|
|
|
movement := &movementSystem{ |
|
positionComponentID: positionComponentID, |
|
velocityComponentID: velocityComponentID, |
|
} |
|
w.AddSystem(movement) |
|
|
|
return w, e, positionComponentID, velocityComponentID |
|
} |
|
|
|
// Round values to eliminate floating point precision errors. This is only |
|
// necessary during testing because we validate the final values. |
|
func round(f float64) float64 { |
|
return math.Round(f*10) / 10 |
|
}
|
|
|