openquell/game/grid.go

175 lines
3.8 KiB
Go

package game
import (
"fmt"
"image"
"log"
"openquell/assets"
"openquell/components"
. "openquell/config"
"github.com/alecthomas/repr"
"github.com/mlange-42/arche/generic"
)
type Grid struct {
Width int
Height int
Size int
Tilesize int
TilesX int
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(game *Game, tilesize 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.NewMap4[
components.Position,
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
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, _ = 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")
}
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: game.ScreenWidth,
Height: game.ScreenHeight,
TilesX: game.ScreenWidth / tilesize,
TilesY: game.ScreenHeight / tilesize,
Map: mapslice,
}
}
func (grid *Grid) GetSolidNeighborPosition(
position *components.Position,
velocity *components.Velocity,
solid bool) (bool, *components.Position) {
if !solid {
return false, nil
}
// set to true, ifwe are already on the last tile in the current
// direction, i.e. on the edge of the grid
edge := true
neighborpos := position.Point()
switch velocity.Direction {
case East:
if neighborpos.X < grid.TilesX {
neighborpos.X++
edge = false
}
case West:
if neighborpos.X > 0 {
neighborpos.X--
edge = false
}
case South:
if neighborpos.Y < grid.TilesY {
neighborpos.Y++
edge = false
}
case North:
if neighborpos.Y > 0 {
neighborpos.Y--
edge = false
}
}
newpos := components.NewPosition(neighborpos, grid.Tilesize)
repr.Println(newpos)
if !edge && grid.Map[neighborpos].Solid {
return true, newpos
}
return false, nil
}
func (grid *Grid) BumpEdge(
pos *components.Position,
velocity *components.Velocity) (bool, *components.Position) {
x := pos.X + velocity.Data.X
y := pos.Y + velocity.Data.Y
if x < 0 || x > grid.Width-grid.Tilesize || y < 0 || y > grid.Height-grid.Tilesize {
newpos := &components.Position{}
X := pos.X
Y := pos.Y
switch velocity.Direction {
case East:
X = 0
fmt.Println("east X=0")
case West:
X = grid.Width - grid.Tilesize
fmt.Println("west X=max")
case South:
Y = 0
fmt.Println("south y=0")
case North:
Y = grid.Height - grid.Tilesize
fmt.Println("north y=max")
}
newpos.Update(X, Y, grid.Tilesize)
return true, newpos
}
return false, nil
}