[solved]problems rotating a character using the mouse

Hanfling

29-04-2007 19:50:49

im trying to make a player controlled character, and i already managed to get the movement working (forward/back strafe right/left), but i still have a huge problem getting the character to rotate using the mouse.

this is how i setup my collision objects (using a simple capsule and an UpVector):

//create materials and friction setup!
OgreNewt::MaterialID *mat1 = terMat;
OgreNewt::MaterialID *mat2 = new OgreNewt::MaterialID(mWorld);
OgreNewt::MaterialPair *pair = new OgreNewt::MaterialPair(mWorld, mat1, mat2);pair->setDefaultCollidable(1);
pair->setDefaultFriction(0.0,0.0);
pair->setDefaultElasticity(0);

// UPPER BODY
OgreNewt::Collision *col;
Vector3 *pos = new Vector3(0,4.5,0);
Quaternion *q = new Quaternion(Degree(90), Vector3::UNIT_Z);
col = new OgreNewt::CollisionPrimitives::Capsule(mWorld, max.x, max.y*0.8, *q, *pos);
OgreNewt::Body *uBody = new OgreNewt::Body(mWorld, col);

uBody->setMaterialGroupID(mat2);

Ogre::Vector3 inertia;

size = new Vector3(1,1,1);

inertia = OgreNewt::MomentOfInertia::CalcEllipsoidSolid(2, *size);

uBody->attachToNode( ninjaNode );

uBody->setAutoFreeze(false);
uBody->setMassMatrix( 2, inertia );

// add a joint to keep the upper body upright
OgreNewt::Joint* joint;
joint = new OgreNewt::BasicJoints::UpVector( mWorld, uBody, Vector3(Vector3::UNIT_Y));

delete col;


desired rotation amount is set using the MouseListener interface

bool MouseListener::mouseMoved( const OIS::MouseEvent &e ) {
using namespace OIS;
mCamRot_y = e.state.X.rel * mRotate;
return true;
}


and this is my force callback function:

void updateForce(OgreNewt::Body *me){

Real gain = 20.0;
if(moveFB != 0)
mDirection.z = moveFB * mAccel;
else {
mDirection.z = 0;
Vector3 netForce = Vector3(0,0,-mBody->getVelocity().z*gain);
mBody->addLocalForce(netForce, Vector3::ZERO);
}
if(moveLR != 0)
mDirection.x = moveLR * mAccel;
else {
mDirection.x = 0;
Vector3 netForce = Vector3(-mBody->getVelocity().x*gain,0,0);
mBody->addLocalForce(netForce, Vector3::ZERO);
}
if(moveUD != 0)
mDirection.y = moveUD * mAccel;
else {
mDirection.y = 0;
}

me->addLocalForce(mDirection, Vector3(0,0,0));


if(mCamRot_y != 0){
me->setOmega(Vector3(0,mCamRot_y,0));
mCamRot_y = 0;
} else {
me->setOmega(Vector3::ZERO);
}

/*
if(mCamRot_y != 0){
Vector3 torq = Vector3(0,mCamRot_y*0.2,0);
me->addTorque(torq);
}
*/

/*
if(mCamRot_y != 0){
Vector3 force = Vector3(0,0,mCamRot_y);
me->addLocalForce(force, Vector3(3,0,0));
force.z=-mCamRot_y;
me->addLocalForce(force, Vector3(-3,0,0));
mCamRot_y=0;
}
*/

//add gravity force
Real mass;
Vector3 in;
me->getMassMatrix(mass, in);
Vector3 *grav = new Vector3(0,-18.0f,0);
*grav = *grav * mass;
me->addForce(*grav);

//limit speed
if(mDirection.length() > mMoveMax){
mDirection.normalise();
mDirection = mDirection * mMoveMax;
}

}


the force callback still has some other attempts to rotate the char in it, of which none worked.
as soon as i move the mouse, the character starts rotating as wanted, but will eventually just bounce off the ground, rotate around some point at the center of the scene (like a ball on a rope) and then fly off.

i searched the forums for character control threads, and saw different approaches for rotating a character using torque, setting the rotation speed manually, or applying forces like you can see above.
i tried nearly all of these (and obviously im too dumb to get it working or something :oops: ), except the one where the torque is calculated using the current and desired rotation.
so here are my questions:
how can i calculate the desired rotation using the mouse event?
or, if my code isn't that far from a possible solution: where are my mistakes? :)

JackyE

29-04-2007 22:43:57

Not really a solution to you problem, but have you considered rotating the Entity and just applying forces depending on the player rotation.

Since you are using a capsule for collision, you can just apply running force in the direction of the player view and rotate the model without different results.

We once had the same problem, this is how we fixed it. Works nice. Unless of course the rotation interaction with the world is an important factor of you application (ie. rotation causes friction and thus stuff to move), then just ignore this reply :)

Hanfling

30-04-2007 15:10:06


Since you are using a capsule for collision, you can just apply running force in the direction of the player view and rotate the model without different results.


