Implementing Crouching And Jumping

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
Post Reply
android_808
Posts: 13
Joined: Mon Feb 28, 2005 4:12 pm

Implementing Crouching And Jumping

Post by android_808 »

I was wondering if someone could give me an example of how to code crouching and jumping into a FPS style game. I am new to both Irrlicht and C++, but I am eager to learn. In just a couple of hours I managed to be able to understand some of the basic concepts and wrote a console based menu for one of the tutorials.

I am now examining the demo that comes with the latest (0.8) release of Irrlicht and have started to create my own demo by learning from the code. I have been investigating ways of implementing these two features but have not yet found a concrete solution.

Jumping I see as being the easiest to implement as the createCollisionResponseAnimator function allows you to set the gravity and acceleration per second of the camera. One would simply have to give the camera a vertical speed.

Crouching on the other hand has me stumped. I have found that it is possible to set the radius of the elipsoid using:

virtual void irr::scene::ISceneNodeAnimatorCollisionResponse::setEllipsoidRadius ( const core::vector3df & radius ) [pure virtual]

However is it possible to do this after the animator has already been applied to the scene node using addAnimator. If so, does it remove the old animator as well?

Final question. Using SKeyMap like in the included demo, is it possible for the actions to be a call to a function, say for example the action of space to call jump().
android_808
Posts: 13
Joined: Mon Feb 28, 2005 4:12 pm

Post by android_808 »

Another problem I have is with the movement of the camera. Using the default movement code for the FPS camera, when moving forward whilst looking up or backwards whilst looking down causes the camera to jump up and down. Would this just require a change to the vectors of the animation code so they are respond to the x and z axis and not the y.
cartoonit
Posts: 286
Joined: Mon Nov 15, 2004 6:36 pm

Post by cartoonit »

The second post has been answered I think somewhere else, I think Bal got annoyed by it. I can't remember where the post is but search and you will find, need to have 2 conditions really, and inserting an AND will help too.

As for the jumping and crouching, I started trying to implement it using the engine, and its quite difficult compared to some of the other options that are available to you. I've just implemented Newton physics engine in to my game, and it takes around about 5 LOC to implement the jump functionality, also its more realistic with the Physics engine. However, other functionality does take time to implement.

In my opinion I would run before I could jump or crouch, sorry for the pun. But get most of the application made then implement the other nice features in to the application like jumping and crouching later on. Get used to handling the engine, then see how other things can be implemented in to the engine.

However, you could do it the other way and learn both a physics engine and the irrlicht engine at the same time.
android_808
Posts: 13
Joined: Mon Feb 28, 2005 4:12 pm

Post by android_808 »

Yeah, I forgot about run. Maybe implementing a physics engine would be a better idea. Just out of interest, how difficult is Newton to learn. The only issue I have with it is that I believe it is Win32 only.
cartoonit
Posts: 286
Joined: Mon Nov 15, 2004 6:36 pm

Post by cartoonit »

The integration demo does quite a bit of work for you, the mercior tutorial, then theres quite a few threads on here about it. Its not overly complicated to understand, like any engine, at the start you don't know a lot but over time everything starts to become clear... If its only WIN32 there must be other options, like ODE, Tokamak, and the others that bal posted when I asked the other day. I think its in the offtopic thread...
android_808
Posts: 13
Joined: Mon Feb 28, 2005 4:12 pm

Post by android_808 »

Ok, I've finished stripping down the demo code to remove the portals, models etc, but I now have a problem with the OnEvent reciever. The application crashes on running CGame::run().

CGame.cpp

Code: Select all

#include "CGame.h"
#include <stdio.h>

CGame::CGame(bool f, bool s, bool a, bool v, int w, int h, video::E_DRIVER_TYPE d)
: fullscreen(f), shadows(s), additive(a), vsync(v), screenwidth(w), screenheight(h), driverType(d), 
currentScene(-2), timeForThisScene(0), mapSelector(0), metaSelector(0), quakeLevelMesh(0), quakeLevelNode(0), skyboxNode(0)
{
}

CGame::~CGame()
{
   	if (mapSelector)
		mapSelector->drop();
   	if (metaSelector)
		metaSelector->drop();
}

void CGame::run()
{


	device = createDevice(driverType,
		core::dimension2d<s32>(screenwidth, screenheight), 32, fullscreen, shadows, vsync, this);;

	device->getFileSystem()->addZipFileArchive("media/irrlicht.dat");
	device->getFileSystem()->addZipFileArchive("maps/map-20kdm2.pk3");

	video::IVideoDriver* driver = device->getVideoDriver();
	scene::ISceneManager* smgr = device->getSceneManager();
	gui::IGUIEnvironment* guienv = device->getGUIEnvironment();

	device->setWindowCaption(L"Irrlicht Engine Demo");

	wchar_t tmp[255];

	while(device->run() && driver)
	{
		if (device->isWindowActive())
		{
			// load next scene if necessary
			u32 now = device->getTimer()->getTime();
			if (now - sceneStartTime > timeForThisScene && timeForThisScene!=-1)
				switchToNextScene();

			// draw everything

			driver->beginScene(true, true, backColor);

			smgr->drawAll();
			guienv->drawAll();

			driver->endScene();

			// write statistics

			swprintf(tmp, 255, L"%s fps:%d", driver->getName(),	driver->getFPS());

			statusText->setText(tmp);
		}
	}

	device->drop();
}


bool CGame::OnEvent(SEvent event)
{
	if (!device)
		return false;

	if (event.EventType == EET_KEY_INPUT_EVENT &&
		event.KeyInput.Key == KEY_ESCAPE &&
		event.KeyInput.PressedDown == false)
	{
		// user wants to quit.
		if (currentScene < 3)
			timeForThisScene = 0;
		else
			device->closeDevice();
	}
	else
	if ((event.EventType == EET_KEY_INPUT_EVENT &&
		event.KeyInput.Key == KEY_SPACE &&
		event.KeyInput.PressedDown == false) ||
		(event.EventType == EET_MOUSE_INPUT_EVENT &&
		event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP) &&
		currentScene == 3)
	{
		// shoot 
		shoot();
	}
	else
#ifdef _DEBUG
	if (event.EventType == irr::EET_MOUSE_INPUT_EVENT &&
		event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP)
	{
		char tmp[255];
		core::vector3df pos = device->getSceneManager()->getActiveCamera()->getAbsolutePosition();
		sprintf(tmp, "points.push_back(core::vector3df(%ff, %ff, %ff)); // %d\n", pos.X, pos.Y, pos.Z,
			sceneStartTime - device->getTimer()->getTime());
		OutputDebugString(tmp);
		return true;
	}
	else
#endif
	/*if (device->getSceneManager()->getActiveCamera())
	{
		device->getSceneManager()->getActiveCamera()->OnEvent(event);
		return true;
	}
    */
	return false;
}


void CGame::switchToNextScene()
{
	currentScene++;
	if (currentScene > 3)
		currentScene = 1;

	scene::ISceneManager* sm = device->getSceneManager();
	scene::ISceneNodeAnimator* sa = 0;
	scene::ICameraSceneNode* camera = 0;

	camera = sm->getActiveCamera();
	if (camera)
	{
		sm->setActiveCamera(0);
		camera->remove();
	}

	switch(currentScene)
	{
	case -1: // loading screen
		timeForThisScene = 0;
		createLoadingScreen();
		break;

	case 0: // load scene
		timeForThisScene = 0;
		loadSceneData();
		//currentScene += 2;
		break;

	case 1: // panorama camera
		{
			#if 0
			camera = sm->addCameraSceneNodeFPS(0, 100, 500);
			timeForThisScene = 14000000;
			#else
			currentScene += 1;
			camera = sm->addCameraSceneNode(0, core::vector3df(0,0,0), core::vector3df(-586,708,52));
			camera->setTarget(core::vector3df(0,400,0));
			
			core::array<core::vector3df> points;
		 
			points.push_back(core::vector3df(-931.473755f, 138.300003f, 987.279114f)); // -49873
			points.push_back(core::vector3df(-847.902222f, 136.757553f, 915.792725f)); // -50559
			points.push_back(core::vector3df(-748.680420f, 152.254501f, 826.418945f)); // -51964
			points.push_back(core::vector3df(-708.428406f, 213.569580f, 784.466675f)); // -53251
			points.push_back(core::vector3df(-686.217651f, 288.141174f, 762.965576f)); // -54015
			points.push_back(core::vector3df(-679.685059f, 365.095612f, 756.551453f)); // -54733
			points.push_back(core::vector3df(-671.317871f, 447.360107f, 749.394592f)); // -55588
			points.push_back(core::vector3df(-669.468445f, 583.335632f, 747.711853f)); // -56178
			points.push_back(core::vector3df(-667.611267f, 727.313232f, 746.018250f)); // -56757
			points.push_back(core::vector3df(-665.853210f, 862.791931f, 744.436096f)); // -57859
			points.push_back(core::vector3df(-642.649597f, 1026.047607f, 724.259827f)); // -59705
			points.push_back(core::vector3df(-517.793884f, 838.396790f, 490.326050f)); // -60983
			points.push_back(core::vector3df(-474.387299f, 715.691467f, 344.639984f)); // -61629
			points.push_back(core::vector3df(-444.600250f, 601.155701f, 180.938095f)); // -62319
			points.push_back(core::vector3df(-414.808899f, 479.691406f, 4.866660f)); // -63048
			points.push_back(core::vector3df(-410.418945f, 429.642242f, -134.332687f)); // -63757
			points.push_back(core::vector3df(-399.837585f, 411.498383f, -349.350983f)); // -64418
			points.push_back(core::vector3df(-390.756653f, 403.970093f, -524.454407f)); // -65005
			points.push_back(core::vector3df(-334.864227f, 350.065491f, -732.397400f)); // -65701
			points.push_back(core::vector3df(-195.253387f, 349.577209f, -812.475891f)); // -66335
			points.push_back(core::vector3df(16.255573f, 363.743134f, -833.800415f)); // -67170
			points.push_back(core::vector3df(234.940964f, 352.957825f, -820.150696f)); // -67939
			points.push_back(core::vector3df(436.797668f, 349.236450f, -816.914185f)); // -68596
			points.push_back(core::vector3df(575.236206f, 356.244812f, -719.788513f)); // -69166
			points.push_back(core::vector3df(594.131042f, 387.173828f, -609.675598f)); // -69744
			points.push_back(core::vector3df(617.615234f, 412.002899f, -326.174072f)); // -70640
			points.push_back(core::vector3df(606.456848f, 403.221954f, -104.179291f)); // -71390
			points.push_back(core::vector3df(610.958252f, 407.037750f, 117.209778f)); // -72085
			points.push_back(core::vector3df(597.956909f, 395.167877f, 345.942200f)); // -72817
			points.push_back(core::vector3df(587.383118f, 391.444519f, 566.098633f)); // -73477
			points.push_back(core::vector3df(559.572449f, 371.991333f, 777.689453f)); // -74124
			points.push_back(core::vector3df(423.753204f, 329.990051f, 925.859741f)); // -74941
			points.push_back(core::vector3df(247.520050f, 252.818954f, 935.311829f)); // -75651
			points.push_back(core::vector3df(114.756012f, 199.799759f, 805.014160f));
			points.push_back(core::vector3df(96.783348f, 181.639481f, 648.188110f));
			points.push_back(core::vector3df(97.865623f, 138.905975f, 484.812561f));
			points.push_back(core::vector3df(99.612457f, 102.463669f, 347.603210f));
			points.push_back(core::vector3df(99.612457f, 102.463669f, 347.603210f));
			points.push_back(core::vector3df(99.612457f, 102.463669f, 347.603210f));


			timeForThisScene = (points.size()-3)* 1000;
			
			sa = sm->createFollowSplineAnimator(device->getTimer()->getTime(), 
				points);
			camera->addAnimator(sa);
			sa->drop();			
			#endif
		inOutFader->fadeIn(7000);
	
		break;
		}
	case 2:	// down fly anim camera
		camera = sm->addCameraSceneNode(0, core::vector3df(100,40,-80), core::vector3df(844,670,-885));
		sa = sm->createFlyStraightAnimator(	core::vector3df(94, 1002, 127),
			core::vector3df(108, 15, -60), 10000, true);
		camera->addAnimator(sa);
		timeForThisScene = 9900;
		sa->drop();
		break;

	case 3: // interactive, go around
		{
			timeForThisScene = (u32)-1;

			SKeyMap keyMap[8];
			keyMap[0].Action = EKA_MOVE_FORWARD;
			keyMap[0].KeyCode = KEY_UP;
			keyMap[1].Action = EKA_MOVE_FORWARD;
			keyMap[1].KeyCode = KEY_KEY_W;
	        
			keyMap[2].Action = EKA_MOVE_BACKWARD;
			keyMap[2].KeyCode = KEY_DOWN;
			keyMap[3].Action = EKA_MOVE_BACKWARD;
			keyMap[3].KeyCode = KEY_KEY_S;
	        
			keyMap[4].Action = EKA_STRAFE_LEFT;
			keyMap[4].KeyCode = KEY_LEFT;
			keyMap[5].Action = EKA_STRAFE_LEFT;
			keyMap[5].KeyCode = KEY_KEY_A;
	        
			keyMap[6].Action = EKA_STRAFE_RIGHT;
			keyMap[6].KeyCode = KEY_RIGHT;
			keyMap[7].Action = EKA_STRAFE_RIGHT;
			keyMap[7].KeyCode = KEY_KEY_D;

			camera = sm->addCameraSceneNodeFPS(0, 100.0f, 300.0f, -1, keyMap, 8);
			camera->setPosition(core::vector3df(108,140,-140));
			
			scene::ISceneNodeAnimatorCollisionResponse* collider = 
				sm->createCollisionResponseAnimator(
				metaSelector, camera, core::vector3df(30,50,30), 
				core::vector3df(0, quakeLevelMesh ? -3.0f : 0.0f,0), 
					core::vector3df(0,40,0), 0.0005f);
		    
			camera->addAnimator(collider);
			collider->drop();
		}
		break;
	}

	sceneStartTime = device->getTimer()->getTime();

	// if we've got a new created camera, we call OnPostRender to let all animators
	// set the right position of the camera, otherwise the camera would
	// be at a wrong position in the first frame
	if (device->getSceneManager()->getActiveCamera())
		device->getSceneManager()->getActiveCamera()->OnPostRender(sceneStartTime);
}


