简体   繁体   中英

Moving Forward in the direction its facing

My problem is that I have an object I want to move forward in the direction it's facing, right now I'm able to rotate it, but unable to make it move forward. can anyone tell me how to fix this ? Some of the code (the comments are in Swedish, but it should be understandable what the function do)

Game Code:

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 Code:

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

Moving Game Object Code:

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

Tank Code:

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

I have tried many different things but nothing seems to work. What I want is that when I press W the "tank" moves forward in the direction its facing.

I haven't checked your code deeply, but usually it's as simple as

position = position + directionVector * velocity * deltaTime;

Keep in mind that you can use a debugger to locate the problem, adding a breakpoint in the if(Enemy == false) to see which condition you assume works that doesn't.

Also, in code like this, always use your deltaTime when incrementing / decrementing values, otherwise you will have different results on different frame rates (for example, the game will play faster on a faster computer)

Edit : while your code looks "functional" to me, keep in mind that going forward / backward is mapped on the Up and Down arrows... not W like you are asking in the question, is this the only thing not working? If so, simply replace Keys.Up to Keys.W ...

It is late and I am tired so here is the answer you want to work with.

You have a rotation called "Angle" with an offset of "PI / 2" I am going to call this 'r' for rotation, so:

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

What you need to do is rotate a forward vector to match it, this is how I do it when I need a quick forward vector. To begin with, we need a standard forward vector, which would be the forward vector of a tank with r = 0, ie:

Vector2 v = new Vector2(0, -1)

This is a vector going straight up the screen. If we rotate this by r, then we have the forward vector. I am going to use a Quaternion to do so.

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

v = Vector2.Transform(v, q)

This will return a rotated vector that will be the forward of the tank.

You may need to tweak it with an offset angle, it is late and I am very tired and shouldn't be posting really...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM