diff --git a/internal/game/entity/entity_animation.go b/internal/game/entity/entity_animation.go index 4e71b8c..261e484 100644 --- a/internal/game/entity/entity_animation.go +++ b/internal/game/entity/entity_animation.go @@ -1,6 +1,8 @@ package entity -import "github.com/veandco/go-sdl2/sdl" +import ( + "github.com/veandco/go-sdl2/sdl" +) type SpriteAnimation interface { Draw(frame int32, worldPosition *sdl.Point, angle float64, center *sdl.Point, flip sdl.RendererFlip) error @@ -38,6 +40,6 @@ func NewEntityAnimation( return &e } -func (e *entityAnimation) Draw(frame int32, worldPosition *sdl.Point) error { - return e.spriteAnimation.Draw(frame, worldPosition, e.angle, e.center, e.flip) +func (e *entityAnimation) Draw(frame int32, windowPosition *sdl.Point) error { + return e.spriteAnimation.Draw(frame, windowPosition, e.angle, e.center, e.flip) } diff --git a/internal/game/entity/penguin.go b/internal/game/entity/penguin.go index 259b69d..4db8889 100644 --- a/internal/game/entity/penguin.go +++ b/internal/game/entity/penguin.go @@ -2,25 +2,36 @@ package entity import ( "log" + "math" + "gitea.wisellama.rocks/Project-Ely/project-ely/internal/vector" "github.com/veandco/go-sdl2/sdl" ) type penguin struct { - worldPosition *sdl.Point + // Animation parameters currentAnimation *entityAnimation animationStep int32 facingRight bool + + // Physical parameters + worldPosition *vector.Vec2F + direction *vector.Vec2F + speed float64 } func NewPenguin(renderer *sdl.Renderer) *penguin { - position := sdl.Point{} + position := vector.Vec2F{} + direction := vector.Vec2F{} p := penguin{ - worldPosition: &position, currentAnimation: penguinAnimations[PENGUIN_DEFAULT], animationStep: 0, facingRight: true, + + worldPosition: &position, + speed: 2.0, + direction: &direction, } return &p @@ -29,7 +40,13 @@ func NewPenguin(renderer *sdl.Renderer) *penguin { func (p *penguin) Draw() error { step := p.animationStep / p.currentAnimation.speed - err := p.currentAnimation.Draw(step, p.worldPosition) + //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 } @@ -39,8 +56,8 @@ func (p *penguin) Draw() error { return nil } -func (p *penguin) SetPosition(point *sdl.Point) { - p.worldPosition = point +func (p *penguin) SetPosition(vec *vector.Vec2F) { + p.worldPosition = vec } func (p *penguin) SetAnimation(name string) { @@ -59,31 +76,70 @@ func (p *penguin) SetAnimation(name string) { } func (p *penguin) MoveRight() { - p.worldPosition.X += 1 - p.SetAnimation(PENGUIN_WALK_RIGHT) + p.direction.X = 1 p.facingRight = true + p.SetMoveAnimation() } func (p *penguin) MoveLeft() { - p.worldPosition.X -= 1 - p.SetAnimation(PENGUIN_WALK_LEFT) + p.direction.X = -1 p.facingRight = false + p.SetMoveAnimation() } func (p *penguin) MoveUp() { // (0,0) is the top left, so negative y moves up - p.worldPosition.Y -= 1 + p.direction.Y = -1 + p.SetMoveAnimation() } func (p *penguin) MoveDown() { // positive y moves down - p.worldPosition.Y += 1 + p.direction.Y = 1 + p.SetMoveAnimation() } func (p *penguin) StopMove() { - if p.facingRight { - p.SetAnimation(PENGUIN_STATIONARY_RIGHT) + p.direction.X = 0 + p.direction.Y = 0 + p.SetMoveAnimation() +} + +func (p *penguin) StopHorizontal() { + p.direction.X = 0 + p.SetMoveAnimation() +} + +func (p *penguin) StopVertical() { + p.direction.Y = 0 + p.SetMoveAnimation() +} + +func (p *penguin) SetMoveAnimation() { + if p.direction.X == 0 && p.direction.Y == 0 { + // Stationary + if p.facingRight { + p.SetAnimation(PENGUIN_STATIONARY_RIGHT) + } else { + p.SetAnimation(PENGUIN_STATIONARY_LEFT) + } } else { - p.SetAnimation(PENGUIN_STATIONARY_LEFT) + // Moving + if p.facingRight { + p.SetAnimation(PENGUIN_WALK_RIGHT) + } else { + p.SetAnimation(PENGUIN_WALK_LEFT) + } } } + +func (p *penguin) Update() error { + p.direction.Normalize() + x := p.direction.X * p.speed + y := p.direction.Y * p.speed + + log.Printf("X: %v, Y: %v\n", x, y) + p.worldPosition.X += x + p.worldPosition.Y += y + return nil +} diff --git a/internal/game/entity/penguin_animations.go b/internal/game/entity/penguin_animations.go index 042e573..b82edb1 100644 --- a/internal/game/entity/penguin_animations.go +++ b/internal/game/entity/penguin_animations.go @@ -31,7 +31,7 @@ func DefinePenguinAnimations() { penguinAnimations = make(map[string]*entityAnimation) // Walking Right is in the spritesheet. - speed = 10 + speed = 5 offset = sdl.Point{X: 0, Y: 2} length = 4 center = nil // center is for rotation, nil will default to w/2 h/2 diff --git a/internal/game/sprite/animation.go b/internal/game/sprite/sprite_animation.go similarity index 93% rename from internal/game/sprite/animation.go rename to internal/game/sprite/sprite_animation.go index 59b44a4..b6c87fa 100644 --- a/internal/game/sprite/animation.go +++ b/internal/game/sprite/sprite_animation.go @@ -21,6 +21,7 @@ func NewAnimation( offset sdl.Point, length int32, ) *spriteAnimation { + spritesheet := GetSpritesheet(filename) a := spriteAnimation{ @@ -35,7 +36,7 @@ func NewAnimation( func (a *spriteAnimation) Draw( frame int32, - worldPosition *sdl.Point, + windowPosition *sdl.Point, angle float64, center *sdl.Point, flip sdl.RendererFlip, @@ -63,10 +64,9 @@ func (a *spriteAnimation) Draw( return err } - // TODO convert to window position eventually placement := sdl.Rect{ - X: worldPosition.X, - Y: worldPosition.Y, + X: windowPosition.X, + Y: windowPosition.Y, W: width, H: height, } diff --git a/internal/vector/vector.go b/internal/vector/vector.go new file mode 100644 index 0000000..f38aaf6 --- /dev/null +++ b/internal/vector/vector.go @@ -0,0 +1,34 @@ +package vector + +import "math" + +// This is a small-scale vector implementation for a Vec2F. +// If you need anything more complicated than just normals and dot-products, +// then you should probably just switch to the glmath library instead. + +type Vec2F struct { + X float64 + Y float64 +} + +func (v *Vec2F) NonZero() bool { + return v.LengthSquared() > 0 +} + +func (v *Vec2F) LengthSquared() float64 { + return v.X*v.X + v.Y*v.Y +} + +func (v *Vec2F) Normalize() { + length := math.Hypot(v.X, v.Y) + if length == 0 { + return + } + + v.X = v.X / length + v.Y = v.Y / length +} + +func (v *Vec2F) Dot(other *Vec2F) float64 { + return v.X*other.X + v.Y*other.Y +} diff --git a/main.go b/main.go index 0efbf05..8cf85d4 100644 --- a/main.go +++ b/main.go @@ -9,6 +9,7 @@ import ( "gitea.wisellama.rocks/Project-Ely/project-ely/internal/game" "gitea.wisellama.rocks/Project-Ely/project-ely/internal/game/entity" "gitea.wisellama.rocks/Project-Ely/project-ely/internal/game/sprite" + "gitea.wisellama.rocks/Project-Ely/project-ely/internal/vector" "gitea.wisellama.rocks/Wisellama/gosimpleconf" "github.com/veandco/go-sdl2/sdl" ) @@ -90,7 +91,7 @@ func run(configMap gosimpleconf.ConfigMap) error { penguin := entity.NewPenguin(renderer) p2 := entity.NewPenguin(renderer) - p2.SetPosition(&sdl.Point{X: 100, Y: 100}) + p2.SetPosition(&vector.Vec2F{X: 100, Y: 100}) p2.SetAnimation(entity.PENGUIN_WALK_LEFT) keystates := make(map[sdl.Keycode]bool) @@ -128,12 +129,16 @@ func run(configMap gosimpleconf.ConfigMap) error { penguin.MoveRight() } else if keystates[sdl.K_a] { penguin.MoveLeft() + } else { + penguin.StopHorizontal() } if keystates[sdl.K_w] { penguin.MoveUp() } else if keystates[sdl.K_s] { penguin.MoveDown() + } else { + penguin.StopVertical() } if !keystates[sdl.K_a] && !keystates[sdl.K_d] && !keystates[sdl.K_w] && !keystates[sdl.K_s] { @@ -154,10 +159,19 @@ func run(configMap gosimpleconf.ConfigMap) error { }) // Everything else + err = penguin.Update() + if err != nil { + log.Printf("error updating: %v\n", err) + } err = penguin.Draw() if err != nil { log.Printf("error drawing: %v\n", err) } + + err = p2.Update() + if err != nil { + log.Printf("error updating: %v\n", err) + } err = p2.Draw() if err != nil { log.Printf("error drawing: %v\n", err)