added duration from asesprite json, background animation, prepared

idle animation
This commit is contained in:
Thomas von Dein 2024-04-07 19:10:27 +02:00
parent 0b0252022e
commit 2edaccbfda
12 changed files with 216 additions and 23 deletions

View File

@ -11,6 +11,7 @@ import (
"log/slog" "log/slog"
"path" "path"
"strings" "strings"
"time"
"github.com/hajimehoshi/ebiten/v2" "github.com/hajimehoshi/ebiten/v2"
) )
@ -23,6 +24,7 @@ type assetData struct {
Registry AssetRegistry Registry AssetRegistry
} }
// to parse asesprite animation json
type AnimationGeo struct { type AnimationGeo struct {
X int `json:"x"` X int `json:"x"`
Y int `json:"y"` Y int `json:"y"`
@ -32,7 +34,7 @@ type AnimationGeo struct {
type AnimationFrame struct { type AnimationFrame struct {
Position AnimationGeo `json:"frame"` Position AnimationGeo `json:"frame"`
Duration int Duration int `json:"duration"`
} }
type AnimationMeta struct { type AnimationMeta struct {
@ -46,10 +48,15 @@ type AnimationJSON struct {
Frames []AnimationFrame `json:"frames"` Frames []AnimationFrame `json:"frames"`
} }
// Animation data // used to store Animation data
type AnimationSprite struct {
Sprite *ebiten.Image
Duration time.Duration
}
type AnimationSet struct { type AnimationSet struct {
Width, Height int Width, Height int
Sprites []*ebiten.Image Sprites []AnimationSprite
File string File string
} }
@ -153,11 +160,12 @@ func ProcessAnimations(rawanimations []AnimationJSON, imagedata *assetData) Anim
frame.Position.Y+frame.Position.Height, frame.Position.Y+frame.Position.Height,
)).(*ebiten.Image) )).(*ebiten.Image)
animationset.Sprites = append(animationset.Sprites, sprite) animationset.Sprites = append(animationset.Sprites,
AnimationSprite{Sprite: sprite, Duration: time.Duration(frame.Duration)})
} }
animationset.Width = animationset.Sprites[0].Bounds().Dx() animationset.Width = animationset.Sprites[0].Sprite.Bounds().Dx()
animationset.Height = animationset.Sprites[0].Bounds().Dy() animationset.Height = animationset.Sprites[0].Sprite.Bounds().Dy()
animations[animationset.File] = animationset animations[animationset.File] = animationset
} }

View File

