newton FPS camera... needs tweaking

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
zillion42
Posts: 324
Joined: Wed Aug 29, 2007 12:32 am
Location: Hamburg, Germany

newton FPS camera... needs tweaking

Post by zillion42 »

ok...

the code below should compile with irrlicht1.4.2 & irrnewt 0.4 if you follow this link for the irrnewt compile errors... It's based on the irrnewt character controlling.cpp example... however I changed the camera so that it's inside the collsion bubble + strafing instead of rotating which is now done with the mouse... its W-A-S-D, SPACE to jump and F2 to show newton debug info.

It needs tweaking... the camera node is scaled so that the position is not on the ground. The problem is that the camera is now in the center of the newton::EBT_PRIMITIVE_CAPSULE; not on top, where the head should normally be... another problem is that crouch (KEY_KEY_C) currently makes us fall through the level... Standing close before an edge makes the rigell_body->setClimbStairForce(core::vector3df(0,2,0)); trigger and the camera bounces up and down on the spot...

any tweaking and feedback very much appreciated

binary download

Code: Select all

//this example show character controlling

#include <string>
#include <direct.h>
#include <iostream>
#include "irrlicht.h"
#include "../../include/IrrNewt.hpp"

#pragma comment(lib,"irrlicht.lib")
using namespace irr;

IrrlichtDevice* device;
video::IVideoDriver* driver;
scene::ISceneManager* smgr;
scene::ICameraSceneNode* camera;
scene::ICameraSceneNode* camera2;

irr::newton::ICharacterController* rigell_body;
irr::newton::IWorld* p_world;
irr::newton::ITreeBody* world_p_node;
bool debug_info=false;

const float rigell_speed=6;
const float rotation_speed = 2.0f * 100;
const float gravity_force=-30.0f;

bool up=false,down=false,left=false,right=false,jump=false,crouch=false;

class MyeventReceiver:public IEventReceiver {
public:
	virtual bool OnEvent(const SEvent& event) {
	if(event.EventType == EET_KEY_INPUT_EVENT) {

		if(event.KeyInput.PressedDown == true) {

			if(event.KeyInput.Key==KEY_KEY_A)
				left=true;
			if(event.KeyInput.Key==KEY_KEY_D)
				right=true;
			if(event.KeyInput.Key==KEY_KEY_W) 
				up=true;
			if(event.KeyInput.Key==KEY_KEY_S)
				down=true;
			if(event.KeyInput.Key==KEY_SPACE)
				jump=true;
			if(event.KeyInput.Key==KEY_KEY_C)
				crouch=true;
		}

		if(event.KeyInput.PressedDown == false) {

			if(event.KeyInput.Key==KEY_KEY_A)
				left=false;
			if(event.KeyInput.Key==KEY_KEY_D)
				right=false;
			if(event.KeyInput.Key==KEY_KEY_W) 
				up=false;
			if(event.KeyInput.Key==KEY_KEY_S)
				down=false;
			if(event.KeyInput.Key==KEY_SPACE)
				jump=false;
			if(event.KeyInput.Key==KEY_KEY_C)
				crouch=false;
			if(event.KeyInput.Key==KEY_F2)
				debug_info=!debug_info;
		
		}
	}
	return false;
	}
}my_event_receiver;

