Advertisement

Get direction of a ship base on where the booster is position?

Started by October 12, 2016 12:48 AM
8 comments, last by Norman Barrows 8 years, 1 month ago

So I am trying to do the old asteroid game.

Untitled_1.png

In the image above. I would like to get the direction in vector. Is there a way to get the direction of the ship say for example if I move the booster to left or right?

ooookkkkkaaaayyy

Yes, in fact I wrote a tutorial on it.

http://virtuallyprogramming.com/XNATutorials/TwoDTutorials/Acceleration/2DAcceleration.html

It's in XNA, but most of it is math and physics that will apply to anything.

The real guts of the tutorial is here:

http://virtuallyprogramming.com/XNATutorials/TwoDTutorials/Acceleration/AccelerationOf2DObjects.html

The XNA program was just a demo of the concept, but it was one of the most fun things I've ever coded because the ship acts on real world physics. And I didn't program it to keep the ship center screen or scroll at the screen edges. So, once it went off screen it was off screen and controlling it when you can't see it is nearly impossible and so it was nearly impossible to get it back on screen. So, the challenge was to pilot it around the fairly small screen without going off screen where you were nearly certain to never be able to get it back on screen again.

In the demo code, I have an engine directly behind the ship that you could "vector" and point at different angles to see how that affects movement, and then I had two engines with a fixed direction on either side. Turning one on would put the ship into a permanent spin (it's space, so once you apply a force nothing stops it until something stops it), which you could only get out of by turning that engine off and applying an equal force from the opposite engine. To move forward with those two, you had to apply them equally. Any small difference between them would spin the ship, which is how you turn. The vectored engine made it easier to control because you could just point it. The two fixed engines were harder to control.

And keep in mind that there are two things here: the facing of the ship and the direction of the ship. The ship can easily be facing a completely different direction than the one it is traveling in. The facing only affects where the engines are relative to the ship's center of gravity, allowing you to change where the engines are. The direction is the actual momentum of the ship, which is independent of the ship's facing and only changes when an acceleration is applied.

The tutorial may be a more complicated physics simulation that what you really want to get into, but it may at least give you some ideas. Sometimes realism needs to be sacrificed for game play, although I kind of like the real world physics.

I just downloaded the source code. It's been years since I've looked at this code, but here is the main body of the code to save you the trouble of downloading it when you may not even be coding in XNA (or probably are not). There was actually very little code for this; most of it was just math.


using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace ShipTorque2D
{
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        SpriteEffects Effect;
        Vector2 ShipSpriteSize;
        KeyboardState KB;
        KeyboardState PrevKB;
        Texture2D Ship;
        SpriteFont Font;
        int PortEngineThrotle;
        int StarboardEngineThrotle;
        float PortEngineThrust;
        float StarboardEngineThrust;
        
        Vector2 ShipsPosition;
        Vector2 ShipsVelocity;    //In meters per second in a given direction.
        Vector2 ShipsFacing;   //In radians.

        float ShipsAngularVelocity;   //In radians per frame. (We'll assume 60 fps.)

        const int FramesPerSecond = 60;
        const float EngineTorqueArm = 16f;  //Distance from center of gravity to engine's tangent in pixels (or meters).
        const float EngineForce = 4000f;  //Maximum force exerted by a single engine in Newtons (kilogram meters per second each second).
        const float ShipsMass = 18143.7f;    //In kilograms. 20 short tons =18143.7kg.
        const float ShipsEngineMaxAcceleration = (EngineForce / ShipsMass)/FramesPerSecond;   //In meters per second each second divided by FPS to give meters per second each frame.


        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            graphics.PreferredBackBufferWidth = 1280;   //Screen width horizontal
            graphics.PreferredBackBufferHeight = 720;   //Screen width vertical
            graphics.IsFullScreen = false;   //Set to false when debugging.
            graphics.ApplyChanges();
            Content.RootDirectory = "Content";

            Effect = new SpriteEffects();
        }

        
        protected override void Initialize()
        {
            ShipsPosition = new Vector2(200f, 200f);
            PortEngineThrust = 0;
            StarboardEngineThrust = 0;
            ShipsAngularVelocity = 0f;  
            ShipsFacing = Vector2.UnitX;  //Start with ship heading towards right side of the screen.
            ShipSpriteSize = new Vector2(192f, 256f);   //Scale ship's icon.
            base.Initialize();
        }

        
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);
            Ship = Content.Load<Texture2D>("SquarishShip");
            Font = Content.Load<SpriteFont>("SpriteFont1");

        }

        
        protected override void UnloadContent()
        {
        
        }

        
        protected override void Update(GameTime gameTime)
        {
            float AngularAcceleration;
            float ShipsAcceleration =0f;


            PrevKB = KB;
            KB = Keyboard.GetState();
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();
            if (KB.IsKeyDown(Keys.Escape)) this.Exit();

            if (KB.IsKeyDown(Keys.A)) PortEngineThrotle += 1;
            if (KB.IsKeyDown(Keys.Z)) PortEngineThrotle -= 1;
                        
            if (KB.IsKeyDown(Keys.D)) StarboardEngineThrotle += 1;
            if (KB.IsKeyDown(Keys.C)) StarboardEngineThrotle -= 1;

            if (PortEngineThrotle < 0) PortEngineThrotle = 0;
            if (PortEngineThrotle > 100) PortEngineThrotle = 100;

            if (StarboardEngineThrotle < 0) StarboardEngineThrotle = 0;
            if (StarboardEngineThrotle > 100) StarboardEngineThrotle = 100;

            PortEngineThrust = ShipsEngineMaxAcceleration * (PortEngineThrotle / 100f); //Div by 100 to turn into a percentage.
            StarboardEngineThrust = ShipsEngineMaxAcceleration * (StarboardEngineThrotle / 100f);
            AngularAcceleration = 0f;
            
            if (PortEngineThrust == StarboardEngineThrust)
            {
                ShipsAcceleration += (PortEngineThrust + StarboardEngineThrust);
            }
            else
            {
                if (PortEngineThrust > StarboardEngineThrust)
                {
                    ShipsAcceleration += StarboardEngineThrust;
                }
                else
                {
                    ShipsAcceleration += PortEngineThrust;
                }
                AngularAcceleration = ((PortEngineThrust - StarboardEngineThrust)) / EngineTorqueArm;
            }
            
            ShipsAngularVelocity += AngularAcceleration;
            ShipsFacing = Vector2.Transform(ShipsFacing, Matrix.CreateRotationZ(ShipsAngularVelocity));   //Rotate ships heading by angular velocity per frame.
            ShipsVelocity += (ShipsFacing * ShipsAcceleration);
            ShipsPosition += ShipsVelocity;

            base.Update(gameTime);
        }

        
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.Black);


            spriteBatch.Begin();
            spriteBatch.DrawString(Font, "Port:" + PortEngineThrotle.ToString()+"%", new Vector2(10f, 10f), Color.Yellow);
            spriteBatch.DrawString(Font, "Starboard:" + StarboardEngineThrotle.ToString()+"%", new Vector2(10f, 30f), Color.Yellow);
            spriteBatch.Draw(Ship, ShipsPosition, null, Color.White, VectorToAngle(ShipsFacing), ShipSpriteSize/2, 0.25f, Effect, 0f);
            spriteBatch.End();
            base.Draw(gameTime);
        }


        private Vector2 AngleToVector(float angle)
        {
            return new Vector2((float)Math.Sin(angle), -(float)Math.Cos(angle));
        }

        private float VectorToAngle(Vector2 vector)
        {
            return (float)Math.Atan2(vector.X, -vector.Y);
        }
    }
}


