openquell/grid/grid.go

158 lines
4.0 KiB
Go

package grid
import (
"image"
"log"
"openquell/assets"
"openquell/components"
"openquell/config"
"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
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.Speed,
components.Player](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.NewMap5[
components.Position,
components.Velocity,
components.Renderable,
components.Speed,
components.Obstacle](world)
transmapper := generic.NewMap3[
components.Position,
components.Renderable,
components.Transient](world)
var pos *components.Position
var vel *components.Velocity
var render *components.Renderable
var speed *components.Speed
var transient *components.Transient
var player *components.Player
playerobserver := observers.GetPlayerObserver(world)
obstacleobserver := observers.GetObstacleObserver(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, _, render, speed, player = playermapper.Get(entity)
playerobserver.AddEntity(entity)
speed.Value = config.PLAYERSPEED
player.IsPrimary = tile.IsPrimary
player.Sprites = tile.Tiles
case tile.Collectible:
entity := colmapper.New()
pos, render, _ = colmapper.Get(entity)
case tile.Obstacle:
entity := obsmapper.New()
pos, vel, render, speed, _ = obsmapper.Get(entity)
vel.Direction = tile.Direction
vel.PointingAt = tile.Direction
speed.Value = config.PLAYERSPEED
obstacleobserver.AddEntity(entity)
case tile.Transient:
entity := transmapper.New()
pos, render, transient = transmapper.Get(entity)
transient.Sprites = tile.TileNames
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,
}
}
// 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) SetTile(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)
}