XNA 2D变换matrix比例缩放问题

这是我目前用于我的相机的完整代码。 这是不完整的,只能被我部分地理解(我正在做一个例子),但是我用一些暴力手段破坏了一些function,只是意识到我所做的一切都是错误的。

using System; using System.Collections.Generic; using System.Linq; using System.Text; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Graphics; namespace _2DCameraPractice { class Camera { int speed; int maxZoom; float zoom; float rotation; bool moveToWorldPoint; bool keyPressed; Game game; GraphicsDevice graphicsDevice; Camera camera; Matrix matrixTransform; Vector2 cameraPosition; Vector2 worldPoint; KeyboardState currKeyboardState; MouseState currMouseState; MouseState prevMouseState; public Camera(Game game, GraphicsDevice graphicsDevice) { this.game = game; this.graphicsDevice = graphicsDevice; zoom = 1; maxZoom = 5; rotation = 0; cameraPosition = Vector2.Zero; camera = this; } public float Zoom { get { return zoom; } // Negative flips image set { zoom = value; if (zoom < 0.1f) zoom = 0.1f; } } public float Rotation { get { return rotation; } set { rotation = value; } } public Vector2 Position { get { return cameraPosition; } set { cameraPosition = value; } } Vector2 CamCenterOffset { get { return new Vector2(game.Window.ClientBounds.Height / 2, game.Window.ClientBounds.Width / 2); } } Vector2 CamCenterInWorld { get { return cameraPosition + CamCenterOffset; } } Vector2 MouseCursorInWorld { get { currMouseState = Mouse.GetState(); return cameraPosition + new Vector2(currMouseState.X, currMouseState.Y); } } public void Direction(Vector2 direction) { cameraPosition += direction; } public Matrix Transform(GraphicsDevice graphicsDevice) { float ViewportWidth = graphicsDevice.Viewport.Width; float ViewportHeight = graphicsDevice.Viewport.Height; matrixTransform = Matrix.CreateTranslation(new Vector3(-cameraPosition.X, -cameraPosition.Y, 0)) * Matrix.CreateRotationZ(Rotation) * Matrix.CreateScale(new Vector3(Zoom, Zoom, 0)) * Matrix.CreateTranslation( new Vector3(ViewportWidth * 0.5f, ViewportHeight * 0.5f, 0)); return matrixTransform; } //Zoom in to mouse cursor. private Vector2 ZoomToMouse(Vector2 mousePos, Vector2 cameraPos) { Vector2 newCamPosition = cameraPos + ((mousePos - CamCenterOffset) / 3); //Need to figure a way to center mouse on screen as zooming. return newCamPosition; } private void CenterMouseOnZoom(Vector2 mousePos) { //The farther from center the cursor is, the more shifts it takes to center bool shift = false; int X = 0; int Y = 0; //If the X axis is within 100 units of center, jump once. if ( (mousePos.X - CamCenterOffset.X) <= 100 && (mousePos.X - CamCenterOffset.X) >= -100) { shift = true; X = (int)CamCenterOffset.X; //Mouse.SetPosition((int)GetCamCenterInView.X, Y); } if ((mousePos.Y - CamCenterOffset.Y) <= 100 && (mousePos.Y - CamCenterOffset.Y) >= -100) { shift = true; Y = (int)CamCenterOffset.Y; } if(shift) Mouse.SetPosition(X, Y); } public void CameraControlls() { MouseControl(); KeyboardControl(); KeyboardSpecials(); //Camera special commands if (moveToWorldPoint == true) CenterCameraOnWorldPoint(); } private void KeyboardSpecials() { //Output camera and mouse coordinate details. if(currKeyboardState.IsKeyDown(Keys.Space)) { //Bool check to prevent repeat outputs. if(!keyPressed) { System.Console.WriteLine("Camera : " + cameraPosition); System.Console.WriteLine("Zoom : " + camera.Zoom); System.Console.WriteLine("InWorld: " + CamCenterInWorld + "Camera"); System.Console.WriteLine(); System.Console.WriteLine("WorldPT: " + worldPoint); System.Console.WriteLine("InWOrld: " + MouseCursorInWorld + "Mouse"); System.Console.WriteLine(); System.Console.WriteLine(); keyPressed = true; } } if(currKeyboardState.IsKeyUp(Keys.Space)) keyPressed = false; } private void KeyboardControl() { //Camera movement (Keyboard) if(currKeyboardState.IsKeyDown(Keys.Right) || currKeyboardState.IsKeyDown(Keys.A)) { camera.Direction(new Vector2(-(1 * speed), 0)); moveToWorldPoint = false; } if(currKeyboardState.IsKeyDown(Keys.Left) || currKeyboardState.IsKeyDown(Keys.D)) { camera.Direction(new Vector2(1 * speed, 0)); moveToWorldPoint = false; } if(currKeyboardState.IsKeyDown(Keys.Up) || currKeyboardState.IsKeyDown(Keys.S)) { camera.Direction(new Vector2(0, 1 * speed)); moveToWorldPoint = false; } if(currKeyboardState.IsKeyDown(Keys.Down) || currKeyboardState.IsKeyDown(Keys.W)) { camera.Direction(new Vector2(0, -(1 * speed))); moveToWorldPoint = false; } //Camera zoom (Keyboard) if(currKeyboardState.IsKeyDown(Keys.Z)) camera.Zoom += 0.1f; if(currKeyboardState.IsKeyDown(Keys.X)) camera.Zoom -= 0.1f; //Camera rotation (Keyboard) if(currKeyboardState.IsKeyDown(Keys.C)) camera.Rotation += 0.1f; if(currKeyboardState.IsKeyDown(Keys.V)) camera.Rotation -= 0.1f; if(currKeyboardState.IsKeyDown(Keys.Home)) camera.Rotation = 0.0f; //Speed up scroll when zoomed way out. if(camera.Zoom < 0.2) speed = 1 + ((1 - (int)camera.Zoom) * 40); else if(camera.Zoom < 0.4) speed = 1 + ((1 - (int)camera.Zoom) * 20); else if(camera.Zoom < 0.7) speed = 1 + ((1 - (int)camera.Zoom) * 8); else if(camera.Zoom < 1) speed = 2 + ((1 - (int)camera.Zoom) * 4); else speed = 6 - (int)camera.Zoom; if(speed < 1) speed = 1; } private void MouseControl() { Vector2 mousePosition = new Vector2(currMouseState.X, currMouseState.Y); //Enable moveTo for world Point on [L.CTRL + L.Click] if mouse is inside // window bounds. if (currMouseState.LeftButton == ButtonState.Pressed && mousePosition.X >= 0 && mousePosition.Y >= 0 && mousePosition.X <= game.Window.ClientBounds.Width && mousePosition.Y <= game.Window.ClientBounds.Height) { //SetWorldPoint(MouseCursorInWorld); SetWorldPoint(MouseCursorInWorld); } //Enable moveTo for world Point on [L.CTRL + L.Click] if(currMouseState.LeftButton == ButtonState.Pressed && currKeyboardState.IsKeyDown(Keys.LeftControl)) //if (currKeyboardState.IsKeyDown(Keys.LeftControl)) { moveToWorldPoint = true; } //Camera zoom (MouseWheel) //Mouse wheel is (up to) ~120 points per click... No shit. if(currMouseState.ScrollWheelValue < prevMouseState.ScrollWheelValue) { //Holding shift while zooming 10+ times more sensative. if(currKeyboardState.IsKeyDown(Keys.LeftShift)) { camera.Zoom += (float)((prevMouseState.ScrollWheelValue - currMouseState.ScrollWheelValue) / 10) * 0.001f; } else { camera.Zoom -= (float)((prevMouseState.ScrollWheelValue - currMouseState.ScrollWheelValue) / 10) * 0.015f; } } if(currMouseState.ScrollWheelValue > prevMouseState.ScrollWheelValue) { if(camera.Zoom <= maxZoom) { if(currKeyboardState.IsKeyDown(Keys.LeftShift)) { camera.Zoom -= (float)((currMouseState.ScrollWheelValue - prevMouseState.ScrollWheelValue) / 10) * 0.001f; } else { camera.Zoom += (float)((currMouseState.ScrollWheelValue - prevMouseState.ScrollWheelValue) / 10) * 0.015f; //Reposition camera towards cursor durring zoom. // cameraPosition = ZoomToMouse(mousePosition, cameraPosition); // CenterMouseOnZoom(mousePosition); } } } prevMouseState = currMouseState; } private void SetWorldPoint(Vector2 worldPoint) { this.worldPoint = worldPoint; } private void CenterCameraOnWorldPoint() { int pixelsLarge = 10; int pixelsFine = 1; //Shift Left if (worldPoint.X < (cameraPosition.X + CamCenterOffset.X) && (cameraPosition.X + CamCenterOffset.X) - worldPoint.X > 20) cameraPosition.X -= pixelsLarge; else cameraPosition.X -= pixelsFine; //Shift Right if (worldPoint.X > (cameraPosition.X + CamCenterOffset.X) && worldPoint.X - (cameraPosition.X + CamCenterOffset.X) > 20) cameraPosition.X += pixelsLarge; else cameraPosition.X += pixelsFine; //Shift Up if(worldPoint.Y < (cameraPosition.Y + CamCenterOffset.Y) && (cameraPosition.Y + CamCenterOffset.Y) - worldPoint.Y > 20) cameraPosition.Y -= pixelsLarge; else cameraPosition.Y -= pixelsFine; //Shift Down if (worldPoint.Y > (cameraPosition.Y + CamCenterOffset.Y) && worldPoint.Y - (cameraPosition.Y + CamCenterOffset.Y) > 20) cameraPosition.Y += pixelsLarge; else cameraPosition.Y += pixelsFine; if(worldPoint.X - (cameraPosition.X + CamCenterOffset.X) < 5 && worldPoint.Y - (cameraPosition.Y + CamCenterOffset.Y) < 5) { moveToWorldPoint = false; } } public void Update(GameTime gameTime) { currKeyboardState = Keyboard.GetState(); currMouseState = Mouse.GetState(); this.CameraControlls(); } } 

}

基本上我想要做的是使这些基本function的2D相机:

  • [可选]直线缩小,放大鼠标光标(以它为中心)
  • [可选] Hotkey + L.Click,将视图切换到点击位置。 (更远的变焦=更快的移动)
  • L.点击,select世界对象,在任何缩放级别。
  • WASD和箭头,查看移动(S)。

正如你所看到的,我设法破解了一些非常古怪的例子(还没有圆顶箭头select),但是它们并没有像我期望的那样工作,我相信这与matrix变换有关,而且我缺乏理解它在代码方面。 (我已经在很多地方读过)

例如。 在缩放1时,一切都非常有效,X,Y坐标与窗口分辨率保持一致。 但是,如果我放大或缩小,X,Y坐标不会随着可视世界空间的新大小而缩放。 曾经的600×600像素现在是60×60(变焦0.1),但是在最右下角点击,仍然会返回一个600×600的世界vector,而不是更远的距离。

我已经寻找HOURS来find如何在XNA中编码matrix的一个很好的解释,以及为什么你会使用一个重载与另一个。 但我find的只是简单的静态JRPG和一些成熟的相机示例。 或第一人称射击types的相机。

现在,在你回答之前,我希望你能理解我说我是一个盯着比较学习者的人。 如果我有一个有代表性的例子,我可以通过最less的解释来推断其余大部分内容,并通过戳它看看会发生什么。 所以如果有人愿意简单地调整我发布的VERBOSE COMMENTING的代码,那对我最有帮助。 但是我会很感激你愿意给予的任何帮助。

我似乎已经想出了如何获得坐标的规模…

我假设目前的鼠标状态将反映它所点击的世界matrix,但显然它从来没有实际做到这一点。 它总是链接到视图matrix。 (屏幕本身),并且该值需要随着世界matrix(在变换中)而缩放。

因此,通过缩放Matrix.CreateScale(新的Vector3(缩放,缩放,0))来实现变换,鼠标状态的X和Y坐标也需要按比例缩放以虚拟反映世界matrix。

  //Offsets any cam location by a zoom scaled window bounds Vector2 CamCenterOffset { get { return new Vector2((game.Window.ClientBounds.Height / Zoom) * 0.5f, (game.Window.ClientBounds.Width / Zoom) * 0.5f); } } //Scales the mouse.X and mouse.Y by the same Zoom as everything. Vector2 MouseCursorInWorld { get { currMouseState = Mouse.GetState(); return cameraPosition + new Vector2(currMouseState.X / Zoom, currMouseState.Y / Zoom); } }