朝着它面向的方向前进

时间:2012-11-27 14:14:32

标签: c# math object xna rotation

我的问题是,我有一个物体,我想朝着它面向的方向前进,现在我能够旋转它,但无法让它向前移动。谁能告诉我如何解决这个问题?一些代码(评论是瑞典语,但应该可以理解函数的作用)

游戏代码:

namespace MultiPlayerTanks
{
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        Tank Player1, Player2; //skapa två spelare/tanks
        GameObj Bana; //Skapa ett GameObj som ska användas som bana
        SpriteFont font; //Spritefont för utskrift
        Meter PowerMeter,PowerMeter2, Player1LifeMeter, Player2LifeMeter; //Mätare för liv och kraft

        List<Shot> allShots = new List<Shot>();
        List<Shot> allShots2 = new List<Shot>();//Ny lista för alla skott(-objekt)
        Texture2D shot1Gfx; //Grafik till skotten

        List<Explosion> allExplosions = new List<Explosion>();
        List<Explosion> allExplosions2 = new List<Explosion>();//Ny lista för alla explosioner
        Texture2D explosionGfx; //Grafik till explosionen
        string displayMessage = ""; //Text som skalman skrivas ut

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";

            // Change of resolution.
            this.graphics.PreferredBackBufferWidth = 800;
            this.graphics.PreferredBackBufferHeight = 600;

