better drawordering?

This commit is contained in:
Josh Deprez 2021-09-09 19:11:25 +10:00
parent 724b5af8a3
commit 5afa3a9b00
8 changed files with 35 additions and 27 deletions

View file

@ -41,9 +41,9 @@ func (d *DebugToast) Draw(screen *ebiten.Image, _ *ebiten.DrawImageOptions) {
ebitenutil.DebugPrintAt(screen, d.Text, d.Pos.X, d.Pos.Y) ebitenutil.DebugPrintAt(screen, d.Text, d.Pos.X, d.Pos.Y)
} }
func (d *DebugToast) DrawOrder() (int, int) { func (d *DebugToast) DrawOrder() float64 {
// Always draw on top // Always draw on top
return math.MaxInt, 0 return math.MaxFloat64
} }
func (d *DebugToast) Toast(text string) { func (d *DebugToast) Toast(text string) {
@ -68,7 +68,7 @@ func (p PerfDisplay) Draw(screen *ebiten.Image, _ *ebiten.DrawImageOptions) {
ebitenutil.DebugPrint(screen, fmt.Sprintf("TPS: %0.2f FPS: %0.2f", ebiten.CurrentTPS(), ebiten.CurrentFPS())) ebitenutil.DebugPrint(screen, fmt.Sprintf("TPS: %0.2f FPS: %0.2f", ebiten.CurrentTPS(), ebiten.CurrentFPS()))
} }
func (PerfDisplay) DrawOrder() (int, int) { func (PerfDisplay) DrawOrder() float64 {
// Always draw on top // Always draw on top
return math.MaxInt, 0 return math.MaxFloat64
} }

View file

@ -431,17 +431,12 @@ type tombstone struct{}
func (tombstone) Draw(*ebiten.Image, *ebiten.DrawImageOptions) {} func (tombstone) Draw(*ebiten.Image, *ebiten.DrawImageOptions) {}
func (tombstone) DrawOrder() (int, int) { return math.MaxInt, math.MaxInt } func (tombstone) DrawOrder() float64 { return math.Inf(1) }
type drawList []Drawer type drawList []Drawer
func (d drawList) Less(i, j int) bool { func (d drawList) Less(i, j int) bool {
a0, a1 := d[i].DrawOrder() return d[i].DrawOrder() < d[j].DrawOrder()
b0, b1 := d[j].DrawOrder()
if a0 == b0 {
return a1 < b1
}
return a0 < b0
} }
func (d drawList) Len() int { return len(d) } func (d drawList) Len() int { return len(d) }

View file

@ -65,7 +65,7 @@ type Disabler interface {
// passed to Game.Register or returned from Scan). // passed to Game.Register or returned from Scan).
type Drawer interface { type Drawer interface {
Draw(screen *ebiten.Image, opts *ebiten.DrawImageOptions) Draw(screen *ebiten.Image, opts *ebiten.DrawImageOptions)
DrawOrder() (z, bias int) DrawOrder() float64
} }
// Hider components can be hidden. // Hider components can be hidden.

View file

@ -40,8 +40,8 @@ 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 }
// ZOrder implements DrawOrder (in Drawer) directly (as an int value). // ZOrder implements DrawOrder (in Drawer) directly (as a numeric value).
type ZOrder int type ZOrder float64
// DrawOrder returns z as a int with 0 bias. // DrawOrder returns z.
func (z ZOrder) DrawOrder() (int, int) { return int(z), 0 } func (z ZOrder) DrawOrder() float64 { return float64(z) }

View file

@ -149,9 +149,8 @@ func (p *Prism) Draw(screen *ebiten.Image, opts *ebiten.DrawImageOptions) {
screen.DrawImage(p.m.Sheet.SubImage(p.Cell), opts) screen.DrawImage(p.m.Sheet.SubImage(p.Cell), opts)
} }
func (p *Prism) DrawOrder() (int, int) { func (p *Prism) DrawOrder() float64 {
return p.m.PosToWorld.Apply(p.pos).Z, return p.m.game.Projection.DrawOrder(p.m.PosToWorld.Apply(p.pos))
geom.Dot(p.pos.XY(), image.Point(p.m.game.Projection).Mul(-1))
} }
func (p *Prism) Transform() (opts ebiten.DrawImageOptions) { func (p *Prism) Transform() (opts ebiten.DrawImageOptions) {

View file

@ -35,9 +35,9 @@ func (s *Sprite) Draw(screen *ebiten.Image, opts *ebiten.DrawImageOptions) {
screen.DrawImage(s.Sheet.SubImage(s.anim.Cell()), opts) screen.DrawImage(s.Sheet.SubImage(s.anim.Cell()), opts)
} }
// DrawOrder returns the Z position from Actor.Pos, and 0 bias. // DrawOrder returns the projected draw order.
func (s *Sprite) DrawOrder() (int, int) { func (s *Sprite) DrawOrder() float64 {
return s.Actor.Pos.Z, 0 return s.Actor.game.Projection.DrawOrder(s.Actor.Pos)
} }
// Scan returns the Actor and the Sheet. // Scan returns the Actor and the Sheet.

View file

@ -265,11 +265,11 @@ func Level1() *engine.Scene {
CollisionDomain: "level_1", CollisionDomain: "level_1",
Pos: geom.Pt3(100, -64, 100), Pos: geom.Pt3(100, -64, 100),
Bounds: geom.Box{ Bounds: geom.Box{
Min: geom.Pt3(-4, -16, -1), Min: geom.Pt3(-4, -15, -1),
Max: geom.Pt3(4, 0, 1), Max: geom.Pt3(4, 1, 1),
}, },
}, },
DrawOffset: image.Pt(-5, -16), DrawOffset: image.Pt(-5, -15),
Sheet: engine.Sheet{ Sheet: engine.Sheet{
AnimDefs: map[string]*engine.AnimDef{ AnimDefs: map[string]*engine.AnimDef{
"idle_left": {Steps: []engine.AnimStep{ "idle_left": {Steps: []engine.AnimStep{

View file

@ -17,8 +17,8 @@ func (π IntProjection) Project(p Int3) image.Point {
Dividing is used because there's little reason for an isometric Dividing is used because there's little reason for an isometric
projection in a game to exaggerate the Z position. projection in a game to exaggerate the Z position.
Integers are used to preserve that "pixel perfect" calculation in case Integers are used to preserve "pixel perfect" calculation in case you
you are making the next Celeste. are making the next Celeste.
*/ */
q := p.XY() q := p.XY()
if π.X != 0 { if π.X != 0 {
@ -29,3 +29,17 @@ func (π IntProjection) Project(p Int3) image.Point {
} }
return q return q
} }
// DrawOrder computes a draw-order value for a point under this projection.
// Each projection has an implied camera angle - Z alone is insufficient to
// order things properly.
func (π IntProjection) DrawOrder(p Int3) float64 {
z := float64(p.Z)
if π.X != 0 {
z -= float64(p.X) / float64(π.X)
}
if π.Y != 0 {
z -= float64(p.Y) / float64(π.Y)
}
return z
}