Tweaking movement physics

Discuss any questions about BEPUphysics or problems encountered.
Post Reply
al9191
Posts: 68
Joined: Wed Nov 16, 2011 11:19 pm

Tweaking movement physics

Post by al9191 »

We are writing a game which involves the main player moving around in the world in third person. We have the player object moving around and rotating by applying velocities to the object (which is represented as a ConvexHull.)

We now want to make the movement physics better, smoother etc as at the moment it either feels sluggish or if it is sped up, like driving around on ice. We want to go for the kind of motion you get with the Ghost's (purple alien small ground vehicle) in Halo.

I was just wondering how we go about fine tuning the movement physics. What settings can we change that alter how the model moves in the world?

Thanks very much.
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Tweaking movement physics

Post by Norbo »

You could fiddle with damping and such, but to really get close to what you want, it's probably going to take some tighter controls. The core tools on the entity side of things are the LinearVelocity/AngularVelocity properties or, equivalently, the momentum and impulse methods. Velocities may be the most natural to develop with.

First thing's first: I have to admit I haven't actually played Halo :) But, judging by videos of the vehicle in action, it needs to float a bit off the ground at all times. This keeps it from bumping on every tiny obstacle and allows it to bank and tilt a bit without scraping the ground.

To get it into the air, perform some queries- possibly just a single ray cast- to find support(s). For example, you could raycast down using the entity.OrientationMatrix.Down direction, or along world down. That will get you a distance to impact in the form of the 'T' value in the ray hit data. Note that the T value is the distance in terms of the length of the ray direction, but entity.Orientation.Down and Vector3.Down are both unit length. Pick some goal distance and compare it to the T value. If you're farther away than your desired goal distance, push the ship down towards the ground. If you're too close to the ground, push the ship up.

Your camera in combination with the down direction will define which direction forward, left, backward, and right are. Pick the forward direction using your camera (using the x and z coordinates of the direction or whatever else suits your control scheme). Pick right and left so that they are perpendicular to the forward vector (and probably your down vector too, unless you've gone with a different down vector; use a cross product of forward and down to get the right/left vectors).

You can compute velocities in a particular direction by dotting the LinearVelocity with the normalized direction. So, pick a goal velocity for a direction, compute the current velocity in a direction, and change the velocity so it gets closer to the goal without exceeding it. The acceleration value you apply to change the velocity can be arbitrarily large if proper clamping is implemented, so extremely precise response is possible. The SimpleCharacterController's horizontal motion handling shows an example of doing this.

Ghost-like angular motion is a little trickier. You may want to just use a SingleEntityAngularMotor in servo mode with its servo spring settings weakened. Compute a target orientation, give it to the SingleEntityAngularMotor, and it will do the rest. To compute the target orientation, you'll need to know the desired Up direction (not necessarily same as the down direction above; this is the direction you want your ship to eventually align with) along with the desired Forward direction (probably your camera facing direction projected onto the current support plane). From that, you can create a rotation, perhaps with Matrix.CreateWorld().


If you don't want to manage the support raycasts, you could use the Vehicle class to do it for you. Disable the motors and make the friction values negligible. The suspensions will keep the car floating (simply don't draw the wheels). The motion can then be controlled as described previously. If you don't care about floating at all, you could probably use something pretty similar to the SimpleCharacterController directly- or even the more robust SphereCharacterController and CharacterController. If you use the character controllers, the orientation will need to be a purely graphical effect as the characters won't actually be rotating.
al9191
Posts: 68
Joined: Wed Nov 16, 2011 11:19 pm

Re: Tweaking movement physics

Post by al9191 »

Thanks for such a detailed answer. You have provided lots of useful information, I will post any extra questions I have, if I encounter any problems. Cheers.
al9191
Posts: 68
Joined: Wed Nov 16, 2011 11:19 pm

Re: Tweaking movement physics

Post by al9191 »

I have put the SingleEntityAngularMotor in servo mode and added it to the Space.
How do you go about setting its TargetOrientation, in an EntityMotor it was as simple as setting the TargetOrientation field, however, this SingleEntityAngularMotor doesn't seem to have a TargetOrientation field?

Thanks :).
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Tweaking movement physics

Post by Norbo »

If you'd like, you can just use an EntityRotator. For dynamic entities, it uses a SingleEntityAngularMotor internally anyway. You can look at its source for an example of its usage.

The setup for a motor alone would look something like this:

