Monogame中如何为相机边界限制集成Zoom缩放并修复显示问题
问题:Monogame相机缩放后的边界适配
我正在使用Monogame开发一款2D游戏,现有Camera类、基础渲染方法和玩家相机边界限制方法如下:
Camera类代码
class Camera { private Matrix transform; private Vector2 centre; private Viewport viewport; private int mapWidthInPx; private int mapHeightInPx; private float zoom; private float rotation; private Rectangle oldViewArea; private Rectangle viewArea; public Camera(Viewport nViewport) { viewport = nViewport; zoom = 1f; rotation = 0f; } public Viewport Viewport { get { return viewport; } } public Matrix Transform { get { return transform; } } public int MapWidthInPx { get { return mapWidthInPx; } set { mapWidthInPx = value; } } public int MapHeightInPx { get { return mapHeightInPx; } set { mapHeightInPx = value; } } public float X { get { return centre.X; } set { centre.X = value; } } public float Y { get { return centre.Y; } set { centre.Y = value; } } public float Zoom { get { return zoom; } set { zoom = value; if (zoom < 0.1f) { zoom = 0.1f; } } } public float Rotation { get { return rotation; } set { rotation = value; } } public Rectangle OldViewArea { get { return oldViewArea; } set { oldViewArea = value; } } public Rectangle ViewArea { get { return viewArea; } } public void Update(Vector2 position) { SetCentrePosition(position); transform = GetTransformMatrix(); oldViewArea = viewArea; viewArea = GetViewArea(Zoom); } private void SetCentrePosition(Vector2 position) { if (position.X < viewport.Width / 2) { centre.X = viewport.Width / 2; } else if (position.X > mapWidthInPx - (viewport.Width / 2)) { centre.X = mapWidthInPx - (viewport.Width / 2); } else { centre.X = position.X; } if (position.Y < viewport.Height / 2) { centre.Y = viewport.Height / 2; } else if (position.Y > mapHeightInPx - (viewport.Height / 2)) { centre.Y = mapHeightInPx - (viewport.Height / 2); } else { centre.Y = position.Y; } } private Matrix GetTransformMatrix() { Matrix matrix = Matrix.CreateTranslation( new Vector3(-centre.X, -centre.Y, 0)) * Matrix.CreateRotationZ(Rotation) * Matrix.CreateScale(new Vector3(Zoom, Zoom, 0)) * Matrix.CreateTranslation(new Vector3(viewport.Width / 2, viewport.Height / 2, 0)); return matrix; } private Rectangle GetViewArea(float zoom) { Rectangle rectangle = new Rectangle( Convert.ToInt32(X - ((Viewport.Width / 2) / zoom)), Convert.ToInt32(Y - ((Viewport.Height / 2) / zoom)), Convert.ToInt32(Viewport.Width / zoom), Convert.ToInt32(Viewport.Height / zoom)); return rectangle; } }
基础渲染方法
public static void Render() { transform = camera.Transform; gDevice.SetRenderTarget(renderTarget); spriteBatch.Begin( SpriteSortMode.Deferred, BlendState.AlphaBlend, samplerState, null, null, null, transformMatrix: transform); currentScreen.Render(); spriteBatch.End(); gDevice.SetRenderTarget(null); spriteBatch.Begin(); spriteBatch.Draw(renderTarget, renderDestination, Color.White); spriteBatch.End(); }
玩家类相机边界限制方法
private void ClampCamBounds() { if (position.X < 0) { position.X = 0; } if (position.X > Basic.camera.MapWidthInPx - boundingBox.Width) { position.X = Basic.camera.MapWidthInPx - boundingBox.Width; } if (position.Y < 0) { position.Y = 0; } if (position.Y > Basic.camera.MapHeightInPx - boundingBox.Height) { position.Y = Basic.camera.MapHeightInPx - boundingBox.Height; } }
当前启用缩放后,玩家初始不可见,相机仍按无缩放逻辑限制边界。需要调整代码实现:移动时玩家保持屏幕中央,缩放后相机触达地图边缘时停止,同时玩家可以走到地图边缘。
解决方案
核心问题
原相机边界逻辑未考虑缩放因子,导致缩放后可视区域计算错误,相机与玩家的位置适配失效。
1. 修复Camera类的SetCentrePosition方法
缩放后,相机的实际可视半宽/半高需要结合缩放比例计算,替换原固定视口尺寸的逻辑:
private void SetCentrePosition(Vector2 position) { // 计算缩放后的可视半宽/半高 float halfVisibleWidth = (viewport.Width / 2f) / Zoom; float halfVisibleHeight = (viewport.Height / 2f) / Zoom; // X轴边界限制 if (position.X < halfVisibleWidth) { centre.X = halfVisibleWidth; } else if (position.X > mapWidthInPx - halfVisibleWidth) { centre.X = mapWidthInPx - halfVisibleWidth; } else { centre.X = position.X; } // Y轴边界限制 if (position.Y < halfVisibleHeight) { centre.Y = halfVisibleHeight; } else if (position.Y > mapHeightInPx - halfVisibleHeight) { centre.Y = mapHeightInPx - halfVisibleHeight; } else { centre.Y = position.Y; } }
2. 简化玩家的ClampCamBounds方法
玩家的边界限制是地图坐标系内的逻辑,与相机缩放无关,用MathHelper.Clamp简化代码:
private void ClampCamBounds() { position.X = MathHelper.Clamp(position.X, 0, Basic.camera.MapWidthInPx - boundingBox.Width); position.Y = MathHelper.Clamp(position.Y, 0, Basic.camera.MapHeightInPx - boundingBox.Height); }
效果验证
- 缩放时,相机可视区域随缩放比例调整,边界限制基于缩放后的范围计算,确保不超出地图边缘;
- 玩家未到达地图边缘时,相机始终将玩家保持在屏幕中央;
- 玩家靠近地图边缘时,相机先停止移动,玩家可继续走到地图边界;
- 初始状态下,相机基于缩放后的可视范围正确定位,玩家不会出现不可见问题。
内容的提问来源于stack exchange,提问作者Canox
相关产品推荐
相关产品推荐

