www.pudn.com > RCApp-src.zip > Engine.cpp


/* 
	RedEye Project (http://members.ozemail.com.au/~ndmcevoy/) 
	Copyright (C) 2003  Nick McEvoy 
 
	This library is free software; you can redistribute it and/or 
	modify it under the terms of the GNU Library General Public 
	License as published by the Free Software Foundation; either 
	version 2 of the License, or (at your option) any later version. 
 
	This library is distributed in the hope that it will be useful, 
	but WITHOUT ANY WARRANTY; without even the implied warranty of 
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
	Library General Public License for more details. 
 
	You should have received a copy of the GNU Library General Public 
	License along with this library; if not, write to the Free 
	Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
 
	----------------------------------------------------------------- 
 
		Commented for use with Doxygen (http://www.doxygen.org) 
 
	----------------------------------------------------------------- 
*/ 
 
/*! \file Engine.cpp 
 *	\brief Game engine. 
 * 
 *		This file contains the game engine. 
 */ 
 
// GLUT includes 
#include  
 
// PLIB include 
#include  
 
// ODE includes 
#include "ode/common.h" 
#include "ode/contact.h" 
#include "ode/objects.h" 
#include "ode/geom.h" 
 
// RedEye includes 
#include "Engine.h" 
#include "ModelManager.h" 
#include "PlayerManager.h" 
#include "EntityManager.h" 
#include "EnvironmentManager.h" 
#include "MaterialManager.h" 
#include "SoundManager.h" 
#include "FPSCounter.h" 
#include "Status.h" 
#include "GUI.h" 
#include "Collision.h" 
 
//! The one and only instance 
reGameEngine* reGameEngine::mpInstance = NULL; 
 
//! Called by dSpaceCollide when two objects in space are potentially colliding 
static void 
reODENearCallback(void* pData, dGeomID o1, dGeomID o2) 
{ 
	((reGameEngine*)pData)->CollisionEventHandler(o1, o2); 
} 
 
 
 
 
reGameEngine::reGameEngine() 
{ 
	reGetSoundManager(); 
	reGetMaterialManager(); 
	reGetModelManager(); 
	reGetPlayerManager(); 
	reGetEntityManager(); 
	reGetEnvironmentManager(); 
	reGetFPSCounter(); 
	reGetGameGUI(); 
 
	msLevelFile[0] = 0; 
 
	meGameMode = eGameInit; 
 
	mbTextureOn = true; 
	mbWireFrameOn = false; 
	//meShadingMode = GL_SMOOTH; 
	mbGravityOn = false; 
	mfGravityValue = 1.0f; 
 
	mODEWorldId = NULL; 
	mODESpaceId = NULL; 
	mODEJointGroupId = NULL; 
 
	miLastUpdateTimeMs = 0; 
} 
 
 
 
 
reGameEngine::~reGameEngine() 
{ 
	delete reGetGameGUI(); 
	delete reGetFPSCounter(); 
	delete reGetPlayerManager(); 
	delete reGetEntityManager(); 
	delete reGetEnvironmentManager(); 
	delete reGetModelManager(); 
	delete reGetMaterialManager(); 
	delete reGetSoundManager(); 
 
	if (mODEJointGroupId) 
	{ 
		dJointGroupDestroy(mODEJointGroupId); 
		mODEJointGroupId = NULL; 
	} 
 
	if (mODESpaceId) 
	{ 
		dSpaceDestroy(mODESpaceId); 
		mODESpaceId = NULL; 
	} 
 
	if (mODEWorldId) 
	{ 
		dWorldDestroy(mODEWorldId); 
		mODEWorldId = NULL; 
	} 
 
	mpInstance = NULL; 
} 
 
 
 
 
reGameEngine* 
reGameEngine::GetInstance() 
{ 
	if (mpInstance == NULL) 
	{ 
		mpInstance = new reGameEngine; 
	} 
	return mpInstance; 
} 
 
 
 
 
void 
reGameEngine::Init() 
{ 
	// Open config file 
	if (mXMLConfig.LoadFile("data/config.xml")) 
	{ 
		// Get data 
		TiXmlNode* pNode = mXMLConfig.FirstChild("Config"); 
		SetFullscreen(reGetXMLChildValue(pNode, "Fullscreen", false)); 
		reGetSoundManager()->SetMusicOn(reGetXMLChildValue(pNode, "MusicOn", false)); 
		reGetSoundManager()->SetSoundFxOn(reGetXMLChildValue(pNode, "SoundFxOn", false)); 
	} 
	else // warning 
	{ 
		ulSetError(UL_FATAL,  
			 "Init() Could not open %s.", "data/config.xml"); 
		exit(0); 
	} 
 
	// Show load level dialog box 
	reGetGameGUI()->ShowLoadLevel(); 
} 
 
 
 
