2021-08-02 15:16:58 +10:00
|
|
|
package engine
|
|
|
|
|
2021-08-03 14:56:53 +10:00
|
|
|
import (
|
|
|
|
"encoding/gob"
|
|
|
|
"image"
|
|
|
|
"math"
|
|
|
|
)
|
|
|
|
|
2021-08-03 18:26:14 +10:00
|
|
|
const gravity = 0.5
|
|
|
|
|
2021-08-03 14:56:53 +10:00
|
|
|
func init() {
|
|
|
|
gob.Register(Actor{})
|
|
|
|
}
|
2021-08-02 15:16:58 +10:00
|
|
|
|
|
|
|
// Thorson-style movement:
|
|
|
|
// https://maddythorson.medium.com/celeste-and-towerfall-physics-d24bd2ae0fc5
|
|
|
|
|
2021-08-03 14:56:53 +10:00
|
|
|
// Collider components have tangible form.
|
|
|
|
type Collider interface {
|
|
|
|
CollidesWith(image.Rectangle) bool
|
|
|
|
}
|
2021-08-02 15:16:58 +10:00
|
|
|
|
2021-08-04 15:07:57 +10:00
|
|
|
// Actor handles basic movement.
|
2021-08-02 15:16:58 +10:00
|
|
|
type Actor struct {
|
2021-08-03 14:56:53 +10:00
|
|
|
Position image.Point
|
|
|
|
Size image.Point
|
2021-08-02 15:16:58 +10:00
|
|
|
|
|
|
|
game *Game
|
|
|
|
xRem, yRem float64
|
|
|
|
}
|
|
|
|
|
2021-08-04 15:07:57 +10:00
|
|
|
func (a *Actor) CollidesAt(p image.Point) bool {
|
2021-08-03 14:56:53 +10:00
|
|
|
// TODO: more efficient test?
|
|
|
|
hit := false
|
2021-08-04 12:40:51 +10:00
|
|
|
Walk(a.game, func(c interface{}) bool {
|
2021-08-03 14:56:53 +10:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2021-08-02 15:16:58 +10:00
|
|
|
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 {
|
2021-08-04 15:07:57 +10:00
|
|
|
if a.CollidesAt(a.Position.Add(image.Pt(sign, 0))) {
|
2021-08-02 15:16:58 +10:00
|
|
|
if onCollide != nil {
|
|
|
|
onCollide()
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
2021-08-03 14:56:53 +10:00
|
|
|
a.Position.X += sign
|
2021-08-02 15:16:58 +10:00
|
|
|
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 {
|
2021-08-04 15:07:57 +10:00
|
|
|
if a.CollidesAt(a.Position.Add(image.Pt(0, sign))) {
|
2021-08-02 15:16:58 +10:00
|
|
|
if onCollide != nil {
|
|
|
|
onCollide()
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
2021-08-03 14:56:53 +10:00
|
|
|
a.Position.Y += sign
|
2021-08-02 15:16:58 +10:00
|
|
|
move -= sign
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *Actor) Build(g *Game) {
|
|
|
|
a.game = g
|
|
|
|
}
|
|
|
|
|
|
|
|
func sign(m int) int {
|
|
|
|
if m < 0 {
|
|
|
|
return -1
|
|
|
|
}
|
|
|
|
return 1
|
|
|
|
}
|