219 lines
4.1 KiB
Go
219 lines
4.1 KiB
Go
package entity
|
|
|
|
import (
|
|
"context"
|
|
"log"
|
|
"math"
|
|
"time"
|
|
|
|
"gitea.wisellama.rocks/Project-Ely/project-ely/internal/channels"
|
|
"gitea.wisellama.rocks/Project-Ely/project-ely/internal/vector"
|
|
"github.com/veandco/go-sdl2/sdl"
|
|
)
|
|
|
|
type penguin struct {
|
|
ctx context.Context
|
|
timeout time.Duration
|
|
commandChan chan EntityCommand
|
|
|
|
// Animation parameters
|
|
currentAnimation *entityAnimation
|
|
animationStep int32
|
|
facingRight bool
|
|
updateAnimation bool
|
|
|
|
// Physical parameters
|
|
worldPosition *vector.Vec2F
|
|
direction *vector.Vec2F
|
|
speed float64
|
|
}
|
|
|
|
func NewPenguin(ctx context.Context, renderer *sdl.Renderer) *penguin {
|
|
commandChan := make(chan EntityCommand, 10)
|
|
defaultTimeout := time.Second
|
|
|
|
position := vector.Vec2F{}
|
|
direction := vector.Vec2F{}
|
|
speed := 1.0
|
|
|
|
p := penguin{
|
|
ctx: ctx,
|
|
commandChan: commandChan,
|
|
timeout: defaultTimeout,
|
|
|
|
currentAnimation: penguinAnimations[PENGUIN_DEFAULT],
|
|
animationStep: 0,
|
|
facingRight: true,
|
|
|
|
worldPosition: &position,
|
|
speed: speed,
|
|
direction: &direction,
|
|
}
|
|
|
|
return &p
|
|
}
|
|
|
|
func (p *penguin) Draw() error {
|
|
step := p.animationStep / p.currentAnimation.speed
|
|
|
|
//windowPosition := worldPosToWindowPos()
|
|
windowPosition := &sdl.Point{
|
|
X: int32(math.Round(p.worldPosition.X)),
|
|
Y: int32(math.Round(p.worldPosition.Y)),
|
|
}
|
|
|
|
err := p.currentAnimation.Draw(step, windowPosition)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
p.animationStep = 1 + p.animationStep
|
|
|
|
return nil
|
|
}
|
|
|
|
func (p *penguin) SetPosition(vec *vector.Vec2F) {
|
|
p.worldPosition = vec
|
|
}
|
|
|
|
func (p *penguin) SetAnimation(id int) {
|
|
a, exists := penguinAnimations[id]
|
|
|
|
if !exists {
|
|
log.Printf("animation does not exist: %v", id)
|
|
a = penguinAnimations[PENGUIN_DEFAULT]
|
|
}
|
|
|
|
if a != p.currentAnimation {
|
|
p.animationStep = 0
|
|
}
|
|
|
|
p.currentAnimation = a
|
|
}
|
|
|
|
func (p *penguin) MoveX(x float64) {
|
|
p.direction.X = x
|
|
p.direction.Normalize()
|
|
p.updateAnimation = true
|
|
}
|
|
|
|
func (p *penguin) MoveY(y float64) {
|
|
// (0,0) is the top left, so negative y moves up
|
|
p.direction.Y = y
|
|
p.direction.Normalize()
|
|
p.updateAnimation = true
|
|
}
|
|
|
|
func (p *penguin) SetSpeed(s float64) {
|
|
p.speed = s
|
|
}
|
|
|
|
func (p *penguin) GetSpeed() float64 {
|
|
return p.speed
|
|
}
|
|
|
|
func (p *penguin) SetMoveAnimation() {
|
|
x := p.direction.X
|
|
y := p.direction.Y
|
|
|
|
if x == 0 && y == 0 {
|
|
// Stationary
|
|
if p.facingRight {
|
|
p.SetAnimation(PENGUIN_STATIONARY_RIGHT)
|
|
} else {
|
|
p.SetAnimation(PENGUIN_STATIONARY_LEFT)
|
|
}
|
|
} else {
|
|
// Moving
|
|
|
|
// Update which direction we're facing
|
|
if x > 0 {
|
|
p.facingRight = true
|
|
} else if x < 0 {
|
|
p.facingRight = false
|
|
}
|
|
|
|
// if x == 0, stay facing whatever direction we were previously facing
|
|
|
|
if p.facingRight {
|
|
p.SetAnimation(PENGUIN_WALK_RIGHT)
|
|
} else {
|
|
p.SetAnimation(PENGUIN_WALK_LEFT)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (p *penguin) Update() error {
|
|
if p.updateAnimation {
|
|
p.SetMoveAnimation()
|
|
p.updateAnimation = false
|
|
}
|
|
|
|
x := p.direction.X * p.speed
|
|
y := p.direction.Y * p.speed
|
|
|
|
p.worldPosition.X += x
|
|
p.worldPosition.Y += y
|
|
|
|
return nil
|
|
}
|
|
|
|
func (p *penguin) GetCommandChan() chan EntityCommand {
|
|
return p.commandChan
|
|
}
|
|
|
|
func (p *penguin) Run() {
|
|
running := true
|
|
for running {
|
|
select {
|
|
case c := <-p.commandChan:
|
|
go func(cmd EntityCommand) {
|
|
p.HandleWithTimeout(cmd)
|
|
}(c)
|
|
case <-p.ctx.Done():
|
|
// Graceful shutdown
|
|
running = false
|
|
// Finish up anything in the queue
|
|
for c := range p.commandChan {
|
|
p.HandleWithTimeout(c)
|
|
}
|
|
log.Printf("entity shutdown\n")
|
|
}
|
|
}
|
|
}
|
|
|
|
func (p *penguin) HandleWithTimeout(c EntityCommand) {
|
|
err := channels.RunWithTimeout(p.timeout, func() error {
|
|
return p.Handle(c)
|
|
})
|
|
if err != nil {
|
|
log.Printf("%v\n", err)
|
|
}
|
|
}
|
|
|
|
func (p *penguin) Handle(c EntityCommand) error {
|
|
var err error
|
|
switch c.key {
|
|
case COMMAND_DRAW:
|
|
err = p.Draw()
|
|
if err != nil {
|
|
log.Printf("error drawing entity: %v", err)
|
|
}
|
|
case COMMAND_UPDATE:
|
|
err = p.Update()
|
|
if err != nil {
|
|
log.Printf("error updating entity: %v", err)
|
|
}
|
|
case COMMAND_MOVE_X:
|
|
p.MoveX(c.value)
|
|
case COMMAND_MOVE_Y:
|
|
p.MoveY(c.value)
|
|
case COMMAND_SET_SPEED:
|
|
p.SetSpeed(c.value)
|
|
default:
|
|
log.Printf("unknown entity command: %v", c.key)
|
|
}
|
|
|
|
return nil
|
|
}
|