XNA 4.0屏幕上的相机和对象处理

时间:2016-08-08 02:48:50

标签: camera xna 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;

并且。绘图方法适用于相机。

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

当我停下来的时候会出现这个部分,所以我想做的就是制作2个2D房间。按房间我的意思是我经常放置物体的地方。像这样“Vector2(74,63)”所以我想创建一个地方,我可以绘制会粘在屏幕上并且不会移动的项目,并使屏幕界限使我的算法工作,将会是总是在屏幕上,作为一个补充,它将检查屏幕“房间”的一个边框是否到达地图“房间”的某个坐标。 我认为这样做的原因很明显,因为我不希望玩家在到达墙壁时将相机移动到地图之外,否则玩家就会看到下一张地图的一部分,他将在那里进行转换。 将两张地图彼此相邻绘制的原因是再次减少加载时间,这样玩家就不必等待播放下一张地图。

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

// 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;
                    }

我不确定如何处理相机,就像我使用你的方法一样,结果往往会导致相机单独移动或根本不移动。

1 个答案:

答案 0 :(得分:0)

如果您不希望物体像HUD那样随相机移动,则需要第二个spriteBatch.Begin(),而不需要在实际场景之后绘制相机矩阵。

要使相机不移出地图,您可以使用某种碰撞检测。只需计算相机的右边框即可。这取决于相机原点的位置。

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

这就是我的样子。

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

Viewport.Width / Height * 0.5使您的相机居中。 您也可以在Pos.X / Y

后面应用此功能

相机跟随播放器

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

    }