@ -6,7 +6,7 @@
"trimmed": false, "trimmed": false,
"spriteSourceSize": { "x": 0, "y": 0, "w": 640, "h": 384 }, "spriteSourceSize": { "x": 0, "y": 0, "w": 640, "h": 384 },
"sourceSize": { "w": 640, "h": 384 }, "sourceSize": { "w": 640, "h": 384 },
"duration": 500 "duration": 2000
}, },
{ {
"filename": "backgroundstars 1.ase", "filename": "backgroundstars 1.ase",
@ -24,7 +24,7 @@
"trimmed": false, "trimmed": false,
"spriteSourceSize": { "x": 0, "y": 0, "w": 640, "h": 384 }, "spriteSourceSize": { "x": 0, "y": 0, "w": 640, "h": 384 },
"sourceSize": { "w": 640, "h": 384 }, "sourceSize": { "w": 640, "h": 384 },
"duration": 500 "duration": 100
}, },
{ {
"filename": "backgroundstars 3.ase", "filename": "backgroundstars 3.ase",
@ -42,7 +42,7 @@
"trimmed": false, "trimmed": false,
"spriteSourceSize": { "x": 0, "y": 0, "w": 640, "h": 384 }, "spriteSourceSize": { "x": 0, "y": 0, "w": 640, "h": 384 },
"sourceSize": { "w": 640, "h": 384 }, "sourceSize": { "w": 640, "h": 384 },
"duration": 500 "duration": 2000
}, },
{ {
"filename": "backgroundstars 5.ase", "filename": "backgroundstars 5.ase",
@ -52,6 +52,114 @@
"spriteSourceSize": { "x": 0, "y": 0, "w": 640, "h": 384 }, "spriteSourceSize": { "x": 0, "y": 0, "w": 640, "h": 384 },
"sourceSize": { "w": 640, "h": 384 }, "sourceSize": { "w": 640, "h": 384 },
"duration": 100 "duration": 100
},
{
"filename": "backgroundstars 6.ase",
"frame": { "x": 3840, "y": 0, "w": 640, "h": 384 },
"rotated": false,
"trimmed": false,
"spriteSourceSize": { "x": 0, "y": 0, "w": 640, "h": 384 },
"sourceSize": { "w": 640, "h": 384 },
"duration": 100
},
{
"filename": "backgroundstars 7.ase",
"frame": { "x": 4480, "y": 0, "w": 640, "h": 384 },
"rotated": false,
"trimmed": false,
"spriteSourceSize": { "x": 0, "y": 0, "w": 640, "h": 384 },
"sourceSize": { "w": 640, "h": 384 },
"duration": 100
},
{
"filename": "backgroundstars 8.ase",
"frame": { "x": 5120, "y": 0, "w": 640, "h": 384 },
"rotated": false,
"trimmed": false,
"spriteSourceSize": { "x": 0, "y": 0, "w": 640, "h": 384 },
"sourceSize": { "w": 640, "h": 384 },
"duration": 2000
},
{
"filename": "backgroundstars 9.ase",
"frame": { "x": 5760, "y": 0, "w": 640, "h": 384 },
"rotated": false,
"trimmed": false,
"spriteSourceSize": { "x": 0, "y": 0, "w": 640, "h": 384 },
"sourceSize": { "w": 640, "h": 384 },
"duration": 100
},
{
"filename": "backgroundstars 10.ase",
"frame": { "x": 6400, "y": 0, "w": 640, "h": 384 },
"rotated": false,
"trimmed": false,
"spriteSourceSize": { "x": 0, "y": 0, "w": 640, "h": 384 },
"sourceSize": { "w": 640, "h": 384 },
"duration": 100
},
{
"filename": "backgroundstars 11.ase",
"frame": { "x": 7040, "y": 0, "w": 640, "h": 384 },
"rotated": false,
"trimmed": false,
"spriteSourceSize": { "x": 0, "y": 0, "w": 640, "h": 384 },
"sourceSize": { "w": 640, "h": 384 },
"duration": 100
},
{
"filename": "backgroundstars 12.ase",
"frame": { "x": 7680, "y": 0, "w": 640, "h": 384 },
"rotated": false,
"trimmed": false,
"spriteSourceSize": { "x": 0, "y": 0, "w": 640, "h": 384 },
"sourceSize": { "w": 640, "h": 384 },
"duration": 2000
},
{
"filename": "backgroundstars 13.ase",
"frame": { "x": 8320, "y": 0, "w": 640, "h": 384 },
"rotated": false,
"trimmed": false,
"spriteSourceSize": { "x": 0, "y": 0, "w": 640, "h": 384 },
"sourceSize": { "w": 640, "h": 384 },
"duration": 100
},
{
"filename": "backgroundstars 14.ase",
"frame": { "x": 8960, "y": 0, "w": 640, "h": 384 },
"rotated": false,
"trimmed": false,
"spriteSourceSize": { "x": 0, "y": 0, "w": 640, "h": 384 },
"sourceSize": { "w": 640, "h": 384 },
"duration": 100
},
{
"filename": "backgroundstars 15.ase",
"frame": { "x": 9600, "y": 0, "w": 640, "h": 384 },
"rotated": false,
"trimmed": false,
"spriteSourceSize": { "x": 0, "y": 0, "w": 640, "h": 384 },
"sourceSize": { "w": 640, "h": 384 },
"duration": 100
},
{
"filename": "backgroundstars 16.ase",
"frame": { "x": 10240, "y": 0, "w": 640, "h": 384 },
"rotated": false,
"trimmed": false,
"spriteSourceSize": { "x": 0, "y": 0, "w": 640, "h": 384 },
"sourceSize": { "w": 640, "h": 384 },
"duration": 100
},
{
"filename": "backgroundstars 17.ase",
"frame": { "x": 10880, "y": 0, "w": 640, "h": 384 },
"rotated": false,
"trimmed": false,
"spriteSourceSize": { "x": 0, "y": 0, "w": 640, "h": 384 },
"sourceSize": { "w": 640, "h": 384 },
"duration": 2000
} }
], ],
"meta": { "meta": {
@ -59,12 +167,13 @@
"version": "1.x-dev", "version": "1.x-dev",
"image": "backgroundstars-animated.png", "image": "backgroundstars-animated.png",
"format": "RGBA8888", "format": "RGBA8888",
"size": { "w": 3840, "h": 384 }, "size": { "w": 11520, "h": 384 },
"scale": "1", "scale": "1",
"frameTags": [ "frameTags": [
], ],
"layers": [ "layers": [
{ "name": "Layer", "opacity": 255, "blendMode": "normal" } { "name": "background", "opacity": 255, "blendMode": "normal" },
{ "name": "stars", "opacity": 124, "blendMode": "normal" }
], ],
"slices": [ "slices": [
] ]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

View File

@ -0,0 +1,67 @@
{ "frames": [
{
"filename": "collectible #Idle 0.ase",
"frame": { "x": 0, "y": 0, "w": 64, "h": 64 },
"rotated": false,
"trimmed": false,
"spriteSourceSize": { "x": 0, "y": 0, "w": 64, "h": 64 },
"sourceSize": { "w": 64, "h": 64 },
"duration": 200
},
{
"filename": "collectible #Idle 1.ase",
"frame": { "x": 64, "y": 0, "w": 64, "h": 64 },
"rotated": false,
"trimmed": false,
"spriteSourceSize": { "x": 0, "y": 0, "w": 64, "h": 64 },
"sourceSize": { "w": 64, "h": 64 },
"duration": 200
},
{
"filename": "collectible #Idle 2.ase",
"frame": { "x": 128, "y": 0, "w": 64, "h": 64 },
"rotated": false,
"trimmed": false,
"spriteSourceSize": { "x": 0, "y": 0, "w": 64, "h": 64 },
"sourceSize": { "w": 64, "h": 64 },
"duration": 200
},
{
"filename": "collectible #Idle 3.ase",
"frame": { "x": 192, "y": 0, "w": 64, "h": 64 },
"rotated": false,
"trimmed": false,
"spriteSourceSize": { "x": 0, "y": 0, "w": 64, "h": 64 },
"sourceSize": { "w": 64, "h": 64 },
"duration": 200
}
],
"meta": {
"app": "http://www.aseprite.org/",
"version": "1.x-dev",
"image": "collectible-idle.png",
"format": "I8",
"size": { "w": 256, "h": 64 },
"scale": "1",
"frameTags": [
{ "name": "Detonation", "from": 1, "to": 14, "direction": "forward" },
{ "name": "Idle", "from": 15, "to": 18, "direction": "forward" }
],
"layers": [
{ "name": "Yellow Sphere", "opacity": 255, "blendMode": "normal" },
{ "name": "Layer 8", "opacity": 255, "blendMode": "normal" },
{ "name": "Layer 7", "opacity": 255, "blendMode": "normal" },
{ "name": "Layer 6", "opacity": 255, "blendMode": "normal" },
{ "name": "Layer 5", "opacity": 255, "blendMode": "normal" },
{ "name": "Layer 4", "opacity": 255, "blendMode": "normal" },
{ "name": "Layer 3", "opacity": 255, "blendMode": "normal" },
{ "name": "Layer 2", "opacity": 255, "blendMode": "normal" },
{ "name": "Layer 1", "opacity": 255, "blendMode": "normal" },
{ "name": "Blitz Outer", "opacity": 70, "blendMode": "normal" },
{ "name": "Blitz Middle", "opacity": 84, "blendMode": "normal" },
{ "name": "Blitz Inner", "opacity": 97, "blendMode": "normal" }
],
"slices": [
]
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 685 B

Binary file not shown.

BIN
assets/sprites/stars.ase Normal file

Binary file not shown.

View File

@ -1,7 +1,9 @@
package components package components
import ( import (
"openquell/assets"
"openquell/config" "openquell/config"
"time"
"github.com/hajimehoshi/ebiten/v2" "github.com/hajimehoshi/ebiten/v2"
) )
@ -11,7 +13,7 @@ type Animation struct {
Active bool // animation is running Active bool // animation is running
Loop bool // remove the entity if false, loop endless otherwise Loop bool // remove the entity if false, loop endless otherwise
Index int // where we are currently Index int // where we are currently
Tiles []*ebiten.Image Sprites []assets.AnimationSprite
Width, Height int // single sprite measurements Width, Height int // single sprite measurements
Timer Timer Timer Timer
Trigger string Trigger string
@ -24,6 +26,7 @@ type Renderable struct {
Damaged int Damaged int
Shader *ebiten.Shader Shader *ebiten.Shader
Animate Animation Animate Animation
IdleAnimate Animation
Hidden bool Hidden bool
} }
@ -41,3 +44,11 @@ func (render *Renderable) StartAnimation() {
render.Animate.Loop = true render.Animate.Loop = true
} }
} }
func (animation *Animation) GetSprite() *ebiten.Image {
return animation.Sprites[animation.Index].Sprite
}
func (animation *Animation) GetDuration() time.Duration {
return animation.Sprites[animation.Index].Duration * time.Millisecond
}

View File

@ -162,7 +162,7 @@ func NewGrid(world *ecs.World,
//if tile.AnimateOnDestruct { //if tile.AnimateOnDestruct {
if tile.AnimationTrigger != "" { if tile.AnimationTrigger != "" {
// FIXME: be more generic, use LDTK enum // FIXME: be more generic, use LDTK enum
render.Animate.Tiles = tile.AnimationSpriteSheet.Sprites render.Animate.Sprites = tile.AnimationSpriteSheet.Sprites
render.Animate.Width = tile.AnimationSpriteSheet.Width render.Animate.Width = tile.AnimationSpriteSheet.Width
render.Animate.Height = tile.AnimationSpriteSheet.Height render.Animate.Height = tile.AnimationSpriteSheet.Height
render.Animate.Trigger = tile.AnimationTrigger render.Animate.Trigger = tile.AnimationTrigger

View File

@ -36,7 +36,7 @@ func (system *AnimationSystem) Update() error {
if render.Animate.Timer.IsReady() { if render.Animate.Timer.IsReady() {
switch { switch {
// animation shows from earlier tick, animate // animation shows from earlier tick, animate
case render.Animate.Index > -1 && render.Animate.Index < len(render.Animate.Tiles)-1: case render.Animate.Index > -1 && render.Animate.Index < len(render.Animate.Sprites)-1:
render.Animate.Index += 1 render.Animate.Index += 1
render.Animate.Timer.Start(config.ANIMATION_LOOPWAIT) render.Animate.Timer.Start(config.ANIMATION_LOOPWAIT)
default: default:
@ -71,7 +71,7 @@ func (system *AnimationSystem) Draw(screen *ebiten.Image) {
if render.Animate.Active { if render.Animate.Active {
op.GeoM.Reset() op.GeoM.Reset()
op.GeoM.Translate(float64(pos.X), float64(pos.Y)) op.GeoM.Translate(float64(pos.X), float64(pos.Y))
screen.DrawImage(render.Animate.Tiles[render.Animate.Index], op) screen.DrawImage(render.Animate.GetSprite(), op)
} }
} }
} }

View File

@ -1,7 +1,6 @@
package systems package systems
import ( import (
"log/slog"
"openquell/assets" "openquell/assets"
"openquell/components" "openquell/components"
. "openquell/components" . "openquell/components"
@ -51,9 +50,9 @@ func NewGridSystem(world *ecs.World, width, height,
system.BackgroundAnimated = true system.BackgroundAnimated = true
system.Animate = components.Animation{ system.Animate = components.Animation{
Active: true, Active: true,
Loop: true, Loop: true,
Tiles: assets.Animations[background+"-animated"].Sprites, Sprites: assets.Animations[background+"-animated"].Sprites,
} }
system.Animate.Timer.Start(config.ANIMATION_LOOPWAIT) system.Animate.Timer.Start(config.ANIMATION_LOOPWAIT)
@ -64,13 +63,12 @@ func NewGridSystem(world *ecs.World, width, height,
func (system *GridSystem) Update() error { func (system *GridSystem) Update() error {
if system.BackgroundAnimated { if system.BackgroundAnimated {
slog.Debug("animate bg?", "timer", system.Animate.Timer)
if system.Animate.Timer.IsReady() { if system.Animate.Timer.IsReady() {
switch { switch {
// animation shows from earlier tick, animate // animation shows from earlier tick, animate
case system.Animate.Index > -1 && system.Animate.Index < len(system.Animate.Tiles)-1: case system.Animate.Index > -1 && system.Animate.Index < len(system.Animate.Sprites)-1:
system.Animate.Index += 1 system.Animate.Index += 1
system.Animate.Timer.Start(config.ANIMATION_LOOPWAIT) system.Animate.Timer.Start(system.Animate.GetDuration())
default: default:
// last sprite reached // last sprite reached
if system.Animate.Loop { if system.Animate.Loop {
@ -93,7 +91,7 @@ func (system *GridSystem) Draw(screen *ebiten.Image) {
if !system.UseCache || query.Count() != system.Count || system.BackgroundAnimated { if !system.UseCache || query.Count() != system.Count || system.BackgroundAnimated {
// map not cached or cacheable, write it to the cache // map not cached or cacheable, write it to the cache
if system.BackgroundAnimated { if system.BackgroundAnimated {
system.Cache.DrawImage(system.Animate.Tiles[system.Animate.Index], op) system.Cache.DrawImage(system.Animate.GetSprite(), op)
} else { } else {
system.Cache.DrawImage(system.Background, op) system.Cache.DrawImage(system.Background, op)
} }