feat: implemented basic animation. (very raw)

This commit is contained in:
Andrey Parhomenko 2024-01-13 23:46:12 +03:00
parent 60cd4e9e75
commit f2d7feb8a4
7 changed files with 118 additions and 29 deletions

View file

@ -1,15 +1,67 @@
package gg package gg
import ( import (
"time" "github.com/hajimehoshi/ebiten/v2"
"fmt"
) )
type Animation struct { type Animation []*Image
Frames []*Image
type AnimationDefine struct{
Id AnimationId
Indexes []ImageRectIndex
}
// Animation define
func AD(id AnimationId, indexes ...ImageRectIndex) AnimationDefine {
return AnimationDefine{
Id: id,
Indexes: indexes,
}
}
func (ad AnimationDefine) DefRow(y int, xs ...int) AnimationDefine {
for _, x := range xs {
ad.Indexes = append(ad.Indexes, ImageRectIndex{x, y})
}
return ad
}
func (ad AnimationDefine) DefCol(x int, ys ...int) AnimationDefine {
for _, y := range ys {
ad.Indexes = append(ad.Indexes, ImageRectIndex{x, y})
}
return ad
} }
type AnimationId int type AnimationId int
type AnimationSet map[AnimationId] *Animation type AnimationSet map[AnimationId] Animation
func AnimationSetFromImage(
img *Image,
w, h int,
defines ...AnimationDefine,
) (AnimationSet, error) {
set := AnimationSet{}
r := img.Bounds()
fw, fh := r.Dx()/w, r.Dy()/h
for _, define := range defines {
fmt.Println("def-idx-len:", len(define.Indexes))
animation := make(Animation, len(define.Indexes))
for i := range animation {
idx := define.Indexes[i]
animation[i] = ebiten.NewImageFromImage(img.SubImage(
ImageRect{
Min: ImagePoint{idx.X*fw, idx.Y*fh},
Max: ImagePoint{(idx.X+1)*fw, (idx.Y+1)*fh},
},
))
}
fmt.Println("animation-len:", len(animation))
set[define.Id] = animation
}
return set, nil
}
// The type implements animated sprites. // The type implements animated sprites.
type AnimatedSprite struct { type AnimatedSprite struct {
@ -17,18 +69,31 @@ type AnimatedSprite struct {
Animations AnimationSet Animations AnimationSet
AnimationId AnimationId AnimationId AnimationId
CurrentFrame int CurrentFrame int
TimeBetweenFrames time.Duration // This is time between animation frames, not
// engine ones.
TimeBetweenFrames Duration
duration Duration
} }
func (as *AnimatedSprite) Animate(id AnimationId) bool { func (as *AnimatedSprite) Animate(id AnimationId) bool {
_, ok := as.Animations[id] _, ok := as.Animations[id]
if ok { if ok {
as.duration = 0
as.AnimationId = id as.AnimationId = id
} }
return ok return ok
} }
func (as *AnimatedSprite) Draw(c *Context) []EVertex { func (as *AnimatedSprite) Draw(c *Context) []EVertex {
return nil as.duration += c.DrawDt()
frames := as.Animations[as.AnimationId]
fmt.Println("len:", len(frames))
fullTime := Duration(len(frames)) * as.TimeBetweenFrames
if as.duration > fullTime {
as.duration -= fullTime
}
as.Images[0] = frames[(as.duration/as.TimeBetweenFrames)%Duration(len(frames))]
return as.Sprite.Draw(c)
} }

View file

@ -21,7 +21,13 @@ const (
LowestL LowestL
) )
const (
Stand gg.AnimationId = iota
Walk
)
var ( var (
playerAnimations gg.AnimationSet
playerImg *gg.Image playerImg *gg.Image
player *Player player *Player
rectMove gg.Rectangle rectMove gg.Rectangle
@ -45,6 +51,12 @@ func main() {
} }
rect = NewRect() rect = NewRect()
playerAnimations, _ = gg.AnimationSetFromImage(
playerImg,
8, 3,
gg.AD(Walk).DefRow(0, 0, 1, 2, 3, 4),
)
player = NewPlayer() player = NewPlayer()
tri = NewTri() tri = NewTri()
@ -82,6 +94,7 @@ func main() {
} }
e.Spawn(txt) e.Spawn(txt)
//fmt.Println(rect.GetLayer(), player.GetLayer()) //fmt.Println(rect.GetLayer(), player.GetLayer())
fmt.Println("Starting...") fmt.Println("Starting...")
err = e.Run() err = e.Run()