Code: Select all

            //Create a motor.
            var angularMotor = new SingleEntityAngularMotor(entity);
            //Make it a servo (as opposed to a velocity motor) so it follows an orientation goal.
            angularMotor.Settings.Mode = MotorMode.Servomechanism;
            //Weaken the corrective spring.  This might be too much or too little depending on the mass of the entity.
            angularMotor.Settings.Servo.SpringSettings.DampingConstant /= 100;
            angularMotor.Settings.Servo.SpringSettings.StiffnessConstant /= 100;
            Space.Add(angularMotor);
...

            //Set the goal each frame.
            angularMotor.Settings.Servo.Goal = TargetOrientation;
al9191
Posts: 68
Joined: Wed Nov 16, 2011 11:19 pm

Re: Tweaking movement physics

Post by al9191 »

Ok thanks very much. We can now set the servo settings. Are the servo settings the fields that will control how the entity feels to rotate?
I have produced Quaternions from normalized vectors before, however, if say I want to rotate the entity 0.5 radians, how do I go about getting a Quaternion that represents 0.5 radians?
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Tweaking movement physics

Post by Norbo »

Are the servo settings the fields that will control how the entity feels to rotate?
The servo attempts to reach a goal like a spring. The damping and stiffness constants define how that spring approaches the goal. By default, the constants are set up to be roughly critically damped and quite rigid. It approaches the goal quickly without overshooting. If damping was significantly higher relative to the stiffness, the spring would become 'overdamped' and it would take longer to approach the goal. If the damping was significantly lower relative to the stiffness, the spring would become 'underdamped' and it would swing past the goal and oscillate while converging.

Increasing or decreasing both constants by the same factor is a good way to maintain the same general behavior, but at a lower speed. Because the default settings are nearly rigid, it corrects very quickly. That might be disturbing for a player who might expect his hovercraft to act a bit more floaty. By substantially reducing the spring settings by the same factor, the time it takes to reach the goal will be longer- less of a 'snap' and more of a 'woosh.'
I have produced Quaternions from normalized vectors before, however, if say I want to rotate the entity 0.5 radians, how do I go about getting a Quaternion that represents 0.5 radians?
The static XNA methods can do it:

Code: Select all

            var rotatedOrientation = Quaternion.Concatenate(originalOrientation, Quaternion.CreateFromAxisAngle(Vector3.Up, 0.5f));
Note the usage of the Quaternion.Concatenate method as opposed to Quaternion.Multiply or the * operator. Quaternion.Concatenate uses the same order as Matrix.Multiply. Quaternion.Multiply uses the opposite order.
al9191
Posts: 68
Joined: Wed Nov 16, 2011 11:19 pm

Re: Tweaking movement physics

Post by al9191 »

Ok thanks very much.
We have a problem at the moment, where we tell it to rotate by 0.5 radians every game update.
However, when this is tested the speed it rotates gradually slows down until it will stop rotating completely after about a quarter turn. It is as if it's rotation is tending towards a goal gradually rather than repeatedly rotating by 0.5 radians.

It is written in the same way as you posted above and called from the XNA update() method.
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Tweaking movement physics

Post by Norbo »

