Creating an arrow object

Topics: Developer Forum, User Forum
Mar 21, 2012 at 8:39 AM
Edited Mar 21, 2012 at 5:40 PM

Hello,

i try to create an arrow object on WP7 in an XNA game.

So far i got a circle, and when i touch inside the circle an arrow body is created at the origin of the circle by a class that i wrote.

Moving the finger inside the circle rotates my arrow body around the origin of the circle based on the touch position.

On touch release i set a boolean variable (isFlying) to true. In my update method take the direction vector between the touch position and my circle origin and apply a linear impulse to each flying arrow body with this direction vector.

Three things are did not react like i expect.

1. Moving speed is really slow even when i  multiply my direction vector with a  big value.

2. There seem no gravity taking effect to my arrow body object.

3. The arrow object tip shows no rotation like a real arrow would

My simulated physics world update is calculated down to 30fps thats ok for WP7 and gravity in Y direction is set to 9.

I'am doing something wrong. Even arrow.ApplyForce(0,200) does not take correct effect to the gravity.

Any ideas how to solve my problem?

 

Here is my code so far:

// My custom Body Factory
 /// <summary>
    /// Body factory to create physics body's with custom user data
    /// </summary>
    public class FarseerBodyFactory
    {
        private static Body _body;

        /// <summary>
        /// Creates a new physics body and loads the assigned texture
        /// </summary>
        /// <param name="content">ContentManager to load texture2D</param>
        /// <param name="_world">Physics world simulation</param>
        /// <param name="_bodyType">Type of body physic</param>
        /// <param name="_bodyPosition">Startposition of the body</param>
        /// <param name="_texturePathAndName">Path and name for the Texture to be loaded</param>
        /// <returns></returns>
        public static Body CreateFarseerBody(ContentManager content, World _world, BodyType _bodyType, Vector2 _bodyPosition, string _texturePathAndName)
        {
            FarseerBodyUserData userData = new FarseerBodyUserData
            {
                _bodyTexture = content.Load<Texture2D>(_texturePathAndName),
                isFlying = false,
                eCustomBodyType = ECustomBodyType.Projectile,
            };
            _body = BodyFactory.CreateRectangle(_world, userData._bodyTexture.Width, userData._bodyTexture.Height, 1);
            _body.Position = _bodyPosition;
            _body.BodyType = _bodyType;
            _body.UserData = userData;

            return _body;
        }
    }

    /// <summary>
    /// Stores custom user data for physics body
    /// </summary>
    public class FarseerBodyUserData
    {
        /// <summary>
        /// Texture that will be loaded for the physics body
        /// </summary>
        public Texture2D _bodyTexture { get; set; }

        /// <summary>
        /// Stores the flying state
        /// </summary>
        public bool isFlying { get; set; }

        /// <summary>
        /// Enumaration for custom body types
        /// </summary>
        public ECustomBodyType eCustomBodyType { get; set; }

        /// <summary>
        /// Stores the physics body velocity as vector2
        /// </summary>
        public Vector2 velocity { get; set; }
    }




// My BowCircle handle input method that calculates arrow rotation around bow circle origin
/// <summary>
        /// Detects the Touch input, if inside BowCircle a new physics body arrow gets created
        /// Calculates the arrow rotation around the BowCircle Origin
        /// On Touch release 
        /// </summary>
        /// <param name="content">ContentManager is needed to load body texture </param>
        /// <param name="world">Physics simulated world</param>
        /// <param name="bodysList">Global list of physics bodys to add new created physics body</param>
        /// <param name="input">InputState to handle input</param>
        /// <returns></returns>
        public float HandleInput(ContentManager content, World world, List<Body> bodysList, InputState input)
        {
            double x = 0; // Ankathete
            double y = 0; // Gegenkathete
            double angle = 0;
            Body _arrowBody = null;

            // Read in our gestures
            foreach ( TouchLocation l in input.TouchState )
            {
                // If Touch is inside of BowCircle
                if ( l.Position.X > _BowCirclePosition.X && l.Position.X < _BowCirclePosition.X + _BowCircleTexture.Width
                    && l.Position.Y > _BowCirclePosition.Y && l.Position.Y < _BowCirclePosition.Y + _BowCircleTexture.Height )
                {
                    if ( ScreenManager.isCreateable )
                    {
                        //Create new arrow physics body 
                        _arrowBody = FarseerBodyFactory.CreateFarseerBody(content, world, BodyType.Kinematic, _BowCircleOrigin, @"GlobalAssets\LaserProjectile");

                        //Add arrow body to global body list
                        bodysList.Add(_arrowBody);

                        // Set the global variable to false so a no new arrow can be created
                        // while touch is not released
                        ScreenManager.isCreateable = false;
                    }
                }

                //Calculate X-Y-distance between circle origin and Touch position
                x = l.Position.X - _BowCircleOrigin.X;
                y = _BowCircleOrigin.Y - l.Position.Y;
                //Calculate rotation angle around BowCircle origin
                angle = Math.Atan2(y, x);

                // Set the arrow body status to isFlying on touch release
                if ( l.State == TouchLocationState.Released )
                {
                    foreach ( Body b in bodysList )
                    {
                        // getting my custom UserDatat
                        FarseerBodyUserData userdata = (FarseerBodyUserData)b.UserData;
                        userdata.isFlying = true;
                        userdata.eCustomBodyType = ECustomBodyType.Projectile;
                        userdata.velocity = new Vector2((float)Math.Cos(b.Rotation), (float)Math.Sin(b.Rotation));
                        b.BodyType = BodyType.Dynamic;
                    }

                    // Set the global variable to true so a new arrow can be created
                    ScreenManager.isCreateable = true;
                }
            }
            return (float)angle * -1;
        }
    }




