C++ Zoom into the centre of the screen in 2D coord

2019-03-03 11:59发布

问题:

I'm having difficulty working out the correct calculations in order to zoom into the centre of the screen in 2D coordinates whilst keeping everything in the correct scale.

I have a vector which I use to handle moving around my map editor as follows:

scroll = sf::Vector2<float>(-640.0f, -360.0f);

It's set at -640.0f, -360.0f to make 0,0 the centre of the screen on initialising (based on my window being 1280x720).

My zoom value ranges from 0.1f to 2.0f and it's increased or decreased in 0.05 increments:

zoomScale = zoomScale + 0.05;

When drawing elements on to the screen they are drawn using the following code:

sf::Rect<float> dRect;
dRect.left = (mapSeg[i]->position.x - scroll.x) * (layerScales[l] * zoomScale);
dRect.top = (mapSeg[i]->position.y - scroll.y) * (layerScales[l] * zoomScale);
dRect.width = (float)segDef[mapSeg[i]->segmentIndex]->width;
dRect.height = (float)segDef[mapSeg[i]->segmentIndex]->height;

sf::Sprite segSprite;
segSprite.setTexture(segDef[mapSeg[i]->segmentIndex]->tex);
segSprite.setPosition(dRect.left, dRect.top);
segSprite.setScale((layerScales[l] * zoomScale), (layerScales[l] * zoomScale));
segSprite.setOrigin(segDef[mapSeg[i]->segmentIndex]->width / 2, segDef[mapSeg[i]->segmentIndex]->height / 2);
segSprite.setRotation(mapSeg[i]->rotation);
Window.draw(segSprite);

layerScales is a value used to scale up layers of segments for parallax scrolling.

This seems to work fine when zooming in and out but the centre point seems to shift (an element that I know should always be at 0,0 will be located at different co-ordinates as soon as I zoom). I use the following to calculate what the position as at the mouse to test this as follows:

mosPosX = ((float)input.mousePos.x + scroll.x) / zoomScale)
mosPosY = ((float)input.mousePos.y + scroll.y) / zoomScale)

I'm sure there's a calculation I should be doing to the 'scroll' vector to take into account this zoom but I can't seem to get it to work right.

I tried implementing something like below but it didn't produce the correct results:

scroll.x = (scroll.x - (SCREEN_WIDTH / 2)) * zoomScale - (scroll.x - (SCREEN_WIDTH / 2));
scroll.y = (scroll.y - (SCREEN_HEIGHT / 2)) * zoomScale - (scroll.y - (SCREEN_HEIGHT / 2));

Any ideas what I'm doing wrong?

回答1:

I will do this the easy way (not most efficient but works fine) and only for single axis (second is the same)

it is better to have offset unscaled:

scaledpos = (unscaledpos*zoomscale)+scrolloffset

know center point should not move after scale change (0 means before 1 means after):

scaledpos0 == scaledpos1

so do this:

scaledpos0 = (midpointpos*zoomscale0)+scrolloffset0; // old scale
scaledpos1 = (midpointpos*zoomscale1)+scrolloffset0; // change zoom only
scrolloffset1+=scaledpos0-scaledpos1;                  // correct offset so midpoint stays where is ... i usualy use mouse coordinate instead of midpoint so i zoom where the mouse is 

when you can not change the scaling equation then just do the same with yours

scaledpos0 = (midpointpos+scrolloffset0)*zoomscale0;
scaledpos1 = (midpointpos+scrolloffset0)*zoomscale1;
scrolloffset1+=(scaledpos0-scaledpos1)/zoomscale1;

Hope I did no silly error in there (writing from memory). For more info see

  • Zooming graphics based on current mouse position