Character Controller in Irrlicht

Petskull
Posts: 5
Joined: Wed Sep 01, 2010 4:42 pm

Character Controller in Irrlicht

Post by Petskull »

Character Controller in Irrlicht

I'm trying to make a version of the CharacterDemo using the Irrlicht graphics engine, and I'm getting a segfault when the capsule and my static plane collide. I understand I may need to react to contact myself, but a segfault?

The code is simple, it's mostly the CharacterDemo code with a little Irrlicht thrown in. Running the code in gdb gives me the following:

Code: Select all

Program received signal SIGSEGV, Segmentation fault.
0x082bc2e0 in btKinematicClosestNotMeConvexResultCallback::addSingleResult(btCollisionWorld::LocalConvexResult&, bool) ()
Which you'll notice isn't even in my code (below). I found an addSingleResult() in the docs, but can't inherit it.

Code: Select all

#include <irrlicht.h>
#include "btBulletDynamicsCommon.h"
#include "BulletCollision/CollisionDispatch/btGhostObject.h"
#include "BulletDynamics/Character/btKinematicCharacterController.h"

using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;

// Parameters for Irrlight Window/Device
SIrrlichtCreationParameters initIrrParams(){
	SIrrlichtCreationParameters cp;
	cp.DriverType = EDT_OPENGL;
	cp.WindowSize = dimension2d<s32>(640,480);
	cp.Bits = 32;
	cp.Fullscreen = false;
	cp.Vsync = false;
	cp.Stencilbuffer = false;
	cp.AntiAlias = 8;
	cp.EventReceiver = 0;
	cp.WindowId = 0;

	return cp;
}

