XNA 2D相机不会保持精灵中心

时间:2013-03-12 14:08:35

标签: c# xna 2d xna-4.0

我一直在研究一种太空飞船游戏,你可以在这种游戏中使用着陆器并从地面起飞,然后尽可能高地飞起来直到你崩溃。我遇到的问题是我试图实现的相机没有将着陆器保持在中心,着陆器最终比相机更快,然后离开屏幕。我不明白为什么,我已经尝试了一切让它发挥作用。我创建了一个测试用例,其中我在一个简单的程序中使用了相机,其中精灵在四个方向上移动。那个工作正常,但是当我在主游戏上实现相机时,它无法正常工作。任何帮助将不胜感激。

这是相机类:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace WindowsGame4.Main
{
  class Camera
  {
    public Matrix transform;
    Viewport view;
    Vector2 centre;

    public Camera(Viewport newView)
    {
        view = newView;
    }

    public void Update(GameTime gameTime, Game1 lander, Lander _lander)
    {
        centre = new Vector2(_lander.Position.X + (lander.lander.Width / 2) - 455, _lander.Position.Y + (lander.lander.Height/2)-910);
        transform = Matrix.CreateTranslation(new Vector3(-centre.X - _lander.Velocity.X, -centre.Y - _lander.Velocity.Y, 0));
    }
    }
    }

这是Game1中的主要更新方法:

    // Creates the handler to allow the use of the keyboard inputs
            KeyboardState keyboard = Keyboard.GetState(); 
            // Sets up the launch position to allow for scoring and height determining
            startPos = 700f;                
            // Mainly for debug, allows for leaving the game whenever desired
            if (keyboard.IsKeyDown(Keys.Escape))
            {
                Exit();
            }

       // The logic for the thruster, checks for if the space key is down and if 
       // the lander has any fuel remaining.  If there is no fuel the thrusters
       // will not work.
        if (keyboard.IsKeyDown(Keys.Space) && !empty)
        {
            _lander.Accelerate(_thruster.GetAcceleration(), gameTime.ElapsedGameTime);               
            // Turns on the thruster
            _thruster.Active = true; 
            // Tells the program that the lander has taken off, allowing the gravity to kick in
            landed = false;
            // Keeps track of the amount of fuel you have
            if (_lander.Fuel > 0)
            {
                // Subtracts 1 from the fuel for every second that the 'SPACE' key is down
                _lander.Fuel--;
            }
            else if (_lander.Fuel <= 0)
            {
                empty = true;
                endPos = _lander.Position.Y;
            }
        }
        if (keyboard.IsKeyUp(Keys.Space) || empty)
        {
            // Turns off the thruster as long as the player is not pressing 'SPACE'
            _thruster.Active = false; 
        }

        // This is the logic structure for the landing portion of the game, it sets up a 
        // level area in which the player can land on, which in turn then checks the Position.X value
        // to see how many points to give based on their close proximity to the landing site.  
        // ** Could possibly add depth or different levels based on location, like landing on a mountain
        // ** Or landing in the bottom of a crater
        if (_lander.Position.Y >= 800)
        {
            landed = true;
            // If you have died or Failed a mission 3 times then the game is over
            if (_lander.Lives == 1)
            {
                currentGameState = GameState.GameOver;                    
            }
            // As long as you have a life left the game will continue
            // This logic also is only applied if the player has landed on the ground
            // ** Add a rotational fixer as to make the lander stand straight up as opposed to the way its oriented
            // ** Upon landing
            else if (_lander.Lives > 0)
            {                   
                    // Sets the landers position to the current position that its landed at, thus stopping the gravity
                    // Resets the velocity, thus making sure it doesnt continue to fall
                    _lander.Position = new Vector2(_lander.Position.X, _lander.Position.Y);
                    _lander.Velocity = new Vector2();

                    // Sets up the first landing site, this particular one is the highset value landing site is almost right 
                    // On top of the flag that is placed to indicate where to land.
                    // *** Will Not Use In Final Version, Will Substitue With Logic For Height And Cash Gained ***
                    if ((_lander.Position.X >= 600 && _lander.Position.X <= 650) || (_lander.Position.X <= 600 && _lander.Position.X >= 550))
                    {   
                        // *** Will be implemented to display a "YOU HAVE FAILED THE MISSION" screen. ***
                        failure = false;
                        // This is for debugging purposes only, will change to be automatic once all functions are complete
                        if (keyboard.IsKeyDown(Keys.Enter))
                        {
                            // (1) -- Resets the position of the lander back to its original position and Velocity
                            // (2) -- Add 150 points to the score based on the location that the lander set down at
                            // (3) -- Continues on to the next level

                            _lander.Position = new Vector2(graphics.PreferredBackBufferWidth / 2, 100); // (1)
                            _lander.Velocity = new Vector2(); // (1)
                            _lander.Score += 150; // (2)
                            currentGameState = GameState.Level2; // (3) 
                        }
                    }
                    // Sets up the second landing site, this particular one is the second highest value landing site that is 
                    // A large circle surrounding the landing site above
                    else if ((_lander.Position.X >= 651 && _lander.Position.X <= 750 ) || (_lander.Position.X <= 549 && _lander.Position.X >= 450))
                    {
                        // *** Will be implemented to display a "YOU HAVE FAILED THE MISSION" screen. ***
                        failure = false;
                        // This is for debugging purposes only, will change to be automatic once all functions are complete
                        if (keyboard.IsKeyDown(Keys.Enter))
                        {
                            // (1) -- Resets the position of the lander back to its original position and Velocity
                            // (2) -- Add 50 points to the score based on the location that the lander set down at
                            // (3) -- Continues on to the next level

                            _lander.Position = new Vector2(graphics.PreferredBackBufferWidth / 2, 100); // (1)
                            _lander.Velocity = new Vector2(); // (1)
                            _lander.Score += 50; // (2)
                            currentGameState = GameState.Level2; // (3)
                        }                            
                    }
                    // Sets up the final landing site, this particular one is the failing portion of the map that is 
                    // A large area that encompasses the rest of the map.
                    else if ((_lander.Position.X >= 751 && _lander.Position.X <= 850) || (_lander.Position.X <= 449 && _lander.Position.X >= 0))
                    {
                        // You get no points so it does not only need to done once, it can be done as many times as needed
                        // And it will not change the data
                        _lander.Score = 0;
                        // *** Will be implemented to display a "YOU HAVE FAILED THE MISSION" screen. ***
                        failure = true;
                        // This is for debugging purposes only, will change to be automatic once all functions are complete
                        if (keyboard.IsKeyDown(Keys.Enter))
                        {
                            // (1) -- Resets the position of the lander back to its original position and Velocity
                            // (2) -- Takes away one of your lives as a result of the players failure to land correctly

                            _lander.Position = new Vector2(graphics.PreferredBackBufferWidth / 2, 100); // (1)
                            _lander.Velocity = new Vector2(); // (1)
                            _lander.Lives--; // (2)
                        }                              

                    }
                    // This is just a loop that gives a visual representation of refueling before the next level begins.
                    for (double i = _lander.Fuel; i < 500; i++)
                    {
                        _lander.Fuel += .05;                            
                    }
                }
            }
        // A very simple call to the Gravity and Lander classes that simulates gravity as long as the 
        // lander has not landed            
        else if (!landed)
        {
           _lander.Accelerate(_gravity.GetAcceleration(), gameTime.ElapsedGameTime);               
        }

        // Moves the lander according to gravity calculated by the lander class
        _lander.DoMovement(gameTime.ElapsedGameTime);

        // Calculates the height achieved based off of starting height and ending height
        height = startPos - endPos;
        // This will rotate the lander when the keys are pressed down
        // They will also check to make sure if it is landed or not
        // If it's landed then it will not allow the lander to rotate.
        if (keyboard.IsKeyDown(Keys.Left) && landed == false)
        {
            // (1) -- This will also change the angle of rotation for the thruster as to all for movement in 
            // That specific direction. 
            // Example: if you rotate to the left and turn on the thrusters you will starting moving
            // to the left

            rotation -= 0.1f;
            _lander.Rotation = rotation;
            _thruster.Rotation = rotation; // (1)
        }
        if (keyboard.IsKeyDown(Keys.Right) && landed == false)
        {
            // (1) -- This will also change the angle of rotation for the thruster as to all for movement in that specific direction.
            // (2) -- This will also change the angle of rotation for the lander as to all for movement in that specific direction.
            // Example: if you rotate to the right and turn on the thrusters you will starting moving
            // to the right

            rotation += 0.1f;
            _lander.Rotation = rotation; // (2)
            _thruster.Rotation = rotation;   // (1)
        }

        // Calls the camera class to allow the screen to move with the player
        camera.Update(gameTime, this, _lander);

