Per-Collision Friction

Post Reply
User avatar
nikki
Posts: 22
Joined: Sat Jun 14, 2008 3:38 pm
Location: Doha, Qatar.
Contact:

Per-Collision Friction

Post by nikki »

Is there a way to set a friction per-collision within the collisionAddedCallback by modifying the properties of btManifoldPoint? I just wanted to ask this, because I was coming from ODE, and in ODE, you could change a lot of the properties of the collison through the contact point itself (such as restitution, friction etc.).

Also, is it possible to just check for a collision, but not let it happen 'physically' per-collision through the callback (like, the objects can pass through each other, the physics engine should not stop them, but I also need to check for collision, like for a one-way portal, collision on one side, no collision on other side)?

Thanks for your help! :)

------

EDIT: After a little more investigation, I found the 'm_combinedFriction' public variable in btManifoldPoint. I should modify this in the appropriate callback? Should I also modify the directional lateral frictions?

------

EDIT 2: Perhaps I should explain how I have my callbacks setup.

I had written a little game framework that helps manage GameObjects. Each type of GameObject derives from 'GameObject', and implements the given methods (create event, destroy event, tick (step) event etc.). This way, the logic for the Player, Enemy, Pickup, etc. can be seperated into their own GameObjects. A GameObject need not know any details about the implementation of another. This makes it very modular, and easy to modify. GameObjects can create the appropriate graphics and sounds etc., whenever needed.

Optionally, this framework can also connect with Bullet. The only thing that the framework needs to do is inform GameObjects when they collide with other GameObjects. However, all GameObjects don't need this feature (for example, a GameObject managing sound or HUD).

For this, the framework needs to know which collision objects (maybe there's no physics, only collision) are associated with which GameObjects. This is done through the userObject (I use the OgreBullet userObject here, not the Bullet one).

The framework calls a 'collide' event on the GameObject at the appropriate time, passing on the 'other' GameObject collided with, and also the Bullet object.

The GameObjectManager (a singleton) manages the GameObjects (creates, destroys, calls events). The Bullet-related code is here (I use OgreBullet, but its not a very complete wrapper, so I have to directly talk to Bullet many times):-

Code: Select all

//This is to tell the framework about the connection. The GameObject calls this after making its physics stuff.
void registerForCollision(GameObject *object, OgreBulletCollisions::Object *physic)
{
	physic->setUserObject(object);

	btCollisionObject *bullObj = physic->getBulletObject();
	bullObj->setCollisionFlags(bullObj->getCollisionFlags() | btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK);
}

//The callback just tells the singleton instance.
static bool GameObjectManager::_contactAddedCallback(btManifoldPoint& cp,const btCollisionObject* colObj0,int partId0,int index0,const btCollisionObject* colObj1,int partId1,int index1)
{
	return GameObjectManager::getSingletonPtr()->_contactAdded(cp, colObj0, partId0, index0, colObj1, partId1, index1);
}

//This retrieves the GameObjects, and informs them.
bool GameObjectManager::_contactAdded(btManifoldPoint& cp, const btCollisionObject* colObj0, int partId0, int index0, const btCollisionObject* colObj1, int partId1, int index1)
{
	//Get the OgreBullet objects.
	btCollisionObject *bull1 = const_cast<btCollisionObject *>(colObj0);
	btCollisionObject *bull2 = const_cast<btCollisionObject *>(colObj1);
	OgreBulletCollisions::Object *phy1 = mPhysicsWorld->findObject(bull1); //I use the Ogre-Bullet wrapper.
	OgreBulletCollisions::Object *phy2 = mPhysicsWorld->findObject(bull2); //I hope this part can be understood.

	if(!(phy1 && phy2))
		return true;

	//Get the NGF GameObjects, and call the relevant methods.
	GameObject *obj1 = getObjectFromPhysicsObject(phy1); //The code for this isn't shown here.
	GameObject *obj2 = getObjectFromPhysicsObject(phy2); //But I know it works.

	if (obj1 && obj2)
	{
		obj1->collide(obj2, phy2, cp);
		obj2->collide(obj1, phy1, cp);
	}
	else if (obj1)
	{
		obj1->collide(0, phy2, cp);
	}
	else if (obj2)
	{
		obj2->collide(0, phy1, cp);
	}

	return true;
}

//......
//......

//The GameObject::collide function. Overriden by children if needed.
virtual void collide(GameObject *other, OgreBulletCollisions::Object *otherPhysicsObject, btManifoldPoint &contact)
{
}
This way, I can just do this (this works):-

Code: Select all

void Player::collide(GameObject *other, OgreBulletCollisions::Object *otherPhysicsObject, btManifoldPoint &contact)
{
	if (other->hasFlag("Enemy"))
	{
		loseHealth(20);
	}
}
So, my question is, how can I do the following?:-

Code: Select all

void Player::collide(GameObject *other, OgreBulletCollisions::Object *otherPhysicsObject, btManifoldPoint &contact)
{
	if (other->hasFlag("Ice"))
	{
		//..<friction 0 here>..
	}
	if (other->hasFlag("Powerup"))
	{
		mPower += 10;
		//..<don't let collision physics engine handle this>..
	}
}
I'm assuming I can do the 'friction 0' thing through 'contact.m_combinedFriction', 'contact.m_lateralFrictionDir1' and 'contact.m_lateralFrictionDir2'.

But how can I let the collision not physically happen? I need to do this directly in the collide event, not through masks.

Once again, thanks for your help, and for this great physics engine! :)
Post Reply