camera responsible for drawing scene

This commit is contained in:
Josh Deprez 2021-08-18 15:41:03 +10:00
parent cdcad14245
commit a50731023a
2 changed files with 37 additions and 15 deletions

View file

@ -6,8 +6,9 @@ import (
"github.com/hajimehoshi/ebiten/v2" "github.com/hajimehoshi/ebiten/v2"
) )
// Camera models a camera that is viewing a scene. Changes to the // Camera models a camera that is viewing a scene.
// configuration take effect immediately. // Changes to the configuration take effect immediately.
// Camera ignores Scene.Draw and calls Scene's children's Draw.
type Camera struct { type Camera struct {
ID ID
Scene *Scene Scene *Scene
@ -15,16 +16,20 @@ type Camera struct {
// Camera controls // Camera controls
Bounds image.Rectangle // world coordinates Bounds image.Rectangle // world coordinates
Centre image.Point // world coordinates Centre image.Point // world coordinates
//Rotation float64 // radians
Zoom float64 // unitless
Filter ebiten.Filter Filter ebiten.Filter
Zoom float64 // unitless
game *Game game *Game
} }
// 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 {
return
}
// Compute the geometry matrix for the camera controls.
// 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
@ -54,19 +59,30 @@ func (c *Camera) Draw(screen *ebiten.Image, opts ebiten.DrawImageOptions) {
centre.Y = c.Bounds.Max.Y - shz centre.Y = c.Bounds.Max.Y - shz
} }
// Apply camera controls to geom.
// 1. Move centre to the origin
opts.GeoM.Translate(-float64(centre.X), -float64(centre.Y))
// 2. Zoom and rotate
opts.GeoM.Scale(zoom, zoom)
//geom.Rotate(c.Rotation)
// 3. Move the origin to the centre of screen space.
opts.GeoM.Translate(sw2, sh2)
// Apply other options // Apply other options
opts.Filter = c.Filter opts.Filter = c.Filter
c.Scene.Draw(screen, opts) // Draw everything.
og := opts.GeoM
for _, i := range c.Scene.Components {
if d, ok := i.(Drawer); ok {
cs := 1.0
if s, ok := i.(CoordScaler); ok {
cs = s.CoordScale()
}
var geom ebiten.GeoM
// 1. Move centre to the origin, subject to CoordScale
geom.Translate(-float64(centre.X)*cs, -float64(centre.Y)*cs)
// 2. Zoom (this is also where rotation would be)
geom.Scale(zoom, zoom)
// 3. Move the origin to the centre of screen space.
geom.Translate(sw2, sh2)
// 4. Apply transforms from the caller.
geom.Concat(og)
opts.GeoM = geom
d.Draw(screen, opts)
}
}
} }
// Update passes the call to c.Scene. // Update passes the call to c.Scene.

View file

@ -11,6 +11,12 @@ type Collider interface {
CollidesWith(image.Rectangle) bool CollidesWith(image.Rectangle) bool
} }
// CoordScaler components have a scaling factor. This is used for
// e.g. parallax layers in a scene, and can be thought of as 1/distance.
type CoordScaler interface {
CoordScale() float64
}
// Drawer components can draw themselves. Draw is called often. // Drawer components can draw themselves. Draw is called often.
// Each component is responsible for calling Draw on its child components // Each component is responsible for calling Draw on its child components
// (so that hiding the parent can hide the children, etc). // (so that hiding the parent can hide the children, etc).