ichigo/engine/walls.go

112 lines
2.6 KiB
Go
Raw Normal View History

2021-08-26 20:06:38 +10:00
package engine
import (
"image"
"github.com/hajimehoshi/ebiten/v2"
)
var (
_ interface {
Collider
Identifier
Scanner
2021-09-01 13:46:26 +10:00
Prepper
Transformer
2021-08-26 20:06:38 +10:00
} = &Wall{}
_ interface {
Drawer
Disabler
Hider
2021-09-01 09:52:40 +10:00
Scanner
Transformer
2021-08-26 20:06:38 +10:00
} = &WallUnit{}
)
// Wall is a more flexible kind of tilemap. WallUnits can be added at the same
// level as other components and are responsible for their own drawing, so that
2021-09-01 09:55:18 +10:00
// Game can do draw ordering, e.g. hide the player character behind a wall.
2021-08-26 20:06:38 +10:00
// But Wall is still responsible for collisions.
type Wall struct {
ID
2021-08-27 12:00:20 +10:00
Ersatz bool // disables collisions ("fake wall")
2021-08-26 20:06:38 +10:00
Offset image.Point // offset the whole wall
Sheet Sheet
UnitOffset image.Point // drawing offset
UnitSize image.Point // tile size
2021-09-01 13:46:26 +10:00
Units map[image.Point]*WallUnit
2021-08-26 20:06:38 +10:00
}
2021-09-01 13:46:26 +10:00
// CollidesWith implements a tilerange collosion check, similar to Tilemap.
2021-08-26 20:06:38 +10:00
func (w *Wall) CollidesWith(r image.Rectangle) bool {
if w.Ersatz {
return false
}
// Probe the map at all tilespace coordinates overlapping the rect.
r = r.Sub(w.Offset)
2021-09-02 13:42:44 +10:00
min := cdiv(r.Min, w.UnitSize)
max := cdiv(r.Max.Sub(image.Pt(1, 1)), w.UnitSize) // NB: fencepost
2021-08-26 20:06:38 +10:00
for j := min.Y; j <= max.Y; j++ {
for i := min.X; i <= max.X; i++ {
2021-09-01 13:46:26 +10:00
if w.Units[image.Pt(i, j)] != nil {
2021-08-26 20:06:38 +10:00
return true
}
}
}
return false
}
2021-09-01 13:46:26 +10:00
// Scan returns the Sheet and all WallUnits.
func (w *Wall) Scan() []interface{} {
c := make([]interface{}, 1, len(w.Units)+1)
c[0] = &w.Sheet
for _, unit := range w.Units {
c = append(c, unit)
}
return c
}
// Prepare makes sure all WallUnits know about Wall.
func (w *Wall) Prepare(*Game) error {
// Ensure all child units know about wall, which houses common attributes
for _, u := range w.Units {
u.wall = w
}
return nil
}
// Transform returns a GeoM translation by Offset.
func (w *Wall) Transform() (opts ebiten.DrawImageOptions) {
2021-09-02 13:42:44 +10:00
opts.GeoM.Translate(cfloat(w.Offset))
2021-09-01 13:46:26 +10:00
return opts
}
2021-08-26 20:06:38 +10:00
2021-08-31 15:44:25 +10:00
// WallUnit is a unit in a wall. Unlike a tile in a tilemap, WallUnit is
// responsible for drawing itself.
2021-08-26 20:06:38 +10:00
type WallUnit struct {
Disabled
Hidden
Pos image.Point // tilespace coordinates
Tile Tile // chooses which cell in wall.Sheet to draw
WallID string
ZOrder
wall *Wall
}
2021-09-01 13:46:26 +10:00
// Draw draws this wall unit.
func (u *WallUnit) Draw(screen *ebiten.Image, opts *ebiten.DrawImageOptions) {
2021-09-02 11:53:04 +10:00
screen.DrawImage(u.wall.Sheet.SubImage(u.Tile.Cell()), opts)
2021-08-26 20:06:38 +10:00
}
2021-09-01 13:46:26 +10:00
// Scan returns the Tile.
2021-09-01 09:17:08 +10:00
func (u *WallUnit) Scan() []interface{} { return []interface{}{u.Tile} }
func (u *WallUnit) Transform() (opts ebiten.DrawImageOptions) {
2021-09-02 13:42:44 +10:00
opts.GeoM.Translate(cfloat(cmul(u.Pos, u.wall.UnitSize).Add(u.wall.UnitOffset)))
return opts
}