使背景或相机“滚动”基于角色位置

时间:2012-08-28 04:10:27

标签: c# background xna scroll 2d

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

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

2 个答案:

答案 0 :(得分:2)

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

  1. 你有一个头顶相机直接向下看到一个二维平面。我们可以将它表示为一个简单的{x,y}坐标对,对应于摄像机所在平面上的点。
  2. 相机可以跟踪某些物体(可能是玩家)的移动,但更常见的是游戏世界中的任何物体。
  3. 相机必须保持在游戏世界的有限范围内。
  4. 这很容易实现。从广义上讲,在Update()方法中的某个位置,您需要执行以满足每个要求的步骤:

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

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

    ClampCameraToBounds()也很容易实现。假设您有一些对象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;
    

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

答案 1 :(得分:0)

您可以在简单的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

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

这应该让你开始吧。

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

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

   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);

        }

希望这有帮助!