parent
6871736381
commit
7c89210c85
|
@ -5,15 +5,15 @@ import (
|
|||
)
|
||||
|
||||
type SpriteAnimation interface {
|
||||
Draw(frame int32, worldPosition *sdl.Point, angle float64, center *sdl.Point, flip sdl.RendererFlip) error
|
||||
Draw(frame int, 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
|
||||
speed int
|
||||
length int
|
||||
angle float64
|
||||
center *sdl.Point
|
||||
flip sdl.RendererFlip
|
||||
|
@ -21,8 +21,8 @@ type entityAnimation struct {
|
|||
|
||||
func NewEntityAnimation(
|
||||
spriteAnimation SpriteAnimation,
|
||||
speed int32,
|
||||
length int32,
|
||||
speed int,
|
||||
length int,
|
||||
angle float64,
|
||||
center *sdl.Point,
|
||||
flip sdl.RendererFlip,
|
||||
|
@ -40,11 +40,11 @@ func NewEntityAnimation(
|
|||
return &e
|
||||
}
|
||||
|
||||
func (e *entityAnimation) Draw(frame int32, windowPosition *sdl.Point) error {
|
||||
func (e *entityAnimation) Draw(frame int, windowPosition *sdl.Point) error {
|
||||
return e.spriteAnimation.Draw(frame, windowPosition, e.angle, e.center, e.flip)
|
||||
}
|
||||
|
||||
func (e *entityAnimation) GetSpeed() int32 {
|
||||
func (e *entityAnimation) GetSpeed() int {
|
||||
return e.speed
|
||||
}
|
||||
|
||||
|
|
|
@ -14,10 +14,12 @@ const (
|
|||
PENGUIN_WALK_DOWN
|
||||
PENGUIN_STATIONARY_RIGHT
|
||||
PENGUIN_STATIONARY_LEFT
|
||||
PENGUIN_STATIONARY_UP
|
||||
PENGUIN_STATIONARY_DOWN
|
||||
)
|
||||
|
||||
const (
|
||||
PENGUIN_NUM_ANIMS = 6
|
||||
PENGUIN_NUM_ANIMS = 8
|
||||
PENGUIN_DEFAULT = PENGUIN_STATIONARY_RIGHT
|
||||
)
|
||||
|
||||
|
@ -28,9 +30,9 @@ func DefinePenguinAnimations() {
|
|||
dimensions sdl.Point
|
||||
offset sdl.Point
|
||||
center *sdl.Point
|
||||
length int32
|
||||
speed int32
|
||||
border int32
|
||||
length int
|
||||
speed int
|
||||
border int
|
||||
)
|
||||
|
||||
dimensions = sdl.Point{X: 13, Y: 17}
|
||||
|
@ -48,7 +50,7 @@ func DefinePenguinAnimations() {
|
|||
// 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.
|
||||
// Stationary Right/Left is just the first frame.
|
||||
length = 1
|
||||
stationaryRight := sprite.NewAnimation(filename, dimensions, offset, length, border)
|
||||
PenguinAnimations[PENGUIN_STATIONARY_RIGHT] = NewEntityAnimation(stationaryRight, speed, length, 0, center, sdl.FLIP_NONE)
|
||||
|
@ -60,9 +62,19 @@ func DefinePenguinAnimations() {
|
|||
walkUp := sprite.NewAnimation(filename, dimensions, offset, length, border)
|
||||
PenguinAnimations[PENGUIN_WALK_UP] = NewEntityAnimation(walkUp, speed, length, 0, center, sdl.FLIP_NONE)
|
||||
|
||||
// Stationary Up
|
||||
length = 1
|
||||
stationaryUp := sprite.NewAnimation(filename, dimensions, offset, length, border)
|
||||
PenguinAnimations[PENGUIN_STATIONARY_UP] = NewEntityAnimation(stationaryUp, speed, length, 0, center, sdl.FLIP_NONE)
|
||||
|
||||
// Walk Down
|
||||
length = 4
|
||||
offset = sdl.Point{X: 0, Y: 0}
|
||||
walkDown := sprite.NewAnimation(filename, dimensions, offset, length, border)
|
||||
PenguinAnimations[PENGUIN_WALK_DOWN] = NewEntityAnimation(walkDown, speed, length, 0, center, sdl.FLIP_NONE)
|
||||
|
||||
// Stationary Down
|
||||
length = 1
|
||||
stationaryDown := sprite.NewAnimation(filename, dimensions, offset, length, border)
|
||||
PenguinAnimations[PENGUIN_STATIONARY_DOWN] = NewEntityAnimation(stationaryDown, speed, length, 0, center, sdl.FLIP_NONE)
|
||||
}
|
||||
|
|
|
@ -1,8 +1,52 @@
|
|||
package types
|
||||
|
||||
import "github.com/veandco/go-sdl2/sdl"
|
||||
import (
|
||||
"gitea.wisellama.rocks/Project-Ely/project-ely/internal/vector"
|
||||
"github.com/veandco/go-sdl2/sdl"
|
||||
)
|
||||
|
||||
type EntityAnimation interface {
|
||||
Draw(step int32, windowPosition *sdl.Point) error
|
||||
GetSpeed() int32
|
||||
Draw(step int, windowPosition *sdl.Point) error
|
||||
GetSpeed() int
|
||||
}
|
||||
|
||||
const (
|
||||
// These line up with the VEC_DIRECTIONS slice
|
||||
DIR_LEFT int = iota
|
||||
DIR_RIGHT
|
||||
DIR_UP
|
||||
DIR_DOWN
|
||||
)
|
||||
|
||||
// The following are axis direction vectors based on world coordinates.
|
||||
// UP/DOWN is intentionally UP = positive (which is different from window coordinates)
|
||||
var (
|
||||
VEC_LEFT = &vector.Vec2F{X: -1, Y: 0}
|
||||
VEC_RIGHT = &vector.Vec2F{X: 1, Y: 0}
|
||||
VEC_UP = &vector.Vec2F{X: 0, Y: 1}
|
||||
VEC_DOWN = &vector.Vec2F{X: 0, Y: -1}
|
||||
|
||||
VEC_DIRECTIONS = []*vector.Vec2F{
|
||||
// Prefer left/right animations by checking them first in the list
|
||||
VEC_LEFT,
|
||||
VEC_RIGHT,
|
||||
VEC_UP,
|
||||
VEC_DOWN,
|
||||
}
|
||||
)
|
||||
|
||||
func determineClosestDirection(velocity *vector.Vec2F) int {
|
||||
closest := DIR_RIGHT
|
||||
max := 0.0
|
||||
buffer := 0.5 // This buffer lets us stick to the left/right animations for diagonal movement
|
||||
|
||||
for i, dir := range VEC_DIRECTIONS {
|
||||
dot := velocity.Dot(dir)
|
||||
if dot > max+buffer {
|
||||
max = dot
|
||||
closest = i
|
||||
}
|
||||
}
|
||||
|
||||
return closest
|
||||
}
|
||||
|
|
|
@ -14,30 +14,30 @@ type penguin struct {
|
|||
mx sync.RWMutex
|
||||
|
||||
// Animation parameters
|
||||
currentAnimation EntityAnimation
|
||||
animationStep int32
|
||||
facingRight bool
|
||||
updateAnimation bool
|
||||
currentAnimation EntityAnimation // pointer to current animation loop
|
||||
animationStep int // index of animation loop
|
||||
direction int // direction facing for sprite animations
|
||||
updateAnimation bool // if false, don't change the animation
|
||||
|
||||
// Physical parameters
|
||||
worldPosition *vector.Vec2F
|
||||
direction *vector.Vec2F
|
||||
speed float64
|
||||
worldPosition *vector.Vec2F // where is the center of this object
|
||||
velocity *vector.Vec2F // movement direction to be applied each tick
|
||||
speed float64 // movement magnitude to multiply with the velocity
|
||||
}
|
||||
|
||||
func NewPenguin(renderer *sdl.Renderer) *penguin {
|
||||
position := vector.Vec2F{}
|
||||
direction := vector.Vec2F{}
|
||||
velocity := vector.Vec2F{}
|
||||
speed := 1.0
|
||||
|
||||
p := penguin{
|
||||
currentAnimation: animation.PenguinAnimations[animation.PENGUIN_DEFAULT],
|
||||
animationStep: 0,
|
||||
facingRight: true,
|
||||
direction: DIR_RIGHT,
|
||||
|
||||
worldPosition: &position,
|
||||
speed: speed,
|
||||
direction: &direction,
|
||||
velocity: &velocity,
|
||||
}
|
||||
|
||||
return &p
|
||||
|
@ -50,7 +50,7 @@ func (p *penguin) Draw() error {
|
|||
//windowPosition := worldPosToWindowPos()
|
||||
windowPosition := &sdl.Point{
|
||||
X: int32(math.Round(p.worldPosition.X)),
|
||||
Y: int32(math.Round(p.worldPosition.Y)),
|
||||
Y: int32(math.Round(-1 * p.worldPosition.Y)),
|
||||
}
|
||||
|
||||
err := p.currentAnimation.Draw(step, windowPosition)
|
||||
|
@ -67,6 +67,10 @@ func (p *penguin) SetPosition(vec *vector.Vec2F) {
|
|||
p.worldPosition = vec
|
||||
}
|
||||
|
||||
func (p *penguin) SetDirection(dir int) {
|
||||
p.direction = dir
|
||||
}
|
||||
|
||||
func (p *penguin) SetAnimation(id int) {
|
||||
a, exists := animation.PenguinAnimations[id]
|
||||
|
||||
|
@ -86,8 +90,8 @@ func (p *penguin) MoveX(x float64) {
|
|||
p.mx.Lock()
|
||||
defer p.mx.Unlock()
|
||||
|
||||
p.direction.X = x
|
||||
p.direction.Normalize()
|
||||
p.velocity.X = x
|
||||
p.velocity.Normalize()
|
||||
p.updateAnimation = true
|
||||
}
|
||||
|
||||
|
@ -96,8 +100,8 @@ func (p *penguin) MoveY(y float64) {
|
|||
defer p.mx.Unlock()
|
||||
|
||||
// (0,0) is the top left, so negative y moves up
|
||||
p.direction.Y = y
|
||||
p.direction.Normalize()
|
||||
p.velocity.Y = y
|
||||
p.velocity.Normalize()
|
||||
p.updateAnimation = true
|
||||
}
|
||||
|
||||
|
@ -110,32 +114,38 @@ func (p *penguin) GetSpeed() float64 {
|
|||
}
|
||||
|
||||
func (p *penguin) SetMoveAnimation() {
|
||||
x := p.direction.X
|
||||
y := p.direction.Y
|
||||
|
||||
if x == 0 && y == 0 {
|
||||
// Stationary
|
||||
if p.facingRight {
|
||||
p.SetAnimation(animation.PENGUIN_STATIONARY_RIGHT)
|
||||
} else {
|
||||
if p.velocity.Zero() {
|
||||
// Stay facing whatever direction we were facing
|
||||
switch p.direction {
|
||||
case DIR_LEFT:
|
||||
p.SetAnimation(animation.PENGUIN_STATIONARY_LEFT)
|
||||
case DIR_RIGHT:
|
||||
p.SetAnimation(animation.PENGUIN_STATIONARY_RIGHT)
|
||||
case DIR_UP:
|
||||
p.SetAnimation(animation.PENGUIN_STATIONARY_UP)
|
||||
case DIR_DOWN:
|
||||
p.SetAnimation(animation.PENGUIN_STATIONARY_DOWN)
|
||||
default:
|
||||
log.Printf("unknown direction: %v", p.direction)
|
||||
p.SetAnimation(animation.PENGUIN_DEFAULT)
|
||||
}
|
||||
|
||||
} else {
|
||||
// Moving
|
||||
// Figure out which way we are facing now that we're moving
|
||||
p.direction = determineClosestDirection(p.velocity)
|
||||
|
||||
// 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(animation.PENGUIN_WALK_RIGHT)
|
||||
} else {
|
||||
switch p.direction {
|
||||
case DIR_LEFT:
|
||||
p.SetAnimation(animation.PENGUIN_WALK_LEFT)
|
||||
case DIR_RIGHT:
|
||||
p.SetAnimation(animation.PENGUIN_WALK_RIGHT)
|
||||
case DIR_UP:
|
||||
p.SetAnimation(animation.PENGUIN_WALK_UP)
|
||||
case DIR_DOWN:
|
||||
p.SetAnimation(animation.PENGUIN_WALK_DOWN)
|
||||
default:
|
||||
log.Printf("unknown direction: %v", p.direction)
|
||||
p.SetAnimation(animation.PENGUIN_DEFAULT)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -146,8 +156,8 @@ func (p *penguin) Update() error {
|
|||
p.updateAnimation = false
|
||||
}
|
||||
|
||||
x := p.direction.X * p.speed
|
||||
y := p.direction.Y * p.speed
|
||||
x := p.velocity.X * p.speed
|
||||
y := p.velocity.Y * p.speed
|
||||
|
||||
p.worldPosition.X += x
|
||||
p.worldPosition.Y += y
|
||||
|
|
|
@ -106,7 +106,7 @@ func Run(ctx context.Context, configMap gosimpleconf.ConfigMap) error {
|
|||
for i := 0; i < 10; i++ {
|
||||
entity := types.NewPenguin(renderer)
|
||||
entityCmd := command.NewCommandHandler(ctx, entity)
|
||||
randomPos := vector.Vec2F{X: rand.Float64() * 500, Y: rand.Float64() * 500}
|
||||
randomPos := vector.Vec2F{X: rand.Float64() * 500, Y: rand.Float64() * -500}
|
||||
entity.SetPosition(&randomPos)
|
||||
entity.SetAnimation(rand.Intn(animation.PENGUIN_NUM_ANIMS))
|
||||
entityList = append(entityList, entityCmd)
|
||||
|
|
|
@ -58,9 +58,9 @@ func (p *player) Update() error {
|
|||
|
||||
// Move Y
|
||||
if p.inputHandler.Keystate(sdl.K_w) {
|
||||
p.entityChan <- command.NewCommand(command.MOVE_Y, -1.0)
|
||||
} else if p.inputHandler.Keystate(sdl.K_s) {
|
||||
p.entityChan <- command.NewCommand(command.MOVE_Y, 1.0)
|
||||
} else if p.inputHandler.Keystate(sdl.K_s) {
|
||||
p.entityChan <- command.NewCommand(command.MOVE_Y, -1.0)
|
||||
} else if !p.inputHandler.Keystate(sdl.K_w) && !p.inputHandler.Keystate(sdl.K_s) {
|
||||
p.entityChan <- command.NewCommand(command.MOVE_Y, 0.0)
|
||||
}
|
||||
|
|
|
@ -12,16 +12,16 @@ type spriteAnimation struct {
|
|||
spritesheet *spritesheet
|
||||
dimensions sdl.Point
|
||||
offset sdl.Point
|
||||
length int32
|
||||
border int32
|
||||
length int
|
||||
border int
|
||||
}
|
||||
|
||||
func NewAnimation(
|
||||
filename string,
|
||||
dimensions sdl.Point,
|
||||
offset sdl.Point,
|
||||
length int32,
|
||||
border int32,
|
||||
length int,
|
||||
border int,
|
||||
) *spriteAnimation {
|
||||
|
||||
spritesheet := GetSpritesheet(filename)
|
||||
|
@ -38,7 +38,7 @@ func NewAnimation(
|
|||
}
|
||||
|
||||
func (a *spriteAnimation) Draw(
|
||||
frame int32,
|
||||
frame int,
|
||||
windowPosition *sdl.Point,
|
||||
angle float64,
|
||||
center *sdl.Point,
|
||||
|
@ -47,17 +47,18 @@ func (a *spriteAnimation) Draw(
|
|||
|
||||
width := a.dimensions.X
|
||||
height := a.dimensions.Y
|
||||
border := int32(a.border)
|
||||
|
||||
base := sdl.Point{
|
||||
X: (width+a.border)*a.offset.X + a.border,
|
||||
Y: (height+a.border)*a.offset.Y + a.border,
|
||||
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 := frame % a.length
|
||||
f := int32(frame % a.length)
|
||||
section := sdl.Rect{
|
||||
X: base.X + f*(width+a.border),
|
||||
X: base.X + f*(width+border),
|
||||
Y: base.Y,
|
||||
W: width,
|
||||
H: height,
|
||||
|
@ -71,7 +72,7 @@ func (a *spriteAnimation) Draw(
|
|||
placement := sdl.Rect{
|
||||
X: windowPosition.X,
|
||||
Y: windowPosition.Y,
|
||||
W: width * 2, // TODO just testing with x2
|
||||
W: width * 2, // TODO just testing with x2, eventually scale based on screen size or something
|
||||
H: height * 2,
|
||||
}
|
||||
|
||||
|
|
|
@ -11,8 +11,8 @@ type Vec2F struct {
|
|||
Y float64
|
||||
}
|
||||
|
||||
func (v *Vec2F) NonZero() bool {
|
||||
return v.LengthSquared() > 0
|
||||
func (v *Vec2F) Zero() bool {
|
||||
return v.X == 0.0 && v.Y == 0.0
|
||||
}
|
||||
|
||||
func (v *Vec2F) LengthSquared() float64 {
|
||||
|
|
Loading…
Reference in New Issue