int main(int argc, char** argv) {

	//int i;
	device=createDevice(video::EDT_DIRECT3D9, core::dimension2d<s32>(1920, 1200), 32, true);
	device->setEventReceiver(&my_event_receiver);
	device->getCursorControl()->setVisible(false);
	smgr=device->getSceneManager();
	driver=device->getVideoDriver();
	
	//change working dir
	_chdir("../../");
	
	//load a bsp quake map
	device->getFileSystem()->addZipFileArchive("media/level/map-20kdm2.pk3");
	scene::IAnimatedMesh* world_mesh = smgr->getMesh("media/level/20kdm2.bsp");
	scene::ISceneNode* world_node =
		smgr->addOctTreeSceneNode(world_mesh->getMesh(0));
	world_node->setPosition(core::vector3df(45,0,0));
	scene::ITriangleSelector* world_tri_selector=smgr->createOctTreeTriangleSelector(world_mesh->getMesh(0),world_node);
	
	camera=smgr->addCameraSceneNodeFPS(0,100,0,-1,0,0,true,0);
	camera->setPosition(core::vector3df(1469.6f,280.474f,1363.34f));
	camera->setVisible(true);
	camera->setScale(core::vector3df(10,25,10));
	
	//camera->bindTargetAndRotation(true);
	
	camera2=smgr->addCameraSceneNodeFPS();
	camera2->setPosition(core::vector3df(1469.6f,280.474f,1363.34f));
	smgr->setActiveCamera(camera);
	
	
	//PHYSICS

	//create world
	p_world = irr::newton::createPhysicsWorld(device);

	//create level tree
	newton::SBodyFromNode worldData;
	worldData.Node = world_node;
	worldData.Mesh = world_mesh->getMesh(0);
	world_p_node = (irr::newton::ITreeBody*) p_world->createBody(worldData);

	//body 1
	newton::SBodyFromNode bodyData;
	bodyData.Type = newton::EBT_PRIMITIVE_CAPSULE;
	bodyData.Node = camera;
	bodyData.Mass = 1;
//	bodyData.Mesh = rigell_mesh->getMesh(1);

	rigell_body = p_world->createCharacterController(p_world->createBody(bodyData));
	rigell_body->setRotationUpdate(false);
	rigell_body->setContinuousCollisionMode(true);

	//the body rotate never
	p_world->getUtils()->avoidRotationOnAllAxes(rigell_body);

	//materials!! see materials and shapes example
	irr::newton::IMaterial* rigell_material;
	irr::newton::IMaterial* level_material;

	rigell_material = p_world->createMaterial();
	level_material  = p_world->createMaterial();

	rigell_body->setMaterial(rigell_material);
	world_p_node->setMaterial(level_material);

	//rigell<->level comportaments
	rigell_material->setElasticity(level_material, 0.0f);
	rigell_material->setFriction(level_material, 0.0f,0.0f);
	rigell_material->setSoftness(level_material, 1.0f);



	// set the force to apply if in front of the character there is a stair
	rigell_body->setClimbStairForce(core::vector3df(0,2,0));
	
	//set the max stair-step height from floor for the first stair-step
	//from the below stair-step for all the stairs-step except the first
	rigell_body->setStairMaxHeight(20);

	//add gravity
	rigell_body->addForceContinuous(core::vector3df(0,
		gravity_force,
		0));
	
	//loop
	while(device->run()) {

		//CHARACTER CONTROLLING
		core::vector3df rigell_rotation=camera->getRotation();

		//STEP 1: ROTATING
		//make node rotation frame rate indipendent by multiply it by time elasped from last update
		//float rotation_to_apply = rotation_speed * p_world->getTimeElapsed();
		
		//camera->setRotation(rigell_rotation);
		
		//STEP 2: MOVING
		core::vector3df velocity = rigell_body->getVelocity();
		velocity.X=velocity.Z=0;

		if(up) //without FRI in function name the movement is not frame rate indipendent
			velocity += rigell_body->FRIgetDirectionPositionY(core::vector3df(0,0,rigell_speed));
		if(down)
			velocity += rigell_body->FRIgetDirectionPositionY(core::vector3df(0,0,-rigell_speed));
		if(right) 
			velocity += rigell_body->FRIgetDirectionPositionY(core::vector3df(rigell_speed,0,0));
		if(left) 
			velocity += rigell_body->FRIgetDirectionPositionY(core::vector3df(-rigell_speed,0,0));

		rigell_body->setVelocity(velocity);
		
		//STEP 3:JUMPING
		//the function jump(f32) take the velocity of the jumping
		if(jump)
			rigell_body->jump(12,60);

		//STEP 4:CROUNCHING
		//the crouch() function takes the new scale of y of the node for crouching
		//example 0.5 will reduce the character height by 1/2 (  so new_height = current_height - (current_height/2)  )
		//0.25 will reduce the chracter height by 1/4 (  so new_height = current_height - (current_height/2)  )
		//2 will double the character height

		const f32 crouch_value = 1;

		if(crouch)
			rigell_body->crouch(crouch_value);

		else 
			rigell_body->stand(0);


		//END OF CHARACTER CONTROLLING

		p_world->update();

		driver->beginScene(true,true,video::SColor(0,0,0,0));
		smgr->drawAll();

		//show debug info
		if(debug_info)
			p_world->drawAllDebugInfos();

		driver->endScene();

	}

	device->drop();
	return 0;
}




