2021-08-02 15:16:58 +10:00
|
|
|
package engine
|
|
|
|
|
2021-08-03 14:56:53 +10:00
|
|
|
import (
|
|
|
|
"encoding/gob"
|
|
|
|
)
|
|
|
|
|
2021-08-18 16:34:51 +10:00
|
|
|
// Ensure Actor satisfies interfaces.
|
2021-09-02 16:55:12 +10:00
|
|
|
var _ Prepper = &Actor{}
|
2021-08-20 15:01:31 +10:00
|
|
|
|
2021-08-03 14:56:53 +10:00
|
|
|
func init() {
|
2021-08-25 15:04:38 +10:00
|
|
|
gob.Register(&Actor{})
|
2021-08-03 14:56:53 +10:00
|
|
|
}
|
2021-08-02 15:16:58 +10:00
|
|
|
|
|
|
|
// Thorson-style movement:
|
|
|
|
// https://maddythorson.medium.com/celeste-and-towerfall-physics-d24bd2ae0fc5
|
|
|
|
|
2021-08-04 15:07:57 +10:00
|
|
|
// Actor handles basic movement.
|
2021-08-02 15:16:58 +10:00
|
|
|
type Actor struct {
|
2021-09-02 16:55:12 +10:00
|
|
|
CollisionDomain string // id of component to look for colliders inside of
|
|
|
|
Pos, Size Point3
|
|
|
|
xRem, yRem, zRem float64
|
2021-08-02 15:16:58 +10:00
|
|
|
|
2021-09-02 16:55:12 +10:00
|
|
|
game *Game
|
2021-08-02 15:16:58 +10:00
|
|
|
}
|
|
|
|
|
2021-09-02 16:55:12 +10:00
|
|
|
func (a *Actor) CollidesAt(p Point3) bool {
|
2021-09-02 20:17:45 +10:00
|
|
|
bounds := Box{Min: p, Max: p.Add(a.Size)}
|
2021-08-30 15:03:22 +10:00
|
|
|
for c := range a.game.Query(a.CollisionDomain, ColliderType) {
|
|
|
|
if c.(Collider).CollidesWith(bounds) {
|
2021-08-27 15:39:10 +10:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
2021-08-03 14:56:53 +10:00
|
|
|
}
|
|
|
|
|
2021-08-02 15:16:58 +10:00
|
|
|
func (a *Actor) MoveX(dx float64, onCollide func()) {
|
|
|
|
a.xRem += dx
|
2021-08-05 14:26:23 +10:00
|
|
|
move := int(a.xRem + 0.5) // Note: math.Round can lead to vibration
|
2021-08-02 15:16:58 +10:00
|
|
|
if move == 0 {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
a.xRem -= float64(move)
|
|
|
|
sign := sign(move)
|
|
|
|
for move != 0 {
|
2021-09-02 16:55:12 +10:00
|
|
|
if a.CollidesAt(a.Pos.Add(Pt3(sign, 0, 0))) {
|
2021-08-02 15:16:58 +10:00
|
|
|
if onCollide != nil {
|
|
|
|
onCollide()
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
2021-08-05 12:26:41 +10:00
|
|
|
a.Pos.X += sign
|
2021-08-02 15:16:58 +10:00
|
|
|
move -= sign
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *Actor) MoveY(dy float64, onCollide func()) {
|
|
|
|
a.yRem += dy
|
2021-08-05 14:26:23 +10:00
|
|
|
move := int(a.yRem + 0.5)
|
2021-08-02 15:16:58 +10:00
|
|
|
if move == 0 {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
a.yRem -= float64(move)
|
|
|
|
sign := sign(move)
|
|
|
|
for move != 0 {
|
2021-09-02 16:55:12 +10:00
|
|
|
if a.CollidesAt(a.Pos.Add(Pt3(0, sign, 0))) {
|
2021-08-02 15:16:58 +10:00
|
|
|
if onCollide != nil {
|
|
|
|
onCollide()
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
2021-08-05 12:26:41 +10:00
|
|
|
a.Pos.Y += sign
|
2021-08-02 15:16:58 +10:00
|
|
|
move -= sign
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-02 16:55:12 +10:00
|
|
|
func (a *Actor) MoveZ(dz float64, onCollide func()) {
|
2021-09-02 17:24:08 +10:00
|
|
|
a.zRem += dz
|
2021-09-02 16:55:12 +10:00
|
|
|
move := int(a.zRem + 0.5)
|
|
|
|
if move == 0 {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
a.zRem -= float64(move)
|
|
|
|
sign := sign(move)
|
|
|
|
for move != 0 {
|
2021-09-02 17:24:08 +10:00
|
|
|
if a.CollidesAt(a.Pos.Add(Pt3(0, 0, sign))) {
|
2021-09-02 16:55:12 +10:00
|
|
|
if onCollide != nil {
|
|
|
|
onCollide()
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
a.Pos.Z += sign
|
|
|
|
move -= sign
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-27 14:52:24 +10:00
|
|
|
func (a *Actor) Prepare(g *Game) error {
|
2021-08-30 15:03:22 +10:00
|
|
|
a.game = g
|
2021-08-27 14:52:24 +10:00
|
|
|
return nil
|
2021-08-02 15:16:58 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
func sign(m int) int {
|
|
|
|
if m < 0 {
|
|
|
|
return -1
|
|
|
|
}
|
|
|
|
return 1
|
|
|
|
}
|