This question already has an answer here:

I'm working on a game in XNA with a 2D tilemap as the playfield. I'm using a spritebatch with a transformation matrix to provide movement and scaling of the playfield. I'm trying to add a zoom function, so the player can click anywhere on the screen and it will zoom in to that point. The issue is that when I increase or decrease the scale, the "focus" of the zoom is always at the top-left hand corner of the screen.

So unzoomed: unzoomed image

And when zoomed in (note the position of the chequered tile): zoomed image, incorrect

What I'd like to happen when the player zooms is that it zooms into the centre of the screen, like so: (I achieved this by moving the playfield around after zooming)

zoomed image, correct

I realise that the way to do this is probably to add or subtract from the X/Y co-ordinates that get fed into the transformation matrix, and probably at a fraction of the scale, but I can't figure this out. Everything I try tends to result in crazy effects while zooming.

Ideally I'd like to be able to set any arbitrary point on the screen, and zoom to that point. Can you help?

The code of the Draw function:

   protected override void Draw(GameTime gameTime)
        Matrix transformMatrix =
           Matrix.CreateTranslation(-baseX, -baseY, 0) *
            Matrix.CreateScale(baseR, baseR, 1) ; 


        // "World" spritebatch. Scaling applied.
        spriteBatch.Begin(SpriteSortMode.FrontToBack, null, SamplerState.PointClamp, null, null, null, transformMatrix);

        foreach (Vector3 Square in Squares)
            spriteBatch.Draw(Textures[(int)Square.Z], new Vector2(Square.X, Square.Y), null, Color.White, 0, new Vector2(0, 0), 1, SpriteEffects.None, 0.82f);



        // "UI" spritebatch. No scaling applied.
        spriteBatch.Begin(SpriteSortMode.FrontToBack, null, SamplerState.PointClamp, null, null);
        spriteBatch.Draw(Textures[0], new Vector2(ScreenMidX, ScreenMidY), null, Color.White, 0, new Vector2(0, 0), 1, SpriteEffects.None, 1f);

        SpriteFont aFnt = Content.Load<SpriteFont>("Font1");
        spriteBatch.DrawString(aFnt, "" + baseX, new Vector2(5, 0), Color.White, 0f, Vector2.Zero, 1f, SpriteEffects.None, 1f);
        spriteBatch.DrawString(aFnt, "" + baseY, new Vector2(100, 0), Color.White, 0f, Vector2.Zero, 1f, SpriteEffects.None, 1f);

Full code available here: https://www.dropbox.com/s/zft5b20st8o7jv7/ZoomTest3.zip

Thanks for any help!


marked as duplicate by Anko, bummzack, Sean Middleditch, Seth Battin, MichaelHouse Mar 12 '14 at 14:27

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

  • \$\begingroup\$ This might help: gamedev.stackexchange.com/questions/29686/… \$\endgroup\$ – OriginalDaemon Mar 5 '14 at 14:28
  • \$\begingroup\$ Try translating EVERYTHING by -mapWidth / 2 and -mapHeight / 2 before you scale. \$\endgroup\$ – Ben Mar 5 '14 at 14:54
  • \$\begingroup\$ @OriginalDaemon That looks very promising, I'll try that! \$\endgroup\$ – Kieran Mar 5 '14 at 15:30
  • \$\begingroup\$ @OriginalDaemon that worked perfectly; if you post that link as an answer I'll accept \$\endgroup\$ – Kieran Mar 5 '14 at 23:39
  • \$\begingroup\$ I think this counts as a duplicate of my question. However, you have described the problem better than me. So maybe we should vote to close this as a duplicate and you can edit my question to make it clearer. \$\endgroup\$ – OriginalDaemon Mar 6 '14 at 10:10

Browse other questions tagged or ask your own question.