Scenerise Camera and i am g.Root

This commit is contained in:
Josh Deprez 2021-08-20 16:46:26 +10:00
parent 45e2b300e8
commit af89c01dbd
4 changed files with 31 additions and 19 deletions

View file

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

View file

@ -11,17 +11,19 @@ func init() {
} }
// Game implements the ebiten methods using a collection of components. // Game implements the ebiten methods using a collection of components.
// One component must be the designated root component - usually a
// scene of some kind.
type Game struct { type Game struct {
ScreenWidth int ScreenWidth int
ScreenHeight int ScreenHeight int
Scener Root DrawUpdater // typically a *Scene or SceneRef though
componentsByID map[string]interface{} componentsByID map[string]interface{}
} }
// Draw draws the entire thing, with default draw options. // Draw draws the entire thing, with default draw options.
func (g *Game) Draw(screen *ebiten.Image) { func (g *Game) Draw(screen *ebiten.Image) {
g.Scene().Draw(screen, ebiten.DrawImageOptions{}) g.Root.Draw(screen, ebiten.DrawImageOptions{})
} }
// Layout returns the configured screen width/height. // Layout returns the configured screen width/height.
@ -29,6 +31,9 @@ func (g *Game) Layout(outsideWidth, outsideHeight int) (w, h int) {
return g.ScreenWidth, g.ScreenHeight return g.ScreenWidth, g.ScreenHeight
} }
// Update updates the scene.
func (g *Game) Update() error { return g.Root.Update() }
// RegisterComponent tells the game there is a new component. Currently this is // RegisterComponent tells the game there is a new component. Currently this is
// only necessary for components with IDs. // only necessary for components with IDs.
func (g *Game) RegisterComponent(c interface{}) { func (g *Game) RegisterComponent(c interface{}) {
@ -61,7 +66,7 @@ func (g *Game) UnregisterComponent(c interface{}) {
func (g *Game) Component(id string) interface{} { return g.componentsByID[id] } func (g *Game) Component(id string) interface{} { return g.componentsByID[id] }
// Scan implements Scanner. // Scan implements Scanner.
func (g *Game) Scan() []interface{} { return []interface{}{g.Scener} } func (g *Game) Scan() []interface{} { return []interface{}{g.Root} }
// Walk calls v with every component reachable from c via Scan, recursively, // Walk calls v with every component reachable from c via Scan, recursively,
// for as long as visit returns nil. // for as long as visit returns nil.
@ -84,7 +89,7 @@ func Walk(c interface{}, v func(interface{}) error) error {
// Load calls Load on all Loaders reachable via Scan (using Walk). // Load calls Load on all Loaders reachable via Scan (using Walk).
// It stops on the first error. // It stops on the first error.
func (g *Game) Load() error { func (g *Game) Load() error {
return Walk(g.Scener, func(c interface{}) error { return Walk(g.Root, func(c interface{}) error {
l, ok := c.(Loader) l, ok := c.(Loader)
if !ok { if !ok {
return nil return nil
@ -99,11 +104,11 @@ func (g *Game) Load() error {
// fastidiously calling RegisterComponent/UnregisterComponent). // fastidiously calling RegisterComponent/UnregisterComponent).
func (g *Game) Prepare() { func (g *Game) Prepare() {
g.componentsByID = make(map[string]interface{}) g.componentsByID = make(map[string]interface{})
Walk(g.Scener, func(c interface{}) error { Walk(g.Root, func(c interface{}) error {
g.RegisterComponent(c) g.RegisterComponent(c)
return nil return nil
}) })
Walk(g.Scener, func(c interface{}) error { Walk(g.Root, func(c interface{}) error {
if p, ok := c.(Prepper); ok { if p, ok := c.(Prepper); ok {
p.Prepare(g) p.Prepare(g)
} }

View file

@ -23,6 +23,13 @@ type DrawOrderer interface {
DrawOrder() float64 DrawOrder() float64
} }
// DrawUpdater components can be both drawn and updated.
// Same comments as for Drawer and Updater.
type DrawUpdater interface {
Drawer
Updater
}
// Identifier components have a sense of self. This makes it easier for // Identifier components have a sense of self. This makes it easier for
// components to find and interact with one another. // components to find and interact with one another.
type Identifier interface { type Identifier interface {

View file

@ -105,7 +105,7 @@ func main() {
game := &engine.Game{ game := &engine.Game{
ScreenHeight: 240, ScreenHeight: 240,
ScreenWidth: 320, ScreenWidth: 320,
Scener: &engine.Scene{ Root: &engine.Scene{
ID: "root", ID: "root",
Components: []interface{}{ Components: []interface{}{
&engine.GobDumper{ &engine.GobDumper{