diff --git a/assets/loader-levels.go b/assets/loader-levels.go index ba97dbd..0fb9f76 100644 --- a/assets/loader-levels.go +++ b/assets/loader-levels.go @@ -14,62 +14,66 @@ import ( var Project = LoadLDTK("levels") var Tiles = InitTiles() +type TileAnimation struct { + OnCollision bool // wether to animate a collision + OnDestruction bool // wether to animate destruction + OnIdle bool // wether to animate during idling + + CollisionSheet AnimationSet // an entry in assets.Animations[name] + DestructionSheet AnimationSet + IdleSheet AnimationSet +} + // Tile: contains image, identifier (as used in level data) and // additional properties type Tile struct { - Id, Ref string - Sprite *ebiten.Image - ToggleSprite *ebiten.Image - Solid bool // wall brick - Player bool // player sphere - IsPrimary bool // primary player sphere - Renderable bool // visible, has sprite - Velocity bool // movable - Collectible bool // collectible, vanishes once collected - Transient bool // turns into brick wall when traversed - Destroyable bool // turns into empty floor when bumped into twice - Animation int // -1=unused, 0-3 = show image of slice - Tiles []*ebiten.Image // has N sprites - TileNames []string // same thing, only the names - Obstacle bool // is an obstacle/enemy - Direction int // obstacle business end shows into this direction - Shader *ebiten.Shader - Alpha *ebiten.Image - Bond bool // denotes an entity which can have a relation to another - Door bool // a door, can be manipulated by a switch - Switch bool // opens|closes a door - AnimateOnDestruct bool // wether to animate destruction - AnimationTrigger string // dynamically configured via LDTP - AnimationSpriteSheet AnimationSet // which sprites to use (refers to an entry in assets.Animations[name]) + Id, Ref string + Sprite *ebiten.Image + ToggleSprite *ebiten.Image + Solid bool // wall brick + Player bool // player sphere + IsPrimary bool // primary player sphere + Renderable bool // visible, has sprite + Velocity bool // movable + Collectible bool // collectible, vanishes once collected + Transient bool // turns into brick wall when traversed + Destroyable bool // turns into empty floor when bumped into twice + Tiles []*ebiten.Image // has N sprites + TileNames []string // same thing, only the names + Obstacle bool // is an obstacle/enemy + Direction int // obstacle business end shows into this direction + Shader *ebiten.Shader + Alpha *ebiten.Image + Bond bool // denotes an entity which can have a relation to another + Door bool // a door, can be manipulated by a switch + Switch bool // opens|closes a door + Animation TileAnimation } func (tile *Tile) Clone() *Tile { newtile := &Tile{ - Id: tile.Id, - Ref: tile.Ref, - Sprite: tile.Sprite, - ToggleSprite: tile.ToggleSprite, - Solid: tile.Solid, - Player: tile.Player, - IsPrimary: tile.IsPrimary, - Renderable: tile.Renderable, - Velocity: tile.Velocity, - Collectible: tile.Collectible, - Transient: tile.Transient, - Destroyable: tile.Destroyable, - Animation: tile.Animation, - Tiles: tile.Tiles, - TileNames: tile.TileNames, - Obstacle: tile.Obstacle, - Direction: tile.Direction, - Alpha: tile.Alpha, - Shader: tile.Shader, - Bond: tile.Bond, - Door: tile.Door, - Switch: tile.Switch, - AnimateOnDestruct: tile.AnimateOnDestruct, - AnimationSpriteSheet: tile.AnimationSpriteSheet, - AnimationTrigger: tile.AnimationTrigger, + Id: tile.Id, + Ref: tile.Ref, + Sprite: tile.Sprite, + ToggleSprite: tile.ToggleSprite, + Solid: tile.Solid, + Player: tile.Player, + IsPrimary: tile.IsPrimary, + Renderable: tile.Renderable, + Velocity: tile.Velocity, + Collectible: tile.Collectible, + Transient: tile.Transient, + Destroyable: tile.Destroyable, + Tiles: tile.Tiles, + TileNames: tile.TileNames, + Obstacle: tile.Obstacle, + Direction: tile.Direction, + Alpha: tile.Alpha, + Shader: tile.Shader, + Bond: tile.Bond, + Door: tile.Door, + Switch: tile.Switch, + Animation: tile.Animation, } return newtile @@ -115,6 +119,12 @@ func NewTileCollectible() *Tile { Solid: false, Renderable: true, Collectible: true, + Animation: TileAnimation{ + OnDestruction: true, + DestructionSheet: Animations["collectible-detonating"], + OnIdle: true, + IdleSheet: Animations["collectible-idle"], + }, } } @@ -128,17 +138,6 @@ func NewTileObstacle(direction int) *Tile { } } -func NewTileAnimation(class []string) *Tile { - sprites := GetSprites(class) - - return &Tile{ - Solid: false, - Renderable: false, - Animation: 0, - Tiles: sprites, - } -} - func NewTileTranswall() *Tile { return &Tile{ Solid: false, @@ -191,39 +190,22 @@ func InitTiles() TileRegistry { "ObstacleSouth": NewTileObstacle(config.South), "ObstacleWest": NewTileObstacle(config.West), "ObstacleEast": NewTileObstacle(config.East), - "Animation": NewTileAnimation([]string{ - "collectible-detonating1", - "collectible-detonating2", - "collectible-detonating3", - "collectible-detonating4", - "collectible-detonating5", - "collectible-detonating6", - "collectible-detonating7", - "collectible-detonating8", - "collectible-detonating9", - "collectible-detonating10", - "collectible-detonating11", - "collectible-detonating12", - "collectible-detonating13", - "collectible-detonating14", - "collectible-detonating15", - }), - "Transient": NewTileTranswall(), - "HiddenDoor": NewTileHiddenDoor("damage"), - "HiddenDoor2": NewTileHiddenDoor("damage"), - "HiddenDoor3": NewTileHiddenDoor("damage"), - "HiddenDoor4": NewTileHiddenDoor("damage"), - "HiddenDoor5": NewTileHiddenDoor("damage"), - "HiddenDoor6": NewTileHiddenDoor("damage"), - "HiddenDoor7": NewTileHiddenDoor("damage"), - "HiddenDoor8": NewTileHiddenDoor("damage"), - "HiddenDoor9": NewTileHiddenDoor("damage"), - "HiddenDoor10": NewTileHiddenDoor("damage"), - "HiddenDoor11": NewTileHiddenDoor("damage"), - "HiddenDoor12": NewTileHiddenDoor("damage"), - "HiddenDoor13": NewTileHiddenDoor("damage"), - "Switch": NewTileSwitch(), - "Door": NewTileDoor(), + "Transient": NewTileTranswall(), + "HiddenDoor": NewTileHiddenDoor("damage"), + "HiddenDoor2": NewTileHiddenDoor("damage"), + "HiddenDoor3": NewTileHiddenDoor("damage"), + "HiddenDoor4": NewTileHiddenDoor("damage"), + "HiddenDoor5": NewTileHiddenDoor("damage"), + "HiddenDoor6": NewTileHiddenDoor("damage"), + "HiddenDoor7": NewTileHiddenDoor("damage"), + "HiddenDoor8": NewTileHiddenDoor("damage"), + "HiddenDoor9": NewTileHiddenDoor("damage"), + "HiddenDoor10": NewTileHiddenDoor("damage"), + "HiddenDoor11": NewTileHiddenDoor("damage"), + "HiddenDoor12": NewTileHiddenDoor("damage"), + "HiddenDoor13": NewTileHiddenDoor("damage"), + "Switch": NewTileSwitch(), + "Door": NewTileDoor(), } } diff --git a/assets/loader-sprites.go b/assets/loader-sprites.go index 9c07f68..6d6fcda 100644 --- a/assets/loader-sprites.go +++ b/assets/loader-sprites.go @@ -60,6 +60,9 @@ type AnimationSet struct { File string } +// names in the registry match the sprite set png file name, the JSON +// file names are irrelevant as they point to the matching file using +// the "image" field. type AnimationRegistry map[string]AnimationSet //go:embed sprites/*.png fonts/*.ttf levels/*.ldtk shaders/*.kg sprites/*.json diff --git a/assets/sprites/collectible.json b/assets/sprites/collectible-detonating.json similarity index 82% rename from assets/sprites/collectible.json rename to assets/sprites/collectible-detonating.json index 3383e79..eaaf633 100644 --- a/assets/sprites/collectible.json +++ b/assets/sprites/collectible-detonating.json @@ -1,42 +1,42 @@ { "frames": [ { - "filename": "collectible 0.ase", + "filename": "collectible #Detonation 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": 100 + "duration": 20 }, { - "filename": "collectible 1.ase", + "filename": "collectible #Detonation 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": 100 + "duration": 20 }, { - "filename": "collectible 2.ase", + "filename": "collectible #Detonation 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": 100 + "duration": 20 }, { - "filename": "collectible 3.ase", + "filename": "collectible #Detonation 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": 100 + "duration": 20 }, { - "filename": "collectible 4.ase", + "filename": "collectible #Detonation 4.ase", "frame": { "x": 256, "y": 0, "w": 64, "h": 64 }, "rotated": false, "trimmed": false, @@ -45,7 +45,7 @@ "duration": 100 }, { - "filename": "collectible 5.ase", + "filename": "collectible #Detonation 5.ase", "frame": { "x": 320, "y": 0, "w": 64, "h": 64 }, "rotated": false, "trimmed": false, @@ -54,7 +54,7 @@ "duration": 100 }, { - "filename": "collectible 6.ase", + "filename": "collectible #Detonation 6.ase", "frame": { "x": 384, "y": 0, "w": 64, "h": 64 }, "rotated": false, "trimmed": false, @@ -63,7 +63,7 @@ "duration": 100 }, { - "filename": "collectible 7.ase", + "filename": "collectible #Detonation 7.ase", "frame": { "x": 448, "y": 0, "w": 64, "h": 64 }, "rotated": false, "trimmed": false, @@ -72,7 +72,7 @@ "duration": 100 }, { - "filename": "collectible 8.ase", + "filename": "collectible #Detonation 8.ase", "frame": { "x": 512, "y": 0, "w": 64, "h": 64 }, "rotated": false, "trimmed": false, @@ -81,7 +81,7 @@ "duration": 100 }, { - "filename": "collectible 9.ase", + "filename": "collectible #Detonation 9.ase", "frame": { "x": 576, "y": 0, "w": 64, "h": 64 }, "rotated": false, "trimmed": false, @@ -90,7 +90,7 @@ "duration": 100 }, { - "filename": "collectible 10.ase", + "filename": "collectible #Detonation 10.ase", "frame": { "x": 640, "y": 0, "w": 64, "h": 64 }, "rotated": false, "trimmed": false, @@ -99,7 +99,7 @@ "duration": 100 }, { - "filename": "collectible 11.ase", + "filename": "collectible #Detonation 11.ase", "frame": { "x": 704, "y": 0, "w": 64, "h": 64 }, "rotated": false, "trimmed": false, @@ -108,7 +108,7 @@ "duration": 100 }, { - "filename": "collectible 12.ase", + "filename": "collectible #Detonation 12.ase", "frame": { "x": 768, "y": 0, "w": 64, "h": 64 }, "rotated": false, "trimmed": false, @@ -117,22 +117,13 @@ "duration": 100 }, { - "filename": "collectible 13.ase", + "filename": "collectible #Detonation 13.ase", "frame": { "x": 832, "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": 100 - }, - { - "filename": "collectible 14.ase", - "frame": { "x": 896, "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": 100 } ], "meta": { @@ -140,9 +131,10 @@ "version": "1.x-dev", "image": "collectible-detonating.png", "format": "I8", - "size": { "w": 960, "h": 64 }, + "size": { "w": 896, "h": 64 }, "scale": "1", "frameTags": [ + { "name": "Detonation", "from": 1, "to": 14, "direction": "forward" } ], "layers": [ { "name": "Yellow Sphere", "opacity": 255, "blendMode": "normal" }, diff --git a/assets/sprites/collectible-detonating.png b/assets/sprites/collectible-detonating.png index d0aff47..8ec9a01 100644 Binary files a/assets/sprites/collectible-detonating.png and b/assets/sprites/collectible-detonating.png differ diff --git a/assets/sprites/collectible-idle.ase b/assets/sprites/collectible-idle.ase new file mode 100644 index 0000000..890bbf0 Binary files /dev/null and b/assets/sprites/collectible-idle.ase differ diff --git a/assets/sprites/collectible-idle.json b/assets/sprites/collectible-idle.json index f084798..625893b 100644 --- a/assets/sprites/collectible-idle.json +++ b/assets/sprites/collectible-idle.json @@ -1,38 +1,38 @@ { "frames": [ { - "filename": "collectible #Idle 0.ase", - "frame": { "x": 0, "y": 0, "w": 64, "h": 64 }, + "filename": "collectible-idle 0.ase", + "frame": { "x": 0, "y": 0, "w": 32, "h": 32 }, "rotated": false, "trimmed": false, - "spriteSourceSize": { "x": 0, "y": 0, "w": 64, "h": 64 }, - "sourceSize": { "w": 64, "h": 64 }, + "spriteSourceSize": { "x": 0, "y": 0, "w": 32, "h": 32 }, + "sourceSize": { "w": 32, "h": 32 }, "duration": 200 }, { - "filename": "collectible #Idle 1.ase", - "frame": { "x": 64, "y": 0, "w": 64, "h": 64 }, + "filename": "collectible-idle 1.ase", + "frame": { "x": 32, "y": 0, "w": 32, "h": 32 }, "rotated": false, "trimmed": false, - "spriteSourceSize": { "x": 0, "y": 0, "w": 64, "h": 64 }, - "sourceSize": { "w": 64, "h": 64 }, + "spriteSourceSize": { "x": 0, "y": 0, "w": 32, "h": 32 }, + "sourceSize": { "w": 32, "h": 32 }, "duration": 200 }, { - "filename": "collectible #Idle 2.ase", - "frame": { "x": 128, "y": 0, "w": 64, "h": 64 }, + "filename": "collectible-idle 2.ase", + "frame": { "x": 64, "y": 0, "w": 32, "h": 32 }, "rotated": false, "trimmed": false, - "spriteSourceSize": { "x": 0, "y": 0, "w": 64, "h": 64 }, - "sourceSize": { "w": 64, "h": 64 }, + "spriteSourceSize": { "x": 0, "y": 0, "w": 32, "h": 32 }, + "sourceSize": { "w": 32, "h": 32 }, "duration": 200 }, { - "filename": "collectible #Idle 3.ase", - "frame": { "x": 192, "y": 0, "w": 64, "h": 64 }, + "filename": "collectible-idle 3.ase", + "frame": { "x": 96, "y": 0, "w": 32, "h": 32 }, "rotated": false, "trimmed": false, - "spriteSourceSize": { "x": 0, "y": 0, "w": 64, "h": 64 }, - "sourceSize": { "w": 64, "h": 64 }, + "spriteSourceSize": { "x": 0, "y": 0, "w": 32, "h": 32 }, + "sourceSize": { "w": 32, "h": 32 }, "duration": 200 } ], @@ -40,26 +40,13 @@ "app": "http://www.aseprite.org/", "version": "1.x-dev", "image": "collectible-idle.png", - "format": "I8", - "size": { "w": 256, "h": 64 }, + "format": "RGBA8888", + "size": { "w": 128, "h": 32 }, "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" } + { "name": "Layer 1", "opacity": 255, "blendMode": "normal" } ], "slices": [ ] diff --git a/assets/sprites/collectible-idle.png b/assets/sprites/collectible-idle.png index 8b5c56a..5e9160e 100644 Binary files a/assets/sprites/collectible-idle.png and b/assets/sprites/collectible-idle.png differ diff --git a/assets/sprites/collectible.ase b/assets/sprites/collectible.ase index 3e7ca23..a599a0d 100644 Binary files a/assets/sprites/collectible.ase and b/assets/sprites/collectible.ase differ diff --git a/components/components.go b/components/components.go index 61102cb..8be3044 100644 --- a/components/components.go +++ b/components/components.go @@ -4,7 +4,9 @@ package components type Tilish struct{} type Solid struct{} type Floor struct{} -type Collectible struct{} +type Collectible struct { + Hit bool +} type Obstacle struct { Direction int diff --git a/components/renderable.go b/components/renderable.go index d9bd7e9..b1d9622 100644 --- a/components/renderable.go +++ b/components/renderable.go @@ -8,40 +8,66 @@ import ( "github.com/hajimehoshi/ebiten/v2" ) +const ( + Destruction = iota + Idle + Collision +) + // virtual location, aka tile address type Animation struct { - Active bool // animation is running - Loop bool // remove the entity if false, loop endless otherwise - Index int // where we are currently - Sprites []assets.AnimationSprite - Width, Height int // single sprite measurements + Active bool // animation is running + Loop bool // remove the entity if false, loop endless otherwise + Index int // where we are currently + Sprites []assets.AnimationSprite // each element contains the sprite and duration + Width, Height int // single sprite measurements Timer Timer Trigger string + Data assets.TileAnimation } type Renderable struct { - Pos *Position // just for debugging, will not used as positiion! - Image *ebiten.Image - DamageImage *ebiten.Image // FIXME: put into its own struct - Damaged int - Shader *ebiten.Shader - Animate Animation - IdleAnimate Animation - Hidden bool + Pos *Position // just for debugging, will not used as positiion! + Image *ebiten.Image + DamageImage *ebiten.Image // FIXME: put into its own struct + Damaged int + Shader *ebiten.Shader + DestructionAnimate Animation + IdleAnimate Animation + CollisionAnimate Animation + Hidden bool } -func (render *Renderable) StartAnimation() { - render.Hidden = true - render.Animate.Active = true - render.Animate.Timer.Start(config.ANIMATION_STARTWAIT) - - switch render.Animate.Trigger { - case "OnCollision": +func (render *Renderable) StartAnimation(which int) { + switch which { + case Collision: fallthrough - case "OnDestruct": - render.Animate.Loop = false - case "OnIdle": - render.Animate.Loop = true + case Destruction: + render.Hidden = true + render.DestructionAnimate.Active = true + render.DestructionAnimate.Timer.Start(config.ANIMATION_STARTWAIT) + render.IdleAnimate.Active = false + case Idle: + render.IdleAnimate.Active = true + render.IdleAnimate.Loop = true + render.IdleAnimate.Timer.Start(0) + } +} + +func (render *Renderable) StopAnimation(which int) { + switch which { + case Collision: + render.CollisionAnimate.Active = false + case Idle: + render.IdleAnimate.Active = false + } +} + +func (render *Renderable) Animations() map[int]*Animation { + return map[int]*Animation{ + Collision: &render.CollisionAnimate, + Destruction: &render.DestructionAnimate, + Idle: &render.IdleAnimate, } } diff --git a/config/static.go b/config/static.go index a24cbbf..a7e0e61 100644 --- a/config/static.go +++ b/config/static.go @@ -18,8 +18,8 @@ const ( PLAYERSPEED int = 5 ANIMATION_STARTWAIT time.Duration = 30 * time.Millisecond // how long to wait to start collectible animation ANIMATION_LOOPWAIT time.Duration = 40 * time.Millisecond // how much time to wait between the sprites - LEVEL_END_WAIT time.Duration = 500 * time.Millisecond - version string = "1.3.0" + LEVEL_END_WAIT time.Duration = 100 * time.Millisecond + version string = "1.4.0" MenuRectX int = 600 MenuRectY int = 0 diff --git a/game/levels.go b/game/levels.go index c1b49cf..b5a01fd 100644 --- a/game/levels.go +++ b/game/levels.go @@ -2,7 +2,6 @@ package game import ( "image" - "log" "log/slog" "openquell/assets" "openquell/components" @@ -198,27 +197,6 @@ func LevelToSlice(game *Game, level *ldtkgo.Level, tilesize int) (Map, Map) { } tileRect := entity.TileRect - animationtrigger := util.GetPropertyString(entity, "AnimationTrigger") - slog.Debug("got trigger", "trigger", animationtrigger) - - //animateondestruct := util.GetPropertyBool(entity, "AnimateOnDestruct") - // FIXME: also check for AnimationLoop and other animation reasons - // if animateondestruct { - if animationtrigger != "" { - tile.AnimateOnDestruct = true - - animation := util.GetPropertyString(entity, "AnimateSpriteSheet") - if animation != "" { - if !util.Exists(assets.Animations, animation) { - log.Fatalf("entity %s refers to non existent animation set %s", - entity.Identifier, animation) - } - } - - tile.AnimationSpriteSheet = assets.Animations[animation] - tile.AnimationTrigger = animationtrigger - } - tile.Sprite = tileset.SubImage( image.Rect(tileRect.X, tileRect.Y, tileRect.X+tileRect.W, diff --git a/grid/grid.go b/grid/grid.go index f34dbeb..9799f2c 100644 --- a/grid/grid.go +++ b/grid/grid.go @@ -159,13 +159,24 @@ func NewGrid(world *ecs.World, render.Image = tile.Sprite render.Pos = pos - //if tile.AnimateOnDestruct { - if tile.AnimationTrigger != "" { - // FIXME: be more generic, use LDTK enum - render.Animate.Sprites = tile.AnimationSpriteSheet.Sprites - render.Animate.Width = tile.AnimationSpriteSheet.Width - render.Animate.Height = tile.AnimationSpriteSheet.Height - render.Animate.Trigger = tile.AnimationTrigger + if tile.Animation.OnCollision { + render.CollisionAnimate.Sprites = tile.Animation.CollisionSheet.Sprites + render.CollisionAnimate.Width = tile.Animation.CollisionSheet.Width + render.CollisionAnimate.Height = tile.Animation.CollisionSheet.Height + } + + if tile.Animation.OnDestruction { + render.DestructionAnimate.Sprites = tile.Animation.DestructionSheet.Sprites + render.DestructionAnimate.Width = tile.Animation.DestructionSheet.Width + render.DestructionAnimate.Height = tile.Animation.DestructionSheet.Height + } + + if tile.Animation.OnIdle { + render.IdleAnimate.Sprites = tile.Animation.IdleSheet.Sprites + render.IdleAnimate.Width = tile.Animation.IdleSheet.Width + render.IdleAnimate.Height = tile.Animation.IdleSheet.Height + render.StartAnimation(components.Idle) + render.Hidden = true // we do NOT render the sprite, but the idle animation instead } default: diff --git a/systems/animation_system.go b/systems/animation_system.go index e0808e1..254eb22 100644 --- a/systems/animation_system.go +++ b/systems/animation_system.go @@ -1,8 +1,9 @@ package systems import ( + "log/slog" + "openquell/components" . "openquell/components" - "openquell/config" "github.com/hajimehoshi/ebiten/v2" "github.com/mlange-42/arche/ecs" @@ -32,28 +33,35 @@ func (system *AnimationSystem) Update() error { for query.Next() { _, render := query.Get() - if render.Animate.Active { - if render.Animate.Timer.IsReady() { - switch { - // animation shows from earlier tick, animate - 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: - // last sprite reached - if render.Animate.Loop { - render.Animate.Index = 0 - } else { - EntitiesToRemove = append(EntitiesToRemove, query.Entity()) + + for animationtype, animate := range render.Animations() { + if animate.Active { + if animate.Timer.IsReady() { + switch { + // animation shows from earlier tick, animate + case animate.Index > -1 && animate.Index < len(animate.Sprites)-1: + animate.Index += 1 + animate.Timer.Start(animate.GetDuration()) + default: + // last sprite reached + if animate.Loop { + animate.Index = 0 + animate.Timer.Start(animate.GetDuration()) + } + + if animationtype == components.Destruction { + EntitiesToRemove = append(EntitiesToRemove, query.Entity()) + } } + } else { + animate.Timer.Update() } - } else { - render.Animate.Timer.Update() } } } for _, entity := range EntitiesToRemove { + slog.Debug("remove collectible") system.World.RemoveEntity(entity) } @@ -68,10 +76,13 @@ func (system *AnimationSystem) Draw(screen *ebiten.Image) { for query.Next() { pos, render := query.Get() - if render.Animate.Active { - op.GeoM.Reset() - op.GeoM.Translate(float64(pos.X), float64(pos.Y)) - screen.DrawImage(render.Animate.GetSprite(), op) + for _, animate := range render.Animations() { + if animate.Active { + op.GeoM.Reset() + op.GeoM.Translate(float64(pos.X), float64(pos.Y)) + sprite := animate.GetSprite() + screen.DrawImage(sprite, op) + } } } } diff --git a/systems/collectible_system.go b/systems/collectible_system.go index 79765b2..777d823 100644 --- a/systems/collectible_system.go +++ b/systems/collectible_system.go @@ -4,6 +4,7 @@ import ( "log/slog" "openquell/components" . "openquell/components" + . "openquell/config" "openquell/observers" @@ -38,12 +39,18 @@ func (system *CollectibleSystem) Update() error { numcollectibles := query.Count() if numcollectibles == 0 || observer.Lost { + slog.Debug("WON") + timer := observers.GetGameObserver(system.World).StopTimer + if !timer.Running { + timer.Start(LEVEL_END_WAIT) + + } query.Close() return nil } for query.Next() { - colposition, _, render := query.Get() + colposition, collectible, render := query.Get() for _, player := range observer.GetPlayers() { if !system.World.Alive(player) { @@ -54,10 +61,10 @@ func (system *CollectibleSystem) Update() error { playervelocity := (*Velocity)(system.World.Get(player, veloID)) ok, _ := colposition.Intersects(playerposition, playervelocity) - if ok && !render.Hidden { + if ok && !collectible.Hit { slog.Debug("bumped into collectible", "colpos", colposition) - render.StartAnimation() + render.StartAnimation(components.Destruction) // position the animation relative to the middle of the current entity colposition.Update( @@ -65,19 +72,13 @@ func (system *CollectibleSystem) Update() error { colposition.Y-(system.Cellsize/2), 64, ) + + collectible.Hit = true numcollectibles-- } } } - if numcollectibles == 0 { - // winner, winner, chicken dinner! - timer := observers.GetGameObserver(system.World).StopTimer - if !timer.Running { - timer.Start(LEVEL_END_WAIT) - } - } - return nil }