View file

@ -3,12 +3,13 @@ package main
import ( import (
//"math/rand" //"math/rand"
"fmt" "fmt"
"time"
) )
import "vultras.su/core/gg" import "vultras.su/core/gg"
type Player struct { type Player struct {
gg.Sprite gg.AnimatedSprite
MoveSpeed gg.Float MoveSpeed gg.Float
ScaleSpeed gg.Float ScaleSpeed gg.Float
Spawned bool Spawned bool
@ -17,17 +18,15 @@ type Player struct {
func NewPlayer() *Player { func NewPlayer() *Player {
ret := &Player{} ret := &Player{}
ret.Transform = gg.T() ret.Transform = gg.T()
fmt.Println("transform:", ret.Transform)
//ret.Parent = rect
ret.Scale = gg.V2(1) ret.Scale = gg.V2(1)
// Around center.
ret.Around = gg.V2(.5) ret.Around = gg.V2(.5)
ret.MoveSpeed = 90. ret.MoveSpeed = 90.
ret.ScaleSpeed = .2 ret.ScaleSpeed = .2
ret.Animations = playerAnimations
ret.TimeBetweenFrames = time.Second/5
fmt.Println("player-walk", ret.Animate(Walk))
ret.Visible = true ret.Visible = true
ret.Images[0] = playerImg
ret.Layer = PlayerL ret.Layer = PlayerL
return ret return ret
@ -40,7 +39,7 @@ func (p *Player) Update(c *Context) {
if p.Spawned { if p.Spawned {
return return
} }
dt := c.Dt() dt := c.Dt().Seconds()
cam := c.Camera cam := c.Camera
keys := c.Keys() keys := c.Keys()
@ -124,7 +123,7 @@ func (p *Player) Update(c *Context) {
c.Camera.Position = pos.Sub(ec.Abs) c.Camera.Position = pos.Sub(ec.Abs)
case *gg.WheelChange: case *gg.WheelChange:
c.Camera.Scale = c.Camera.Scale.Add(gg.V2( c.Camera.Scale = c.Camera.Scale.Add(gg.V2(
ec.Offset.Y * c.Dt() * p.ScaleSpeed * 40, ec.Offset.Y * dt * p.ScaleSpeed * 40,
)) ))
}} }}
} }

View file

@ -32,7 +32,7 @@ func NewTri() *Tri {
} }
func (t *Tri) Update(c *Context) { func (t *Tri) Update(c *Context) {
dt := c.Dt() dt := c.Dt().Seconds()
if t.ContainsPoint(c.AbsCursorPosition()) { if t.ContainsPoint(c.AbsCursorPosition()) {
t.Color = gg.Rgba(0, 1, 0, 1) t.Color = gg.Rgba(0, 1, 0, 1)
} else { } else {
@ -53,12 +53,12 @@ func (t *Tri) Update(c *Context) {
case gg.KeyM: case gg.KeyM:
absPos := t.AbsPosition() absPos := t.AbsPosition()
t.SetAbsPosition( t.SetAbsPosition(
absPos.Add(gg.V(0, 100*c.Dt()*d)), absPos.Add(gg.V(0, 100*dt*d)),
) )
case gg.KeyN: case gg.KeyN:
absPos := t.AbsPosition() absPos := t.AbsPosition()
t.SetAbsPosition( t.SetAbsPosition(
absPos.Add(gg.V(100*c.Dt()*d, 0)), absPos.Add(gg.V(100*dt*d, 0)),
) )
case gg.KeyV: case gg.KeyV:
t.Rotation += d * gg.Pi * 0.3 * dt t.Rotation += d * gg.Pi * 0.3 * dt

View file

@ -61,12 +61,12 @@ type Engine struct {
// If is set to nil then the engine will panic. // If is set to nil then the engine will panic.
Camera *Camera Camera *Camera
lastTime time.Time drawLastTime time.Time
dt Float drawdt Duration
// Frame delta time. // Frame delta time.
fdt Float dt Duration
fLastTime time.Time lastTime time.Time
// Temporary stuff // Temporary stuff
keys, prevKeys []Key keys, prevKeys []Key
@ -228,7 +228,7 @@ func (e *Engine) AbsCursorPosition() Vector {
func (e *engine) Update() error { func (e *engine) Update() error {
eng := (*Engine)(e) eng := (*Engine)(e)
e.fdt = time.Since(e.fLastTime).Seconds() e.dt = time.Since(e.lastTime)
// Buffering the context for faster. // Buffering the context for faster.
@ -302,7 +302,7 @@ func (e *engine) Update() error {
object.Input() <- c object.Input() <- c
} }
e.wg.Wait() e.wg.Wait()
e.fLastTime = time.Now() e.lastTime = time.Now()
e.frame++ e.frame++
return nil return nil
} }
@ -323,7 +323,7 @@ var (
defaultTriOptions = &ebiten.DrawTrianglesOptions{} defaultTriOptions = &ebiten.DrawTrianglesOptions{}
) )
func (e *engine) Draw(img *ebiten.Image) { func (e *engine) Draw(img *ebiten.Image) {
e.dt = time.Since(e.lastTime).Seconds() e.drawdt = time.Since(e.drawLastTime)
eng := (*Engine)(e) eng := (*Engine)(e)
m := map[Layer][]Drawer{} m := map[Layer][]Drawer{}
for _, object := range eng.Objects.store { for _, object := range eng.Objects.store {
@ -378,7 +378,7 @@ func (e *engine) Draw(img *ebiten.Image) {
// Empty the buff to generate it again. // Empty the buff to generate it again.
eng.Camera.buffered = false eng.Camera.buffered = false
e.lastTime = time.Now() e.drawLastTime = time.Now()
e.dframe++ e.dframe++
} }
@ -391,8 +391,8 @@ func (e *engine) Layout(ow, oh int) (int, int) {
} }
// Return the delta time. // Return the delta time.
func (e *Engine) Dt() Float { func (e *Engine) DrawDt() Duration {
return e.dt return e.drawdt
} }
func (e *Engine) Dframe() uint { func (e *Engine) Dframe() uint {
@ -400,8 +400,8 @@ func (e *Engine) Dframe() uint {
} }
// Return the current fixed delta time. // Return the current fixed delta time.
func (e *Engine) Fdt() Float { func (e *Engine) Dt() Duration {
return 1/60 return e.dt
} }
func (e *Engine) Frame() uint { func (e *Engine) Frame() uint {

5
img.go
View file

@ -9,6 +9,11 @@ import (
) )
type Image = ebiten.Image type Image = ebiten.Image
type ImageRect = image.Rectangle
type ImagePoint = image.Point
type ImageRectIndex struct {
X, Y int
}
type ColorV uint32 type ColorV uint32
type ColorM = ebiten.ColorM type ColorM = ebiten.ColorM

View file

@ -7,3 +7,10 @@ import (
type Time = time.Time type Time = time.Time
type Duration = time.Duration type Duration = time.Duration
const (
ZeroDuration Duration = 0
Microsecond = time.Microsecond
Millisecond = time.Millisecond
Second = time.Second
)