Page 1 of 1

Camera Collision Detection

Posted: Mon Feb 11, 2008 10:30 pm
by Elmo115
I am creating a third person game and I'm not sure how to limit the camera so you cant see through walls, objects, etc. I already have the collision detection working fine for my character. How can I limit the camera movement? I am fairly new at the whole game creating process. Thanks

Posted: Mon Feb 11, 2008 11:24 pm
by ebo
If you haven't already done it, download the irrlicht source code. Look up the collision detection part. Learn how it works and apply it to your camera.

Or use the forum search... I'm pretty sure that topic came up a few times.

Posted: Mon Feb 11, 2008 11:28 pm
by xDan
Well first get your third person camera working without this ;)

Then, in your update or where ever, you can create a ray/line from the character's position to the *desired* camera position. Then collide this ray with the scenery, and the closest collision point to the character is the *actual* camera position.

Posted: Tue Feb 12, 2008 10:28 pm
by Elmo115
I already have the camera working ok. If I create a ray, does the ray collide or is it just like a connection from the hero to the camera? Also, how do you create a ray? :oops:

Posted: Tue Feb 12, 2008 11:34 pm
by xDan

Code: Select all

// Ray from player to camera
core::line3df camRay = core::line3df(playerPos, desiredCameraPos);

// not used
core::triangle3df triangle;

// Collide the ray with your triangleSelector. If a collision occurs
// then desiredCameraPos is set to the collision point
smgr->getSceneCollisionManager()->getCollisionPoint(camRay, triangleSelector, desiredCameraPos, triangle);
I haven't tested it, but I dare say you will post if it doesn't work. :P

Posted: Wed Feb 13, 2008 12:31 am
by Elmo115
When I try to compile the code it says that playerPos and desiredCameraPos are undeclared. What are they supposed to be linked to ?

Posted: Wed Feb 13, 2008 8:53 am
by JP
What do their names suggest? :lol:

playerPos is obviously the position of your player, define it yourself.

desiredCameraPos is the current position of the camera, where it really wants to be based on your third person camera setup, define it yourself.

Also, you should do the collision test in the opposite direction, not from camera to player but from player to camera because if there are two objects inbetween the camera and the player, casting the line from camera to player will only detect the collision with the first object and will mean the second object will block the view. If you do it backwards, from player to camera, it will find the farthest point from the player that the camera can be placed without being blocked by any objects.

Of course if the resulting position is 'too close' to the player, e.g. the player mesh is now blocking the view or you can't see the player mesh (and you want to be able to at all times) then you'd have to do some extra work like rotate the camera around a bit to find some free space.

Posted: Wed Feb 13, 2008 8:48 pm
by Elmo115
First, I am a total Noob at all this so bear with me. :lol: Their names do represent the positions of the player and camera. So when I name them do I have to link the player and camera position to the names of the player and camera nodes?

Also, is the collision already not from player to camera?

Here is the code I have so far if this will help at all:

Code: Select all

#include <irrlicht.h>
#include <math.h>
#include <iostream>

#define PI (3.14159265)
#define radtodeg (180.0/PI)
#define degtorad (PI/180.0)

using namespace irr;

IrrlichtDevice* device = 0;
scene::IAnimatedMeshSceneNode* hero = 0;

//Camera rotation
float camX=-90, camY=40, camDistance=150 /*this one is a distance */, test=0;

//Resolution declaration
int width=1024,height=768,depth=32;

//Key states
bool up    = false;
bool down  = false;
bool right = false;
bool left  = false;

class charControl : public IEventReceiver
{
public:
   virtual bool OnEvent(SEvent event)
   {
      //Get key states      
      if (event.EventType == EET_KEY_INPUT_EVENT)
      {
         if(event.KeyInput.Key==KEY_KEY_W)
          if(event.KeyInput.PressedDown)
             hero->setMD2Animation(scene::EMAT_RUN);
          else
             hero->setMD2Animation(scene::EMAT_STAND);
         switch(event.KeyInput.Key)
         {
          case KEY_KEY_W: up = event.KeyInput.PressedDown; break;
          case KEY_KEY_S: down = event.KeyInput.PressedDown; break;
          case KEY_KEY_A: left = event.KeyInput.PressedDown; break;
          case KEY_KEY_D: right = event.KeyInput.PressedDown; break;
         }

         //return true;
      }
      if (event.EventType == EET_MOUSE_INPUT_EVENT)
      {
         camX+=(event.MouseInput.X-width/2)*0.1;//0.5
         camY+=(event.MouseInput.Y-height/2)*0.1;//0.5
    	 
         if (event.MouseInput.Event == EMIE_MOUSE_WHEEL) camDistance-         =event.MouseInput.Wheel*7; 
         
         //Limit the movement
         if (camDistance<0) camDistance=0.1;
         if (camY>60) camY=60; //85
         if (camY<0) camY=0;  
      }

      return false;
   }
}; 

