added collectibles support
This commit is contained in:
parent
ce7fcd038a
commit
a0b40139c7
@ -9,9 +9,9 @@ Background: background-orange
|
||||
# ######## ###
|
||||
#
|
||||
############ #
|
||||
# # #
|
||||
# o # #
|
||||
# # ######## #
|
||||
# #
|
||||
# # o
|
||||
# ############
|
||||
|
||||
|
||||
|
||||
@ -20,13 +20,14 @@ var Tiles = InitTiles()
|
||||
// Tile: contains image, identifier (as used in level data) and
|
||||
// additional properties
|
||||
type Tile struct {
|
||||
Id byte
|
||||
Sprite *ebiten.Image
|
||||
Class string
|
||||
Solid bool
|
||||
Player bool
|
||||
Renderable bool
|
||||
Velocity bool
|
||||
Id byte
|
||||
Sprite *ebiten.Image
|
||||
Class string
|
||||
Solid bool
|
||||
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"),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -15,3 +15,4 @@ type Tilish struct{}
|
||||
type Solid struct{}
|
||||
type Floor struct{}
|
||||
type Player struct{}
|
||||
type Collectible struct{}
|
||||
|
||||
10
game/grid.go
10
game/grid.go
@ -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")
|
||||
}
|
||||
|
||||
126
game/levels.go
126
game/levels.go
@ -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,53 +55,35 @@ 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"]))
|
||||
|
||||
switch {
|
||||
case ebiten.IsKeyPressed(ebiten.KeyRight):
|
||||
velocity.Change(East)
|
||||
case ebiten.IsKeyPressed(ebiten.KeyLeft):
|
||||
velocity.Change(West)
|
||||
case ebiten.IsKeyPressed(ebiten.KeyDown):
|
||||
velocity.Change(South)
|
||||
case ebiten.IsKeyPressed(ebiten.KeyUp):
|
||||
velocity.Change(North)
|
||||
// other keys: <tab>: switch player, etc
|
||||
if !velocity.Moving() {
|
||||
switch {
|
||||
case ebiten.IsKeyPressed(ebiten.KeyRight):
|
||||
velocity.Change(East)
|
||||
case ebiten.IsKeyPressed(ebiten.KeyLeft):
|
||||
velocity.Change(West)
|
||||
case ebiten.IsKeyPressed(ebiten.KeyDown):
|
||||
velocity.Change(South)
|
||||
case ebiten.IsKeyPressed(ebiten.KeyUp):
|
||||
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)
|
||||
if ok {
|
||||
@ -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,16 +138,41 @@ 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)
|
||||
|
||||
query := level.World.Query(selector)
|
||||
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))
|
||||
|
||||
@ -11,6 +11,7 @@ type LevelScene struct {
|
||||
Levels []*Level
|
||||
Next int
|
||||
Whoami int
|
||||
UseCache bool
|
||||
}
|
||||
|
||||
// Implements the actual playing Scene
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user