使背景或相机“滚动”基于字符位置

我正在开发一款具有自上而下视图的RPG游戏。 我想将一张图片加载到背景中,这是角色正在行走的内容,但到目前为止,我还没有弄清楚如何正确地重新绘制背景,以便它“滚动”。 我发现的大多数示例都是自动滚动。

我希望相机保持在角色的中心,直到您的背景图像到达其边界,然后角色将移动,而图像不会在另一个位置重新绘制。

你的问题有点不清楚,但我想我得到了它的要点。 让我们来看看你的要求。

  1. 你有一个高架摄像头直接向下看到一个二维平面。 我们可以将其表示为一个简单的{x,y}坐标对,对应于摄像机所在平面上的点。
  2. 相机可以跟踪某些物体(可能是玩家)的移动,但更常见的是游戏世界中的任何物体。
  3. 相机必须保持在游戏世界的有限范围内。

这很容易实现。 从广义上讲,在Update()方法中的某个位置,您需要执行以下步骤来满足每个要求:

 if (cameraTarget != null) { camera.Position = cameraTarget.Position; ClampCameraToWorldBounds(); } 

换句话说:如果我们有一个目标对象,将我们的位置锁定到它的位置; 但要确保我们不会超出界限。

ClampCameraToBounds()也很容易实现。 假设你有一个object, world ,它包含一个Bounds属性,表示世界的像素范围:

 private void ClampCameraToWorldBounds() { var screenWidth = graphicsDevice.PresentationParameters.BackBufferWidth; var screenHeight = graphicsDevice.PresentationParameters.BackBufferHeight; var minimumX = (screenWidth / 2); var minimumY = (screnHeight / 2); var maximumX = world.Bounds.Width - (screenWidth / 2); var maximumY = world.Bounds.Height - (screenHeight / 2); var maximumPos = new Vector2(maximumX, maximumY); camera.Position = Vector2.Clamp(camera.Position, minimumPos, maximumPos); } 

这可以确保相机永远不会超过屏幕的一半到达世界的边缘。 为什么半屏? 因为我们已经将相机的{x,y}定义为相机正在观察的点 ,这意味着它应始终以屏幕为中心。

这应该会为您提供一个摄像头,其中包含您在问题中指定的行为。 从这里开始,只需要实现地形渲染器,就可以相对于摄像机对象指定的{x,​​y}坐标绘制背景。

给定对象在游戏世界坐标中的位置,我们可以将该位置转换为相机空间:

 var worldPosition = new Vector2(x, y); var cameraSpace = camera.Position - world.Postion; 

然后从相机空间进入屏幕空间:

 var screenSpaceX = (screenWidth / 2) - cameraSpace.X; var screenSpaceY = (screenHeight / 2) - cameraSpace.Y; 

然后,您可以使用对象的屏幕空间坐标来渲染它。

您可以在简单的Vector2中表示位置并将其移向任何实体。 public Vector2 cameraPosition;

当您加载关卡时,您需要将相机位置设置为您的播放器(或它应该处于的对象)

您将需要一个矩阵和其他一些东西,如下面的代码所示。 评论中对此进行了解释。 这样做可以防止您必须将cameraPosition添加到您绘制的所有内容中。

  //This will move our camera ScrollCamera(spriteBatch.GraphicsDevice.Viewport); //We now must get the center of the screen Vector2 Origin = new Vector2(spriteBatch.GraphicsDevice.Viewport.Width / 2.0f, spriteBatch.GraphicsDevice.Viewport.Height / 2.0f); //Now the matrix, It will hold the position, and Rotation/Zoom for advanced features Matrix cameraTransform = Matrix.CreateTranslation(new Vector3(-cameraPosition, 0.0f)) * Matrix.CreateTranslation(new Vector3(-Origin, 0.0f)) * Matrix.CreateRotationZ(rot) * //Add Rotation Matrix.CreateScale(zoom, zoom, 1) * //Add Zoom Matrix.CreateTranslation(new Vector3(Origin, 0.0f)); //Add Origin //Now we can start to draw with our camera, using the Matrix overload spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.Default, RasterizerState.CullCounterClockwise, null, cameraTransform); DrawTiles(spriteBatch); //Or whatever method you have for drawing tiles spriteBatch.End(); //End the camera spritebatch // After this you can make another spritebatch without a camera to draw UI and things that will not move 

如果你想添加任何花哨的东西,我添加了缩放和旋转,只需替换变量。

这应该让你开始吧。

但是,您需要确保相机处于边界内,并使其跟随。

我将向您展示如何添加平滑滚动,但是如果您想要简单滚动,请参阅此示例 。

  private void ScrollCamera(Viewport viewport) { //Add to the camera positon, So we can see the origin cameraPosition.X = cameraPosition.X + (viewport.Width / 2); cameraPosition.Y = cameraPosition.Y + (viewport.Height / 2); //Smoothly move the camera towards the player cameraPosition.X = MathHelper.Lerp(cameraPosition.X , Player.Position.X, 0.1f); cameraPosition.Y = MathHelper.Lerp(cameraPosition.Y, Player.Position.Y, 0.1f); //Undo the origin because it will be calculated with the Matrix (I know this isnt the best way but its what I had real quick) cameraPosition.X = cameraPosition.X -( viewport.Width / 2); cameraPosition.Y = cameraPosition.Y - (viewport.Height / 2); //Shake the camera, Use the mouse to scroll or anything like that, add it here (Ex, Earthquakes) //Round it, So it dosent try to draw in between 2 pixels cameraPosition.Y= (float)Math.Round(cameraPosition.Y); cameraPosition.X = (float)Math.Round(cameraPosition.X); //Clamp it off, So it stops scrolling near the edges cameraPosition.X = MathHelper.Clamp(cameraPosition.X, 1f, Width * Tile.Width); cameraPosition.Y = MathHelper.Clamp(cameraPosition.Y, 1f, Height * Tile.Height); } 

希望这可以帮助!