int main(int argc, char *argv[])
{
    //check screen dimensions from arguments
    if(argc==3)
     if(strcmp(argv[1],"-screen")==0)
     {
      sscanf(argv[2],"%dx%dx%d",&width,&height,&depth);
     }

	// create device
    charControl receiver; 

	// create device and exit if creation failed
	IrrlichtDevice* device= createDevice(video::EDT_OPENGL, core::dimension2d<s32>(width,height),depth,true,true,true,&receiver);
	//IrrlichtDevice *device = createDevice(video::EDT_OPENGL, core::dimension2d<s32>(640, 480),depth,false,false,false,&receiver);
	if (device == 0)	return 1; // could not create selected driver.
	// set caption & hide cursor
	device->setWindowCaption(L"Subversion");
	device->getCursorControl()->setVisible(false);
    device->getCursorControl()->setPosition(width/2,height/2);   //center cursor
	// create scenes
	video::IVideoDriver* driver = device->getVideoDriver();
	scene::ISceneManager* smgr = device->getSceneManager();
	// load the scene
	smgr->loadScene("scenes/level1.irr");

    scene::ISceneNode* node = node=smgr->getSceneNodeFromId(0);
    scene::IAnimatedMesh* mesh = smgr->getMeshCache()->getMeshByIndex(0);
    
    scene::ITriangleSelector* selector = 0; 
    selector = smgr->createOctTreeTriangleSelector(mesh->getMesh(0), node, 128);    

    // add a user controlled camera
	scene::ICameraSceneNode* camera = 
	camera = smgr->addCameraSceneNode(0);
	camera->setPosition(core::vector3df(-20,20,-20));

    // add animated hero.
	video::SMaterial material;
	material.Textures[0] = driver->getTexture("characters/sydney/texture.bmp");
	material.Lighting = true;
	//scene::IAnimatedMeshSceneNode* node = 0;
	scene::IAnimatedMesh* heromesh = smgr->getMesh("characters/sydney/amesh.md2");
	if (heromesh)
	{
		hero = smgr->addAnimatedMeshSceneNode(heromesh);
		hero->setPosition(core::vector3df(20,-15,20));
		hero->setMD2Animation(scene::EMAT_STAND);
		hero->setScale(core::vector3df(1.5,1.5,1.5));
		hero->getMaterial(0) = material;
	}
	
   if (selector) 
   { 
      scene::ISceneNodeAnimator* anim =
      smgr->createCollisionResponseAnimator( 
          selector, hero,
          core::vector3df(17,25,20), 
          core::vector3df(0,-3,0),
          core::vector3df(0,8,0));        
      hero->addAnimator(anim); 
      anim->drop(); 
      selector->drop(); 
   } 

     // Ray from player to camera 
     core::line3df camRay = core::line3df(playerPos, desiredCameraPos); 

     // not used 
     core::triangle3df triangle; 

     // Collide the ray with your triangleSelector. If a collision occurs 
     // then desiredCameraPos is set to the collision point 
     smgr->getSceneCollisionManager()->getCollisionPoint(camRay, selector, desiredCameraPos, triangle);

	// render loop
	while(device->run())
	if (device->isWindowActive())
	{
		driver->beginScene(true, true, video::SColor(0,255,255,255));
        device->getCursorControl()->setPosition(width/2,height/2);   //center cursor
        
    	
		//Execute moving		//float relDisplacement;
		float speed=4;//6
		float rotspeed=2.5;//4.5
	    
		//Get Position&Rotation
		core::vector3df position = hero->getPosition();
		core::vector3df camposition = position;
        core::vector3df rotation = hero->getRotation();
        
        //Change camera settings
        camera->setTarget(position);
        camposition.X+=sin(camX*degtorad)*camDistance;
        camposition.Z+=cos(camX*degtorad)*camDistance;
        camposition.Y+=sin(camY*degtorad)*camDistance;
        camera->setPosition(camposition);
        
        
         //Modify Position and Rotation        //relDisplacement=0;
        if (up||down)
        {
           float relDisplacement = down ? speed : -speed;
           position.X+= -cos(rotation.Y * degtorad)*relDisplacement;
           position.Z+=  sin(rotation.Y * degtorad)*relDisplacement;
           rotation.Y = camX + 90.0; /*yuuuuuk*/
        }
           
//#define RIGHT_LEFT_ROTATES        
#ifndef RIGHT_LEFT_ROTATES
        if (left||right)
        { 
           float relDisplacement = left ? speed : -speed;
           position.X += sin(rotation.Y * degtorad) * relDisplacement;
           position.Z += cos(rotation.Y * degtorad) * relDisplacement;  //cos
           rotation.Y = camX + 90.0; /*yuuuuuk*/
        }
                   
#else          
        if (left||right)
        {
           rotation.Y += right ? rotspeed : -rotspeed;              
        }
#endif
        //Set Position&Rotation
        hero->setPosition(position);
        hero->setRotation(rotation);
               
        
		smgr->drawAll();
		driver->endScene();
  	}

	device->drop();
	
	//scanf("%c");
	return 0;
}

Posted: Thu Feb 14, 2008 12:12 am
by xDan
You have to do that every frame, right? The character/camera is moving. :?

So right after you have found out the "camposition" (what I called desiredCameraPos), just before the line
camera->setPosition(camposition);

Of COURSE, you have to replace the arguments I named (e.g. playerPos, desiredCameraPos with what ever you are calling those. "position", "cameraposition")

It might help if you learnt to code before you attempted to write a game. (just some friendly advice y'know 8) )

Posted: Thu Feb 14, 2008 11:32 pm
by Elmo115
I am sort of learning as I go. I am in a group in school where we are trying to make a video game. We were all given a part and mine was to get the collision detection working for the character and the camera.

When I try to compile it now says that core::line3df camRay = core::line3df(hero, camera); and smgr->getSceneCollisionManager()->getCollisionPoint(camRay, selector, camera); have no matching functions. Any ideas? :lol:

Posted: Fri Feb 15, 2008 12:49 am
by Acki
a short look into the API shows you all you need to know... ;)
line3d (const vector3d< T > &start, const vector3d< T > &end)
so pass the positions to it and not the nodes...
virtual bool getCollisionPoint (const core::line3d< f32 > &ray, ITriangleSelector *selector, core::vector3df &outCollisionPoint, core::triangle3df &outTriangle)=0
and here you see that you miss one parameter and your last parameter (your camera) and the missing one are pointers to store the results...

the api is realy a magic file... ,)