added collectibles support

This commit is contained in:
Thomas von Dein 2024-02-07 18:01:58 +01:00
parent ce7fcd038a
commit a0b40139c7
7 changed files with 116 additions and 53 deletions

View File

@ -9,9 +9,9 @@ Background: background-orange
# ######## ###
#
############ #
# # #
# o # #
# # ######## #
# #
# # o
# ############

View File

@ -27,6 +27,7 @@ type Tile struct {
Player bool
Renderable bool
Velocity bool
Collectible bool
}
func NewTilePlayer() *Tile {
@ -50,6 +51,17 @@ func NewTileBlock(class string) *Tile {
}
}
func NewTileCollectible(class string) *Tile {
return &Tile{
Id: 'o',
Sprite: Assets[class],
Class: class,
Solid: false,
Renderable: true,
Collectible: true,
}
}
// used to map level data bytes to actual tiles
type TileRegistry map[byte]*Tile
@ -77,6 +89,7 @@ func InitTiles() TileRegistry {
' ': {Id: ' ', Class: "floor", Renderable: false},
'#': NewTileBlock("block-grey32"),
'S': NewTilePlayer(),
'o': NewTileCollectible("collectible-orange"),
}
}

View File

@ -15,3 +15,4 @@ type Tilish struct{}
type Solid struct{}
type Floor struct{}
type Player struct{}
type Collectible struct{}

View File

@ -32,13 +32,20 @@ func NewGrid(game *Game, tilesize int, mapslice map[image.Point]*assets.Tile) *G
components.Velocity,
components.Renderable,
components.Player](game.World)
solidmapper := generic.NewMap4[
components.Position,
components.Renderable,
components.Tilish,
components.Solid](game.World)
emptymapper := generic.NewMap2[components.Position, components.Tilish](game.World)
colmapper := generic.NewMap3[
components.Position,
components.Renderable,
components.Collectible](game.World)
var pos *components.Position
var render *components.Renderable
@ -53,6 +60,9 @@ func NewGrid(game *Game, tilesize int, mapslice map[image.Point]*assets.Tile) *G
entity := playermapper.New()
pos, _, render, _ = playermapper.Get(entity)
fmt.Printf("player start pos: %d,%d\n", point.X*tilesize, point.Y*tilesize)
case tile.Collectible:
entity := colmapper.New()
pos, render, _ = colmapper.Get(entity)
default:
log.Fatalln("unsupported tile type encountered")
}

View File