如果你们需要更多代码,我可以上传你们需要的任何其他内容

2 个答案:

答案 0 :(得分:0)

为什么需要使用2D相机的翻译?对于可以做得更简单的事情来说,这是一种非常复杂的方式。在我看来,2D相机应该只是一个对应于相机视口左上角的矢量。然后从任何精灵位置中减去相机矢量,它将与相机一起移动。

因此,在您的情况下,只需将相机矢量设置为中心点减去屏幕宽度和高度的一半:

Camera = SpriteCenter - new Vector2(GraphicsDevice.Viewport.Width / 2, GraphicsDevice.Viewport.Height / 2);

对于每个绘图调用,从精灵的实际位置中减去Camera矢量。 你去了,你的精灵将永远居中。

如果你正在做一些不能让它发挥作用的特殊事物,那么我无法理解你的实际问题。我希望这会有所帮助。

答案 1 :(得分:0)

我不同意@Sarkilas,我认为使用转换会简化您的代码,而不是每次都需要指定相机。

您可以将此代码用作位置,原点,缩放和旋转的基础。

return Matrix.CreateTranslation(new Vector3(-Position, 0.0f)) *
       Matrix.CreateTranslation(new Vector3(-Origin, 0.0f)) *
       Matrix.CreateRotationZ(Rotation) *
       Matrix.CreateScale(Zoom, Zoom, 1) *
       Matrix.CreateTranslation(new Vector3(Origin, 0.0f));

问题是着陆器不是你的原点,它应该是你的位置,而原点应该是你的视口大小的一半,如此

Position = lander.Position;
Origin = new Vector2(view.Width / 2, view.Height / 2);

如果看起来有点偏离,您可能需要将着陆器位置的一半添加回原点或位置。