            //this.graphics.IsFullScreen = true;
        }

        protected override void Initialize()
        {
            base.Initialize();
        }

        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);

            //Ladar in grafiken
            Texture2D greenTankGfx = Content.Load<Texture2D>("green_tank");
            Texture2D redTankGfx = Content.Load<Texture2D>("red_tank");
            Texture2D level1Gfx = Content.Load<Texture2D>("level");
            Texture2D redMeterGfx = Content.Load<Texture2D>("meter");
            Texture2D lifeMeterGfx = Content.Load<Texture2D>("life_meter");
            shot1Gfx = Content.Load<Texture2D>("shot");
            explosionGfx = Content.Load<Texture2D>("explosion");
            //Load basic texture to make it recognizable :)

            //Skapa Objekt
            //Tilldelning av properties direkt.. slipper skriva konstruktorer
            Player1 = new Tank()
            {
                Gfx = greenTankGfx,
                Position = new Vector2(400, 300),
                Speed = 0,
                Direction = new Vector2(0, -1),
                Enemy = false
            };
            Player2 = new Tank()
            {
                Gfx = redTankGfx,
                Position = new Vector2(400, 300),
                Speed = 0,
                Direction = new Vector2(0, -1),
                Enemy = true
            };
            Bana = new GameObj() { Gfx = level1Gfx, Position = new Vector2(0, 0), Angle = 0 };
            PowerMeter = new Meter() { Gfx = redMeterGfx, Position = new Vector2 (Player1.Position.X,Player1.Position.Y) };
            PowerMeter2 = new Meter() { Gfx = redMeterGfx, Position = new Vector2(Player2.Position.X,Player2.Position.Y) };
            Player1LifeMeter = new Meter() { Gfx = lifeMeterGfx, Position = new Vector2(50, 50) };
            Player2LifeMeter = new Meter() { Gfx = lifeMeterGfx, Position = new Vector2(250, 50) };
            font = Content.Load<SpriteFont>("SpriteFont1");
        }

        protected override void UnloadContent()
        {
        }

        protected override void Update(GameTime gameTime)
        {
            Player1.Update(gameTime);   //Uppdatera spelare1
            Player2.Update(gameTime);
            //Sätter Kraftmätarens värde till vår spelares "skottkraft"
            PowerMeter2.Value = Player2.ShotPower;
            PowerMeter.Value = Player1.ShotPower;
            //Sätter Livmätarnas värde till resp. spelares liv-värde
            Player1LifeMeter.Value = Player1.Life;
            Player2LifeMeter.Value = Player2.Life;

            #region player 2 shotfired
            if (Player2.ShotFired) //Ifall ett skott avfyrats
            {
                //Lägger till ett nytt skott i listan
                allShots2.Add(new Shot()
                {
                    Gfx = shot1Gfx,
                    Position = Player2.Position + (Player2.Direction * (Player2.Gfx.Height) / 2) +
                                (Player2.Direction * shot1Gfx.Height / 2),
                    Angle = Player2.Angle,
                    Speed = 5.0F + Player2.Speed,
                    Power = Player2.ShotPower,
                    Direction = Player2.Direction
                });
                Player2.ShotPower = 0;
                Player2.ShotFired = false;
            }
            for (int i = 0; i < allShots2.Count; i++) //Loopar igenom alla skott
            {
                allShots2[i].Update(gameTime); //uppdaterar skott
                if (allShots2[i].Power < 0) //Är skottets "kraft" slut?
                {
                    //Lägg till en ny Explosion
                    allExplosions2.Add(new Explosion() { Gfx = explosionGfx, Position = allShots2[i].Position });
                    allShots2.RemoveAt(i); //Tar bort skottet
                }
            }
            for (int i = 0; i < allExplosions2.Count; i++) //Loopa igenom alla explosioner
            {
                allExplosions2[i].Update(gameTime); //Uppdatera explosion
                //Ta bort "färdiga" explosioner
                if (allExplosions2[i].Active == false) allExplosions2.RemoveAt(i);
            }



            #endregion
            if (Player1.ShotFired) //Ifall ett skott avfyrats
            {
                //Lägger till ett nytt skott i listan
                allShots.Add(new Shot()
                {
                    Gfx = shot1Gfx,
                    Position = Player1.Position + (Player1.Direction * (Player1.Gfx.Height) / 2) +
                                (Player1.Direction * shot1Gfx.Height / 2),
                    Angle = Player1.Angle,
                    Speed = 5.0F + Player1.Speed,
                    Power = Player1.ShotPower,
                    Direction = Player1.Direction
                });
                Player1.ShotPower = 0;
                Player1.ShotFired = false;
            }
            for (int i = 0; i < allShots.Count; i++) //Loopar igenom alla skott
            {
                allShots[i].Update(gameTime); //uppdaterar skott
                if (allShots[i].Power < 0) //Är skottets "kraft" slut?
                {
                    //Lägg till en ny Explosion
                    allExplosions.Add(new Explosion() { Gfx = explosionGfx, Position = allShots[i].Position });
                    allShots.RemoveAt(i); //Tar bort skottet
                }
            }
            for (int i = 0; i < allExplosions.Count; i++) //Loopa igenom alla explosioner
            {
                allExplosions[i].Update(gameTime); //Uppdatera explosion
                //Ta bort "färdiga" explosioner
                if (allExplosions[i].Active == false) allExplosions.RemoveAt(i);
            }
        }
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.Black);

            spriteBatch.Begin();
            //Ritar ut bana, spelare och mätare
            Bana.Draw(spriteBatch, new Vector2(0,0));
            PowerMeter.Draw(spriteBatch, Player1.Position);
            PowerMeter2.Draw(spriteBatch, Player2.Position);
            Player1.Draw(spriteBatch, Player1.Position);
            Player2.Draw(spriteBatch, Player2.Position);
            Player1LifeMeter.Draw(spriteBatch, new Vector2(0, 0));
            Player2LifeMeter.Draw(spriteBatch, new Vector2(0, 0));

            //Loopar igenom alla skott och ritar ut dem
            for (int i = 0; i < allShots.Count; i++)
            {
                allShots[i].Draw(spriteBatch, Player1.Position);
            }

            //Loopar igenom alla explosioner och ritar ut dem
            for (int i = 0; i < allExplosions.Count; i++)
            {
                allExplosions[i].Draw(spriteBatch, Player1.Position);
            }
            ///////////////////////////////////////////////////
            for (int i = 0; i < allShots2.Count; i++)
            {
                allShots2[i].Draw(spriteBatch, Player2.Position);
            }

            //Loopar igenom alla explosioner och ritar ut dem
            for (int i = 0; i < allExplosions2.Count; i++)
            {
                allExplosions2[i].Draw(spriteBatch, Player2.Position);
            }

            //Skriver ut spelarnas namn och liv mm..
            string nameFormat = "{0}\nLife: {1}%\n\nKills: {2}";
            displayMessage = string.Format(nameFormat, "Player1", Player1.Life, Player1.Kills);
            spriteBatch.DrawString(font, displayMessage, new Vector2(51, 4), Color.Black);
            spriteBatch.DrawString(font, displayMessage, new Vector2(50, 5), Color.White);
            displayMessage = string.Format(nameFormat, "Player2", Player2.Life, Player2.Kills);
            spriteBatch.DrawString(font, displayMessage, new Vector2(251, 4), Color.Black);
            spriteBatch.DrawString(font, displayMessage, new Vector2(250, 5), Color.White);
            spriteBatch.End();

            base.Draw(gameTime);
        }
    }
}

GameObject代码:

namespace MultiPlayerTanks
{
    class GameObj
    {
        public Vector2 Position //Objektets position
        {
            get;
            set;

        }

        public Texture2D Gfx //Objektets grafik
        {
            get;
            set;
        }
        public float Angle //Objektets vinkel
        {
            get;
            set;
        }
        public virtual void Draw(SpriteBatch spriteBatch, Vector2 DrawOffset)
        {
            spriteBatch.Draw(Gfx,
                Position - DrawOffset + new Vector2(400, 300), null,
                Color.White, Angle + (float)Math.PI / 2,
                new Vector2(Gfx.Width / 2, Gfx.Height / 2), 1.0f,
                SpriteEffects.None, 0);
        }
    }
}

移动游戏对象代码:

namespace MultiPlayerTanks
{
    class MovingGameObj : GameObj
    {
        public Vector2 Direction //Riktning 
        {
            get;
            set;
        }
        public float spriterotation //Hastighet
        {
            get;
            set;
        }
        public float Speed //Hastighet
        {
            get;
            set;
        }

