XNA 4.0屏幕上的摄像头和物体处理



为了开发侧滚动平台2D游戏,我想实现一个移动相机类,使用该类而不是移动整个地图的原因是我必须同时使用太多对象,这会导致延迟。我不能让这种事发生。

有一个很好的算法来处理相机,当玩家移动的距离超过屏幕的宽度时,相机会向玩家的方向移动,直到他再次位于屏幕中间,我已经花了好几天的时间来实现这个算法,但没有成功。

// Main
public class Camera
{
    protected float _zoom;
    protected Matrix _transform;
    protected Matrix _inverseTransform;
    //The zoom scalar (1.0f = 100% zoom level)
    public float Zoom
    {
        get { return _zoom; }
        set { _zoom = value; }
    }
    // Camera View Matrix Property
    public Matrix Transform
    {
        get { return _transform; }
        set { _transform = value; }
    }
    // Inverse of the view matrix, 
    // can be used to get 
    // objects screen coordinates
    // from its object coordinates
    public Matrix InverseTransform
    {
        get { return _inverseTransform; }
    }
    public Vector2 Pos;
    // Constructor
    public Camera()
    {
        _zoom = 2.4f;
        Pos = new Vector2(0, 0);
    }
    // Update
    public void Update(GameTime gameTime)
    {
        //Clamp zoom value
        _zoom = MathHelper.Clamp(_zoom, 0.0f, 10.0f);
        //Create view matrix
        _transform =    Matrix.CreateScale(new Vector3(_zoom, _zoom, 1)) *
                        Matrix.CreateTranslation(Pos.X, Pos.Y, 0);
        //Update inverse matrix
        _inverseTransform = Matrix.Invert(_transform);
    }
}

这是我为处理屏幕而制作的相机类,它的主要目的是调整屏幕大小,更准确地说,是在我想更改屏幕时放大和缩小,(标题屏幕、播放屏幕、游戏结束等等(使用按键移动相机非常简单,比如这样。

                    if (keyState.IsKeyDown(Keys.D))
                        Cam.Pos.X -= 20;
                    if (keyState.IsKeyDown(Keys.A))
                        Cam.Pos.X += 20;
                    if (keyState.IsKeyDown(Keys.S))
                        Cam.Pos.Y -= 20;
                    if (keyState.IsKeyDown(Keys.W))
                        Cam.Pos.Y += 20;

和ofc。绘图方法采用照相机。

                        spriteBatch.Begin(SpriteSortMode.Texture, BlendState.AlphaBlend, null, null, null, null, Cam.Transform);

当我停下来的时候,这部分就来了,所以我想做的是制作两个2D房间。我所说的房间是指我通常放置物品的地方。像这个"Vector2(74,63(",所以我想创建一个地方,在那里我可以画出粘在屏幕上不会移动的项目,并确定屏幕边界,这将使我的算法发挥作用,witch将始终在屏幕上,作为一个附加项,它将检查屏幕"房间"的边界之一是否达到地图"房间"中的特定坐标。我认为原因是显而易见的,因为我不希望玩家在到达墙壁时将相机移动到地图之外,否则玩家将已经看到下一张地图中他将被改造的部分。将两张地图并排绘制的原因再次是为了减少加载时间,这样玩家就不必等待播放下一张地图。

好吧,所以我遇到了比我预期的更多的麻烦,所以我会添加额外的信息,并从玩家类开始:

// Main
public class Player
{
    public Texture2D AureliusTexture;
    public Vector2 position;
    public Vector2 velocity;
    public Vector2 PosForTheCam; // Variable that holds value for moving the camera
    protected Vector2 dimensions;
    protected CollisionPath attachedPath;
    const float GRAVITY = 18.0f;
    const float WALK_VELOCITY = 120f;
    const float JUMP_VELOCITY = -425.0f;
    // Constructor
    public Player()
    {
        dimensions = new Vector2(23, 46);
        position = new Vector2(50, 770);
    }
    public void Update(float deltaSeconds, List<CollisionPath> collisionPaths)
    {
        #region Input handling
        KeyboardState keyState = Keyboard.GetState();
        if (keyState.IsKeyDown(Keys.Left))
        {
            velocity.X = -WALK_VELOCITY;
        }
        else if (keyState.IsKeyDown(Keys.Right))
        {
            velocity.X = WALK_VELOCITY;
        }
        else
        {
            velocity.X = 0;
        }

        if (attachedPath != null && keyState.IsKeyDown(Keys.Space))
        {
            velocity.Y = JUMP_VELOCITY;
            attachedPath = null;
        }
        velocity.Y += GRAVITY;
        #endregion
        #region Region of handling the camera based on Player
         PosForTheCam.X = velocity.X;

        #endregion
        #region Collision checking
        if (velocity.Y >= 0)
        {
            if (attachedPath != null)
            {
                position.X += velocity.X * deltaSeconds;
                position.Y = attachedPath.InterpolateY(position.X) - dimensions.Y / 2;
                velocity.Y = 0;
                if (position.X < attachedPath.MinimumX || position.X > attachedPath.MaximumX)
                {
                    attachedPath = null;
                }
            }
            else
            {
                Vector2 footPosition = position + new Vector2(0, dimensions.Y / 2);
                Vector2 expectedFootPosition = footPosition + velocity * deltaSeconds;
                CollisionPath landablePath = null;
                float landablePosition = float.MaxValue;

                foreach (CollisionPath path in collisionPaths)
                {
                    if (expectedFootPosition.X >= path.MinimumX && expectedFootPosition.X <= path.MaximumX)
                    {
                        float pathOldY = path.InterpolateY(footPosition.X);
                        float pathNewY = path.InterpolateY(expectedFootPosition.X);
                        if (footPosition.Y <= pathOldY && expectedFootPosition.Y >= pathNewY && pathNewY < landablePosition)
                        {
                            landablePath = path;
                            landablePosition = pathNewY;
                        }
                    }
                }
                if (landablePath != null)
                {
                    velocity.Y = 0;
                    footPosition.Y = landablePosition;
                    attachedPath = landablePath;
                    position.X += velocity.X * deltaSeconds;
                    position.Y = footPosition.Y - dimensions.Y / 2;
                }
                else
                {
                    position = position + velocity * deltaSeconds;
                }
            }
        }
        else
        {
            position += velocity * deltaSeconds;
            attachedPath = null;
        }
        #endregion
    }
}

所以我明确表示,我让我的朋友做大部分工作,因为我想处理重力和斜坡,所以我们让它像在Unity中一样工作。他碰巧知道怎么做。因此,我将添加从Main Class处理相机的Update方法。

                        MM.Update(gameTime); // Map Managher update function for map handling
                    Cam.Update(gameTime); // Camera update
                    Cam.Zoom = 2.4f; // Sets the zoom level for the title screen
                    // Takes the start position for camera in map and then turns off the update 
                    // so the camera position can be changed. Else it would just keep an infinite
                    // loop and we couldn't change the camera.
                    if (StartInNewRoom)
                    {
                        Cam.Pos = MM.CameraPosition; // Applys the camera position value from the map manager class
                        StartInNewRoom = false;
                    }

我不确定如何处理相机,就像我使用了你的方法一样,结果往往是相机自己移动或根本不移动。

如果你不想让物体像HUD一样随着相机移动,你需要第二个spriteBatch。开始((,而不使用在实际场景后绘制的摄影机矩阵。

为了使相机不移出地图,可以使用某种碰撞检测。只需计算相机的右边框即可。这取决于你的相机的来源。

你的相机矩阵是这样工作的吗?因为这个位置应该是负的,否则它会朝着错误的方向移动。

这就是我的样子。

return Matrix.CreateTranslation(new Vector3(-camera.position.X, -camera.position.Y, 0)) * 
    Matrix.CreateRotationZ(Rotation) * Matrix.CreateScale(Zoom) *
    Matrix.CreateTranslation(new Vector3(Viewport.Width * 0.5f, Viewport.Height * 0.5f, 0));

视口。宽度/高度*0.5使相机居中。您也可以在Pos.X/Y 后面应用此功能

To Camera跟随玩家

public void Update(Player player)
    {
        //Clamp zoom value
        _zoom = MathHelper.Clamp(_zoom, 0.0f, 10.0f);
        //Create view matrix
        _transform =    Matrix.CreateScale(new Vector3(_zoom, _zoom, 1)) *
                        Matrix.CreateTranslation(player.Pos.X, player.Pos.Y, 0);
        //Update inverse matrix
        _inverseTransform = Matrix.Invert(_transform);
    }

最新更新