We have a problem at the moment, where we tell it to rotate by 0.5 radians every game update.
0.5 radians is roughly 30 degrees. If the goal is rotated by 0.5 radians per frame with 60 frames per second, the goal will perform around 5 full revolutions per second.
However, when this is tested the speed it rotates gradually slows down until it will stop rotating completely after about a quarter turn. It is as if it's rotation is tending towards a goal gradually rather than repeatedly rotating by 0.5 radians.
5 revolutions per second is extremely fast. Keep in mind that the motor will take the shortest route from the current state to the goal state (it doesn't 'coil up' and store revolutions). The goal is swinging around much, much faster than the spring can keep up with. Imagine it step by step- in roughly half of the frames, the goal is on one side of the current state, and in the other half, the goal is on the opposite side. The motor will push forward, then back, and get stuck in a slowly moving oscillation.
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Tweaking movement physics

Post by Norbo »

Also, if the spring is sufficiently weak compared to the mass of the entity, it will indeed appear to 'tend toward a goal gradually.' Strengthening the spring or lowering the entity mass will increase the rate of correction.
al9191
Posts: 68
Joined: Wed Nov 16, 2011 11:19 pm

Re: Tweaking movement physics

Post by al9191 »

Ok thanks, adjusting the entity's mass and the spring settings sorted it out. It now rotates around properly.
Thanks for the help.
al9191
Posts: 68
Joined: Wed Nov 16, 2011 11:19 pm

Re: Tweaking movement physics

Post by al9191 »

I have managed to get the player character control to be much better and closer to what we want.

Am now trying to alter the control of the enemies. I am using the Servo to rotate them as shown above a SingleEntityAngularMotor.
I am trying to make an enemy move around randomly at the moment. It moves around smoothly, and then every now and then when it touches one of the obstacles in the world it suddenly shoots of the screen away for it, faster than it can travel by itself.
The enemy is a ConvexHull created from the points in the FBX model, and has a mass set as 50f.

For the life of me I cannot work out why this could be happening...the models used in the do slightly go into other models, so the edges of the models can go inside others without causing collision. (Don't know if this has anything to do with the problem.) Thought maybe when the enemy goes inside the obstacle that the physics engine uses a massive force to get it out and that causes it to shoot off. I don't know just an idea.

Was wondering if you had any ideas what it might be?

random move method code shown below. The move(float) and rotate(float) take a value of either 1f or -1f to move/rotate either forwards or backwards / clockwise or anticlockwise.

Code: Select all

private static int ROTATE_CHANCE = 4; //Between 0 and 100
private static int STOP_CHANCE = 1; //Between 0 and 100
private static bool MOVING = false; //Whether it is moving or not

private void randomMove() {

if (MOVING)
            {
                //Either carry on moving or generate new orientation or chance to stop moving
                Random r = new Random((int)(DateTime.Now.Ticks * uniqueId));
                int choice = r.Next(0, 100);
                if (choice < STOP_CHANCE)
                {
                    //Stop moving
                    MOVING = false;
                }
                else if (choice < (STOP_CHANCE + ROTATE_CHANCE))
                {
                    //Generate new orientation
                    double angle = r.Next(0, 90);
                    angle /= 360;
                    angle *= (2 * Math.PI);
                    Quaternion change = Quaternion.CreateFromAxisAngle(Vector3.Up, (float)angle);
                    Quaternion orientation = Quaternion.Concatenate(bv.Body.Orientation, change);
                    servo.Settings.Servo.Goal = orientation;
                }
                else
                {
                    move(-1f);
                }                
            }
            else
            {
                //Randomly decide whether to start moving and generate orientation
                Random r = new Random((int)(DateTime.Now.Ticks * uniqueId));
                int choice = r.Next(0, 100);
                if (choice > STOP_CHANCE)
                {
                    //Start it moving
                    double angle = r.Next(0, 90);
                    angle /= 360;
                    angle *= (2 * Math.PI);
                    Quaternion change = Quaternion.CreateFromAxisAngle(Vector3.Up, (float)angle);
                    Quaternion orientation = Quaternion.Concatenate(bv.Body.Orientation, change);
                    servo.Settings.Servo.Goal = orientation;
                    move(-1f);
                    MOVING = true;
                }
            }
        }
}
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Tweaking movement physics

Post by Norbo »

Thought maybe when the enemy goes inside the obstacle that the physics engine uses a massive force to get it out and that causes it to shoot off. I don't know just an idea.
The engine does try to correct penetration, but the maximum speed that can be achieved by the correction impulse between two single objects is quite low (2 units per second by default, if I remember correctly) and wouldn't be responsible for an explosion by itself. Some amount of penetration happens every time any object collides so you'd be able to see these explosions all over the place. Unless the correction settings have been changed manually or other factors are massively amplifying the effect, this probably isn't the core issue.
Was wondering if you had any ideas what it might be?
Are any objects controlled by teleportation (setting Position and Orientation directly, or the equivalent)? Controlling state with teleportation without controlling velocities to match will cause collision response to fail since it's based upon velocities. The entity might have generated significant velocities from collisions which don't appear because teleportation is holding it in place, but when another object collides, the collision response system looks at the relative velocity and sees the objects ramming into each other at high speed.

Explosive behavior can also occur when massive forces are just barely contained. This can happen when there are constraints fighting each other. From your description, I don't know what these would be. I don't see anything in the posted code which would be directly responsible.
al9191
Posts: 68
Joined: Wed Nov 16, 2011 11:19 pm

Re: Tweaking movement physics

Post by al9191 »

Ok thank you. When I used an alternative method instead of that one that uses different way of randomly running the move and rotate methods, the problem doesn't occur. So it is causes by something in that code I posted. :/ Very confused.

I also don't do any teleportation, things are rotating using servo and moved by setting the linear velocity of the entity.
Post Reply