You can change animation directions!

main
Sean Hickey 2022-10-13 15:37:22 -07:00
parent 9de48f0bab
commit 46a1e33ae8
6 changed files with 141 additions and 30 deletions

View File

@ -0,0 +1,43 @@
package entity
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
}
// An entityAnimation will take a SpriteAnimation and may manipulate it somehow (e.g. flipped for walking the other direction)
// This way you may cut down the actual number of pictures needed to define all the different animations.
type entityAnimation struct {
spriteAnimation SpriteAnimation
speed int32
length int32
angle float64
center *sdl.Point
flip sdl.RendererFlip
}
func NewEntityAnimation(
spriteAnimation SpriteAnimation,
speed int32,
length int32,
angle float64,
center *sdl.Point,
flip sdl.RendererFlip,
) *entityAnimation {
e := entityAnimation{
spriteAnimation: spriteAnimation,
speed: speed,
length: length,
angle: angle,
center: center,
flip: flip,
}
return &e
}
func (e *entityAnimation) Draw(frame int32, worldPosition *sdl.Point) error {
return e.spriteAnimation.Draw(frame, worldPosition, e.angle, e.center, e.flip)
}

View File

@ -1,33 +1,40 @@
package entity package entity
import ( import (
"log"
"github.com/veandco/go-sdl2/sdl" "github.com/veandco/go-sdl2/sdl"
) )
type penguin struct { type penguin struct {
worldPosition *sdl.Point worldPosition *sdl.Point
animationStep int32 currentAnimation *entityAnimation
animationStep int32
facingRight bool
} }
func NewPenguin(renderer *sdl.Renderer) *penguin { func NewPenguin(renderer *sdl.Renderer) *penguin {
position := sdl.Point{} position := sdl.Point{}
p := penguin{ p := penguin{
worldPosition: &position, worldPosition: &position,
currentAnimation: penguinAnimations[PENGUIN_DEFAULT],
animationStep: 0,
facingRight: true,
} }
return &p return &p
} }
func (p *penguin) Draw() error { func (p *penguin) Draw() error {
a := penguinAnimations[PENGUIN_WALK_RIGHT] step := p.animationStep / p.currentAnimation.speed
step := p.animationStep / 10
err := a.Draw(step, p.worldPosition) err := p.currentAnimation.Draw(step, p.worldPosition)
if err != nil { if err != nil {
return err return err
} }
p.animationStep += 1 p.animationStep = 1 + p.animationStep
return nil return nil
} }
@ -36,12 +43,31 @@ func (p *penguin) SetPosition(point *sdl.Point) {
p.worldPosition = point p.worldPosition = point
} }
func (p *penguin) SetAnimation(name string) {
a, exists := penguinAnimations[name]
if !exists {
log.Printf("animation does not exist: %v", name)
a = penguinAnimations[PENGUIN_DEFAULT]
}
if a != p.currentAnimation {
p.animationStep = 0
}
p.currentAnimation = a
}
func (p *penguin) MoveRight() { func (p *penguin) MoveRight() {
p.worldPosition.X += 1 p.worldPosition.X += 1
p.SetAnimation(PENGUIN_WALK_RIGHT)
p.facingRight = true
} }
func (p *penguin) MoveLeft() { func (p *penguin) MoveLeft() {
p.worldPosition.X -= 1 p.worldPosition.X -= 1
p.SetAnimation(PENGUIN_WALK_LEFT)
p.facingRight = false
} }
func (p *penguin) MoveUp() { func (p *penguin) MoveUp() {
@ -53,3 +79,11 @@ func (p *penguin) MoveDown() {
// positive y moves down // positive y moves down
p.worldPosition.Y += 1 p.worldPosition.Y += 1
} }
func (p *penguin) StopMove() {
if p.facingRight {
p.SetAnimation(PENGUIN_STATIONARY_RIGHT)
} else {
p.SetAnimation(PENGUIN_STATIONARY_LEFT)
}
}

View File

@ -5,14 +5,15 @@ import (
"github.com/veandco/go-sdl2/sdl" "github.com/veandco/go-sdl2/sdl"
) )
type Animation interface { var penguinAnimations map[string]*entityAnimation
Draw(frame int32, worldPosition *sdl.Point) error
}
var penguinAnimations map[string]Animation
const ( const (
PENGUIN_WALK_RIGHT = "walk-right" PENGUIN_WALK_RIGHT = "walk-right"
PENGUIN_WALK_LEFT = "walk-left"
PENGUIN_STATIONARY_RIGHT = "stationary-right"
PENGUIN_STATIONARY_LEFT = "stationary-left"
PENGUIN_DEFAULT = PENGUIN_STATIONARY_RIGHT
) )
func DefinePenguinAnimations() { func DefinePenguinAnimations() {
@ -21,13 +22,28 @@ func DefinePenguinAnimations() {
var ( var (
dimensions sdl.Point dimensions sdl.Point
offset sdl.Point offset sdl.Point
center *sdl.Point
length int32 length int32
speed int32
) )
dimensions = sdl.Point{X: 32, Y: 32} dimensions = sdl.Point{X: 32, Y: 32}
penguinAnimations = make(map[string]Animation) penguinAnimations = make(map[string]*entityAnimation)
// Walking Right is in the spritesheet.
speed = 10
offset = sdl.Point{X: 0, Y: 2} offset = sdl.Point{X: 0, Y: 2}
length = 4 length = 4
penguinAnimations[PENGUIN_WALK_RIGHT] = sprite.NewAnimation(filename, dimensions, offset, length) center = nil // center is for rotation, nil will default to w/2 h/2
walkRight := sprite.NewAnimation(filename, dimensions, offset, length)
penguinAnimations[PENGUIN_WALK_RIGHT] = NewEntityAnimation(walkRight, speed, length, 0, center, sdl.FLIP_NONE)
// Walking Left is just that flipped.
penguinAnimations[PENGUIN_WALK_LEFT] = NewEntityAnimation(walkRight, speed, length, 0, center, sdl.FLIP_HORIZONTAL)
// Stationary is just the first frame.
length = 1
stationaryRight := sprite.NewAnimation(filename, dimensions, offset, length)
penguinAnimations[PENGUIN_STATIONARY_RIGHT] = NewEntityAnimation(stationaryRight, speed, length, 0, center, sdl.FLIP_NONE)
penguinAnimations[PENGUIN_STATIONARY_LEFT] = NewEntityAnimation(stationaryRight, speed, length, 0, center, sdl.FLIP_HORIZONTAL)
} }

View File

@ -6,9 +6,9 @@ import (
"github.com/veandco/go-sdl2/sdl" "github.com/veandco/go-sdl2/sdl"
) )
// animation defines a specific for an entity that references a sequence of sections of a sprite sheet. // spriteAnimation specifies which subsections of a spritesheet define this animation.
// For example, walking to the left could be defined by 4 subsections of a sprite sheet. // For example, walking to the right could be defined by 4 subsections of a sprite sheet.
type animation struct { type spriteAnimation struct {
spritesheet *spritesheet spritesheet *spritesheet
dimensions sdl.Point dimensions sdl.Point
offset sdl.Point offset sdl.Point
@ -20,10 +20,10 @@ func NewAnimation(
dimensions sdl.Point, dimensions sdl.Point,
offset sdl.Point, offset sdl.Point,
length int32, length int32,
) *animation { ) *spriteAnimation {
spritesheet := GetSpritesheet(filename) spritesheet := GetSpritesheet(filename)
a := animation{ a := spriteAnimation{
spritesheet: spritesheet, spritesheet: spritesheet,
dimensions: dimensions, dimensions: dimensions,
offset: offset, offset: offset,
@ -33,7 +33,14 @@ func NewAnimation(
return &a return &a
} }
func (a *animation) Draw(frame int32, worldPosition *sdl.Point) error { func (a *spriteAnimation) Draw(
frame int32,
worldPosition *sdl.Point,
angle float64,
center *sdl.Point,
flip sdl.RendererFlip,
) error {
width := a.dimensions.X width := a.dimensions.X
height := a.dimensions.Y height := a.dimensions.Y
@ -64,7 +71,7 @@ func (a *animation) Draw(frame int32, worldPosition *sdl.Point) error {
H: height, H: height,
} }
err = a.spritesheet.Draw(&section, &placement) err = a.spritesheet.Draw(&section, &placement, angle, center, flip)
if err != nil { if err != nil {
return err return err
} }
@ -72,7 +79,7 @@ func (a *animation) Draw(frame int32, worldPosition *sdl.Point) error {
return nil return nil
} }
func (a *animation) checkBounds(section *sdl.Rect) error { func (a *spriteAnimation) checkBounds(section *sdl.Rect) error {
width := a.spritesheet.surface.W width := a.spritesheet.surface.W
height := a.spritesheet.surface.H height := a.spritesheet.surface.H

View File

@ -71,10 +71,17 @@ func (s *spritesheet) Cleanup() {
}() }()
} }
func (s *spritesheet) Draw(section *sdl.Rect, placement *sdl.Rect) error { func (s *spritesheet) Draw(
section *sdl.Rect,
placement *sdl.Rect,
angle float64,
center *sdl.Point,
flip sdl.RendererFlip,
) error {
var err error var err error
sdl.Do(func() { sdl.Do(func() {
err = s.renderer.Copy(s.texture, section, placement) err = s.renderer.CopyEx(s.texture, section, placement, angle, center, flip)
}) })
if err != nil { if err != nil {
return err return err

14
main.go
View File

@ -91,6 +91,7 @@ func run(configMap gosimpleconf.ConfigMap) error {
penguin := entity.NewPenguin(renderer) penguin := entity.NewPenguin(renderer)
p2 := entity.NewPenguin(renderer) p2 := entity.NewPenguin(renderer)
p2.SetPosition(&sdl.Point{X: 100, Y: 100}) p2.SetPosition(&sdl.Point{X: 100, Y: 100})
p2.SetAnimation(entity.PENGUIN_WALK_LEFT)
keystates := make(map[sdl.Keycode]bool) keystates := make(map[sdl.Keycode]bool)
@ -123,19 +124,22 @@ func run(configMap gosimpleconf.ConfigMap) error {
}) })
} }
if keystates[sdl.K_a] {
penguin.MoveLeft()
}
if keystates[sdl.K_d] { if keystates[sdl.K_d] {
penguin.MoveRight() penguin.MoveRight()
} else if keystates[sdl.K_a] {
penguin.MoveLeft()
} }
if keystates[sdl.K_w] { if keystates[sdl.K_w] {
penguin.MoveUp() penguin.MoveUp()
} } else if keystates[sdl.K_s] {
if keystates[sdl.K_s] {
penguin.MoveDown() penguin.MoveDown()
} }
if !keystates[sdl.K_a] && !keystates[sdl.K_d] && !keystates[sdl.K_w] && !keystates[sdl.K_s] {
penguin.StopMove()
}
// Background // Background
sdl.Do(func() { sdl.Do(func() {
err = renderer.SetDrawColor(0, 120, 0, 255) err = renderer.SetDrawColor(0, 120, 0, 255)