const static double WORLD_STEP_TIME_SEC = 0.05; 
static float fTimeToMakeUpSec = 0; 
void 
reGameEngine::Update() 
{ 
	int iCurrentTimeMs = glutGet(GLUT_ELAPSED_TIME); 
	int iDeltaTimeMS = iCurrentTimeMs - miLastUpdateTimeMs; 
	miLastUpdateTimeMs = iCurrentTimeMs; 
 
	// Update sound 
	reGetSoundManager()->Update(); 
 
	if (meGameMode != eGameRunning) 
		return; 
 
	// Make sure time step is not too large 
	if (iDeltaTimeMS > 500) 
		iDeltaTimeMS = 500; 
 
	fTimeToMakeUpSec += iDeltaTimeMS/1000.0f; 
 
	int iNumSteps = (int) (fTimeToMakeUpSec / WORLD_STEP_TIME_SEC); 
	//printf("fTimeToMakeUpSec %.2f iNumSteps %d\n", fTimeToMakeUpSec, iNumSteps); 
 
	for (int i = 0; i < iNumSteps; ++i) 
	{ 
		// Update player, entities, environment & camera 
		reGetPlayerManager()->Update(WORLD_STEP_TIME_SEC); 
		reGetEntityManager()->Update(WORLD_STEP_TIME_SEC); 
		reGetEnvironmentManager()->Update(WORLD_STEP_TIME_SEC); 
		mCamera.Update(WORLD_STEP_TIME_SEC); 
 
		// Check collision of ODE body against PLIB world 
		reGetPlayerManager()->SpaceCollide(); 
		reGetEntityManager()->SpaceCollide(); 
 
		// Check collisions, step and remove contacts in the ODE physics engine 
		dSpaceCollide(mODESpaceId, this, &reODENearCallback); 
		dWorldStep(mODEWorldId, WORLD_STEP_TIME_SEC); 
		dJointGroupEmpty(mODEJointGroupId); 
	} 
 
	fTimeToMakeUpSec -= WORLD_STEP_TIME_SEC * iNumSteps; 
	 
	/* 
	// 
	// OLD CODE ... todo: remove 
	// 
	// Make sure time step is not too small or large 
	if (iDeltaTimeMS < 10) 
		iDeltaTimeMS = 10; 
	else if (iDeltaTimeMS > 50) 
		iDeltaTimeMS = 50; 
	//else if (iDeltaTimeMS > 200) 
	//	iDeltaTimeMS = 200; 
 
	// Update player, entities, environment & camera 
	float fDeltaSec = iDeltaTimeMS/1000.0f; 
	reGetPlayerManager()->Update(fDeltaSec); 
	reGetEntityManager()->Update(fDeltaSec); 
	reGetEnvironmentManager()->Update(fDeltaSec); 
	mCamera.Update(fDeltaSec); 
 
	for (int i = 0; i <= 1; i++)//call world step a few times !??? 
	{ 
		// Check collision of ODE body against PLIB world 
		reGetPlayerManager()->SpaceCollide(); 
		reGetEntityManager()->SpaceCollide(); 
 
		// Check collisions, step and remove contacts in the ODE physics engine 
		dSpaceCollide(mODESpaceId, this, &reODENearCallback); 
		dReal StepSize = iDeltaTimeMS/1000.0f; 
		printf("StepSize %.2f\n", StepSize); 
		dWorldStep(mODEWorldId, StepSize); 
		dJointGroupEmpty(mODEJointGroupId); 
	}*/ 
} 
 
 
 
 
void 
reGameEngine::Display() 
{ 
	// Clear the screen 
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
 
	// Calculate FPS 
	reGetFPSCounter()->Display(); 
 
	//! Position camera 
	mCamera.Display(); 
 
	// Draw world 
	//glEnable(GL_FOG); 
	reGetEnvironmentManager()->PreDraw(); 
	ssgCullAndDraw(&mWorld); 
	reGetEnvironmentManager()->PostDraw(); 
	//glDisable(GL_FOG); 
 
	// Debug text 
	char sDebugText[RE_GUI_STRING_MAX]; 
	sprintf(sDebugText, 
		"fps: %.0f\n" 
		"gravity: %s\n", 
		reGetFPSCounter()->GetFPS(), 
		mbGravityOn ? "on" : "off"); 
	reGetGameGUI()->SetText(reGameGUI::eDebugText, sDebugText, true); 
 
	// Display GUI 
	reGetGameGUI()->Display(); 
 
	// Display 
	glutPostRedisplay(); 
	glutSwapBuffers(); 
} 
 
 
 
 
void 
reGameEngine::Reshape(int w, int h) 
{ 
	// Reshape GUI 
	reGetGameGUI()->Reshape(w, h); 
 
	// Set viewport 
	glViewport(0, 0, w, h); 
} 
 
 
 
 
void 
reGameEngine::LoadLevel(const char* sLevelDir) 
{ 
	if (meGameMode == eGameInit || 
		meGameMode == eGameStopped) 
	{ 
		if (strcmp(msLevelFile, sLevelDir) != 0) 
		{ 
			// Destroy models 
			if (meGameMode != eGameInit) 
				ChangeGameMode(eGameInit); 
			strcpy(msLevelFile, sLevelDir); 
		} 
		ChangeGameMode(eGameLoading); 
	} 
} 
 
 
 
 
void 
reGameEngine::SetGamePaused(bool bPaused) 
{ 
	if (bPaused && meGameMode == eGameRunning) 
		ChangeGameMode(eGamePaused); 
	else if (!bPaused && meGameMode == eGamePaused) 
		ChangeGameMode(eGameRunning); 
} 
 
 
 
 
bool 
reGameEngine::ChangeGameMode(eGameMode eMode) 
{ 
	reGetGameGUI()->SetTextOff(); 
 
	switch (eMode) 
	{ 
		case eGameInit: 
 
			meGameMode = eMode; 
 
			// Destroy everything 
			reGetPlayerManager()->DestroyLevel(); 
			reGetEntityManager()->DestroyLevel(); 
			reGetEnvironmentManager()->DestroyLevel(); 
			reGetModelManager()->DestroyDatabase(); 
			reGetMaterialManager()->DestroyDatabase(); 
			reGetSoundManager()->DestroyDatabase(); 
 
			if (mODEJointGroupId) 
			{ 
				dJointGroupDestroy(mODEJointGroupId); 
				mODEJointGroupId = NULL; 
			} 
			if (mODESpaceId) 
			{ 
				dSpaceDestroy(mODESpaceId); 
				mODESpaceId = NULL; 
			} 
 
			if (mODEWorldId) 
			{ 
				dWorldDestroy(mODEWorldId); 
				mODEWorldId = NULL; 
			} 
			mbGravityOn = false; 
 
			reGetGameGUI()->ShowLoadLevel(); 
 
			break; 
 
		case eGameStopped: 
 
			meGameMode = eMode; 
 
			// Stop the music 
			reGetSoundManager()->SetMusicOn(false); 
 
			// Destroy everything (except models) 
			reGetPlayerManager()->DestroyLevel(); 
			reGetEntityManager()->DestroyLevel(); 
			reGetEnvironmentManager()->DestroyLevel(); 
			if (mODEJointGroupId) 
			{ 
				dJointGroupDestroy(mODEJointGroupId); 
				mODEJointGroupId = NULL; 
			} 
			if (mODESpaceId) 
			{ 
				dSpaceDestroy(mODESpaceId); 
				mODESpaceId = NULL; 
			} 
 
			if (mODEWorldId) 
			{ 
				dWorldDestroy(mODEWorldId); 
				mODEWorldId = NULL; 
			} 
			mbGravityOn = false; 
 
			break; 
 
		case eGameLoading: 
 
			if (meGameMode == eGameInit || 
				meGameMode == eGameStopped) 
			{ 
				if (!mXMLLevel.LoadFile(GetLevelFile())) 
					return false; 
 
				// Get level setup 
				TiXmlNode* pNode = GetXMLLevelNode(); 
				pNode = pNode->FirstChild("Setup"); 
				const char* psMusicTrack = reGetXMLChildValue(pNode, "MusicTrack", ""); 
				mbGravityOn = reGetXMLChildValue(pNode, "GravityOn", false); 
				mfGravityValue = reGetXMLChildValue(pNode, "GravityValue", 0); 
 
				// Set mode 
				bool bLoadDB = false; 
				if (meGameMode == eGameInit) 
					bLoadDB = true; 
 
				meGameMode = eMode; 
				reGetGameGUI()->SetText(reGameGUI::eNotifyText, RE_LOADING_TEXT, true); 
 
				// Create the ODE physics engine 
				mODEWorldId = dWorldCreate(); 
				mODESpaceId = dSimpleSpaceCreate(); 
				mODEJointGroupId = dJointGroupCreate(1000000); 
 
				// Create database 
				if (bLoadDB) 
				{ 
					reGetSoundManager()->CreateDatabase(); 
					reGetSoundManager()->ChangeTrack(psMusicTrack); 
					/* Frantic attempt to keep sound going during level switch. 
					   Set the safety margin up to two seconds and update as 
					   often as possible. */ 
					reGetSoundManager()->SetSafetyMargin(2.0f); 
					reGetSoundManager()->Update(); 
 
					reGetMaterialManager()->CreateDatabase(); 
					reGetModelManager()->CreateDatabase(); 
				} 
 
				// Create level 
				reGetEnvironmentManager()->CreateLevel(); 
				reGetEntityManager()->CreateLevel(); 
				reGetPlayerManager()->CreateLevel(); 
 
				// Set back to default 
				reGetSoundManager()->SetSafetyMargin(); 
				reGetSoundManager()->Update(); 
 
				ChangeGameMode(eGameRunning); 
 
				// Turn gravity on/off 
				if (mbGravityOn) 
					dWorldSetGravity(mODEWorldId, 0, 0, mfGravityValue); 
				else 
					dWorldSetGravity(mODEWorldId, 0, 0, 0); 
			} 
			break; 
 
		case eGameRunning: 
 
			if (meGameMode == eGamePaused || 
				meGameMode == eGameLoading) 
			{ 
				meGameMode = eMode; 
			} 
			break; 
 
		case eGamePaused: 
 
			if (meGameMode == eGameRunning) 
			{ 
				meGameMode = eMode; 
				reGetGameGUI()->SetText(reGameGUI::eNotifyText, RE_PAUSE_TEXT, true); 
			} 
			break; 
 
		default: 
			break; 
	}; 
 
	return true; 
} 
 
 
 
 
void 
reGameEngine::SetFullscreen(bool bFull) 
{ 
	if (bFull) 
		glutFullScreen(); 
	// todo: else unset ??? 
} 
 
 
 
 
void 
reGameEngine::Keyboard(unsigned char key, int x, int y, bool bKeyDown) 
{ 
	// Notify GUI 
	reGetGameGUI()->Keyboard(key, x, y, bKeyDown); 
 
	// Is the game paused ? 
	if (bKeyDown && meGameMode == eGamePaused) 
	{ 
		ChangeGameMode(eGameRunning); 
		return; 
	} 
 
	switch (key) 
	{ 
	case 'r':	// Restart game 
	case 'R': 
		if (bKeyDown) 
		{ 
			ChangeGameMode(eGameStopped); 
			ChangeGameMode(eGameLoading); 
		} 
		break; 
 
	case 'p':	// Pause game 
	case 'P': 
		if (bKeyDown) 
		{ 
			if (meGameMode == eGameRunning) 
				ChangeGameMode(eGamePaused); 
			else if (meGameMode == eGamePaused) 
				ChangeGameMode(eGameRunning); 
		} 
		break; 
 
#if _DEBUG // just here for quick exit :) 
	case 'q':	// Quit game 
	case 'Q': 
		exit(0); 
#endif 
 
	case 27:	// ESC key 
		if (bKeyDown) 
		{ 
			if (meGameMode == eGameRunning || 
				meGameMode == eGamePaused) 
			{ 
				ChangeGameMode(eGameStopped); 
				reGetGameGUI()->ShowLoadLevel(); 
			} 
		} 
		break; 
 
	case 'h':	// Display help 
	case 'H': 
		if (bKeyDown) 
			reGetGameGUI()->ShowHelp(); 
		break; 
 
	case 'f': // Set fullscreen (todo: toggle?) 
	case 'F': 
		SetFullscreen(true); 
		break; 
 
	/*case 's':	// Toggle shading model 
	  case 'S': 
		{ 
			if (bKeyDown) 
			{ 
				meShadingMode = (meShadingMode == GL_SMOOTH ? GL_FLAT : GL_SMOOTH); 
				glShadeModel(meShadingMode); 
			} 
		} 
		break;*/ 
 
	case 'w':	// Toggle wireframe mode 
	case 'W': 
		{ 
			if (bKeyDown && 
				meGameMode == eGameRunning) 
			{ 
				mbWireFrameOn = !mbWireFrameOn; 
 
				if (mbWireFrameOn) 
					glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); 
				else 
					glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); 
			} 
		} 
		break; 
 
	case 'g':	// Toggle gravity 
	case 'G': 
		{ 
			if (bKeyDown && 
				meGameMode == eGameRunning) 
			{ 
				mbGravityOn = !mbGravityOn; 
 
				if (mbGravityOn) 
					dWorldSetGravity(mODEWorldId, 0, 0, mfGravityValue); 
				else 
					dWorldSetGravity(mODEWorldId, 0, 0, 0); 
			} 
		} 
		break; 
 
	default: 
		break; 
	} 
 
	// Notify player 
	reGetPlayerManager()->Keyboard(key, x, y, bKeyDown); 
} 
 
 
 
 
void 
reGameEngine::KeyboardSpecial(int key, int x, int y, bool bKeyDown) 
{ 
	// Notify GUI 
	reGetGameGUI()->KeyboardSpecial(key, x, y, bKeyDown); 
 
	// Is the game paused ? 
	if (bKeyDown && meGameMode == eGamePaused) 
	{ 
		ChangeGameMode(eGameRunning); 
		return; 
	} 
 
	switch (key) 
	{ 
	case GLUT_KEY_F1:	// First person view 
 
		if (bKeyDown) 
			mCamera.SetCameraMode(reGameCamera::eFirstPersonView); 
		break; 
 
	case GLUT_KEY_F2:	// External attached view 
 
		if (bKeyDown) 
			mCamera.SetCameraMode(reGameCamera::eExternalAttachedView); 
		break; 
 
	case GLUT_KEY_F3:	// External detached view 
 
		if (bKeyDown) 
			mCamera.SetCameraMode(reGameCamera::eExternalDetachedView); 
		break; 
 
	case GLUT_KEY_F4:	// External tracking view 
 
		if (bKeyDown) 
			mCamera.SetCameraMode(reGameCamera::eExternalTrackingView); 
		break; 
 
	case GLUT_KEY_F5: 
		break; 
 
	case GLUT_KEY_F6: 
		break; 
 
	case GLUT_KEY_F7: 
		break; 
 
	case GLUT_KEY_F8: 
		break; 
 
	case GLUT_KEY_F9: 
		break; 
 
	case GLUT_KEY_F10: 
		break; 
 
	case GLUT_KEY_F11: 
		break; 
 
	case GLUT_KEY_F12: 
		break; 
 
	case GLUT_KEY_LEFT: // Player (or external view) roll left 
 
		if (glutGetModifiers() & GLUT_ACTIVE_SHIFT) 
			mCamera.SetViewLeft(bKeyDown); 
		else 
			mCamera.SetViewLeft(false); 
		break; 
 
	case GLUT_KEY_UP: // Player (or external view) pitch up 
 
		if (glutGetModifiers() & GLUT_ACTIVE_SHIFT) 
			mCamera.SetViewUp(bKeyDown); 
		else 
			mCamera.SetViewUp(false); 
		break; 
 
	case GLUT_KEY_RIGHT: // Player (or external view) roll right 
 
		if (glutGetModifiers() & GLUT_ACTIVE_SHIFT) 
			mCamera.SetViewRight(bKeyDown); 
		else 
			mCamera.SetViewRight(false); 
		break; 
 
	case GLUT_KEY_DOWN: // Player (or external view) pitch down 
 
		if (glutGetModifiers() & GLUT_ACTIVE_SHIFT) 
			mCamera.SetViewDown(bKeyDown); 
		else 
			mCamera.SetViewDown(false); 
		break; 
 
	case GLUT_KEY_PAGE_UP: // Player (or external view) zoom in 
 
		mCamera.SetViewZoomIn(bKeyDown); 
		break; 
 
	case GLUT_KEY_PAGE_DOWN: // Player (or external view) zoom out 
 
		mCamera.SetViewZoomOut(bKeyDown); 
		break; 
 
	case GLUT_KEY_HOME: // Player (or external view) reset 
 
		// todo 
		break; 
 
	case GLUT_KEY_END: 
		break; 
 
	case GLUT_KEY_INSERT: 
		break; 
 
	default: 
		break; 
	} 
 
	// Notify player 
	reGetPlayerManager()->KeyboardSpecial(key, x, y, bKeyDown); 
} 
 
 
 
 
void 
reGameEngine::MouseFunc(int button, int state, int x, int y) 
{ 
	// Notify GUI 
	reGetGameGUI()->MouseFunc(button, state, x, y); 
} 
 
 
 
 
void 
reGameEngine::MotionFunc(int x, int y) 
{ 
	// Notify GUI 
	reGetGameGUI()->MotionFunc(x, y); 
} 
 
 
 
 
void 
reGameEngine::PassiveMotionFunc(int x, int y) 
{ 
	// Notify GUI 
	reGetGameGUI()->PassiveMotionFunc(x, y); 
} 
 
 
 
 
void 
reGameEngine::CollisionEventHandler(dGeomID o1, dGeomID o2) 
{ 
	dBodyID b1 = dGeomGetBody(o1); 
	dBodyID b2 = dGeomGetBody(o2); 
 
	// Exit without doing anything if the two bodies are connected by a joint 
	if (b1 && b2 && dAreConnected (b1,b2)) 
		return; 
 
	int i; 
	dContact contact[3];			// up to 3 contacts per box 
	for (i = 0; i < 3; i++) 
	{ 
		contact[i].surface.mode = dContactBounce; //dContactMu2; 
		contact[i].surface.mu = dInfinity; 
		contact[i].surface.mu2 = 0; 
		contact[i].surface.bounce = 0.5; 
		contact[i].surface.bounce_vel = 0.1; 
	} 
 
	if (int numc = dCollide (o1, o2, 3, &contact[0].geom, sizeof(dContact))) 
	{ 
		reGameEntity* pEntity1 = (reGameEntity*)dGeomGetData(o1); 
		reGameEntity* pEntity2 = (reGameEntity*)dGeomGetData(o2); 
 
		/*if (pEntity1->GetEntityType() != eWeapon && 
			pEntity2->GetEntityType() != eWeapon) 
		{ 
			// Object-object collision 
			for (i = 0; i < numc; i++) 
			{ 
				dJointID c = dJointCreateContact( 
					mODEWorldId, 
					mODEJointGroupId, 
					contact + i); 
				dJointAttach(c, b1, b2); 
			} 
		} 
		else // Weapon-object collision 
		{ 
			reGameEntity* pWeaponEntity = NULL; 
			reGameEntity* pGameEntity = NULL; 
 
			if (pEntity1->GetEntityType() == eWeapon && pEntity2->GetEntityType() != eWeapon) 
			{ 
				pWeaponEntity = pEntity1; 
				pGameEntity = pEntity2; 
			} 
			else if (pEntity1->GetEntityType() != eWeapon && pEntity2->GetEntityType() == eWeapon) 
			{ 
				pWeaponEntity = pEntity1; 
				pGameEntity = pEntity2; 
			} 
			else // never should happen 
			{ 
				return; 
			} 
 
			// Create an explosion 
			sgCoord Pos = pWeaponEntity->GetPosition(); 
			ssgBranch* pExplosionBranch = new ssgBranch; 
			reExplosion* pExplosion = new reExplosion(pExplosionBranch); 
			pExplosionBranch->addKid(pExplosion); 
			pExplosion->Initialise(reExplosion::MakeState(), 8, 50, 1); 
			pExplosion->SetPosition(Pos.xyz[0], Pos.xyz[1], Pos.xyz[2]); 
			pExplosion->StartAnimation(); 
			mExplosionList.AddTail(pExplosion); 
			mWorld.addKid(pExplosionBranch); 
 
			// Remove the weapon 
			LISTPOSITION pos = mEntityList.GetHeadPosition(); 
			while (pos) 
			{ 
				if (pWeaponEntity == mEntityList.GetAt(pos)) 
				{ 
					mWorld.removeKid(pWeaponEntity->GetRoot()); 
					mEntityList.RemoveAt(pos); 
					break; 
				} 
				mEntityList.GetNext(pos); 
			} 
		}*/ 
	} 
}