void CGame::loadSceneData()
{
	// load quake level

	video::IVideoDriver* driver = device->getVideoDriver();
	scene::ISceneManager* sm = device->getSceneManager();

	quakeLevelMesh = sm->getMesh("20kdm2.bsp");
	
	if (quakeLevelMesh)
	{
		quakeLevelNode = sm->addOctTreeSceneNode(quakeLevelMesh->getMesh(0));
		if (quakeLevelNode)
		{
			quakeLevelNode->setPosition(core::vector3df(-1300,-70,-1249));
			quakeLevelNode->setVisible(true);
			
			// create map triangle selector
			mapSelector = sm->createOctTreeTriangleSelector(quakeLevelMesh->getMesh(0),
				quakeLevelNode, 128);

			// set additive blending if wanted
			if (additive)
				quakeLevelNode->setMaterialType(video::EMT_LIGHTMAP_ADD);
		}
	}

	// create sky box

	//driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false);

	skyboxNode = sm->addSkyBoxSceneNode(
		driver->getTexture("media/skyboxes/irrlicht2_up.jpg"),
		driver->getTexture("media/skyboxes/irrlicht2_dn.jpg"),
		driver->getTexture("media/skyboxes/irrlicht2_lf.jpg"),
		driver->getTexture("media/skyboxes/irrlicht2_rt.jpg"),
		driver->getTexture("media/skyboxes/irrlicht2_ft.jpg"),
		driver->getTexture("media/skyboxes/irrlicht2_bk.jpg"));

	//driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, true);

	// create meta triangle selector with all triangles selectors in it.
	metaSelector = sm->createMetaTriangleSelector();
	metaSelector->addTriangleSelector(mapSelector);

	// set background color

	backColor.set(0,0,0,0);
}



void CGame::createLoadingScreen()
{
	core::dimension2d<int> size = device->getVideoDriver()->getScreenSize();

	device->getCursorControl()->setVisible(false);

	// setup loading screen

	backColor.set(255,90,90,156);

	// create in fader

	inOutFader = device->getGUIEnvironment()->addInOutFader();
	inOutFader->setColor(backColor);

	// irrlicht logo

	gui::IGUIImage* img = device->getGUIEnvironment()->addImage(
		core::rect<int>(10,10,98,41));

	img->setImage(
		device->getVideoDriver()->getTexture("media/irrlichtlogoaligned.jpg"));

	// loading text

	const int lwidth = 120;
	const int lheight = 15;

	core::rect<int> pos(10, size.Height-lheight-10, 10+lwidth, size.Height-10);
	
	device->getGUIEnvironment()->addImage(pos);
	statusText = device->getGUIEnvironment()->addStaticText(L"Loading...",	pos, true);
	statusText->setOverrideColor(video::SColor(255,205,200,200));

	// load bigger font

	device->getGUIEnvironment()->getSkin()->setFont(
		device->getGUIEnvironment()->getFont("media/fonts/fonthaettenschweiler.bmp"));

	// set new font color

	device->getGUIEnvironment()->getSkin()->setColor(gui::EGDC_BUTTON_TEXT,
		video::SColor(255,100,100,100));
}



void CGame::shoot()
{
	scene::ISceneManager* sm = device->getSceneManager();
	scene::ICameraSceneNode* camera = sm->getActiveCamera();


	if (!camera || !mapSelector)
		return;
}
I have managed to deduce that the problem is due to the lines as the application works fine when they are commented out:

Code: Select all

if (device->getSceneManager()->getActiveCamera())
	{
		device->getSceneManager()->getActiveCamera()->OnEvent(event);
		return true;
	}
Any suggestions as to why this could be happening. I am use Dev-Cpp 4.9.9.2 and the irrlicht.dll from the Dev-Cpp folder included in the SDK. The camera is still moveable when this is commented out using the KeyMap defined in the source. Is this code block optional or will the other events fail to work properly.
Post Reply