Quickly looking over the code, it looks like there are some places where it could be cleaned up. The addition of the two engines could probably be coded more simply. I probably wouldn't use a matrix to rotate the ship every frame according to it's rotational velocity, but would rather use the rotation formula. Either way it works but here's the forumla:

x = X * (float)Math.Cos(TurnAngle) - Y * (float)Math.Sin(TurnAngle);
 y = X * (float)Math.Sin(TurnAngle) + Y * (float)Math.Cos(TurnAngle); 
Advertisement

I'm not quite sure what you're asking, but I think you can just do Direction = Normalize(BoosterPostion - ShipCenterOfMass). Center of ship could be either just the middle of the ship, or offset to cause over/understeering.

EDIT: My suggestion does not take into consideration any rotational component based on having the booster on one side of the ship (basically assumes booster fire direction is always directed to prevent it).

Also -- ninjaed by BBeck.

Hello to all my stalkers.

Yes, in fact I wrote a tutorial on it.

Thanks.. Will you going to make a tutorial about game maths? you know the formulas that most beginner dont know about.


I'm not quite sure what you're asking, but I think you can just do Direction = Normalize(BoosterPostion - ShipCenterOfMass). Center of ship could be either just the middle of the ship, or offset to cause over/understeering

Can you tell me what isnt clear about my question? so that I can improve. Cause I thought that the image is self explanatory so I just limit my sentence to just few words to get straight to the point.

