2D top-down car with rotating body and Applying force in direction of rotation

Topics: Developer Forum, User Forum
Aug 5, 2014 at 12:29 PM
I am currently writing a simple top-down 2d game, in which the player object is a car comprised of a single body. I originally wrote this using only XNA, but have since decided to have more realistic collisions. My car is a rectangular body, and the player steers the car by rotating the body.

I am new to farseer and having some issue getting the car to steer in the direction the body/texture is rotated.

Here is the original code from my XNA project:

private void Input(GameTime gameTime)

    {
        GamePadState gamepadstate = GamePad.GetState(PlayerIndex.One);
        if (Keyboard.GetState().IsKeyDown(Keys.Right) || gamepadstate.DPad.Right == ButtonState.Pressed)
        {
            rotation -= 0.03f;
        }

        if (Keyboard.GetState().IsKeyDown(Keys.Left) || gamepadstate.DPad.Left == ButtonState.Pressed)
        {
            rotation += 0.03f;
        }

        if (Keyboard.GetState().IsKeyDown(Keys.S) || gamepadstate.Triggers.Left > .8f)
        //'S'ar is the accelerator
        {
            speed += 1;

        }
        if (Keyboard.GetState().IsKeyDown(Keys.X) || gamepadstate.Triggers.Right > .8f)
        //'X' key is reverse acceleration
        {
            speed -= 1;
        }

        if (Keyboard.GetState().IsKeyDown(Keys.Space))
        {
            //Shoot(gameTime,Player player,Content)
        }


        if (speed <= 0)
        {
            speed = 1;
        }
        if (speed >= 20)
        {
            speed = 20;
        }



        position.X += speed * (float)Math.Cos(rotation);
        position.Y += speed * (float)Math.Sin(rotation);


    }
...

This worked fine. Now that I have converted to farseer, I want to apply (I think) a linear impulse in the direction the car body is rotated.

This works, but the car "drifts" in the direction it was previously heading.
 playerBody.ApplyLinearImpulse(new Vector2(position.X, position.Y));
I'm not sure how to cancel out these forces? Is that what I need to do?
Any help would greatly be appreciated!


```
Aug 8, 2014 at 8:39 PM
Okay, I solved this on my own. What I did was just set the body.position to a vector2, using the position.X and position.Y variables already being handled by my code before i started porting to farseer - though this may screw with the physics?! I guess I will find out.
playerBody.Position = new Vector2(position.X, position.Y);
As nobody has responded, I'm going to mark this answered.
Marked as answer by gatewaygames on 8/8/2014 at 12:39 PM
Oct 6, 2014 at 5:21 AM
I ran into the same issue, I was setting the position directly I ran into some issues where the collisions would not register properly I posted a thread detailing the issue on here. I ended up using the ApplyLinearImpluse and just use Body.LinearVelocity = Vector2.Zero; to cancel out the "drifting".
Oct 8, 2014 at 1:07 PM
Interesting - I suspect my issue with collisions may be similar to yours. When I get the chance I will have to re-visit development of my game, which is currently on the back burner. Take a look here if you are interested as it does show game play.

The YouTube video is located here:
http://youtu.be/lRvo0Il72tU

Peter D
Oct 14, 2014 at 7:34 PM
in my game i used this code:
    internal void getPosition()
    {
        if (position.X == ConvertUnits.ToDisplayUnits(playerBody.Position.X) && position.Y == ConvertUnits.ToDisplayUnits(playerBody.Position.Y))
        {
            return;
        }
        Game1.needToDraw = true;
        position.X = ConvertUnits.ToDisplayUnits(playerBody.Position.X);
        position.Y = ConvertUnits.ToDisplayUnits(playerBody.Position.Y);
        rotation = playerBody.Rotation;
    }

    internal void draw()
    {
        destinationRectangle.X = (int)(position.X + Game1.matrix.X);
        destinationRectangle.Y = -(int)(position.Y + Game1.matrix.Y);
        Game1.spriteBatch.Draw(texture, destinationRectangle, null, Color.White, rotation, origin, SpriteEffects.None, 0f);
    }
Oct 16, 2014 at 3:53 PM
@PabloHenri91

Thanks very much for sharing. When I get a chance I certainly take a look to see if your code will help me with the issue I am having with my game.
Oct 16, 2014 at 6:03 PM
Edited Oct 16, 2014 at 6:04 PM
ok =}
for the rotation you can use something like this:
                if (Game1.input.mouse0)
                {
                    rotation = MathHelper.Pi + (float)-Math.Atan2(position.X - Game1.input.mouseX, position.Y - -Game1.input.mouseY);
                }
                else
                {
                    rotation = MathHelper.Pi + (float)-Math.Atan2(position.X - destination.X, position.Y - destination.Y);
                }

                if (Math.Abs(body.AngularVelocity) < maxAngularVelocity && (needToMove || Game1.input.mouse0))
                {
                    totalRotation = rotation - body.Rotation;
                    while (totalRotation < -MathHelper.Pi) totalRotation += MathHelper.TwoPi;
                    while (totalRotation > MathHelper.Pi) totalRotation -= MathHelper.TwoPi;
                    body.ApplyAngularImpulse(totalRotation * angularImpulse);
                }
I'm not so good at math but it worked perfect for me...

Apply force using
                                    dx = (float)-Math.Sin(body.Rotation);
                                    dy = (float)Math.Cos(body.Rotation);

                                body.ApplyForce(new Vector2(dx * force, dy * force), body.Position);
and to reduce the drift, set body.LinearDamping to 1f, 2f, 20f. Bigger numers mean less drift...