[Cuis-dev] [ANN] Cuis-Smalltalk-RoadTrip idle game + a question on implementing a ZoomPanMorph
Juan Vuletich
juan at cuis.st
Fri Mar 1 10:59:58 PST 2024
Hi Ian,
Welcome to the Cuis community!
On 2/29/2024 3:02 PM, Ian Jeffries via Cuis-dev wrote:
> Hi all,
>
> I'm working on an idle game for learning geography. The first version
> of it's up here: https://github.com/seagreen/Cuis-Smalltalk-RoadTrip
>
> It doesn't do much at the moment, there's just a car that noodles
> around between US cities. However I wanted to go ahead and publish it
> so I could get advice on the zooming and panning mechanism.
>
> Previously when I've implemented zoom-and-pan everything was based on
> screen coordinates. On zoom-in I stored a new scaling factor, and then
> when drawing the game applied this scaling factor to the game
> coordinates to get screen coordinates. Easy enough.
>
> For RoadTrip though I'm taking advantage of Cuis' local coordinate
> system to keep my coordinates in longitude and latitude all the way to
> the user's display. It's extremely neat the users can pull up the
> morph halo and see a grid in long/lat.
>
> But this makes scaling "interesting". On zoom-in when I apply
> `scaleBy:` to the morph the US map wants to shoot up and to the left
> off the screen. I'm currently handling this by moving the
> `morphPosition` after each zoom to offset this, so that while scaleBy
> makes the map jump up and to the left, the morph itself moves within
> its parent down and to the right to make up for it, hopefully keeping
> the map at the same place.
>
> Unfortunately I can't figure out how to make it exactly accurate and
> it jerks around a lot when zoomed in. Before putting more debugging
> work into this I wanted to ask if it seems like I'm on the right track
> or if I've missed something obvious.
>
> Thanks for the help,
> Ian Jeffries
>
You're example is very interesting, and it sparks several ideas to me...
My first thought was "you'd use a PluggableScrollPane". You can put a
simpler morph, that knows nothing about panning and scaling in a
ScrollPane, and play with the halo to scale it. Most likely
PluggableScrollPane could use some tweaks (like handling the scaling,
and the pan / zoom gestures), but it is not far from what you need.
Separating RoadTrip from Zoom/Pan issues, by composing them instead of
subclassing, is better IMO. Besides, in places like City>>drawOn: you're
hiding cities out of bounds yourself, while PluggableScrollPane already
clips for you. At least that what I'd do.
But then I tried to understand what was going on with your code, and I
found a bug in the Cuis image, Rectangle class >> #center:extent: This
is the real reason for the jerking you see. I just pushed an update for
that. Please pull & install. It will be much better.
Still, I think that the zoom behavior can be improved. The attach
includes a tweaked version of your #zoom:mouse: that first sets the
location to keep the point below the mouse exactly at the same place.
Then, I adjust 'origin' to keep the morph display bounds constant too.
I'd also rewrite the pan with mouse, and I'd remove
#adjustPositionInOwner: . But I leave that to you.
One last comment. You'd add ‘JSON’ as a prerequisite to your package, so
it is loaded automatically if needed.
This is a nice project, and I look forward for its evolution. Thanks!
Cheers,
--
Juan Vuletich
cuis.st
github.com/jvuletich
researchgate.net/profile/Juan-Vuletich
independent.academia.edu/JuanVuletich
patents.justia.com/inventor/juan-manuel-vuletich
linkedin.com/in/juan-vuletich-75611b3
twitter.com/JuanVuletich
-------------- next part --------------
'From Cuis6.3 [latest update: #6245] on 1 March 2024 at 3:24:48 pm'!
!ZoomPanMorph methodsFor: 'zoom' stamp: 'jmv 3/1/2024 15:23:04'!
zoom: amount mouse: latLongUnderMouse
"For instance, zoom in might be:
zoom: 1.1
zoom out might be:
zoom: 0.9"
| pixelUnderMouse pixelForOrigin delta |
pixelForOrigin := location externalizePosition: origin.
width := width / amount.
height := height / amount.
pixelUnderMouse := location externalizePosition: latLongUnderMouse.
self scaleBy: amount.
delta := pixelUnderMouse - (location externalizePosition: latLongUnderMouse).
location := location translatedBy: delta.
origin := location internalizePosition: pixelForOrigin.
self submorphsDo: [ :each |
each scaleBy: 1 / amount
].! !
More information about the Cuis-dev
mailing list