//Initializing physics world
_world = new World(new Vector2(0f, 9.81f));





// At Update
 // Run physics simulation                _world.Step(Math.Min((float)gameTime.ElapsedGameTime.TotalSeconds, ( 1f / 30f )));
                foreach ( Body b in _BodyList )
                {
                    // getting my custom UserDatat
                    FarseerBodyUserData userdata = (FarseerBodyUserData)b.UserData;

                    //Rotate around Bow Circle
                    if ( !ScreenManager.isCreateable & !userdata.isFlying )
                        b.Rotation = _arrowRotation;

                    // Set body to dynamic and apply linear Impulse 
                    if ( userdata.eCustomBodyType == ECustomBodyType.Projectile && userdata.isFlying )
                    {
                        //Apply velocity
                        b.ApplyLinearImpulse(userdata.velocity * -10000);
                       //Debug point shows {X:9732,396 Y:-2297,926}
                    }
                }


 
Mar 22, 2012 at 10:43 AM

Nobody got an idea why my bodys are moving so slow and gravity does not taking effect?

Mar 22, 2012 at 1:01 PM

Seems like your timestep is commented out from your code post may be your issue. Also, sometimes you may want to use a higher value for your world. Sometimes a value like 24 in Y won't make your simulation look floaty.

Mar 22, 2012 at 2:50 PM

To add: by looking at the code i see the body is created with dimensions taken from the texture. It's safe to assume it's in pixels. So an arrow will be like 10x5 pixels or something? But Farseer thinks in meters so the arrow is actually a huge solid block of 50 m^2. That's way out of scale and huge forces will be needed to move it around. Also with such dimensions the solver is unstable. Scale down the things to proper sizes using for example the ConvertUnits class from the samples.

Mar 22, 2012 at 3:09 PM

Good call jerrysb, I just assumed this was already being done.

Mar 22, 2012 at 4:37 PM
elijahnomad wrote:

Seems like your timestep is commented out from your code post may be your issue. Also, sometimes you may want to use a higher value for your world. Sometimes a value like 24 in Y won't make your simulation look floaty.

Oh no,

the timestep issue only happened by copy and pasting the code here.

Mar 22, 2012 at 4:43 PM
Edited Mar 22, 2012 at 4:45 PM
jerrysb wrote:

To add: by looking at the code i see the body is created with dimensions taken from the texture. It's safe to assume it's in pixels. So an arrow will be like 10x5 pixels or something? But Farseer thinks in meters so the arrow is actually a huge solid block of 50 m^2. That's way out of scale and huge forces will be needed to move it around. Also with such dimensions the solver is unstable. Scale down the things to proper sizes using for example the ConvertUnits class from the samples.

Thank you, good hint.

I scaled my body down using a constant of 100 and dividing the texture size in my custom body factory.

Now my body moves when i apply velocity without big multiplier.

But i still can't see any gravity taking influence and the speed is also slow even if i set a big multiplier.

Mar 22, 2012 at 7:41 PM
Edited Mar 22, 2012 at 7:54 PM

Ok, i got the gravity work.

What a stupid thing to apply velocity in each Update.

Now i got a nice curve and the rotation of my arrows are set in each update according to the current velocity X-Y-Values.

 

if ( userdata.isFlying && userdata.eCustomBodyType == ECustomBodyType.Projectile )
                    {
                        b.Rotation = (float)Math.Atan2(b.LinearVelocity.Y, b.LinearVelocity.X);
                    }

 

But the speed still seems to be too slow.

Even when i create a dynamic body without Linear impulse its falling really slow in my Physics world.

Any ideas how to check for that?

And next step will be to make the collisions.

Mar 23, 2012 at 12:33 PM

Assuming scale(mass) issues are resolved and your forces are big enough there could be synchronization issues. Are you updating physics with the same framerate as the phone is drawing it? Try increasing the update rate. For more info:

http://gafferongames.com/game-physics/fix-your-timestep/

Mar 23, 2012 at 3:11 PM
Edited Mar 23, 2012 at 3:12 PM

I think your are right.

When i set the step to 

// Run physics simulation
                _world.Step(Math.Min((float)gameTime.ElapsedGameTime.TotalSeconds, ( 1f / 60f )));
Everything is really slow.

But setting it to:
// Run physics simulation
_world.Step(Math.Min((float)gameTime.ElapsedGameTime.TotalSeconds, ( 1f / 1f )));
Seems to make it a little bit faster.
Mar 23, 2012 at 3:25 PM

But its still slow motion movement.

Mar 23, 2012 at 3:45 PM
Edited Mar 23, 2012 at 5:04 PM

I also detected that Boxes which i create did not stacking correctly.

They can go through each other, but they stop at the ground i created.

And in a other game i tryed also the positions of my bodies are in meter.

But now i can use pixel position and they are redered at correct pixel position.

really weird!

Mar 23, 2012 at 5:49 PM

I got it!

it was something in my scaling!

THX very much for all help!