Dynamic Character Control

nord666
Posts: 4
Joined: Sat Aug 23, 2008 9:02 pm

Dynamic Character Control

Post by nord666 »

Hello,

As my first post, i will show the code i use to dynamically control a character(not kinematic control). Currently, it's use the mouse to move the orientation(just on the X axis) and the keyboard to move on Y and X axis. No jump action for now.
I basically use a capsule collision to represent the character. I use Ogre 3D as my render engine, so i'll try to be the more general as possible. This code is based on some part of the Character Control Demo.

Units are: (meter * 10) for size and (kilogram * 10) for weight (i hope i'm not to confusing, i'm not really good with english :oops: )

/*...*/ = i removed useless code. Like Ogre or project related thing

character.h :

Code: Select all

class Character
{
public:

	Character(/*...*/btDiscreteDynamicsWorld * _mWorld, btVector3 _pos);

	void move(bool front, bool back, bool left, bool right); // each boolean indicate if the character move to this direction
	void rotation(int axisX); // axisX = the number of pixel the mouse moved since last frame
private:
	btDiscreteDynamicsWorld * mWorld;
	btRigidBody * body;
	btVector3 frontSpeed, sideSpeed;
	btScalar angleY;
	btScalar sensibility; // from 1 to 200 as %.
	
             // Really often used variables
	btTransform xform;
	btVector3 walkDirection;

};
character.cpp :

Code: Select all

Character::Character(/*...*/btDiscreteDynamicsWorld * _mWorld, btVector3 _pos)
	: /*...*/mWorld(_mWorld), frontSpeed(btVector3(0.0, 0.0, 5.0)), sideSpeed(btVector3(3.0, 0.0, 0.0)), angleY(0.0), sensibility(60.0)
{
 	xform.setIdentity();
 	xform.setOrigin(_pos);
 	
             // this function creates and add a btRigidBody to the world. Just check the demo for the code of this function.
 	body = makeRigidBody(400.0f, transform, new btCapsuleShape(btScalar(2.0), btScalar(8.482)),	mWorld);

	body->setSleepingThresholds(0.0, 0.0);
	body->setAngularFactor(0.0);
}

void Joueur::move(bool front, bool back, bool left, bool right)
{
	body->getMotionState()->getWorldTransform(xform);

	walkDirection = btVector3(0.0, 0.0, 0.0);

	if (left)
		walkDirection -= sideSpeed;
	if (right)
		walkDirection += sideSpeed;

	if (front)
		walkDirection -= frontSpeed;
	if (back)
		walkDirection += frontSpeed;


	if (!front && !back&& !left&& !right)
		body->setLinearVelocity(btVector3(0.0, 0.0, 0.0));
	else
 		body->setLinearVelocity(QmV3(walkDirection, xform.getRotation())); // QmV3 will be displayed in the next code section.

	body->getMotionState()->setWorldTransform(xform);
	body->setCenterOfMassTransform(xform);
}

void Joueur::rotation(int axisX)
{
	if (axisX != 0)
	{
		body->getMotionState()->getWorldTransform(xform);

                          // Here is a part that i can't do without Ogre.
                          // Basically, it transforms the "int" to Ogre::Degree. Then, it transforms again to Ogre::Radian(so, in radian) and it takes the value to float. Finally, it multiplies it by the %.
		angleY -= Ogre::Radian(Ogre::Degree(axeX)).valueRadians() * sensibilite / 100;
		
                          xform.setRotation(btQuaternion(btVector3(0.0, 1.0, 0.0), angleY));
		body->getMotionState()->setWorldTransform(xform);
	}
}
Here's the miraculous function to move in the correct direction: (it's a translation from Ogre to Bullet)

Code: Select all

static btVector3 QmV3(const btVector3 & v, const btQuaternion & q)
{	
	btVector3 qv(q.x(), q.y(), q.z());
	btVector3 uv = qv.cross(v);
	btVector3 uuv = qv.cross(uv);
	uv *= (2.0 * q.w());
	uuv *= 2.0;
	return v + uv + uuv;
}
Each frame you must do the following code to correctly move your character:

Code: Select all

// This part of code must be modified to correctly work for you according with your input system(i use OIS).
//"me" is a Character
me->rotation(mMouse->getMouseState().X.rel);
	
 	me->deplacement(mKeyboard->isKeyDown(OIS::KC_UP) || mKeyboard->isKeyDown(OIS::KC_W), mKeyboard->isKeyDown(OIS::KC_DOWN) || mKeyboard->isKeyDown(OIS::KC_S), mKeyboard->isKeyDown(OIS::KC_LEFT) || mKeyboard->isKeyDown(OIS::KC_A), mKeyboard->isKeyDown(OIS::KC_RIGHT) || mKeyboard->isKeyDown(OIS::KC_D));
If you need help or you see any missing part, just reply.
FailMaT_T
Posts: 10
Joined: Thu Jul 03, 2008 4:51 pm

Re: Dynamic Character Control

Post by FailMaT_T »

Hi. Your code doesn't really seem to address the fundamental issue of preventing the capsule from falling over. How effective is this character class and do you make of use of any constraints elsewhere to make this work? Also do you modify the character only in the tick callback where it's safe to change the state of the rigid body?
nord666
Posts: 4
Joined: Sat Aug 23, 2008 9:02 pm

Re: Dynamic Character Control

Post by nord666 »

Hi,
Your code doesn't really seem to address the fundamental issue of preventing the capsule from falling over.
If you mean the capsule to doesn't stay vectically, it stays.
How effective is this character class and do you make of use of any constraints elsewhere to make this work?
It's only a basic character control (for now), but it works really fine. I didn't notice any bug. And i don't use constraints (i don't know why i should use them).
lickstab
Posts: 8
Joined: Wed Jan 14, 2009 6:00 pm

Re: Dynamic Character Control

Post by lickstab »

UPDATE:
this thread http://www.bulletphysics.com/Bullet/php ... f=9&t=2956 has the solution.

------------
hey, which version of bullet were you using when you wrote this?
i made a version of it where i added jumping, and it worked fine in 2.69, but in 2.73 the capsule doesn't say upright anymore, and it goes completely crazy when i try to rotate.
any ideas?
kamikaze999
Posts: 5
Joined: Wed May 05, 2010 6:31 am

Re: Dynamic Character Control

Post by kamikaze999 »

nice work, however, i noticed that when im translating my character

walkingspeed(0.0f, 0.0f, 6.0f) for example, my character will translate, but when he goes off of the box for groundshape, he won't fall. is there a fix for this or do i need to do it a different way?
kamikaze999
Posts: 5
Joined: Wed May 05, 2010 6:31 am

Re: Dynamic Character Control

Post by kamikaze999 »

well i've changed the Y coordinate for this, to -2 or so and my character falls a bit , but it still doesn't look very well. I guess this control only works well if the player is on the ground. I guess i could throw in an if statement and say if he is only between these Y coordinates or use a bounding box.