added detonation particles after collectibles have been collected

This commit is contained in:
Thomas von Dein 2024-02-08 18:33:59 +01:00
parent d17594dc38
commit 006216398a
9 changed files with 122 additions and 17 deletions

View File

@ -28,6 +28,8 @@ type Tile struct {
Renderable bool
Velocity bool
Collectible bool
Particle int // -1=unused, 0-3 = show image of slice
Particles []*ebiten.Image
}
func NewTilePlayer() *Tile {
@ -62,6 +64,23 @@ func NewTileCollectible(class string) *Tile {
}
}
func NewTileParticle(class []string) *Tile {
sprites := []*ebiten.Image{}
for _, sprite := range class {
sprites = append(sprites, Assets[sprite])
}
return &Tile{
Id: '*',
Class: "particle",
Solid: false,
Renderable: false,
Particle: -1,
Particles: sprites,
}
}
// used to map level data bytes to actual tiles
type TileRegistry map[byte]*Tile
@ -90,6 +109,10 @@ func InitTiles() TileRegistry {
'#': NewTileBlock("block-grey32"),
'S': NewTilePlayer(),
'o': NewTileCollectible("collectible-orange"),
'*': NewTileParticle([]string{
"particle-dust-0", "particle-dust-0", "particle-dust-1", "particle-dust-1",
"particle-dust-0", "particle-dust-2", "particle-dust-3", "particle-dust-3",
}),
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

View File

@ -16,3 +16,8 @@ type Solid struct{}
type Floor struct{}
type Player struct{}
type Collectible struct{}
type Particle struct {
Index int
Particles []*ebiten.Image
}

View File

@ -46,6 +46,11 @@ func NewGrid(game *Game, tilesize int, mapslice map[image.Point]*assets.Tile) *G
components.Renderable,
components.Collectible](game.World)
ptmapper := generic.NewMap2[
components.Position,
components.Particle,
](game.World)
var pos *components.Position
var render *components.Renderable
@ -81,6 +86,12 @@ func NewGrid(game *Game, tilesize int, mapslice map[image.Point]*assets.Tile) *G
pos.Update(point.X*tilesize, point.Y*tilesize, tilesize)
}
// not part of the grid, but add them as well
entity := ptmapper.New()
_, particle := ptmapper.Get(entity)
particle.Index = assets.Tiles['*'].Particle
particle.Particles = assets.Tiles['*'].Particles
return &Grid{
Size: len(mapslice),
Tilesize: tilesize,

View File

@ -36,16 +36,25 @@ func NewLevel(game *Game, cellsize int, plan *assets.RawLevel) *Level {
velocityid := ecs.ComponentID[components.Velocity](game.World)
playerid := ecs.ComponentID[components.Player](game.World)
colid := ecs.ComponentID[components.Collectible](game.World)
ptid := ecs.ComponentID[components.Particle](game.World)
sid := ecs.ComponentID[components.Solid](game.World)
renderid := ecs.ComponentID[components.Renderable](game.World)
selectors := map[string]ecs.Mask{}
selectors["player"] = filter.All(positionid, velocityid, playerid)
selectors["tile"] = filter.All(renderid, positionid, sid)
selectors["movable"] = filter.All(renderid, positionid)
selectors["collectible"] = filter.All(positionid, colid)
selectors["particle"] = filter.All(positionid, ptid)
components := map[string]ecs.ID{}
components["position"] = positionid
components["velocity"] = velocityid
components["player"] = playerid
components["collectible"] = colid
components["particle"] = ptid
components["solid"] = sid
components["renderable"] = renderid
return &Level{
Mapslice: LevelToSlice(game, plan, cellsize),
@ -66,6 +75,7 @@ func (level *Level) Update() {
query := level.World.Query(level.Selector["player"])
toRemove := []ecs.Entity{}
particle_pos := image.Point{}
for query.Next() {
playerposition := (*components.Position)(query.Get(level.Component["position"]))
@ -114,6 +124,8 @@ func (level *Level) Update() {
if ok {
fmt.Printf("bumped into collectible %v\n", collectible)
toRemove = append(toRemove, colquery.Entity())
particle_pos.X = colposition.X
particle_pos.Y = colposition.Y
}
}
}
@ -121,11 +133,39 @@ func (level *Level) Update() {
playerposition.Move(velocity)
}
// remove collectible if collected
for _, entity := range toRemove {
// FIXME: or keep them and prepare an animated death
level.World.RemoveEntity(entity)
}
// display debris after collecting
ptquery := level.World.Query(level.Selector["particle"])
for ptquery.Next() {
// we loop, but it's only one anyway
particle := (*components.Particle)(ptquery.Get(level.Component["particle"]))
colposition := (*components.Position)(ptquery.Get(level.Component["position"]))
if len(toRemove) > 0 {
// particle appears
colposition.Update(
particle_pos.X-(level.Cellsize/2),
particle_pos.Y-(level.Cellsize/2),
64,
)
particle.Index = 0 // start displaying the particle
} else {
switch {
case particle.Index > -1 && particle.Index < len(particle.Particles)-1:
particle.Index++
default:
// last sprite reached, remove it
particle.Index = -1
}
}
}
}
func (level *Level) Position2Point(position *components.Position) image.Point {
@ -136,7 +176,10 @@ func (level *Level) Position2Point(position *components.Position) image.Point {
}
// return the tile the moving object would end up on if indeed moving
func (level *Level) GetTile(position *components.Position, velocity *components.Velocity) *assets.Tile {
func (level *Level) GetTile(
position *components.Position,
velocity *components.Velocity) *assets.Tile {
newpoint := image.Point{
int(position.X+velocity.Data.X) / level.Cellsize,
int(position.Y+velocity.Data.Y) / level.Cellsize,
@ -147,20 +190,22 @@ func (level *Level) GetTile(position *components.Position, velocity *components.
}
func (level *Level) Draw(screen *ebiten.Image) {
rid := ecs.ComponentID[components.Renderable](level.World)
pid := ecs.ComponentID[components.Position](level.World)
sid := ecs.ComponentID[components.Solid](level.World)
level.DrawTiles(screen)
level.DrawMovables(screen)
level.DrawParticles(screen)
}
func (level *Level) DrawTiles(screen *ebiten.Image) {
op := &ebiten.DrawImageOptions{}
if !level.UseCache {
// map not cached or cacheable, write it to the cache
draw.Draw(level.Cache, level.Background.Bounds(), level.Background, image.ZP, draw.Src)
selector := filter.All(rid, pid, sid)
query := level.World.Query(selector)
query := level.World.Query(level.Selector["tile"])
for query.Next() {
pos := (*components.Position)(query.Get(pid))
sprite := (*components.Renderable)(query.Get(rid))
pos := (*components.Position)(query.Get(level.Component["position"]))
sprite := (*components.Renderable)(query.Get(level.Component["renderable"]))
draw.Draw(
level.Cache,
@ -168,31 +213,52 @@ func (level *Level) Draw(screen *ebiten.Image) {
sprite.Image, image.ZP, draw.Over)
}
op := &ebiten.DrawImageOptions{}
op.GeoM.Reset()
screen.DrawImage(level.Cache, op)
level.UseCache = true
} else {
// use the cached map
op := &ebiten.DrawImageOptions{}
op.GeoM.Reset()
screen.DrawImage(level.Cache, op)
}
}
func (level *Level) DrawMovables(screen *ebiten.Image) {
// write the movable tiles
selector := filter.All(rid, pid).Without(sid)
op := &ebiten.DrawImageOptions{}
selector := level.Selector["movable"].Without(level.Component["solid"])
query := level.World.Query(&selector)
for query.Next() {
pos := (*components.Position)(query.Get(pid))
sprite := (*components.Renderable)(query.Get(rid))
op := &ebiten.DrawImageOptions{}
for query.Next() {
pos := (*components.Position)(query.Get(level.Component["position"]))
sprite := (*components.Renderable)(query.Get(level.Component["renderable"]))
op.GeoM.Reset()
op.GeoM.Translate(float64(pos.X), float64(pos.Y))
screen.DrawImage(sprite.Image, op)
}
}
func (level *Level) DrawParticles(screen *ebiten.Image) {
// write particles (these are no tiles!)
op := &ebiten.DrawImageOptions{}
query := level.World.Query(level.Selector["particle"])
for query.Next() {
pos := (*components.Position)(query.Get(level.Component["position"]))
particle := (*components.Particle)(query.Get(level.Component["particle"]))
if particle.Index > -1 {
op.GeoM.Reset()
op.GeoM.Translate(float64(pos.X), float64(pos.Y))
screen.DrawImage(particle.Particles[particle.Index], op)
}
}
}
func (level *Level) SetupGrid(game *Game) {
level.Grid = NewGrid(game, level.Cellsize, level.Mapslice)
}

BIN
src/particle-dust.xcf Normal file

Binary file not shown.