2021-08-26 20:06:38 +10:00
|
|
|
package engine
|
|
|
|
|
|
|
|
import (
|
|
|
|
"image"
|
|
|
|
|
|
|
|
"github.com/hajimehoshi/ebiten/v2"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
_ interface {
|
|
|
|
Collider
|
|
|
|
Identifier
|
|
|
|
Scanner
|
|
|
|
} = &Wall{}
|
|
|
|
|
|
|
|
_ interface {
|
|
|
|
Drawer
|
|
|
|
Disabler
|
|
|
|
Hider
|
|
|
|
Prepper
|
|
|
|
Updater
|
|
|
|
} = &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
|
|
|
|
// Scene can do draw ordering, e.g. hide the player character behind a wall.
|
|
|
|
// 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
|
|
|
|
|
|
|
|
units map[image.Point]*WallUnit
|
|
|
|
}
|
|
|
|
|
|
|
|
func (w *Wall) regUnit(u *WallUnit) {
|
|
|
|
if w.units == nil {
|
|
|
|
w.units = make(map[image.Point]*WallUnit)
|
|
|
|
}
|
|
|
|
w.units[u.Pos] = u
|
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
min := div2(r.Min, w.UnitSize)
|
|
|
|
max := div2(r.Max.Sub(image.Pt(1, 1)), w.UnitSize) // NB: fencepost
|
|
|
|
|
|
|
|
for j := min.Y; j <= max.Y; j++ {
|
|
|
|
for i := min.X; i <= max.X; i++ {
|
|
|
|
if w.units[image.Pt(i, j)] != nil {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
func (w *Wall) Scan() []interface{} { return []interface{}{&w.Sheet} }
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
func (u *WallUnit) Draw(screen *ebiten.Image, opts ebiten.DrawImageOptions) {
|
|
|
|
if u.Hidden {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
var geom ebiten.GeoM
|
|
|
|
geom.Translate(float2(mul2(u.Pos, u.wall.UnitSize).Add(u.wall.UnitOffset).Add(u.wall.Offset)))
|
|
|
|
geom.Concat(opts.GeoM)
|
|
|
|
opts.GeoM = geom
|
|
|
|
|
|
|
|
src := u.wall.Sheet.SubImage(u.Tile.CellIndex())
|
|
|
|
screen.DrawImage(src, &opts)
|
|
|
|
}
|
|
|
|
|
2021-08-27 14:52:24 +10:00
|
|
|
func (u *WallUnit) Prepare(g *Game) error {
|
2021-08-26 20:06:38 +10:00
|
|
|
u.wall = g.Component(u.WallID).(*Wall)
|
|
|
|
u.wall.regUnit(u)
|
2021-08-27 14:52:24 +10:00
|
|
|
return nil
|
2021-08-26 20:06:38 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
func (u *WallUnit) Update() error {
|
|
|
|
if u.Disabled {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
if up, ok := u.Tile.(Updater); ok {
|
|
|
|
return up.Update()
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|