zillion42
Posts: 324
Joined: Wed Aug 29, 2007 12:32 am
Location: Hamburg, Germany

Post by zillion42 »

ok, I dumped the crouching and added another scene node to be the physics body and rotate like the FPS camera, then set the position of the FPS camera to the body +offset, which fixed most of my problems....

I added a VC8 solution and precompiled exe with matching irrlicht, irrnewt and newton dll's this time... download here...

My problem now is the movement itself... If you watch closely it stutters... any ideas ?

Code: Select all

#include <string>
#include <direct.h>
#include <iostream>
#include "irrlicht.h"
#include "IrrNewt.hpp"

#pragma comment(lib,"irrlicht.lib")
using namespace irr;

IrrlichtDevice* device;
gui::IGUIEnvironment* guienv;
video::IVideoDriver* driver;
scene::ISceneManager* smgr;
scene::ICameraSceneNode* camera;
scene::ICameraSceneNode* camera2;
scene::IMeshManipulator* mm;

irr::newton::ICharacterController* rigell_body;
irr::newton::IWorld* p_world;
irr::newton::ITreeBody* world_p_node;
bool debug_info=false;

const float rigell_speed=9;
const float rotation_speed = 2.0f * 100;
const float gravity_force=-30.0f;

bool up=false,down=false,left=false,right=false,jump=false,crouch=false;


