Files
aego/tests/integration/topdown_test.go

131 lines
2.8 KiB
Go

package integration
import (
"testing"
"aego/app/run"
"aego/core/mathx"
"aego/modules/gameplay"
"aego/modules/input"
"aego/scene"
)
type topdown struct {
t *testing.T
app *run.App
in *input.Service
hero scene.NodeHandle
axes [3]float32
}
func openTopdown(t *testing.T) *topdown {
t.Helper()
app := openAt(t, copyExample(t, "topdown"))
sc := app.Scene
td := &topdown{t: t, app: app, hero: sc.Find(sc.Root(), "Hero")}
td.in = input.Of(app.Engine.MainWorld())
if td.in == nil || td.hero.IsZero() {
t.Fatal("the top-down example has no input service or no Hero")
}
return td
}
func (td *topdown) set(i int, name string, v float32) {
if td.axes[i] != v {
td.axes[i] = v
if err := td.in.Inject(0, name, v); err != nil {
td.t.Fatal(err)
}
}
}
// walk steers the hero towards a point with the move axes.
func (td *topdown) walk(to mathx.Vec2) float32 {
d := to.Sub(td.app.Scene.WorldPosition(td.hero))
l := d.Len()
if l > 0.15 {
d = d.Scale(1 / l)
} else {
d = mathx.Vec2{}
}
td.set(0, "MoveX", d.X)
td.set(1, "MoveY", d.Y)
return l
}
func (td *topdown) step() {
td.app.Engine.Step(td.app.Driver())
}
type topdownRun struct {
damaged, chased, patrolAgain bool
stats gameplay.Stats
hash uint64
}
func driveTopdown(t *testing.T) topdownRun {
td := openTopdown(t)
sc := td.app.Scene
grunt := sc.Find(sc.Root(), "GruntC")
coin := sc.WorldPosition(sc.Find(sc.Root(), "Coin1"))
svc := gameplay.Of(td.app.Engine.MainWorld())
var res topdownRun
phase := 0
for i := 0; i < 600; i++ {
fsm, _ := scene.Get[gameplay.StateMachine](sc, grunt)
hp, _ := scene.Get[gameplay.Health](sc, grunt)
if fsm != nil && fsm.Current == "Chase" {
res.chased = true
}
if hp != nil && hp.Current > 0 && hp.Current < hp.Max || !sc.IsAlive(grunt) {
res.damaged = true
}
switch phase {
case 0:
if td.walk(coin) < 0.2 || svc.Stats().Pickups > 0 {
phase = 1
}
case 1:
if td.walk(mathx.Vec2{X: -7, Y: 1}) < 0.3 {
phase = 2
}
case 2:
if !sc.IsAlive(grunt) || res.damaged {
phase = 3
break
}
if td.walk(sc.WorldPosition(grunt)) < 1.3 {
td.set(2, "Attack", float32(i/10%2))
}
case 3:
td.set(2, "Attack", 0)
td.walk(mathx.Vec2{X: -10, Y: -5})
if res.chased && fsm != nil && fsm.Current == "Patrol" {
res.patrolAgain = true
}
}
td.step()
}
res.stats = svc.Stats()
pf := &platformer{app: td.app}
pf.noFaults(t)
res.hash = digest(pf)
return res
}
func TestTopdownExample(t *testing.T) {
a := driveTopdown(t)
if a.stats.Pickups == 0 {
t.Fatal("the hero did not pick up a coin")
}
if !a.damaged {
t.Fatal("the sword never hurt GruntC")
}
if !a.chased || !a.patrolAgain {
t.Fatalf("chase %v, back to patrol %v", a.chased, a.patrolAgain)
}
if b := driveTopdown(t); b.hash != a.hash {
t.Fatal("two runs of the same input differ")
}
}