186 lines
4.9 KiB
Go
186 lines
4.9 KiB
Go
package grid
|
|
|
|
import (
|
|
"image"
|
|
"log"
|
|
"openquell/assets"
|
|
"openquell/components"
|
|
"openquell/config"
|
|
"openquell/handlers"
|
|
"openquell/observers"
|
|
|
|
"github.com/mlange-42/arche/ecs"
|
|
"github.com/mlange-42/arche/generic"
|
|
)
|
|
|
|
type Grid struct {
|
|
World *ecs.World
|
|
Width int
|
|
Height int
|
|
Size int
|
|
Tilesize int
|
|
TilesX, TilesY int
|
|
Map map[image.Point]*assets.Tile
|
|
}
|
|
|
|
// FIXME: put component addition into extra callable function, to be called
|
|
// by game.go in a level-loop. Also remove components of previous level
|
|
func NewGrid(world *ecs.World,
|
|
tilesize, width, height int, mapslice map[image.Point]*assets.Tile) *Grid {
|
|
|
|
// we use this to turn our tiles into iterable entities, used for
|
|
// collision detection, transformation and other things
|
|
playermapper := generic.NewMap5[
|
|
components.Position,
|
|
components.Velocity,
|
|
components.Renderable,
|
|
components.Player,
|
|
components.Collider](world)
|
|
|
|
solidmapper := generic.NewMap4[
|
|
components.Position,
|
|
components.Renderable,
|
|
components.Tilish,
|
|
components.Solid](world)
|
|
|
|
emptymapper := generic.NewMap2[components.Position, components.Tilish](world)
|
|
|
|
colmapper := generic.NewMap3[
|
|
components.Position,
|
|
components.Renderable,
|
|
components.Collectible](world)
|
|
|
|
obsmapper := generic.NewMap4[
|
|
components.Position,
|
|
components.Velocity,
|
|
components.Renderable,
|
|
components.Obstacle](world)
|
|
|
|
transmapper := generic.NewMap3[
|
|
components.Position,
|
|
components.Renderable,
|
|
components.Transient](world)
|
|
|
|
doormapper := generic.NewMap3[
|
|
components.Position,
|
|
components.Renderable,
|
|
components.Destroyable](world)
|
|
|
|
var pos *components.Position
|
|
var vel *components.Velocity
|
|
var render *components.Renderable
|
|
var transient *components.Transient
|
|
var player *components.Player
|
|
var destroyable *components.Destroyable
|
|
var collider *components.Collider
|
|
|
|
playerobserver := observers.GetPlayerObserver(world)
|
|
obstacleobserver := observers.GetObstacleObserver(world)
|
|
entityobserver := observers.GetEntityObserver(world)
|
|
|
|
for point, tile := range mapslice {
|
|
switch tile.Renderable {
|
|
case true:
|
|
switch {
|
|
case tile.Solid:
|
|
entity := solidmapper.New()
|
|
pos, render, _, _ = solidmapper.Get(entity)
|
|
case tile.Player:
|
|
entity := playermapper.New()
|
|
pos, vel, render, player, collider = playermapper.Get(entity)
|
|
playerobserver.AddEntity(entity)
|
|
vel.Speed = config.PLAYERSPEED
|
|
player.IsPrimary = tile.IsPrimary
|
|
player.Sprites = tile.Tiles
|
|
collider.CollisionHandler = handlers.HandlePlayerCollision
|
|
collider.EdgeHandler = handlers.HandlePlayerEdgeBump
|
|
case tile.Collectible:
|
|
entity := colmapper.New()
|
|
pos, render, _ = colmapper.Get(entity)
|
|
entityobserver.AddEntity(entity)
|
|
case tile.Obstacle:
|
|
entity := obsmapper.New()
|
|
pos, vel, render, _ = obsmapper.Get(entity)
|
|
vel.Direction = tile.Direction
|
|
vel.PointingAt = tile.Direction
|
|
vel.Speed = config.PLAYERSPEED
|
|
obstacleobserver.AddEntity(entity)
|
|
entityobserver.AddEntity(entity)
|
|
case tile.Transient:
|
|
entity := transmapper.New()
|
|
pos, render, transient = transmapper.Get(entity)
|
|
transient.Sprites = tile.TileNames
|
|
entityobserver.AddEntity(entity)
|
|
case tile.Destroyable:
|
|
entity := doormapper.New()
|
|
pos, render, destroyable = doormapper.Get(entity)
|
|
destroyable.Sprites = tile.Tiles
|
|
entityobserver.AddEntity(entity)
|
|
default:
|
|
log.Fatalln("unsupported tile type encountered")
|
|
}
|
|
|
|
render.Image = tile.Sprite
|
|
|
|
default:
|
|
// empty cell, this is where the player[s] move. No
|
|
// sprite required since every level has a background
|
|
// image.
|
|
entity := emptymapper.New()
|
|
pos, _ = emptymapper.Get(entity)
|
|
}
|
|
|
|
// however, every tile has a position
|
|
pos.Update(point.X*tilesize, point.Y*tilesize, tilesize)
|
|
}
|
|
|
|
return &Grid{
|
|
Size: len(mapslice),
|
|
Tilesize: tilesize,
|
|
Width: width,
|
|
Height: height,
|
|
Map: mapslice,
|
|
World: world,
|
|
TilesX: width / tilesize,
|
|
TilesY: height / tilesize,
|
|
}
|
|
}
|
|
|
|
// return the tile the moving object would end up on if indeed moving
|
|
func (grid *Grid) GetTile(
|
|
position *components.Position,
|
|
velocity *components.Velocity) *assets.Tile {
|
|
|
|
newpoint := image.Point{
|
|
int(position.X+velocity.Data.X) / grid.Tilesize,
|
|
int(position.Y+velocity.Data.Y) / grid.Tilesize,
|
|
}
|
|
|
|
tile := grid.Map[newpoint]
|
|
return tile
|
|
}
|
|
|
|
func (grid *Grid) RemoveTile(point image.Point) {
|
|
delete(grid.Map, point)
|
|
}
|
|
|
|
func (grid *Grid) SetFloorTile(point image.Point) {
|
|
grid.Map[point] = assets.Tiles[' ']
|
|
}
|
|
|
|
func (grid *Grid) SetSolidTile(tile *assets.Tile, point image.Point) {
|
|
solidmapper := generic.NewMap4[
|
|
components.Position,
|
|
components.Renderable,
|
|
components.Tilish,
|
|
components.Solid](grid.World)
|
|
|
|
grid.Map[point] = tile
|
|
|
|
entity := solidmapper.New()
|
|
pos, render, _, _ := solidmapper.Get(entity)
|
|
|
|
render.Image = tile.Sprite
|
|
pos.Update(point.X*grid.Tilesize, point.Y*grid.Tilesize, grid.Tilesize)
|
|
}
|