class MyeventReceiver:public IEventReceiver {
public:
	virtual bool OnEvent(const SEvent& event) {
		if(event.EventType == EET_KEY_INPUT_EVENT) {

			if(event.KeyInput.PressedDown == true) {

				if(event.KeyInput.Key==KEY_KEY_A)
					left=true;
				if(event.KeyInput.Key==KEY_KEY_D)
					right=true;
				if(event.KeyInput.Key==KEY_KEY_W) 
					up=true;
				if(event.KeyInput.Key==KEY_KEY_S)
					down=true;
				if(event.KeyInput.Key==KEY_SPACE)
					jump=true;
				if(event.KeyInput.Key==KEY_KEY_C)
					crouch=true;
			}

			if(event.KeyInput.PressedDown == false) {

				if(event.KeyInput.Key==KEY_KEY_A)
					left=false;
				if(event.KeyInput.Key==KEY_KEY_D)
					right=false;
				if(event.KeyInput.Key==KEY_KEY_W) 
					up=false;
				if(event.KeyInput.Key==KEY_KEY_S)
					down=false;
				if(event.KeyInput.Key==KEY_SPACE)
					jump=false;
				if(event.KeyInput.Key==KEY_KEY_C)
					crouch=false;
				if(event.KeyInput.Key==KEY_F2)
					debug_info=!debug_info;
				if(event.KeyInput.Key==KEY_F3)
					smgr->setActiveCamera(camera2);
				if(event.KeyInput.Key==KEY_F4)
					smgr->setActiveCamera(camera);
			}
			if (event.MouseInput.Event == EMIE_MOUSE_MOVED){
				//
			}
		}
		return false;
	}
}my_event_receiver;
int main()
{
	irr::SIrrlichtCreationParameters param;
	param.AntiAlias = true;
	param.HighPrecisionFPU= true;
	param.Vsync= true;
	param.DriverType = video::EDT_DIRECT3D9;
	param.WindowSize = core::dimension2di(1280,1024); 
	param.Bits = 32;
	param.Stencilbuffer = true;
	//param.Fullscreen = true;

	device=createDeviceEx(param);
	device->setEventReceiver(&my_event_receiver);
	device->getCursorControl()->setVisible(false);
	smgr = device->getSceneManager();
	driver = device->getVideoDriver();
	guienv = device->getGUIEnvironment(); 
	mm = smgr->getMeshManipulator(); 

	int lastFPS = -1; 

	scene::IAnimatedMesh* collide = smgr->getMesh("../media/grid.x");
	
	if(collide != 0){
		
		mm->recalculateNormals(collide, false);
		scene::ISceneNode* collidenode = 0;
		collidenode = smgr->addOctTreeSceneNode(collide->getMesh(0));
		collidenode->setPosition(core::vector3df(-100,-10,-200));
		
		//add a scene node for 
		scene::ISceneNode* char_node = smgr->addCubeSceneNode();
		char_node->setPosition(core::vector3df(-100,200,-100));
		char_node->setVisible(false);
		camera=smgr->addCameraSceneNodeFPS(0,100,0,-1,0,0,true,0);
		
		// Add a light
		smgr->addLightSceneNode(0, core::vector3df(0,10000,0),video::SColorf(1.0f,1.0f,1.0f),180000.0f);

		//PHYSICS

		//create world
		p_world = irr::newton::createPhysicsWorld(device);

		//create level tree
		newton::SBodyFromNode worldData;
		worldData.Node = collidenode;
		worldData.Mesh = collide->getMesh(0);
		world_p_node = (irr::newton::ITreeBody*) p_world->createBody(worldData);

		//body 1
		newton::SBodyFromNode bodyData;
		bodyData.Type = newton::EBT_PRIMITIVE_CAPSULE;
		bodyData.Node = char_node;
		bodyData.Mass = 0.7;
		
		rigell_body = p_world->createCharacterController(p_world->createBody(bodyData));
		rigell_body->setRotationUpdate(false);
		rigell_body->setContinuousCollisionMode(true);
		rigell_body->setScale(core::vector3df(5,16,5));

		//the body rotate never
		p_world->getUtils()->avoidRotationOnAllAxes(rigell_body);

		//materials!! see materials and shapes example
		irr::newton::IMaterial* rigell_material;
		irr::newton::IMaterial* level_material;

		rigell_material = p_world->createMaterial();
		level_material  = p_world->createMaterial();

		rigell_body->setMaterial(rigell_material);
		world_p_node->setMaterial(level_material);

		//rigell<->level comportaments
		rigell_material->setElasticity(level_material, 0.0f);
		rigell_material->setFriction(level_material, 0.0f,0.0f);
		rigell_material->setSoftness(level_material, 1.0f);

		// set the force to apply if in front of the character there is a stair
		rigell_body->setClimbStairForce(core::vector3df(0,2,0));

		//set the max stair-step height from floor for the first stair-step
		//from the below stair-step for all the stairs-step except the first
		rigell_body->setStairMaxHeight(20);

		//add gravity
		rigell_body->addForceContinuous(core::vector3df(0,
			gravity_force,
			0));

		//loop
		while(device->run()) {

			//CHARACTER CONTROLLING
			core::vector3df rigell_rotation=camera->getRotation();

			//STEP 1: ROTATING
			//make node rotation frame rate indipendent by multiply it by time elasped from last update
			//float rotation_to_apply = rotation_speed * p_world->getTimeElapsed();

			char_node->setRotation(rigell_rotation);
			camera->setPosition(char_node->getPosition()+core::vector3df(0,70,0));

			//STEP 2: MOVING
			core::vector3df velocity = rigell_body->getVelocity();
			velocity.X=velocity.Z=0;

			if(up) //without FRI in function name the movement is not frame rate indipendent
				velocity += rigell_body->FRIgetDirectionPositionY(core::vector3df(0,0,rigell_speed));
			if(down)
				velocity += rigell_body->FRIgetDirectionPositionY(core::vector3df(0,0,-rigell_speed));
			if(right) 
				velocity += rigell_body->FRIgetDirectionPositionY(core::vector3df(rigell_speed,0,0));
			if(left) 
				velocity += rigell_body->FRIgetDirectionPositionY(core::vector3df(-rigell_speed,0,0));

			rigell_body->setVelocity(velocity);
			
			//STEP 3:JUMPING
			//the function jump(f32) take the velocity of the jumping
			if(jump)
				rigell_body->jump(12,60);

			//END OF CHARACTER CONTROLLING

			p_world->update();

			driver->beginScene(true,true,video::SColor(0,0,0,0));
			smgr->drawAll();

			//show debug info
			if(debug_info)
				p_world->drawAllDebugInfos();

			driver->endScene();
			if (driver->getFPS() != lastFPS) {
				lastFPS = driver->getFPS();
				wchar_t tmp[1024];
				swprintf(
					tmp,
					1024,
					L"FPS: %d)",
					lastFPS);
				device->setWindowCaption(tmp);
			}
		}

		device->drop();
		return 0;
	}

}
Post Reply