openquell/grid/collider.go

116 lines
2.7 KiB
Go
Raw Normal View History

package grid
import (
"openquell/components"
. "openquell/config"
)
// Check a collision on the grid. We check if the entity in question
// bumps into the egde of the grid or if it bumps onto a solid wall
// tile. For both cases the user must provide responder funcs in which
// it must be implemented how to react on those events.
func (grid *Grid) CheckGridCollision(
position *components.Position,
velocity *components.Velocity,
respond_edge func(*components.Position, *components.Velocity, *components.Position),
respond_solid func(*components.Position, *components.Velocity, *components.Position),
) {
if velocity.Moving() {
ok, newpos := grid.BumpEdge(position, velocity)
if ok {
//slog.Debug("falling off the edge", "newpos", newpos)
respond_edge(position, velocity, newpos)
} else {
ok, tilepos := grid.GetSolidNeighborPosition(position, velocity, true)
if ok {
// slog.Debug("HaveSolidNeighbor", "ok", ok, "tilepos",
// tilepos.Point(), "playerpos", playerposition)
intersects, newpos := tilepos.Intersects(position, velocity)
if intersects {
respond_solid(position, velocity, newpos)
}
}
}
}
}
func (grid *Grid) GetSolidNeighborPosition(
position *components.Position,
velocity *components.Velocity,
solid bool) (bool, *components.Position) {
if !solid {
return false, nil
}
// set to true if we 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)
// slog.Debug("SolidNeighbor?", "player", position.Point(),
// "neighbor", neighborpos, "edge", edge, "neighbor-solid",
// grid.Map[neighborpos].Solid, "newpos", newpos.Point())
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
case West:
X = grid.Width - grid.Tilesize
case South:
Y = 0
case North:
Y = grid.Height - grid.Tilesize
}
newpos.Update(X, Y, grid.Tilesize)
return true, newpos
}
return false, nil
}