π.Project -> geom.Project(π,

This commit is contained in:
Josh Deprez 2021-09-19 15:51:35 +10:00
parent c533ee63f7
commit ed78ef3d2e
6 changed files with 26 additions and 22 deletions

View file

@ -83,7 +83,7 @@ func (b *Billboard) String() string {
// Transform returns a translation by the projected position.
func (b *Billboard) Transform() (opts ebiten.DrawImageOptions) {
opts.GeoM.Translate(geom.CFloat(
b.game.Projection.Project(b.Pos),
geom.Project(b.game.Projection, b.Pos),
))
return opts
}

View file

@ -41,7 +41,7 @@ func (c *Camera) PointAt(centre geom.Int3, zoom float64) {
// Special sauce: if Child has a BoundingRect, make some adjustments
bnd, ok := c.Child.(BoundingRecter)
if !ok {
c.Centre = c.game.Projection.Project(centre)
c.Centre = geom.Project(c.game.Projection, centre)
c.Zoom = zoom
return
}
@ -63,7 +63,7 @@ func (c *Camera) PointAt(centre geom.Int3, zoom float64) {
// Camera frame currently Rectangle{ centre ± (screen/(2*zoom)) }.
sw2, sh2 := geom.CFloat(c.game.ScreenSize.Div(2))
swz, shz := int(sw2/zoom), int(sh2/zoom)
cent := c.game.Projection.Project(centre)
cent := geom.Project(c.game.Projection, centre)
if cent.X-swz < br.Min.X {
cent.X = br.Min.X + swz
}

View file

@ -212,7 +212,7 @@ func (p *Prism) String() string {
// Transform returns a translation by the projected position.
func (p *Prism) Transform() (opts ebiten.DrawImageOptions) {
opts.GeoM.Translate(geom.CFloat(
p.m.game.Projection.Project(p.pos),
geom.Project(p.m.game.Projection, p.pos),
))
return opts
}

View file

@ -67,7 +67,8 @@ func (s *Sprite) Transform() (opts ebiten.DrawImageOptions) {
// Reaching into Actor for a reference to Game so I don't have to
// implement Prepare in this file, but writing this long comment
// providing exposition...
s.Actor.game.Projection.Project(s.Actor.Pos).Add(s.DrawOffset),
geom.Project(s.Actor.game.Projection, s.Actor.Pos).
Add(s.DrawOffset),
))
return opts
}

View file

@ -80,7 +80,7 @@ func (b Box) BoundingRect(π Projector) image.Rectangle {
// Back returns an image.Rectangle representing the back of the box, using
// the given projection π.
func (b Box) Back(π Projector) image.Rectangle {
p := π.Project(Int3{0, 0, b.Min.Z})
p := π.Project(b.Min.Z)
return image.Rectangle{
Min: b.Min.XY().Add(p),
Max: b.Max.XY().Add(p),
@ -90,7 +90,7 @@ func (b Box) Back(π Projector) image.Rectangle {
// Front returns an image.Rectangle representing the front of the box, using
// the given projection π.
func (b Box) Front(π Projector) image.Rectangle {
p := π.Project(Int3{0, 0, b.Max.Z})
p := π.Project(b.Max.Z)
return image.Rectangle{
Min: b.Min.XY().Add(p),
Max: b.Max.XY().Add(p),

View file

@ -7,8 +7,13 @@ type Projector interface {
// Sign returns a {-1, 0, 1}-valued 2D vector pointing in the direction that
// positive Z values are projected to.
Sign() image.Point
// Project projects a 3D point into 2D.
Project(Int3) image.Point
// Project projects a Z coordinate into 2D offset.
Project(int) image.Point
}
// Project is shorthand for π.Project(p.Z).Add(p.XY()).
func Project(π Projector, p Int3) image.Point {
return π.Project(p.Z).Add(p.XY())
}
// Projection uses floats to define a projection.
@ -18,26 +23,24 @@ func (π Projection) Sign() (s image.Point) {
return image.Pt(int(FSign(π.X)), int(FSign(π.Y)))
}
// Project performs a parallel projection of a 3D coordiante into 2D.
// x projects to (x + z*π.X), and y to (y + z*π.Y)
func (π Projection) Project(p Int3) image.Point {
// Project returns (z*π.X, z*π.Y).
func (π Projection) Project(z int) image.Point {
return image.Pt(
p.X+int(π.X*float64(p.Z)),
p.Y+int(π.Y*float64(p.Z)),
int(π.X*float64(z)),
int(π.Y*float64(z)),
)
}
// IntProjection holds an integer projection definition.
// It is designed for projecting Z onto X and Y with integer fractions as would
// be used in e.g. a diametric projection (IntProjection{X:0, Y:-2}).
// be used in e.g. a diametric projection (IntProjection{X:0, Y:2}).
type IntProjection image.Point
func (π IntProjection) Sign() image.Point { return image.Point(π) }
// Project performs an integer parallel projection of a 3D coordinate into 2D.
// If π.X = 0, the x returned is p.X; similarly for π.Y and y.
// Otherwise, x projects to x + z/π.X and y projects to y + z/π.Y.
func (π IntProjection) Project(p Int3) image.Point {
// Project returns (z/π.X, z/π.Y), unless π.X or π.Y are 0, in which case that
// component is zero
func (π IntProjection) Project(z int) image.Point {
/*
Dividing is used because there's little reason for an isometric
projection in a game to exaggerate the Z position.
@ -45,12 +48,12 @@ func (π IntProjection) Project(p Int3) image.Point {
Integers are used to preserve "pixel perfect" calculation in case you
are making the next Celeste.
*/
q := p.XY()
var q image.Point
if π.X != 0 {
q.X += p.Z / π.X
q.X = z / π.X
}
if π.Y != 0 {
q.Y += p.Z / π.Y
q.Y = z / π.Y
}
return q
}