ichigo/engine/actor.go
Josh Deprez 4c8e8bf4a7 walking
2021-08-08 11:46:03 +10:00

94 lines
1.5 KiB
Go

package engine
import (
"encoding/gob"
"image"
"math"
)
func init() {
gob.Register(Actor{})
}
// Thorson-style movement:
// https://maddythorson.medium.com/celeste-and-towerfall-physics-d24bd2ae0fc5
// Collider components have tangible form.
type Collider interface {
CollidesWith(image.Rectangle) bool
}
// Actor handles basic movement.
type Actor struct {
Position image.Point
Size image.Point
game *Game
xRem, yRem float64
}
func (a *Actor) CollidesAt(p image.Point) bool {
// TODO: more efficient test?
hit := false
Walk(a.game, func(c interface{}) bool {
if coll, ok := c.(Collider); ok {
if coll.CollidesWith(image.Rectangle{Min: p, Max: p.Add(a.Size)}) {
hit = true
return false
}
}
return true
})
return hit
}
func (a *Actor) MoveX(dx float64, onCollide func()) {
a.xRem += dx
move := int(math.Round(a.xRem))
if move == 0 {
return
}
a.xRem -= float64(move)
sign := sign(move)
for move != 0 {
if a.CollidesAt(a.Position.Add(image.Pt(sign, 0))) {
if onCollide != nil {
onCollide()
}
return
}
a.Position.X += sign
move -= sign
}
}
func (a *Actor) MoveY(dy float64, onCollide func()) {
a.yRem += dy
move := int(math.Round(a.yRem))
if move == 0 {
return
}
a.yRem -= float64(move)
sign := sign(move)
for move != 0 {
if a.CollidesAt(a.Position.Add(image.Pt(0, sign))) {
if onCollide != nil {
onCollide()
}
return
}
a.Position.Y += sign
move -= sign
}
}
func (a *Actor) Build(g *Game) {
a.game = g
}
func sign(m int) int {
if m < 0 {
return -1
}
return 1
}