-
Notifications
You must be signed in to change notification settings - Fork 1
Using NGF With Bullet
Note: If the tutorial doesn’t work out for you, chances are there’s an error with the tutorial itself. Ask in the forums.
This is tutorial helps get NGF and Bullet working together from scratch. If you already have them set up but just want to get the ‘collide’ event working, then skip to the good bits toward the end. It assumes some basic familiarity with NGF and Bullet concepts, how to set up an NGF project, how to include the relevant NGF and Bullet headers and link with the relevant Bullet libraries. This tutorial is a great way of learning how to set up Bullet. We will also be using BtOgre for the Bullet-Ogre binding.
First, set up your application to use NGF, Bullet and BtOgre, as described in the respective documentation. We will be using ‘ngftutorial/ngftutorialfinal’ as a staring point. If you’ve already done the NGF tutorial and have come out with your own final version, you can use that too. Remember to copy everything into a new directory. You don’t want to mess up your great previous work!
We have to remove the existing MOC stuff from the code. Remove the pointer from the ‘Globals’ namespace in ‘Globals.h’, and also get rid of the ‘QueryFlags’ enum. Remove the ‘new MOC::CollisionTools’ and ‘delete Globals::col’ from NGFExampleApplication. Lastly, remove the collision detection code from ‘Player’.
A great way to get around this is to delete ‘#include “CollsionTools.h”’ in main.cpp, and try compiling, and letting the compiler find all MOC stuff for you through error messages. ;-)
In ‘Globals.h’, add ‘btDynamicsWorld *phyWorld;’ to the ‘Globals’ namespace to be able to get the pointer from anywhere (we’re really lazy, aren’t we?):-
namespace Globals
{
OIS::Keyboard *keyboard;
RenderWindow *window;
SceneManager *smgr;
NGF::GameObjectManager *gom;
NGF::WorldManager *wom;
NGF::Loading::Loader *load;
btDynamicsWorld *phyWorld;
}Add some code in the class ‘NGFExampleApplication’ for Bullet initialisation and Bullet cleanup. Here’s what the relavant parts of ‘NGFExampleApplication’ might look like after these changes:-
protected:
NGFExampleFrameListener *mFrameListener;
btAxisSweep3 *mBroadphase;
btDefaultCollisionConfiguration *mCollisionConfig;
btCollisionDispatcher *mDispatcher;
btSequentialImpulseConstraintSolver *mSolver;
public:
NGFExampleApplication()
{
//Bullet initialisation.
mBroadphase = new btAxisSweep3(btVector3(-10000,-10000,-10000), btVector3(10000,10000,10000), 1024);
mCollisionConfig = new btDefaultCollisionConfiguration();
mDispatcher = new btCollisionDispatcher(mCollisionConfig);
mSolver = new btSequentialImpulseConstraintSolver();
Globals::phyWorld = new btDiscreteDynamicsWorld(mDispatcher, mBroadphase, mSolver, mCollisionConfig);
Globals::phyWorld→setGravity(btVector3(0,-9.8,0));
}
~NGFExampleApplication()
{
delete mFrameListener;
//Free Bullet stuff.
delete Globals::phyWorld;
delete mSolver;
delete mDispatcher;
delete mCollisionConfig;
delete mBroadphase;
}
Then, add this to ‘NGFExampleFrameListener::frameStarted()’:-
Globals::phyWorld->stepSimulation(evt.timeSinceLastFrame, 10);Build, run. If you’re lucky, it’ll work. If not, ask in the forums. ;-)
Add these two protected variables to Player, to hold the Bullet stuff:-
btRigidBody *mBody;
btCollisionShape *mShape;
After the ‘Create Ogre Stuff’ part in the constructor of ‘Player’, put some usual BtOgre creation code:-
//Create shape.
BtOgre::StaticMeshToShapeConverter converter(mEntity);
mShape = converter.createSphere();
//Calculate inertia.
btScalar mass = 5;
btVector3 inertia;
mShape->calculateLocalInertia(mass, inertia);
//Create BtOgre MotionState (connects Ogre and Bullet).
BtOgre::RigidBodyState *State = new BtOgre::RigidBodyState(mNode);
//Create the Body.
mBody = new btRigidBody(mass, State, mShape, inertia);
Globals::phyWorld->addRigidBody(mBody);
And the destruction code in the destructor, before ‘Destroy Ogre Stuff’:-
//Destory physics stuff.
delete mShape;
delete mBody->getMotionState();
delete mBody;
Globals::phyWorld->removeRigidBody(mBody);Build and run again, and you should see the Player fall.
Now, Bullet-ise the LevelGeometry in the same way, except, instead of ‘createSphere()’, use ‘createTrimesh()’, and you should see the Player actually hit the ground and bounce around.
Add ‘#include <ngfplugins/NgfBullet.h>’ at the top of main.cpp, and add ‘<ngfdir>/plugins/ngfbullet/NgfBullet.cpp’ to your list of files to compile and link using whatever method your build system provides you with. This will add the Ngf-Bullet connection code to your project.
Now, we have to give this functionality to the Player. This is done by deriving from ‘NGF::Bullet::BulletGameObject’, which derives virtually from NGF::GameObject. So, you make Player derive from this but call the NGF::GameObject constructor the normal way. Just change the first line of the Player definition to this:-
class Player : public NGF::Bullet::BulletGameObject
{Now, we have to connect our Player object to the Bullet body. This is as simple as doing this in the constructor, after the Body is created:-
//Registarr!
NGF::Bullet::BulletGameObject::setBulletObject(mBody);And lastly, we can override the ‘collide’ function to get something done:-
void collide(GameObject *other, btCollisionObject *otherPhysicsObject, btManifoldPoint &contact)
{
LogManager::getSingleton().logMessage("We collided!");
}
Yes, it’s that simple. You have to register the LevelGeometry too though (not really needed in this situation, but anyway). Now build and run, and you should see the text ‘We collided!’ being logged whenever Player touches anything else. The parameters to ‘collide’ give you some more information about what exactly happened. So, you can do things like ‘if (other→hasFlag(“Monster”)) mHealth -= 20;’ etc. (the ‘other’ GameObject is identified only if it too connects itself to it’s Bullet Body the same way).
Hope you had fun! ;-)