@ -3,6 +3,7 @@ package game
import (
"fmt"
"image"
"image/draw"
"log"
"openquell/assets"
"openquell/components"
@ -22,9 +23,30 @@ type Level struct {
Description string
Background *ebiten.Image
Mapslice map[image.Point]*assets.Tile
UseCache bool
Cache *ebiten.Image
Selector map[string]ecs.Mask
Component map[string]ecs.ID
}
func NewLevel(game *Game, cellsize int, plan *assets.RawLevel) *Level {
cache := ebiten.NewImage(game.ScreenWidth, game.ScreenHeight)
positionid := ecs.ComponentID[components.Position](game.World)
velocityid := ecs.ComponentID[components.Velocity](game.World)
playerid := ecs.ComponentID[components.Player](game.World)
colid := ecs.ComponentID[components.Collectible](game.World)
selectors := map[string]ecs.Mask{}
selectors["player"] = filter.All(positionid, velocityid, playerid)
selectors["collectible"] = filter.All(positionid, colid)
components := map[string]ecs.ID{}
components["position"] = positionid
components["velocity"] = velocityid
components["player"] = playerid
components["collectible"] = colid
return &Level{
Mapslice: LevelToSlice(game, plan, cellsize),
Cellsize: cellsize,
@ -33,21 +55,22 @@ func NewLevel(game *Game, cellsize int, plan *assets.RawLevel) *Level {
Height: game.ScreenHeight,
Description: plan.Description,
Background: plan.Background,
UseCache: false,
Cache: cache,
Selector: selectors,
Component: components,
}
}
func (level *Level) Update() {
positionid := ecs.ComponentID[components.Position](level.World)
velocityid := ecs.ComponentID[components.Velocity](level.World)
playerid := ecs.ComponentID[components.Player](level.World)
selector := filter.All(positionid, velocityid, playerid)
query := level.World.Query(selector)
query := level.World.Query(level.Selector["player"])
colquery := level.World.Query(level.Selector["collectible"])
for query.Next() {
playerposition := (*components.Position)(query.Get(positionid))
velocity := (*components.Velocity)(query.Get(velocityid))
playerposition := (*components.Position)(query.Get(level.Component["position"]))
velocity := (*components.Velocity)(query.Get(level.Component["velocity"]))
if !velocity.Moving() {
switch {
case ebiten.IsKeyPressed(ebiten.KeyRight):
velocity.Change(East)
@ -59,26 +82,7 @@ func (level *Level) Update() {
velocity.Change(North)
// other keys: <tab>: switch player, etc
}
/*
// Use this to check against obstacles, collectibles etc
for tilequery.Next() {
tilepos := (*components.Position)(tilequery.Get(positionid))
if velocity.Moving() {
intersects, newpos := tilepos.Intersects(playerposition, velocity)
if intersects {
fmt.Printf("collision detected. tile: %s\n", tilepos)
fmt.Printf(" player: %s\n", playerposition)
fmt.Printf(" new: %s\n", newpos)
playerposition.Set(newpos)
fmt.Printf(" player new: %s\n", playerposition)
velocity.Change(Stop)
}
}
}
*/
if velocity.Moving() {
ok, newpos := level.Grid.BumpEdge(playerposition, velocity)
@ -100,6 +104,15 @@ func (level *Level) Update() {
}
}
}
for colquery.Next() {
collectible := (*components.Collectible)(colquery.Get(level.Component["collectible"]))
colposition := (*components.Position)(colquery.Get(level.Component["position"]))
ok, _ := playerposition.Intersects(colposition, velocity)
if ok {
fmt.Printf("bumped into collectible %v\n", collectible)
}
}
}
playerposition.Move(velocity)
@ -125,20 +138,45 @@ func (level *Level) GetTile(position *components.Position, velocity *components.
}
func (level *Level) Draw(screen *ebiten.Image) {
// FIXME: move out
op := &ebiten.DrawImageOptions{}
screen.DrawImage(level.Background, op)
rid := ecs.ComponentID[components.Renderable](level.World)
pid := ecs.ComponentID[components.Position](level.World)
sid := ecs.ComponentID[components.Solid](level.World)
selector := filter.All(rid, pid)
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)
for query.Next() {
pos := (*components.Position)(query.Get(pid))
sprite := (*components.Renderable)(query.Get(rid))
draw.Draw(
level.Cache,
image.Rect(pos.X, pos.Y, pos.X+pos.Cellsize, pos.Y+pos.Cellsize),
sprite.Image, image.ZP, draw.Over)
}
op := &ebiten.DrawImageOptions{}
screen.DrawImage(level.Cache, op)
level.UseCache = true
} else {
// use the cached map
op := &ebiten.DrawImageOptions{}
screen.DrawImage(level.Cache, op)
}
// write the movable tiles
selector := filter.All(rid, pid).Without(sid)
query := level.World.Query(&selector)
for query.Next() {
pos := (*components.Position)(query.Get(pid))
sprite := (*components.Renderable)(query.Get(rid))
op := &ebiten.DrawImageOptions{}
op.GeoM.Translate(float64(pos.X), float64(pos.Y))

View File

@ -11,6 +11,7 @@ type LevelScene struct {
Levels []*Level
Next int
Whoami int
UseCache bool
}
// Implements the actual playing Scene

BIN
openquell

Binary file not shown.