int main(int argc,char** argv){
	// Set up Irrlicht
	IrrlichtDevice *device = createDeviceEx( initIrrParams() );
	device->setWindowCaption(L"Irrlicht+Bullet Character Movement");
	IVideoDriver* driver = device->getVideoDriver();
	ISceneManager* smgr = device->getSceneManager();
	// Set up Bullet
	btDefaultCollisionConfiguration* m_collisionConfiguration = new btDefaultCollisionConfiguration();
	btCollisionDispatcher*	m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration);
	btVector3 worldMin(-1000,-1000,-1000);
	btVector3 worldMax(1000,1000,1000);
	btAxisSweep3* sweepBP = new btAxisSweep3(worldMin,worldMax);
	btBroadphaseInterface* m_overlappingPairCache = sweepBP;
	btConstraintSolver* m_constraintSolver = new btSequentialImpulseConstraintSolver();
	btDiscreteDynamicsWorld* m_dynamicsWorld = new btDiscreteDynamicsWorld(m_dispatcher,m_overlappingPairCache,m_constraintSolver,m_collisionConfiguration);


	/// Setup Character Controlable Capsule Shape
	btTransform startTransform;
	startTransform.setIdentity ();
	startTransform.setOrigin (btVector3(0.0, 150.0, 0.0)); // Create it 150 units in the air, so we have some time before contact with the plane

	btPairCachingGhostObject* m_ghostObject = new btPairCachingGhostObject();
	m_ghostObject->setWorldTransform(startTransform);
	sweepBP->getOverlappingPairCache()->setInternalGhostPairCallback(new btGhostPairCallback());
	btScalar characterHeight=1.75;
	btScalar characterWidth =1.75;
	btConvexShape* capsule = new btCapsuleShape(characterWidth,characterHeight);
	m_ghostObject->setCollisionShape (capsule);
	m_ghostObject->setCollisionFlags (btCollisionObject::CF_CHARACTER_OBJECT);
	m_dynamicsWorld->addCollisionObject(m_ghostObject,btBroadphaseProxy::CharacterFilter, btBroadphaseProxy::StaticFilter|btBroadphaseProxy::DefaultFilter);
	
	btScalar stepHeight = btScalar(0.35);
	btKinematicCharacterController* m_character = new btKinematicCharacterController (m_ghostObject,capsule,stepHeight);
	m_dynamicsWorld->addAction(m_character);
	
	// Create a Cube to follow the Ghost/Character Capsule and a few lights and a camera so we can see the world
	ISceneNode* scene_node = smgr->addCubeSceneNode(2);
	smgr->addLightSceneNode(0, vector3df(6,8,-5), SColorf(0.58f,0.73f,0.89f,1.0f), 19.0f);
	smgr->addLightSceneNode(0, vector3df(-6,1,5), SColorf(0.58f,0.73f,0.89f,1.0f), 19.0f);
	ICameraSceneNode* my_cam = smgr->addCameraSceneNode(0, vector3df(17,80,-17), vector3df((5*2.1)/2,(5*2.1)/2,(5*2.1)/2));


	/// Create a Static Plane to walk around on
	// Segfaults- I think it's segfaulting when the objects collide in the loop
	btDefaultMotionState* bullet_MotionState = new btDefaultMotionState( btTransform(btQuaternion(0,0,0,1), btVector3(0,0,0)));
	btCollisionShape* bullet_Shape = new btStaticPlaneShape( btVector3(0,1,0), 1);			// Create Plane Shape
	btRigidBody::btRigidBodyConstructionInfo bullet_RigidBodyCI( 0, bullet_MotionState, bullet_Shape, btVector3(0,0,0) );
	btRigidBody* bullet_RigidBody = new btRigidBody( bullet_RigidBodyCI );
	m_dynamicsWorld->addRigidBody( bullet_RigidBody );
	// Creating the Terrain in Irrlicht
	float scale_val = 1;
	float hm_size = 512;
	float offset = ((hm_size*scale_val)/2)*-1;
	ITerrainSceneNode *node = smgr->addTerrainSceneNode("tileable_hm.png", 0, -1, vector3df( offset, 0, offset ) , vector3df(0.f, 0.f, 0.f), vector3df(scale_val, 0.0, scale_val) );
	node->setMaterialFlag(EMF_LIGHTING, true);
	node->setMaterialFlag(EMF_WIREFRAME, !node->getMaterial(0).Wireframe);
	node->setMaterialTexture( 0, driver->getTexture("tileable_hm.png") );


	// These controls will eventually be activated by keyboard or mouse
	bool goLeft = false;
	bool goRight = false;
	bool goForward = false;
	bool goBackward = false;
	
	/// The Game Loop
	ITimer* const timer = device->getTimer();
	u32 then = timer->getTime();
	while(device->run()){
		const u32 now = timer->getTime();
		const btScalar dt = (btScalar)(now - then)*0.001; // Time in seconds
		then = now;

		// Set walkDirection and Speed for our character
		btTransform xform;
		xform = m_ghostObject->getWorldTransform ();

		btVector3 forwardDir = xform.getBasis()[2];
		//	printf("forwardDir=%f,%f,%f\n",forwardDir[0],forwardDir[1],forwardDir[2]);
		btVector3 upDir = xform.getBasis()[1];
		btVector3 strafeDir = xform.getBasis()[0];
		forwardDir.normalize ();
		upDir.normalize ();
		strafeDir.normalize ();

		btVector3 walkDirection = btVector3(0.0, 0.0, 0.0);
		btScalar walkVelocity = btScalar(1.1) * 4.0; // 4 km/h -> 1.1 m/s
		btScalar walkSpeed = walkVelocity * dt;

		//rotate view
		if (goLeft){
			btMatrix3x3 orn = m_ghostObject->getWorldTransform().getBasis();
			orn *= btMatrix3x3(btQuaternion(btVector3(0,1,0),0.01));
			m_ghostObject->getWorldTransform ().setBasis(orn);
		}

		if (goRight){
			btMatrix3x3 orn = m_ghostObject->getWorldTransform().getBasis();
			orn *= btMatrix3x3(btQuaternion(btVector3(0,1,0),-0.01));
			m_ghostObject->getWorldTransform ().setBasis(orn);
		}

		if (goForward){ walkDirection += forwardDir; }
		if (goBackward){ walkDirection -= forwardDir; }

		m_character->setWalkDirection(walkDirection*walkSpeed);

		// Set my cube's position and rotation to match m_ghostObject's
		btTransform my_trans;
		my_trans = m_ghostObject->getWorldTransform();
		matrix4 matr;
		my_trans.getOpenGLMatrix(matr.pointer());
		scene_node->setRotation(matr.getRotationDegrees());
		scene_node->setPosition(matr.getTranslation());
		my_cam->setTarget( scene_node->getPosition() );	// Follow with the camera
		
		// Step the simulation and draw everything
		m_dynamicsWorld->stepSimulation(dt,10.0f);

		driver->beginScene(true, true, SColor(255,28,28,30));
		smgr->drawAll();
		driver->endScene();

	}

	return 0;
}
Why is it segfaulting? Any suggestions?