improved parallax implementation

This commit is contained in:
Josh Deprez 2021-09-01 10:27:13 +10:00
parent 3b15a57cf5
commit 840847b25b
6 changed files with 71 additions and 39 deletions

View file

@ -11,7 +11,6 @@ import (
var _ interface { var _ interface {
Identifier Identifier
Drawer Drawer
ParallaxScaler
Scanner Scanner
Transformer Transformer
} = &Billboard{} } = &Billboard{}
@ -24,7 +23,6 @@ func init() {
type Billboard struct { type Billboard struct {
ID ID
Hidden Hidden
Parallax
Pos image.Point Pos image.Point
Src ImageRef Src ImageRef
ZOrder ZOrder

View file

@ -21,7 +21,6 @@ var (
HiderType = reflect.TypeOf((*Hider)(nil)).Elem() HiderType = reflect.TypeOf((*Hider)(nil)).Elem()
IdentifierType = reflect.TypeOf((*Identifier)(nil)).Elem() IdentifierType = reflect.TypeOf((*Identifier)(nil)).Elem()
LoaderType = reflect.TypeOf((*Loader)(nil)).Elem() LoaderType = reflect.TypeOf((*Loader)(nil)).Elem()
ParallaxScalerType = reflect.TypeOf((*ParallaxScaler)(nil)).Elem()
PrepperType = reflect.TypeOf((*Prepper)(nil)).Elem() PrepperType = reflect.TypeOf((*Prepper)(nil)).Elem()
ScannerType = reflect.TypeOf((*Scanner)(nil)).Elem() ScannerType = reflect.TypeOf((*Scanner)(nil)).Elem()
ScenerType = reflect.TypeOf((*Scener)(nil)).Elem() ScenerType = reflect.TypeOf((*Scener)(nil)).Elem()
@ -40,7 +39,6 @@ var (
HiderType, HiderType,
IdentifierType, IdentifierType,
LoaderType, LoaderType,
ParallaxScalerType,
PrepperType, PrepperType,
ScannerType, ScannerType,
ScenerType, ScenerType,
@ -109,12 +107,6 @@ type Loader interface {
Load(fs.FS) error Load(fs.FS) error
} }
// ParallaxScaler components have a scaling factor. This is used for
// parallax layers in a scene, and can be thought of as 1/distance.
type ParallaxScaler interface {
ParallaxFactor() float64
}
// Prepper components can be prepared. It is called after the component // Prepper components can be prepared. It is called after the component
// database has been populated but before the game is run. The component can // database has been populated but before the game is run. The component can
// store the reference to game, if needed, and also query the component database. // store the reference to game, if needed, and also query the component database.

View file

@ -38,12 +38,6 @@ func (h *Hidden) Hide() { *h = true }
// Show sets h to false. // Show sets h to false.
func (h *Hidden) Show() { *h = false } func (h *Hidden) Show() { *h = false }
// Parallax implements ParallaxScaler directly (as a float64 value).
type Parallax float64
// ParallaxFactor returns s as a float64.
func (s Parallax) ParallaxFactor() float64 { return float64(s) }
// ZOrder implements DrawOrder (in Drawer) directly (as a float64 value). // ZOrder implements DrawOrder (in Drawer) directly (as a float64 value).
type ZOrder float64 type ZOrder float64

45
engine/parallax.go Normal file
View file

@ -0,0 +1,45 @@
package engine
import (
"encoding/gob"
"fmt"
"github.com/hajimehoshi/ebiten/v2"
)
var _ interface {
Prepper
Scanner
Transformer
} = &Parallax{}
func init() {
gob.Register(&Parallax{})
}
// Parallax is a container that changes its transform based on the position of a
// camera, intended to produce a "parallax" like effect.
type Parallax struct {
CameraID string
Factor float64 // how much to change in response to the camera
Child interface{}
camera *Camera
}
func (p *Parallax) Prepare(game *Game) error {
c, ok := game.Component(p.CameraID).(*Camera)
if !ok {
return fmt.Errorf("component %q type != *Camera", p.CameraID)
}
p.camera = c
return nil
}
func (p *Parallax) Scan() []interface{} { return []interface{}{p.Child} }
func (p *Parallax) Transform() (opts ebiten.DrawImageOptions) {
x, y := float2(p.camera.Centre)
opts.GeoM.Translate(x*p.Factor, y*p.Factor)
return opts
}

Binary file not shown.

11
main.go
View file

@ -16,7 +16,7 @@ import (
func main() { func main() {
// Change to true to enable cpu profile // Change to true to enable cpu profile
if true && runtime.GOOS != "js" { if false && runtime.GOOS != "js" {
f, err := os.Create("cpuprofile.pprof") f, err := os.Create("cpuprofile.pprof")
if err != nil { if err != nil {
log.Fatal("could not create CPU profile: ", err) log.Fatal("could not create CPU profile: ", err)
@ -33,7 +33,7 @@ func main() {
ebiten.SetWindowTitle("TODO") ebiten.SetWindowTitle("TODO")
// Change to true to rewrite level1.gobz // Change to true to rewrite level1.gobz
if false && runtime.GOOS != "js" { if true && runtime.GOOS != "js" {
writeLevel1() writeLevel1()
} }
@ -116,13 +116,16 @@ func writeLevel1() {
Color: color.Gray{100}, Color: color.Gray{100},
ZOrder: 0, ZOrder: 0,
}, },
&engine.Billboard{ &engine.Parallax{
CameraID: "game_camera",
Child: &engine.Billboard{
ID: "bg_image", ID: "bg_image",
Parallax: 0.5,
ZOrder: 1, ZOrder: 1,
Pos: image.Pt(-160, -120), Pos: image.Pt(-160, -120),
Src: engine.ImageRef{Path: "assets/space.png"}, Src: engine.ImageRef{Path: "assets/space.png"},
}, },
Factor: 0.5,
},
&engine.Tilemap{ &engine.Tilemap{
ID: "terrain", ID: "terrain",
ZOrder: 2, ZOrder: 2,