diff --git a/assets/loader-sprites.go b/assets/loader-sprites.go index 4cc2d41..9c07f68 100644 --- a/assets/loader-sprites.go +++ b/assets/loader-sprites.go @@ -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 } diff --git a/assets/sprites/backgroundstars-animated.json b/assets/sprites/backgroundstars-animated.json index e0b72c3..17438e4 100644 --- a/assets/sprites/backgroundstars-animated.json +++ b/assets/sprites/backgroundstars-animated.json @@ -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": [ ] diff --git a/assets/sprites/backgroundstars-animated.png b/assets/sprites/backgroundstars-animated.png index b966d1b..b9b6690 100644 Binary files a/assets/sprites/backgroundstars-animated.png and b/assets/sprites/backgroundstars-animated.png differ diff --git a/assets/sprites/backgroundstars.ase b/assets/sprites/backgroundstars.ase index 9bb220b..48a3509 100644 Binary files a/assets/sprites/backgroundstars.ase and b/assets/sprites/backgroundstars.ase differ diff --git a/assets/sprites/collectible-idle.json b/assets/sprites/collectible-idle.json new file mode 100644 index 0000000..f084798 --- /dev/null +++ b/assets/sprites/collectible-idle.json @@ -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": [ + ] + } +} diff --git a/assets/sprites/collectible-idle.png b/assets/sprites/collectible-idle.png new file mode 100644 index 0000000..8b5c56a Binary files /dev/null and b/assets/sprites/collectible-idle.png differ diff --git a/assets/sprites/collectible.ase b/assets/sprites/collectible.ase index 0007615..3e7ca23 100644 Binary files a/assets/sprites/collectible.ase and b/assets/sprites/collectible.ase differ diff --git a/assets/sprites/stars.ase b/assets/sprites/stars.ase new file mode 100644 index 0000000..b0ee1a8 Binary files /dev/null and b/assets/sprites/stars.ase differ diff --git a/components/renderable.go b/components/renderable.go index 60af934..d9bd7e9 100644 --- a/components/renderable.go +++ b/components/renderable.go @@ -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 +} diff --git a/grid/grid.go b/grid/grid.go index 1b620d7..f34dbeb 100644 --- a/grid/grid.go +++ b/grid/grid.go @@ -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 diff --git a/systems/animation_system.go b/systems/animation_system.go index 84b7f2a..e0808e1 100644 --- a/systems/animation_system.go +++ b/systems/animation_system.go @@ -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) } } } diff --git a/systems/grid_system.go b/systems/grid_system.go index b2afe10..0c22f45 100644 --- a/systems/grid_system.go +++ b/systems/grid_system.go @@ -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) }