Zoom In/Out Feature: WorldIndexAt Fixed

WorldIndexAt() translates the pixel below the mouse cursor in screen
space (0,0 at top-left corner of the application window) into a world
coordinate in the level shown inside the canvas, taking into account the
canvas's position on the window and the scroll position.

It now translates correctly when zoom In or Out, so the "Abs:" mouse
position level in the status bar shows correctly.

Zoom features that are still jank:

- Scrolling while zoomed in, the chunks to the top/left start unloading
  too rapidly and outpacing the scroll, eventually level is invisible
- Drawing and committing pixels to the image while zoomed in/out is
  unpredictable where the pixels actually land.
- Actors in the level don't move or zoom at all.
This commit is contained in:
Noah 2021-07-12 21:20:45 -07:00
parent ed492a4451
commit 37f6177a17
4 changed files with 41 additions and 11 deletions

View File

@ -4,7 +4,7 @@ package branding
const ( const (
AppName = "Sketchy Maze" AppName = "Sketchy Maze"
Summary = "A drawing-based maze game" Summary = "A drawing-based maze game"
Version = "0.7.1" Version = "0.7.2"
Website = "https://www.sketchymaze.com" Website = "https://www.sketchymaze.com"
Copyright = "2021 Noah Petherbridge" Copyright = "2021 Noah Petherbridge"
Byline = "a game by Noah Petherbridge." Byline = "a game by Noah Petherbridge."

View File

@ -299,9 +299,19 @@ func (w *Canvas) WorldIndexAt(screenPixel render.Point) render.Point {
// Handle Zoomies // Handle Zoomies
if w.Zoom != 0 { if w.Zoom != 0 {
world.X = w.ZoomMultiply(world.X) // Zoom Out - logic is 100% correct, do not touch.
world.Y = w.ZoomMultiply(world.Y) // ZoomDivide's logic at time of writing is to:
// return int(float64(v) * divider)
// Where divider is a map of w.Zoom to:
// -2=4 -1=2 0=1 1=0.5 2=0.25 3=0.125
// The -2 and -1 do the right things (zoom out), zoom
// in was jank. NOW FIXED with the following maps:
// -2=4 -1=2 0=1 1=0.675 2=0.5 3=0.404
// Values for zoom levels 1 and 3 are jank but works?
world.X = w.ZoomDivide(world.X)
world.Y = w.ZoomDivide(world.Y)
} }
return world return world
} }

View File

@ -38,6 +38,14 @@ func (w *Canvas) Present(e render.Engine, p render.Point) {
} }
} }
// Scale the viewport to account for zoom level.
if w.Zoom < 0 {
// Zoomed out (level go tiny)
// TODO: seems unstable as shit on Zoom In.
Viewport.W = w.ZoomDivide(Viewport.W)
Viewport.H = w.ZoomDivide(Viewport.W)
}
// Get the chunks in the viewport and cache their textures. // Get the chunks in the viewport and cache their textures.
for coord := range w.chunks.IterViewportChunks(Viewport) { for coord := range w.chunks.IterViewportChunks(Viewport) {
if chunk, ok := w.chunks.GetChunk(coord); ok { if chunk, ok := w.chunks.GetChunk(coord); ok {
@ -143,10 +151,6 @@ func (w *Canvas) Present(e render.Engine, p render.Point) {
dst.W = S.W - w.BoxThickness(1) dst.W = S.W - w.BoxThickness(1)
} }
if w.Zoom < 0 {
log.Warn("dst: %+v", dst)
}
// When zooming OUT, make sure the source rect is at least the // When zooming OUT, make sure the source rect is at least the
// full size of the chunk texture; otherwise the ZoomMultiplies // full size of the chunk texture; otherwise the ZoomMultiplies
// above do correctly scale e.g. 128x128 to 64x64, but it only // above do correctly scale e.g. 128x128 to 64x64, but it only

View File

@ -62,22 +62,38 @@ func (w *Canvas) ZoomMultiply(value int) int {
/* /*
ZoomDivide divides an integer by the zoom inversely. ZoomDivide divides an integer by the zoom inversely.
The algo is: int(float64(value) * divider)
Where the divider is a map of:
w.Zoom => divider
-2 => 4
-1 => 2
0 => 1
1 => 0.675*
2 => 0.5
3 => 0.404*
The 0.675 and 0.404 numbers I don't understand but were
discovered the hard way when the 1.5x and 2.5x zoom levels
were coming out jank. Expected to be 0.25 and 0.75.
*/ */
func (w *Canvas) ZoomDivide(value int) int { func (w *Canvas) ZoomDivide(value int) int {
var divider float64 var divider float64
switch w.Zoom { switch w.Zoom {
case -2: case -2:
divider = 2 divider = 4
case -1: case -1:
divider = 2 divider = 2
case 0: case 0:
divider = 1 divider = 1
case 1: case 1:
divider = 0.5 divider = 0.675 // JANK
case 2: case 2:
divider = 0.25 divider = 0.5 // GOOD, 2x (200%) zoom in
case 3: case 3:
divider = 0.125 divider = 0.404 // JANK
default: default:
divider = 1 divider = 1
} }