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

View File

@ -6,7 +6,7 @@
"trimmed": false,
"spriteSourceSize": { "x": 0, "y": 0, "w": 640, "h": 384 },
"sourceSize": { "w": 640, "h": 384 },
"duration": 500
"duration": 2000
},
{
"filename": "backgroundstars 1.ase",
@ -24,7 +24,7 @@
"trimmed": false,
"spriteSourceSize": { "x": 0, "y": 0, "w": 640, "h": 384 },
"sourceSize": { "w": 640, "h": 384 },
"duration": 500
"duration": 100
},
{
"filename": "backgroundstars 3.ase",
@ -42,7 +42,7 @@
"trimmed": false,
"spriteSourceSize": { "x": 0, "y": 0, "w": 640, "h": 384 },
"sourceSize": { "w": 640, "h": 384 },
"duration": 500
"duration": 2000
},
{
"filename": "backgroundstars 5.ase",
@ -52,6 +52,114 @@
"spriteSourceSize": { "x": 0, "y": 0, "w": 640, "h": 384 },
"sourceSize": { "w": 640, "h": 384 },
"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": {
@ -59,12 +167,13 @@
"version": "1.x-dev",
"image": "backgroundstars-animated.png",
"format": "RGBA8888",
"size": { "w": 3840, "h": 384 },
"size": { "w": 11520, "h": 384 },
"scale": "1",
"frameTags": [
],
"layers": [
{ "name": "Layer", "opacity": 255, "blendMode": "normal" }
{ "name": "background", "opacity": 255, "blendMode": "normal" },
{ "name": "stars", "opacity": 124, "blendMode": "normal" }
],
"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
import (
"openquell/assets"
"openquell/config"
"time"
"github.com/hajimehoshi/ebiten/v2"
)
@ -11,7 +13,7 @@ type Animation struct {
Active bool // animation is running
Loop bool // remove the entity if false, loop endless otherwise
Index int // where we are currently
Tiles []*ebiten.Image
Sprites []assets.AnimationSprite
Width, Height int // single sprite measurements
Timer Timer
Trigger string
@ -24,6 +26,7 @@ type Renderable struct {
Damaged int
Shader *ebiten.Shader
Animate Animation
IdleAnimate Animation
Hidden bool
}
@ -41,3 +44,11 @@ func (render *Renderable) StartAnimation() {
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.AnimationTrigger != "" {
// 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.Height = tile.AnimationSpriteSheet.Height
render.Animate.Trigger = tile.AnimationTrigger

View File

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