ooookkkkkaaaayyy

Can you tell me what isnt clear about my question?

There were a couple of things:

-- "I would like to get the direction in vector."

Direction from where to where?

-- Blue lines.

I see they are examples of directions, but I don't understand which line you want based on which booster position.

-- Coordinates

I don't understand the xy pairings -- they don't seem to be related to the blue lines (x is always 0?).

I think what would have made it easier for me to understand would have been multiple images. Each image having the booster in a specific position, and indicating what result you're after.

Image1 might have the booster in the middle, and the wanted direction being straight up(?).

Image2 might have the booster on the left, and the wanted direction being somewhere else.

I might also just be having an super-tired day and you can probably blame a lot of this on my mind being very slow until I get more sleep :)

Hello to all my stalkers.

but I think you can just do Direction = Normalize(BoosterPostion - ShipCenterOfMass).

If I understand the OP's question correctly , then yes, this should be the answer.

I love the way vector physics is so elegant.

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

Advertisement

I might also just be having an super-tired day and you can probably blame a lot of this on my mind being very slow until I get more sleep

Nope, cause I just woke up, and i'm not sure what he's asking either! <g>.

One question is: does the direction of thrust change, or only the point on the ship's body where that force is applied?

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

One question is: does the direction of thrust change, or only the point on the ship's body where that force is applied?

Yes it does. Say for example If I move the thrust to right or half between the middle and the right edge, then if the formula is correct I should get the corresponding opposite Y direction.

ANother example. If the thruster is exactly at the middle the Y direction should be 1 only going up. if it is half between left and middle the ship should move North east something like that. English isnt my first language so explaining things is hard.


I don't understand the xy pairings -- they don't seem to be related to the blue lines (x is always 0?).

The blue lines are suppose to be the direction. Yeah it was my bad. I think it isnt clear. But I hope this explanation helps.

For example if I place my thruster between the bottom middle and the bottom right edge of the ship, the ship will move something like in north-west direction. Or if thurster is on left the ship will move north-east. I dont want to assign value to this as I want it to be dynamic. Thats why I would like to know the formula how to get this direction( direction on where the ship should go base on thruster positioning) but in vector.

I hope this clears any confusion

ooookkkkkaaaayyy

For example if I place my thruster between the bottom middle and the bottom right edge of the ship, the ship will move something like in north-west direction. Or if thurster is on left the ship will move north-east.

What I said in my initial post sounds like it's the correct solution, then :)

Hello to all my stalkers.

Does the thrust change direction?

Yes it does.

Then it rotates around some point on the ship, it doesn't move back and forth. If the rotation point is the center of mass, then the direction vector from the thruster to the center will always be the direction in which force is applied and you should get no rotational movement, just displacement in that direction - and Lactose! 's formula is correct. Just multiply your unit direction vector by your speed to get your displacement vector for this update - IE how much to move, and in what direction. Then just add the x and y components of the displacement vector to the x,y position of the ship to get the new x,y position of the ship.

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

This topic is closed to new replies.

Advertisement