added detonation particles after collectibles have been collected
This commit is contained in:
parent
d17594dc38
commit
006216398a
@ -28,6 +28,8 @@ type Tile struct {
|
|||||||
Renderable bool
|
Renderable bool
|
||||||
Velocity bool
|
Velocity bool
|
||||||
Collectible bool
|
Collectible bool
|
||||||
|
Particle int // -1=unused, 0-3 = show image of slice
|
||||||
|
Particles []*ebiten.Image
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTilePlayer() *Tile {
|
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
|
// used to map level data bytes to actual tiles
|
||||||
type TileRegistry map[byte]*Tile
|
type TileRegistry map[byte]*Tile
|
||||||
|
|
||||||
@ -90,6 +109,10 @@ func InitTiles() TileRegistry {
|
|||||||
'#': NewTileBlock("block-grey32"),
|
'#': NewTileBlock("block-grey32"),
|
||||||
'S': NewTilePlayer(),
|
'S': NewTilePlayer(),
|
||||||
'o': NewTileCollectible("collectible-orange"),
|
'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",
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
BIN
assets/sprites/particle-dust-0.png
Normal file
BIN
assets/sprites/particle-dust-0.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.8 KiB |
BIN
assets/sprites/particle-dust-1.png
Normal file
BIN
assets/sprites/particle-dust-1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.2 KiB |
BIN
assets/sprites/particle-dust-2.png
Normal file
BIN
assets/sprites/particle-dust-2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.4 KiB |
BIN
assets/sprites/particle-dust-3.png
Normal file
BIN
assets/sprites/particle-dust-3.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.4 KiB |
@ -16,3 +16,8 @@ type Solid struct{}
|
|||||||
type Floor struct{}
|
type Floor struct{}
|
||||||
type Player struct{}
|
type Player struct{}
|
||||||
type Collectible struct{}
|
type Collectible struct{}
|
||||||
|
|
||||||
|
type Particle struct {
|
||||||
|
Index int
|
||||||
|
Particles []*ebiten.Image
|
||||||
|
}
|
||||||
|
|||||||
11
game/grid.go
11
game/grid.go
@ -46,6 +46,11 @@ func NewGrid(game *Game, tilesize int, mapslice map[image.Point]*assets.Tile) *G
|
|||||||
components.Renderable,
|
components.Renderable,
|
||||||
components.Collectible](game.World)
|
components.Collectible](game.World)
|
||||||
|
|
||||||
|
ptmapper := generic.NewMap2[
|
||||||
|
components.Position,
|
||||||
|
components.Particle,
|
||||||
|
](game.World)
|
||||||
|
|
||||||
var pos *components.Position
|
var pos *components.Position
|
||||||
var render *components.Renderable
|
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)
|
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{
|
return &Grid{
|
||||||
Size: len(mapslice),
|
Size: len(mapslice),
|
||||||
Tilesize: tilesize,
|
Tilesize: tilesize,
|
||||||
|
|||||||
100
game/levels.go
100
game/levels.go
@ -36,16 +36,25 @@ func NewLevel(game *Game, cellsize int, plan *assets.RawLevel) *Level {
|
|||||||
velocityid := ecs.ComponentID[components.Velocity](game.World)
|
velocityid := ecs.ComponentID[components.Velocity](game.World)
|
||||||
playerid := ecs.ComponentID[components.Player](game.World)
|
playerid := ecs.ComponentID[components.Player](game.World)
|
||||||
colid := ecs.ComponentID[components.Collectible](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 := map[string]ecs.Mask{}
|
||||||
selectors["player"] = filter.All(positionid, velocityid, playerid)
|
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["collectible"] = filter.All(positionid, colid)
|
||||||
|
selectors["particle"] = filter.All(positionid, ptid)
|
||||||
|
|
||||||
components := map[string]ecs.ID{}
|
components := map[string]ecs.ID{}
|
||||||
components["position"] = positionid
|
components["position"] = positionid
|
||||||
components["velocity"] = velocityid
|
components["velocity"] = velocityid
|
||||||
components["player"] = playerid
|
components["player"] = playerid
|
||||||
components["collectible"] = colid
|
components["collectible"] = colid
|
||||||
|
components["particle"] = ptid
|
||||||
|
components["solid"] = sid
|
||||||
|
components["renderable"] = renderid
|
||||||
|
|
||||||
return &Level{
|
return &Level{
|
||||||
Mapslice: LevelToSlice(game, plan, cellsize),
|
Mapslice: LevelToSlice(game, plan, cellsize),
|
||||||
@ -66,6 +75,7 @@ func (level *Level) Update() {
|
|||||||
query := level.World.Query(level.Selector["player"])
|
query := level.World.Query(level.Selector["player"])
|
||||||
|
|
||||||
toRemove := []ecs.Entity{}
|
toRemove := []ecs.Entity{}
|
||||||
|
particle_pos := image.Point{}
|
||||||
|
|
||||||
for query.Next() {
|
for query.Next() {
|
||||||
playerposition := (*components.Position)(query.Get(level.Component["position"]))
|
playerposition := (*components.Position)(query.Get(level.Component["position"]))
|
||||||
@ -114,6 +124,8 @@ func (level *Level) Update() {
|
|||||||
if ok {
|
if ok {
|
||||||
fmt.Printf("bumped into collectible %v\n", collectible)
|
fmt.Printf("bumped into collectible %v\n", collectible)
|
||||||
toRemove = append(toRemove, colquery.Entity())
|
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)
|
playerposition.Move(velocity)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// remove collectible if collected
|
||||||
for _, entity := range toRemove {
|
for _, entity := range toRemove {
|
||||||
// FIXME: or keep them and prepare an animated death
|
// FIXME: or keep them and prepare an animated death
|
||||||
level.World.RemoveEntity(entity)
|
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 {
|
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
|
// 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{
|
newpoint := image.Point{
|
||||||
int(position.X+velocity.Data.X) / level.Cellsize,
|
int(position.X+velocity.Data.X) / level.Cellsize,
|
||||||
int(position.Y+velocity.Data.Y) / 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) {
|
func (level *Level) Draw(screen *ebiten.Image) {
|
||||||
rid := ecs.ComponentID[components.Renderable](level.World)
|
level.DrawTiles(screen)
|
||||||
pid := ecs.ComponentID[components.Position](level.World)
|
level.DrawMovables(screen)
|
||||||
sid := ecs.ComponentID[components.Solid](level.World)
|
level.DrawParticles(screen)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (level *Level) DrawTiles(screen *ebiten.Image) {
|
||||||
|
op := &ebiten.DrawImageOptions{}
|
||||||
|
|
||||||
if !level.UseCache {
|
if !level.UseCache {
|
||||||
// map not cached or cacheable, write it to the cache
|
// map not cached or cacheable, write it to the cache
|
||||||
draw.Draw(level.Cache, level.Background.Bounds(), level.Background, image.ZP, draw.Src)
|
draw.Draw(level.Cache, level.Background.Bounds(), level.Background, image.ZP, draw.Src)
|
||||||
|
|
||||||
selector := filter.All(rid, pid, sid)
|
query := level.World.Query(level.Selector["tile"])
|
||||||
|
|
||||||
query := level.World.Query(selector)
|
|
||||||
for query.Next() {
|
for query.Next() {
|
||||||
pos := (*components.Position)(query.Get(pid))
|
pos := (*components.Position)(query.Get(level.Component["position"]))
|
||||||
sprite := (*components.Renderable)(query.Get(rid))
|
sprite := (*components.Renderable)(query.Get(level.Component["renderable"]))
|
||||||
|
|
||||||
draw.Draw(
|
draw.Draw(
|
||||||
level.Cache,
|
level.Cache,
|
||||||
@ -168,31 +213,52 @@ func (level *Level) Draw(screen *ebiten.Image) {
|
|||||||
sprite.Image, image.ZP, draw.Over)
|
sprite.Image, image.ZP, draw.Over)
|
||||||
}
|
}
|
||||||
|
|
||||||
op := &ebiten.DrawImageOptions{}
|
op.GeoM.Reset()
|
||||||
screen.DrawImage(level.Cache, op)
|
screen.DrawImage(level.Cache, op)
|
||||||
|
|
||||||
level.UseCache = true
|
level.UseCache = true
|
||||||
} else {
|
} else {
|
||||||
// use the cached map
|
// use the cached map
|
||||||
op := &ebiten.DrawImageOptions{}
|
op.GeoM.Reset()
|
||||||
screen.DrawImage(level.Cache, op)
|
screen.DrawImage(level.Cache, op)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (level *Level) DrawMovables(screen *ebiten.Image) {
|
||||||
// write the movable tiles
|
// 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)
|
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))
|
op.GeoM.Translate(float64(pos.X), float64(pos.Y))
|
||||||
|
|
||||||
screen.DrawImage(sprite.Image, op)
|
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) {
|
func (level *Level) SetupGrid(game *Game) {
|
||||||
level.Grid = NewGrid(game, level.Cellsize, level.Mapslice)
|
level.Grid = NewGrid(game, level.Cellsize, level.Mapslice)
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
src/particle-dust.xcf
Normal file
BIN
src/particle-dust.xcf
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user