Using CharacterMovementVectorController

JoshPendergrass

07-08-2007 00:46:05

Hi, I'm trying to control speed of character with CharacterMovementVectoryController.

Here is my code:


class myMovement : public NxOgre::CharacterMovementVectorController
{
public:
void NxOgre::CharacterMovementVectorController::move(NxVec3 &out, NxVec3 &moveVector, NxQuat &direction, NxVec3 &g, float t, NxOgre::Character* )
{

NxReal mySpeed = 1.5;
out = ((direction.rot(moveVector) * mySpeed) + g) * t;
}

};


I keep getting the following errors:



1>c:\programming\mecha lord\mecha lord\mech_graphics.h(20) : error C3240: 'move' : must be a non-overloaded abstract member function of 'NxOgre::CharacterMovementVectorController'
1>c:\programming\mecha lord\mecha lord\mech_graphics.h(20) : error C2838: 'move' : illegal qualified name in member declaration
1> An explicit override can only be used for a method that was first introduced in an interface and whose override qualifier is an interface
1>main.cpp

betajaen

07-08-2007 09:00:33

class myMovement : public NxOgre::CharacterMovementVectorController
{
public:
void move(NxVec3 &out, NxVec3 &moveVector, NxQuat &direction, NxVec3 &g, float t, NxOgre::Character* )
{

NxReal mySpeed = 1.5;
out = ((direction.rot(moveVector) * mySpeed) + g) * t;
}

};

JoshPendergrass

07-08-2007 10:09:17

Thanks for the quick responce, getting this error now:
Access violation reading location 0xcdcdcdcd

Line getting the error is:
mWorld->simulate(time * mTimeModifier);

in file nxogrephysxdrive.cpp

void PhysXDriver::simulate(float time) {
if (mTimeModifier) {
mTime += time * mTimeModifier;
mWorld->simulate(time * mTimeModifier);
if (mDebugger)
mDebugger->simulate(time);
}
}


I'm setting it with:
character->mMoveVectorController = movementTest;

betajaen

07-08-2007 10:18:26

0xcdcdcdcd means an unintalised pointer, or at least a bad one. What's your setup? Do you have the System Software installed?

JoshPendergrass

07-08-2007 11:02:09

I'm sorry that post was premature. It was something completely different. It works perfect!
Thanks for the help! :D

JoshPendergrass

08-08-2007 04:15:10

One more questions with movement..
Is it possible to add a force or torque to the character class?
If not would the move function be the place to write our owne code for it?

betajaen

08-08-2007 09:20:26

Force sort of, torque no.

The character class uses a "kinematic" actor which means it doesn't respond to the usual forces that the rest of the Scene does. You can add a force, if you do the calculation and apply the change yourself. Newtons second law of motion, will help you there.

JoshPendergrass

08-08-2007 12:54:20

I see, still I little confused.
Would I need to use the character->setPosition function?
Or is there a way to get the Actor used by the character and a apply forces to it?

Pottej

08-08-2007 13:07:35

Character controllers are not designed to be affected by the laws of physics, they are there to give you as the programmer complete control over orientation and movement within the world.

There is a nice article from the aegia docs on the subject:



Character Controller
The goal of the character controller SDK is to provide a default built on top of the AGEIA PhysX SDK. Roughly it has to support the following:

Character control
Character interactions
This covers a very high number of features, which can be implemented in numerous ways. The goal is not to implement all of them (which would be a daunting task), but to offer a default implementation that people can use as a starting point. For example, the character's bounding volume could be anything, from a box to an inverted pyramid; therefore, in our initial implementation we support two common bounding volumes: an AABB and a capsule.

One might wonder why we didn't use the physics engine directly to implement the character controller. Here is the story.

Implementation Decisions
In the past, games didn't use "real" physics engines. However, they still used a character controller to move a player in a level. These games, such as Quake or even Doom, had a dedicated, customized piece of code to implement collision detection and response, which was often the only piece of physics in the whole game. It actually had little physics, but a lot of carefully tweaked values to provide a good feeling while controlling the player. The particular behavior it implemented is often called the " collide and slide" algorithm, and it has been tweaked for more than a decade. The result is that players expect to find the same well-known behavior in new games, and providing them with anything else is often dangerous (a few games come to mind but I’m not sure it’s appropriate to name them). This is especially true if provided behavior is not as robust and stable as before, which is exactly what happens if you use a typical physics engine directly to control players.

In particular, here is a (non-exhaustive) list of typical problems when using a physics engine for character controllers:

(Lack Of) Continuous Collision Detection: Typical physics engines use discrete collision checks, leading to the famous tunneling effect that has plagued various commercial & non-commercial physics packages for years, which leads to three main problems:


The tunneling effect itself - if the character goes too fast, it might tunnel through a wall.
As a consequence, the maximum velocity of the character might be limited (hence also limiting the game-play possibilities).
Even without tunnel, the character might jitter when pushed forward in a corner. For example, the engine keeps moving it back and forth to slightly different positions.


No Direct Control: A rigid body is typically controlled with impulses or forces. It is nearly impossible to move it directly to its final position until you have converted the delta position vector to impulses or forces and applied them in hopes that the character will be where you wanted it to be as a result. Usually it doesn't work very well, in particular when the physics engine uses an imperfect linear solver.


Trouble with Friction: When the character is standing on a ramp, you don't want it to slide. Infinite friction is desired. When the character is moving forward on that same ramp, or sliding against a wall, you don't want it to slow down, thus a null friction is needed. These are usually defined with either 0 or infinite. However, the friction model might not be perfect, and what you actually get is very little friction, so you can still feel the character slowing down, or a high-but-not-infinite friction, so the character slides very slowly on that ramp no matter how artificially high the friction parameters are. The conflicting requirements for ramps mean that usually there is simply no way to perfectly model desired behavior.


Trouble with Restitution: Basically you don't want any restitution, ever. When the character moves fast and collides with a wall, you don't want it to bump against it. When the character falls from a height and lands on the ground, flexing his legs, you definitely don't want any bumps, which would visually look terrible. But once again, even when the restitution is exactly zero, you sometimes get a small bump nonetheless. This is not only related to the non-perfect nature of the linear solver, but also has to do with how typical penetration-depth-based engines recover from overlap situations, sometimes applying too high a force that repels objects more than desired.


Undesired Jumps: It is often important that a character stick to the ground, no matter what the physical behavior should be. For example, characters in action games tend to move fast, at unrealistic speeds. When they reach the top of a ramp, the physics engine often makes them jump a bit, in the same way a fast car would jump in the streets of San Francisco. But that is often not desired: the character should stick to the ground regardless of its current velocity. This is sometimes implemented using fixed joints, which is a terrible, terrible solution to a very simple problem that has been solved for years without requiring all the modern complexity of a physics engine.


Undesired Rotations: Finally, a character is always standing up and never rotating. However, a physics engine often has poor support for that kind of constraint, and a great deal of effort is put into just preventing a capsule around the character from falling (it should always stand up on its tip). This too is sometimes implemented using artificial joints, and the resulting system is neither very robust nor very fast.
In summary, a lot of time is spent in disabling the physics engine's features, one after the other, for the whole purpose of emulating an otherwise simple piece of customized code. This is not the correct approach.



To move the character you really want to do that in the move() method if possible. You can adjust the orientation there as well by changing the NxQuat direction parameter.

If you really want yoru character to be part of the physics world like all other actors then dont use the character controller, use an actor that you add forces to and freeze its rotation to stop it falling over (although maybe the above article will put you off this ;) ). Alternatively have your character controller follow an invisible actor around, taking its position and orientation from that every frame (we have used this method for certain cases in our game).

Hope that helps,

Pottej

JoshPendergrass

09-08-2007 00:36:13

Thanks for the info it was a great help! I know what my options are now.
Best option for us will be adding code to the move function.

Thanks

milacao

01-06-2008 14:46:55

I have redefined the move() method, as it's said before in this and other posts, but when I run the application, the Ogre character moves due to the translate and yaw calls, but the NxOgre character does not move at all.

m_vDirection = getDirection();
m_pSceneNode = m_pPhysicsCharacter->getNode();
m_pSceneNode->translate( ... );
NxVec3 vDirection(m_vDirection.x, m_vDirection.y, m_vDirection.z);
NxQuat qOrientation;
NxVec3 vPosition;
m_pMovementController->move(vPosition, vDirection, qOrientation, NxVec3(0,-10, 0), fTimeSinceLastFrame, m_pPhysicsCharacter);

m_pSceneNode->yaw(...);
NxU32 unActiveGroups = m_pPhysicsCharacter->getNxController()->getActor()->getGroup();
NxU32 unCollisionFlags;
m_pPhysicsCharacter->getNxController()->move(vPosition, unActiveGroups, 0.1, unCollisionFlags );


Am I missing anything?
Thanks