all in on interfaces

This commit is contained in:
Josh Deprez 2021-08-23 10:34:56 +10:00
parent 7e76032ee2
commit 0f5346bf0e
7 changed files with 71 additions and 29 deletions

View file

@ -126,12 +126,12 @@ func (r *SceneRef) Load(assets fs.FS) error {
return nil
}
// Scene returns the loaded scene, or nil if not yet loaded.
func (r SceneRef) Scene() *Scene { return r.scene }
// The rest of the methods forward to r.scene, as such they will
// panic if the scene isn't loaded.
// BoundingRect returns the Bounds from the scene.
func (r SceneRef) BoundingRect() image.Rectangle { return r.scene.BoundingRect() }
// Draw draws the scene.
func (r SceneRef) Draw(screen *ebiten.Image, opts ebiten.DrawImageOptions) {
r.scene.Draw(screen, opts)
@ -140,6 +140,15 @@ func (r SceneRef) Draw(screen *ebiten.Image, opts ebiten.DrawImageOptions) {
// DrawOrder returns the value of DrawOrder from the scene.
func (r SceneRef) DrawOrder() float64 { return r.scene.DrawOrder() }
// IsHidden returns the value of IsHidden from the scene.
func (r SceneRef) IsHidden() bool { return r.scene.IsHidden() }
// Hide calls Hide on the scene.
func (r SceneRef) Hide() { r.scene.Hide() }
// Show calls Show on the scene.
func (r SceneRef) Show() { r.scene.Show() }
// Ident returns the value of Ident from the scene.
func (r SceneRef) Ident() string { return r.scene.Ident() }

View file

@ -37,14 +37,16 @@ type Camera struct {
// Draw applies transformations to opts, then calls c.Scene.Draw with it.
func (c *Camera) Draw(screen *ebiten.Image, opts ebiten.DrawImageOptions) {
if c.Scene.Scene().Hidden {
if c.Scene.IsHidden() {
return
}
br := c.Scene.BoundingRect()
// The lower bound on zoom is the larger of
// { (ScreenWidth / BoundsWidth), (ScreenHeight / BoundsHeight) }
zoom := c.Zoom
sz := c.Scene.Scene().Bounds.Size()
sz := br.Size()
if z := float64(c.game.ScreenWidth) / float64(sz.X); zoom < z {
zoom = z
}
@ -57,17 +59,17 @@ func (c *Camera) Draw(screen *ebiten.Image, opts ebiten.DrawImageOptions) {
// Camera frame currently Rectangle{ centre ± (screen/(2*zoom)) }.
sw2, sh2 := float64(c.game.ScreenWidth/2), float64(c.game.ScreenHeight/2)
swz, shz := int(sw2/zoom), int(sh2/zoom)
if centre.X-swz < c.Scene.Scene().Bounds.Min.X {
centre.X = c.Scene.Scene().Bounds.Min.X + swz
if centre.X-swz < br.Min.X {
centre.X = br.Min.X + swz
}
if centre.Y-shz < c.Scene.Scene().Bounds.Min.Y {
centre.Y = c.Scene.Scene().Bounds.Min.Y + shz
if centre.Y-shz < br.Min.Y {
centre.Y = br.Min.Y + shz
}
if centre.X+swz > c.Scene.Scene().Bounds.Max.X {
centre.X = c.Scene.Scene().Bounds.Max.X - swz
if centre.X+swz > br.Max.X {
centre.X = br.Max.X - swz
}
if centre.Y+shz > c.Scene.Scene().Bounds.Max.Y {
centre.Y = c.Scene.Scene().Bounds.Max.Y - shz
if centre.Y+shz > br.Max.Y {
centre.Y = br.Max.Y - shz
}
// Apply other options
@ -101,7 +103,7 @@ func (c *Camera) Draw(screen *ebiten.Image, opts ebiten.DrawImageOptions) {
}
// Update passes the call to c.Scene.
func (c *Camera) Update() error { return c.Scene.Scene().Update() }
func (c *Camera) Update() error { return c.Scene.Update() }
// Scan returns the only child (c.Scene).
func (c *Camera) Scan() []interface{} { return []interface{}{c.Scene} }

View file

@ -7,6 +7,11 @@ import (
"github.com/hajimehoshi/ebiten/v2"
)
// Bounder components have a bounding rectangle.
type Bounder interface {
BoundingRect() image.Rectangle
}
// Collider components have tangible form.
type Collider interface {
CollidesWith(image.Rectangle) bool
@ -31,6 +36,13 @@ type DrawUpdater interface {
Updater
}
// Hider components can be hidden.
type Hider interface {
IsHidden() bool
Hide()
Show()
}
// Identifier components have a sense of self. This makes it easier for
// components to find and interact with one another.
type Identifier interface {
@ -75,14 +87,14 @@ type Scener interface {
// }
// It seems cleaner to let the engine assert only for the interface it needs at that moment.
Bounder
Drawer
DrawOrderer
Hider
Identifier
Prepper
Scanner
Updater
Scene() *Scene
}
// Updater components can update themselves. Update is called repeatedly.

View file

@ -1,11 +1,31 @@
package engine
import "image"
// ID implements Identifier directly (as a string value).
type ID string
// Ident returns id as a string.
func (id ID) Ident() string { return string(id) }
// Bounds implements Bounder directly (as an image.Rectangle value).
type Bounds image.Rectangle
// BoundingRect returns b as an image.Rectangle.
func (b Bounds) BoundingRect() image.Rectangle { return image.Rectangle(b) }
// Hidden implements Hider directly (as a bool).
type Hidden bool
// IsHidden returns h as a bool.
func (h Hidden) IsHidden() bool { return bool(h) }
// Hide sets h to true.
func (h *Hidden) Hide() { *h = true }
// Show sets h to false.
func (h *Hidden) Show() { *h = false }
// Parallax implements ParallaxScaler directly (as a float64 value).
type Parallax float64

View file

@ -2,7 +2,6 @@ package engine
import (
"encoding/gob"
"image"
"math"
"sort"
@ -18,11 +17,11 @@ func init() {
// Scene manages drawing and updating a bunch of components.
type Scene struct {
Bounds image.Rectangle // world coordinates
ID
Bounds // world coordinates
Components []interface{}
Disabled bool
Hidden bool
ID
Hidden
ZOrder
}

View file

@ -13,7 +13,7 @@ func init() {
type SolidRect struct {
ID
Rect image.Rectangle
Bounds
}
func (s SolidRect) CollidesWith(r image.Rectangle) bool { return s.Rect.Overlaps(r) }
func (s SolidRect) CollidesWith(r image.Rectangle) bool { return s.BoundingRect().Overlaps(r) }

14
main.go
View file

@ -51,7 +51,7 @@ func main() {
level1 := &engine.Scene{
ID: "level_1",
Bounds: image.Rect(-32, -32, 320+32, 240+32),
Bounds: engine.Bounds(image.Rect(-32, -32, 320+32, 240+32)),
Components: []interface{}{
&engine.Fill{
Color: color.Gray{100},
@ -72,16 +72,16 @@ func main() {
TileSize: 16,
},
&engine.SolidRect{
ID: "ceiling",
Rect: image.Rect(0, -1, 320, 0),
ID: "ceiling",
Bounds: engine.Bounds(image.Rect(0, -1, 320, 0)),
},
&engine.SolidRect{
ID: "left_wall",
Rect: image.Rect(-1, 0, 0, 240),
ID: "left_wall",
Bounds: engine.Bounds(image.Rect(-1, 0, 0, 240)),
},
&engine.SolidRect{
ID: "right_wall",
Rect: image.Rect(320, 0, 321, 240),
ID: "right_wall",
Bounds: engine.Bounds(image.Rect(320, 0, 321, 240)),
},
&game.Awakeman{
CameraID: "game_camera",