        public virtual void Update(GameTime gameTime)
        {

            Position += Direction * Speed;
        }
    }
}

坦克代码:

namespace MultiPlayerTanks
{
    class Tank : MovingGameObj
    {
        public Tank()
        {
            MaxSpeed = 2.5F;
            ShotPower = 0;
            prevKs = Keyboard.GetState();
            prevKs2 = Keyboard.GetState();
            Life = 100F;
            Kills = 0;
            Angle = -(float)(Math.PI / 2);

        }

        public bool Enemy
        {
            get;
            set;
        }
        public float MaxSpeed
        {
            get;
            set;
        }
        public float ShotPower
        {
            get;
            set;
        }
        public int WeaponType
        {
            get;
            set;
        }
        public bool ShotFired
        {
            get;
            set;
        }
        public float Life
        {
            get;
            set;
        }
        public int Kills
        {
            get;
            set;
        }
        protected KeyboardState prevKs;

        protected KeyboardState prevKs2;
        public void Respawn()
        {
            Life = 100F;
            Random randomerare = new Random();
            Position = new Vector2(randomerare.Next(1000), randomerare.Next(1000));
            Angle = 0;

        }
        public override void Update(GameTime gameTime)
        {

            KeyboardState ks = Keyboard.GetState();
            KeyboardState ks2 = Keyboard.GetState();
            #region Player 1
            if (Enemy == false)
            {
                if (ks.IsKeyDown(Keys.Up))
                {
                    if (Speed < 0) Speed = 0;
                    if (Speed < MaxSpeed) Speed = Speed * 1.005F + 0.01F;
                    else Speed = MaxSpeed;


                }
                if (ks.IsKeyDown(Keys.Down))
                {
                    if (Speed > -1.0F) Speed -= 0.04F;
                    else Speed = -1.0F;
                }
                if (ks.IsKeyUp(Keys.Down) && ks.IsKeyUp(Keys.Up) && Speed > 0)
                {
                    Speed -= 0.01F;
                    if (Speed <= 0) Speed = 0;
                }
                if (ks.IsKeyUp(Keys.Down) && ks.IsKeyUp(Keys.Up) && Speed < 0)
                {
                    Speed += 0.01F;
                    if (Speed >= 0) Speed = 0;
                }

                if (ks.IsKeyUp(Keys.Left))
                {
                    Angle += 0.02F;
                }
                if (ks.IsKeyUp(Keys.Right))
                {
                    Angle -= 0.02F;
                }
                if (ks.IsKeyDown(Keys.Space))
                {
                    if (ShotPower < 100)
                        ShotPower += 0.5F;
                    else
                        ShotPower = 100;
                }

                if (ks.IsKeyUp(Keys.Space) && prevKs.IsKeyDown(Keys.Space))
                {
                    //ShotPower = 0;
                    ShotFired = true;
                }
            }
            #endregion

            prevKs = ks;
            Direction = new Vector2((float)Math.Cos(Angle), (float)Math.Sin(Angle));

            base.Update(gameTime);
        }
    }
}

我尝试过很多不同的东西但似乎没什么用。我想要的是,当我按下W时,“坦克”向其朝向的方向前进。

2 个答案:

答案 0 :(得分:2)

我没有深入检查你的代码,但通常它就像

一样简单
position = position + directionVector * velocity * deltaTime;

请注意,您可以使用调试程序找到问题,在breakpoint中添加if(Enemy == false)以查看您认为哪种情况不起作用。

此外,在这样的代码中,在递增/递减值时始终使用deltaTime,否则在不同的帧速率下会有不同的结果(例如,游戏在更快的计算机上播放速度更快)

修改:虽然您的代码看起来“功能性”,但请记住,前进 / 后退映射到向上向下箭头...不是 W 就像你问的问题一样,这是唯一不起作用的吗?如果是这样,只需将Keys.Up替换为Keys.W ...

答案 1 :(得分:0)

已经很晚了,我很累,所以这就是你想要的答案。

你有一个名为“Angle”的旋转,其偏移量为“PI / 2”我将这个'r'称为旋转,所以:

float r = Angle + (float)Math.PI / 2

你需要做的是旋转一个前向矢量来匹配它,这就是我需要一个快速前向矢量时的方法。首先,我们需要一个标准的前向矢量,它是r = 0的坦克的前向矢量,即:

Vector2 v = new Vector2(0, -1)

这是一个直接向上移动的矢量。如果我们用r旋转它,那么我们有前向向量。我将使用Quaternion这样做。

Quaternion q = Quaternion.CreateFromAxisAngle(new Vector3(0, 0, 1), r);

v = Vector2.Transform(v, q)

这将返回一个旋转的矢量,该矢量将成为坦克的前方。

你可能需要用偏移角调整它,它已经很晚了,我很累,不应该发布真的......