我正在开发一款具有自上而下视图的 RPG 游戏。我想将图片加载到角色正在行走的背景中,但到目前为止,我还没有弄清楚如何正确重绘背景以使其“滚动”。我发现的大多数示例都是自动滚动的。
我希望相机始终以角色为中心,直到背景图像到达其边界,然后角色将移动而无需在另一个位置重新绘制图像。
我正在开发一款具有自上而下视图的 RPG 游戏。我想将图片加载到角色正在行走的背景中,但到目前为止,我还没有弄清楚如何正确重绘背景以使其“滚动”。我发现的大多数示例都是自动滚动的。
我希望相机始终以角色为中心,直到背景图像到达其边界,然后角色将移动而无需在另一个位置重新绘制图像。
你的问题有点不清楚,但我想我明白了它的要点。让我们看看你的要求。
这很容易实现。从广义上讲,在您的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;
然后,您可以使用对象的屏幕空间坐标来渲染它。
您可以在简单的 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);
}
希望这可以帮助!