Bullet physics: player collision

Tags

, , , , , , , , , , , , ,

In my last post Bullet physics: user pointer I was able detect the collision of two balls in my virtual world.

But how can I detect whether one of the balls collides with me (or, more precisely, the virtual me)?

Time to crank open the C++ Microsoft Visual Studio application (with OpenGL graphics library and the Oculus SDK for Windows) and fix up the Bullet Real-Time Physics Simulation code.

First, let’s create a physics box shape to represent the virtual me:

playerShape = new btBoxShape(btVector3(1, 1, 1));

btDefaultMotionState * playerMotionState = new btDefaultMotionState(btTransform(btQuaternion(0, 0, 0, 1), btVector3(0, 0, 0)));

btRigidBody::btRigidBodyConstructionInfo playerRigidBodyCI(1, playerMotionState, playerShape, btVector3(0, 0, 0));
playerRigidBody = new btRigidBody(playerRigidBodyCI);

playerRigidBody->setCollisionFlags(playerRigidBody->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT);
playerRigidBody->setActivationState(DISABLE_DEACTIVATION);

dynamicsWorld->addRigidBody(playerRigidBody);

The box shape is added to a rigid body, which in turn is added to the dynamics world.

Notice how we are adding a kinematic flag to our rigid body (and setting DISABLE_DEACTIVATION). As the box is representing a player (i.e. me wearing the Oculus Rift virtual reality headset) it needs to be able to move around in the physics world of its own accord.

Indeed, on each render cycle – when we call the physics step simulation – we set the position of our player rigid body:

void SetPosRigidBody(Vector3f pos, btRigidBody * rigidBody) {
	btTransform transform;
	transform.setIdentity();

	transform.setOrigin(btVector3(
		btScalar(pos.x),
		btScalar(pos.y),
		btScalar(pos.z)));

	rigidBody->getMotionState()->setWorldTransform(transform);
}

Great. The rigid body position is now kept in sync with my coordinates in the virtual world. So as I strut about with my headset on, the physics box is wrapped around me at all times.

All that remains is to detect when I collide with a ball:

if ((obA_Model == NULL && obB_Model->MyModelName == Zoodo_Floor1_Ball_2) ||
	(obB_Model == NULL && obA_Model->MyModelName == Zoodo_Floor1_Ball_2)) {
	IsPlayerCollision = true;
	return;
}

Easy. If one of the colliding objects does not have an associated model, it must be the player (as we don’t render ourselves to the virtual world – well, we render our hands, but that’s another matter). And if the other colliding object is the ball sliding down the ramp, we have detected collision between ball and player.

For now, on collision I simply put the player (that’s me, folks) back into the room from whence I came. Perhaps in time I will splat myself under the ball, render copious amounts of blood, and end the game abruptly under the tones of horrific violins.

Here’s the video of player collision with ball:

Ciao!

P.S.

But what happens if the player collides with the ball, once the ball has come to a standstill?

Let’s get the speed of the ball, and if the ball is barely moving or stationary then we will avoid any unpleasant death to the player:

btScalar speed;
if (obA_Model == NULL) {
	speed = ((btRigidBody *)obB)->getLinearVelocity().length();
} else {
	speed = ((btRigidBody *)obA)->getLinearVelocity().length();
}

if (speed <= 0.2) {
	continue;
}

We’ll also drop the mass of the player, so as not to shunt the ball on collision:

btRigidBody::btRigidBodyConstructionInfo playerRigidBodyCI(0.01, playerMotionState, playerShape, btVector3(0, 0, 0));

I’ve set the player’s mass to 0.01. After all, the ball is huge and unlikely to be moved by the player, unless the player is Hercules. Which the player is not. As the player is me.

Advertisements