project-ely/internal/game/sprite/sprite_animation.go

109 lines
2.1 KiB
Go

package sprite
import (
"fmt"
"github.com/veandco/go-sdl2/sdl"
)
// spriteAnimation specifies which subsections of a spritesheet define this animation.
// For example, walking to the right could be defined by 4 subsections of a sprite sheet.
type spriteAnimation struct {
spritesheet *spritesheet
dimensions sdl.Point
offset sdl.Point
length int
border int
}
func NewAnimation(
filename string,
dimensions sdl.Point,
offset sdl.Point,
length int,
border int,
) spriteAnimation {
spritesheet := GetSpritesheet(filename)
return spriteAnimation{
spritesheet: spritesheet,
dimensions: dimensions,
offset: offset,
length: length,
border: border,
}
}
func (a spriteAnimation) Draw(
frame int,
windowPosition sdl.Point,
angle float64,
center sdl.Point,
flip sdl.RendererFlip,
) error {
width := a.dimensions.X
height := a.dimensions.Y
border := int32(a.border)
base := sdl.Point{
X: (width+border)*a.offset.X + border,
Y: (height+border)*a.offset.Y + border,
}
// Assuming all frames are horizontal going left to right.
// Potentially with a border offset as well.
f := int32(frame % a.length)
section := sdl.Rect{
X: base.X + f*(width+border),
Y: base.Y,
W: width,
H: height,
}
err := a.checkBounds(section)
if err != nil {
return err
}
placement := sdl.Rect{
X: windowPosition.X,
Y: windowPosition.Y,
W: width * 2, // TODO just testing with x2, eventually scale based on screen size or something
H: height * 2,
}
err = a.spritesheet.Draw(section, placement, angle, center, flip)
if err != nil {
return err
}
return nil
}
func (a spriteAnimation) checkBounds(section sdl.Rect) error {
width := a.spritesheet.surface.W
height := a.spritesheet.surface.H
outOfBounds := false
if section.X < 0 {
outOfBounds = true
}
if section.Y < 0 {
outOfBounds = true
}
if section.X+section.W > width {
outOfBounds = true
}
if section.Y+section.H > height {
outOfBounds = true
}
if outOfBounds {
return fmt.Errorf("draw section was out of bounds - section: %v, image: %v", section, a.spritesheet.surface.Bounds())
}
return nil
}