camera stays in bounds

This commit is contained in:
Josh Deprez 2021-08-12 03:49:22 +00:00
parent 238286289e
commit 6354df558f
3 changed files with 50 additions and 19 deletions

View file

@ -6,29 +6,58 @@ import (
"github.com/hajimehoshi/ebiten/v2" "github.com/hajimehoshi/ebiten/v2"
) )
// TODO: should this be integrated with Scene?
type Camera struct { type Camera struct {
ID ID
Scene *Scene Scene *Scene
// camera controls // camera controls
Centre image.Point Bounds image.Rectangle // world coordinates
Rotation float64 Centre image.Point // world coordinates
Zoom float64 //Rotation float64 // radians
Zoom float64 // unitless
game *Game game *Game
// TODO: camera constraints
} }
func (c *Camera) Draw(screen *ebiten.Image, geom ebiten.GeoM) { func (c *Camera) Draw(screen *ebiten.Image, geom ebiten.GeoM) {
// move c.Centre to the origin // If the camera bounds are smaller than the screen dimensions, that
geom.Translate(-float64(c.Centre.X), -float64(c.Centre.Y)) // places a lower bound on zoom.
// zoom and rotate // If the configured centre still puts the camera out of bounds, move it.
geom.Scale(c.Zoom, c.Zoom) centre, zoom := c.Centre, c.Zoom
geom.Rotate(c.Rotation) if sz := c.Bounds.Size(); sz.X < c.game.ScreenWidth || sz.Y < c.game.ScreenHeight {
// move the origin to the centre of screen space if z := float64(c.game.ScreenWidth) / float64(sz.X); zoom < z {
geom.Translate(float64(c.game.ScreenWidth/2), float64(c.game.ScreenHeight/2)) zoom = z
}
if z := float64(c.game.ScreenHeight) / float64(sz.Y); zoom < z {
zoom = z
}
}
// 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.Bounds.Min.X {
centre.X = c.Bounds.Min.X + swz
}
if centre.Y-shz < c.Bounds.Min.Y {
centre.Y = c.Bounds.Min.Y + shz
}
if centre.X+swz > c.Bounds.Max.X {
centre.X = c.Bounds.Max.X - swz
}
if centre.Y+shz > c.Bounds.Max.Y {
centre.Y = c.Bounds.Max.Y - shz
}
// Apply camera controls to geom.
// 1. Move c.Centre to the origin
geom.Translate(-float64(centre.X), -float64(centre.Y))
// 2. Zoom and rotate
geom.Scale(zoom, zoom)
//geom.Rotate(c.Rotation)
// 3. Move the origin to the centre of screen space.
geom.Translate(sw2, sh2)
c.Scene.Draw(screen, geom) c.Scene.Draw(screen, geom)
} }

View file

@ -3,7 +3,6 @@ package game
import ( import (
"encoding/gob" "encoding/gob"
"image" "image"
"math"
"drjosh.dev/gurgle/engine" "drjosh.dev/gurgle/engine"
"github.com/hajimehoshi/ebiten/v2" "github.com/hajimehoshi/ebiten/v2"
@ -72,9 +71,11 @@ func (aw *Awakeman) Update() error {
if ebiten.IsKeyPressed(ebiten.KeyShift) { if ebiten.IsKeyPressed(ebiten.KeyShift) {
aw.camera.Zoom = 2 aw.camera.Zoom = 2
} }
if inpututil.IsKeyJustPressed(ebiten.KeyR) { /*
aw.camera.Rotation += math.Pi / 6 if inpututil.IsKeyJustPressed(ebiten.KeyR) {
} aw.camera.Rotation += math.Pi / 6
}
*/
aw.MoveX(aw.vx, func() { aw.vx = -aw.vx * bounceDampen }) aw.MoveX(aw.vx, func() { aw.vx = -aw.vx * bounceDampen })
aw.MoveY(aw.vy, func() { aw.vy = -aw.vy * bounceDampen }) aw.MoveY(aw.vy, func() { aw.vy = -aw.vy * bounceDampen })
// aw.Pos is top-left corner, so add half size to get centre // aw.Pos is top-left corner, so add half size to get centre

View file

@ -95,8 +95,9 @@ func main() {
KeyCombo: []ebiten.Key{ebiten.KeyControl, ebiten.KeyD}, KeyCombo: []ebiten.Key{ebiten.KeyControl, ebiten.KeyD},
}, },
&engine.Camera{ &engine.Camera{
ID: "level_1_camera", ID: "level_1_camera",
Scene: level1, Bounds: image.Rect(-16, -16, 320+16, 240+16),
Scene: level1,
}, },
engine.PerfDisplay{}, engine.PerfDisplay{},
}, },