views:

53

answers:

1

I'm doing pathfinding where I use force to push body to waypoints. However, once they get close enough to the waypoint, I want to cancel out the force. How can I do this? Do I need to maintain separately all the forces I've applied to the body in question?

I'm using Box2dx (C#/XNA).

Here is my attempt, but it doesn't work at all:

   internal PathProgressionStatus MoveAlongPath(PositionUpdater posUpdater)
    {
        Vector2 nextGoal = posUpdater.Goals.Peek();
        Vector2 currPos = posUpdater.Model.Body.Position;
        float distanceToNextGoal = Vector2.Distance(currPos, nextGoal);
        bool isAtGoal = distanceToNextGoal < PROXIMITY_THRESHOLD;

        Vector2 forceToApply = new Vector2();
        double angleToGoal = Math.Atan2(nextGoal.Y - currPos.Y, nextGoal.X - currPos.X);
        forceToApply.X = (float)Math.Cos(angleToGoal) * posUpdater.Speed;
        forceToApply.Y = (float)Math.Sin(angleToGoal) * posUpdater.Speed;

        float rotation = (float)(angleToGoal + Math.PI / 2);

        posUpdater.Model.Body.Rotation = rotation;

        if (!isAtGoal)
        {
            posUpdater.Model.Body.ApplyForce(forceToApply, posUpdater.Model.Body.Position);
            posUpdater.forcedTowardsGoal = true;
        }

        if (isAtGoal)
        {
            // how can the body be stopped?

            posUpdater.forcedTowardsGoal = false;
            //posUpdater.Model.Body.SetLinearVelocity(new Vector2(0, 0));
            //posUpdater.Model.Body.ApplyForce(-forceToApply, posUpdater.Model.Body.GetPosition());
            posUpdater.Goals.Dequeue();

            if (posUpdater.Goals.Count == 0)
            {
                return PathProgressionStatus.COMPLETE;
            }
        }

UPDATE

If I do keep track of how much force I've applied, it fails to account for other forces that may act on it.

I could use reflection and set _force to zero directly, but that feels dirty.

A: 

If you just want to stop the body dead (cancelling out all forces acting on it) you can just put it to sleep:

posUpdater.Model.Body.SetAwake( false )

This clears the body's linear and angular forces and velocities. Sleeping bodies also don't collide with other sleeping bodies and generally take up less CPU time, as effectively their physics is switched off.

If you actually want the body to take part in physics after it's stopped dead, just wake it immediately:

posUpdater.Model.Body.SetAwake( false )
posUpdater.Model.Body.SetAwake( true)

This may lead to "unnatural" looking results if the body was in the middle of colliding with other things of course.

El Zorko