hm, i already thought about something like that, but i forgot that i could just apply forces relative to the entity to get the correct movement direction.
thanks for the help!

also, any further suggestions how to rotate a character/camera are welcome, maybe just some code samples from the force callback.

on a sidenote: what do you think is the "easiest" free physics engine to use for character controllers (anyone?)

JackyE

30-04-2007 23:19:10

on a sidenote: what do you think is the "easiest" free physics engine to use for character controllers (anyone?)

Nature, and nature's laws, lay hid in night,
God said, let Newton be! And all was light.
— from the grave of Newton, a poem from Alexander Pope


But I expect Ageia PhysX to become the big player. If those physics hardware cards get through to the mainstream, games will have a new dimension. Cool stuff!

Hanfling

01-05-2007 00:28:01

oh boy, this is getting really frustrating right now.
when i tried to rotate only the scenenode its orientation got reset nearly instantly (because it is attached to the body, i guess).
i already tried so many ways to get the damn character to rotate, but everytime it ends up flying off or something.

this is my latest attempt for my force callback:


//gravity
Real mass;
Vector3 in;
me->getMassMatrix(mass, in);
Vector3 *grav = new Vector3(0,-18.0f,0);
*grav = *grav * mass;
me->addForce(*grav);

//movement on the X/Z plane
Real gain = 20.0;
if(moveFB != 0)
mDirection.z = moveFB * mAccel;
else {
mDirection.z = -mBody->getVelocity().z*gain;
}
if(moveLR != 0)
mDirection.x = moveLR * mAccel;
else {
mDirection.x = -mBody->getVelocity().x*gain;
}
if(moveUD != 0)
mDirection.y = moveUD * mAccel;
else {
mDirection.y = 0;
}

me->addLocalForce(mDirection, Vector3(0,0,0));

//rotation around Y
Vector3 torq = Vector3(0,mCamRotY,0);
if(mCamRotY != 0){
me->addTorque(torq);
}
mCamRotY = 0;


angular damping is set to 60 for the y axis of the body.
as soon as i rotate the character with the mouse after moving it with the keys, it gets pushed around in circles no matter what.
i also noticed that this stops once i rotate back to the initial orientation.
am i missing something here?
torque is just as forces supposed to be applied in every callback isn't it?
somehow i have a feeling that the forces and torque gets added up in some strange way...

Hanfling

01-05-2007 14:57:32

well i got it working at last.
i ended up just modifying some code from this thread
somehow my manually applied counter-forces messed it up, but i cant yet figure out why.

my force callback now looks like this:

void updateForce(OgreNewt::Body *me){

//int gain = 20;
//int playerRotateState;
int const ROTATION_SPEED = 1; // must be positive
int const ROTATION_LIMIT = 3;
int const SPEED = 8;
int const SPEED_LIMIT = 4;

Ogre::Real mass;
Ogre::Vector3 inertia;
Ogre::Quaternion orient;
Ogre::Vector3 pos;
me->getPositionOrientation( pos, orient );
me->getMassMatrix( mass, inertia );
//Gravity
Ogre::Vector3 gravity( 0, -19.8, 0 );
Ogre::Vector3 f1( 0, 0, 0 );
Ogre::Vector3 f2( 0, 0, 0 );

Real rotationVelocity = abs( me->getOmega().y );

// Stop rotating
if( mCamRotY == 0 )
{
me->setOmega( Vector3::ZERO );
}

if( mCamRotY != 0)// && rotationVelocity < ROTATION_LIMIT )
{
f1.z += mCamRotY;
f2.z -= mCamRotY;
mCamRotY = 0;
}

// forward/backward movement
if( moveFB == 0)
{
//f1.z += -me->getVelocity().z*gain/2;
//f2.z += -me->getVelocity().z*gain/2;
}
if( moveFB == 1)// && speedVelocity < SPEED_LIMIT && player->getOnFloor() )
{
f1.z += SPEED;
f2.z += SPEED;
}
if( moveFB == -1)// && speedVelocity < SPEED_LIMIT && player->getOnFloor() )
{
f1.z -= SPEED;
f2.z -= SPEED;
}

if( moveLR == 0)
{
//f1.z += -me->getVelocity().z*gain/2;
//f2.z += -me->getVelocity().z*gain/2;
}
if( moveLR == 1)// && speedVelocity < SPEED_LIMIT && player->getOnFloor() )
{
f1.x += SPEED;
f2.x += SPEED;
}
if( moveLR == -1)// && speedVelocity < SPEED_LIMIT && player->getOnFloor() )
{
f1.x -= SPEED;
f2.x -= SPEED;
}

Vector3 centerPos( 0, 0, 0 );
Vector3 leftThrust( 5, 0, 0 );
Vector3 rightThrust( -5, 0, 0 );

me->addLocalForce( f1* mass , leftThrust );
me->addLocalForce( f2* mass , rightThrust );
me->addLocalForce( gravity* mass , centerPos );
}