FirstPersonShooter Camera Movement Help

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.
execute
Posts: 14
Joined: Wed Nov 22, 2006 7:48 pm

FirstPersonShooter Camera Movement Help

Post by execute »

Hey, I'm very new to irrlicht, although I have good experience with C++ and windows development this is my first time trying out the game development side of things.

I was using the "Movement example 4" tutorial, and I understand the basic ideas, such as loading meshes, textures, setting up the camera, and basic movements of the camera. However, the movement I set up for the camera to move around with W S D A keys, which i set to move with WS: the Z coordinate, and DA: the X coordinate. However, it didn't quite work out exactly like I planned, because in FPS games, the rotation of the camera with the mouse also affects the direction of the X and Z coordinates. I was wondering if anyone had any example code to make movement more like an FPS rather than a strict X/Z coordinate in which there are only 4 directions.

Another problem is, right now, it ignores the walls, and clips thru them, and I suppose doesn't have any gravity. I was wondering if there was source code showing that too. I looked at an example FPS game, using irrlicht, but it was very complex, and didn't exactly make it clear. I would rather see the isolated snippets of code.

The last problem is, the Gun position. If the Gun is stationed, I would have to move it the same way I move the camera right? Or is there some other method?

Thanks for your help.

EDIT: I added the source code, and a screenshot of what it looks like. In the scr shot you can see that the gun is there, but it's not in the right position but i believe it does move as you move (at least it should).

Source: http://www.sharebigfile.com/file/23783/ ... t.rar.html
Image
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

See the collision example for the way to avoid passing through walls and get gravity. And make your gun a child of the camera to move it with the camera. The position has to be found by trial and error.
execute
Posts: 14
Joined: Wed Nov 22, 2006 7:48 pm

Post by execute »

But how does the collision example do that? I mean it didn't SHOW that collision worked, just a selector and 3 faerie in place.

Anyway I will give it a try. Also how do you set as a child? (sorry I forgot).
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

Collision in the collision example is between camera and quake mesh, not with the fairies. And adding a child is done by gun->setParent(parent)
execute
Posts: 14
Joined: Wed Nov 22, 2006 7:48 pm

Post by execute »

Ok I understand.
I added the CreateCollisionResponse... and the OctTreeNode or whatever.

However, now I cannot MOVE the camera with WDSA, I'm assuming after I set the camera to collision response, I cannot use SetPosition to move the camera. :(

EDIT:
I also tried something else. Using MouseInput, I detected mouse input, MOUSE_MOVED, and then I got the X and Y of the mouseinput (event.MouseInput.X / Y), and then with the gun I did: gunNode->setRotation(NewVector); (which has the X and Y). I assumed this would create a response such as... me moving the mouse around will also rotate the gun (because the gun is right next to me right now), and so I would be able to see the rotating gun. However, the gun refused to move/rotate.
Acki
Posts: 3496
Joined: Tue Jun 29, 2004 12:04 am
Location: Nobody's Place (Venlo NL)
Contact:

Post by Acki »

Why you don't use the keymap feature of the FPS cam ???
Have a look at the docu (Irrlicht help file) for addCameraSceneNodeFPS, there's an example for this !!!
This way you don't need to handle the movement keys on you own inside the event receiver... ;)

EDIT:
I had a look at your code and made the needed changes !!!
I removed all comments and changed the pathes to the media dir, so you'll have to set them back... ;)

Code: Select all

#include <stdio.h>
#include <wchar.h>
#include <irrlicht.h>

using namespace irr;

//#pragma comment(lib, "Irrlicht.lib")

scene::ICameraSceneNode* camera = 0;
scene::ISceneNode* m_gunNode = 0;
IrrlichtDevice* device = 0;

class MyEventReceiver : public IEventReceiver
{
public:
  virtual bool OnEvent(SEvent event)
  {
    if (camera != 0 && event.EventType == irr::EET_KEY_INPUT_EVENT)
    {
//      switch(event.KeyInput.Key)
//      {
//        case KEY_KEY_W:
//        case KEY_KEY_S:
//        {
//           core::vector3df v = camera->getPosition();
//           v.Z += event.KeyInput.Key == KEY_KEY_W ? 7.0f : -7.0f;
//           camera->setPosition(v);
//           core::vector3df cv = m_gunNode->getPosition();
//           cv.Z += event.KeyInput.Key == KEY_KEY_W ? 7.0f : -7.0f;
//           m_gunNode->setPosition(cv);
//        }
//        case KEY_KEY_A:
//        case KEY_KEY_D:{
//          core::vector3df zv = camera->getPosition();
//          zv.X += event.KeyInput.Key == KEY_KEY_D ? 7.0f : -7.0f;
//          camera->setPosition(zv);
//          core::vector3df vv = m_gunNode->getPosition();
//          vv.Z += event.KeyInput.Key == KEY_KEY_W ? 7.0f : -7.0f;
//          m_gunNode->setPosition(vv);
//        }
//        return true;
//     }
    }
    return false;
  }
};

int main()
{
  MyEventReceiver receiver;

  device = createDevice(video::EDT_OPENGL, core::dimension2d<s32>(800, 600),
		16, false, false, false, &receiver);

  video::IVideoDriver* driver = device->getVideoDriver();
  scene::ISceneManager* smgr = device->getSceneManager();
  device->getFileSystem()->addZipFileArchive("C:/CodeBlocks/AB-AddOn/Media/Irrlicht/map-20kdm2.pk3");


  scene::IAnimatedMesh* q3levelmesh = smgr->getMesh("20kdm2.bsp");
  scene::ISceneNode* q3node = 0;

  if (q3levelmesh)
    q3node = smgr->addOctTreeSceneNode(q3levelmesh->getMesh(0));

  scene::IAnimatedMesh* UziMesh = smgr->getMesh("../uzi.3ds");
  m_gunNode = smgr->addAnimatedMeshSceneNode(UziMesh,NULL);
  m_gunNode->setMaterialFlag(video::EMF_LIGHTING, false);
  m_gunNode->setMaterialTexture(0, driver->getTexture("../uzi.jpg"));

//    core::vector3df m_gunRot = core::vector3df(10.0,-10.0,0.0);
  core::vector3df m_gunDisp = core::vector3df(5.0f,-5.0f,10.0f);

//	m_gunNode->setRotation(m_gunRot);
  m_gunNode->setPosition(m_gunDisp);

  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 = smgr->addCameraSceneNodeFPS(0, 100.0f, 310.0f, -1, keyMap, 8, true);
  camera->setPosition(core::vector3df(1200,320,620));
  m_gunNode->setParent(camera);

  smgr->addLightSceneNode(0, core::vector3df(-60,100,400),
    video::SColorf(1.0f,1.0f,1.0f,1.0f),
    600.0f);

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

  int lastFPS = -1;

  while(device->run())
  {
    driver->beginScene(true, true, video::SColor(255,113,113,133));

    smgr->drawAll(); // draw the 3d scene
    device->getGUIEnvironment()->drawAll(); // draw the gui environment (the logo)

    driver->endScene();

    int fps = driver->getFPS();

    if (lastFPS != fps)
    {
      wchar_t tmp[1024];
      swprintf(tmp, 1024, L"Movement Example - Irrlicht Engine [%ls] fps: %d", driver->getName(), fps);

      device->setWindowCaption(tmp);
      lastFPS = fps;
    }
  }

  device->drop();

  return 0;
}
I hope you see the changes I made... ;)
while(!asleep) sheep++;
IrrExtensions:Image
http://abusoft.g0dsoft.com
try Stendhal a MORPG written in Java
execute
Posts: 14
Joined: Wed Nov 22, 2006 7:48 pm

Post by execute »

Wow... This is amazing. When I tried using parent, the gun would disappear (maybe wrong position?) and in yours it worked perfectly. Also the keys work better. However, it just needs collision/gravity and some extra features for it to be an almost amazing fps game :P.

I added code at the top of events, so that I may switch weapons. I have a couple other weapon model/textures (although another free source anyone can find would be awesome). However, it loads the textures, but doesnt change the weapon, it deletes it, and sometimes it partially loads it, but it doesnt seem to work good. It won't switch it more than once either.

Here's what I did for gun switching:

Code: Select all

if (camera != 0 && event.EventType == irr::EET_KEY_INPUT_EVENT)
    {
        switch(event.KeyInput.Key)
        {
          case KEY_KEY_1:{
               smgr->addToDeletionQueue(m_gunNode);
               UziMesh = smgr->getMesh("../../media/pistol.3ds");
               m_gunNode = smgr->addAnimatedMeshSceneNode(UziMesh,NULL);
               m_gunNode->setMaterialFlag(video::EMF_LIGHTING, false);
               m_gunNode->setMaterialTexture(0, driver->getTexture("../../media/pistol.jpg"));
               m_gunNode->setParent(camera);
               }
          case KEY_KEY_2:{
               smgr->addToDeletionQueue(m_gunNode);
               UziMesh = smgr->getMesh("../../media/uzi.3ds");
               m_gunNode = smgr->addAnimatedMeshSceneNode(UziMesh,NULL);
               m_gunNode->setMaterialFlag(video::EMF_LIGHTING, false);
               m_gunNode->setMaterialTexture(0, driver->getTexture("../../media/uzi.jpg"));
               m_gunNode->setParent(camera);
               }
          case KEY_KEY_3:{
               smgr->addToDeletionQueue(m_gunNode);
               UziMesh = smgr->getMesh("../../media/smach.3ds");
               m_gunNode = smgr->addAnimatedMeshSceneNode(UziMesh,NULL);
               m_gunNode->setMaterialFlag(video::EMF_LIGHTING, false);
               m_gunNode->setMaterialTexture(0, driver->getTexture("../../media/smach.jpg"));
               m_gunNode->setParent(camera);
               }
return true;
}
}
I'm assuming crouch is a simple Y subtracted from the camera, and perhaps lean left and right is probably a camera rotation (perhaps if u wanna make it better, some distortion for the gun while leaning).

The only other thing thats needed is enemy targets, which i will have to do more research on how the collision process works.
zeno60
Posts: 342
Joined: Sun May 21, 2006 2:48 am
Location: NC, USA
Contact:

Post by zeno60 »

Would it not be faster to create/load nodes for each gun before the irrlicht device is run and then simply set the m_gunNode equal to whichever gun is selected when the key is pressed?

Ex.

m_gunNode_pistol = smgr->addAnimatedMeshSceneNode(pistol,0);
//set material flags

m_gunNode_uzi = smgr->addAnimatedMeshSceneNode(uzi, 0);
//set material flags

Then instead of having to load the 3ds object and create the mesh when the key is pressed, it will have already been done before the game started, so you can set your m_gunNode = m_gunNode_pistol, etc.

Just throwing this out there, especially if you notice your program stalling for a sec when you switch guns.
execute
Posts: 14
Joined: Wed Nov 22, 2006 7:48 pm

Post by execute »

Good idea, but i still dont know if this is going to work. Guns dont seem to appear...

I tried your idea of loading textures first. However, now the program crashes if you switch weapons more than once. (i'm assuming access violations although i dont see any).

Anyway, gun switching doesn't seem to work too well. I addToDeleteQuere, then I set the main Weapon SceneNode to the SceneNode of some other weapon according to its key. Doesn't seem to change any of the weapons (the first weapon disappears and thats about it).
Acki
Posts: 3496
Joined: Tue Jun 29, 2004 12:04 am
Location: Nobody's Place (Venlo NL)
Contact:

Post by Acki »

Well, you really should not add the meshes to the deltion queue !!!
Just remove this lines from the event receiver...
And use setVisible(true/false) to show/hide the nodes...

For the nodes not appearing, I'm sure they do appeare !!! ;)
But as you create them new they are at position (0,0,0) what means they are at the center of your camera !!!
So just set the position of the weapon nodes like I did in the previous code to something like vector3df(5.0f,-5.0f,10.0f)... ;)
while(!asleep) sheep++;
IrrExtensions:Image
http://abusoft.g0dsoft.com
try Stendhal a MORPG written in Java
execute
Posts: 14
Joined: Wed Nov 22, 2006 7:48 pm

Post by execute »

Alright I'll try that. However, now the problem goes back to the last one. As soon as I start using Event receiver again, the KeyMap you told me about, stops working. So I believe I have to code movement and the camera rotation myself, otherwise I wont be able to have other hotkey features.

So how exactly would I be coding the movement so that the X Y Z plane rotates so I can go in the direction of the center of the camera rather than a FIXED XYZ plane:

case W:
core::vector3df vctForward;
vctForward = camera->getPosition();
vctForward.X += 2.0f;
vctForward.Z += 2.0f;
// i doubt this is going to work, there must be another way.
// I need to fix it so it will go forward ACCORDING TO THE ROTATION
//OF CAMERA.
case S:

case D:

case A:
Acki
Posts: 3496
Joined: Tue Jun 29, 2004 12:04 am
Location: Nobody's Place (Venlo NL)
Contact:

Post by Acki »

No, you don't have to !!!
The error is inside your event receiver !!!
it must return false at the end, only the handled keys should return true !!!

Code: Select all

if (camera != 0 && event.EventType == irr::EET_KEY_INPUT_EVENT)
    {
        switch(event.KeyInput.Key)
        {
          case KEY_KEY_1:{
               smgr->addToDeletionQueue(m_gunNode);
               UziMesh = smgr->getMesh("../../media/pistol.3ds");
               m_gunNode = smgr->addAnimatedMeshSceneNode(UziMesh,NULL);
               m_gunNode->setMaterialFlag(video::EMF_LIGHTING, false);
               m_gunNode->setMaterialTexture(0, driver->getTexture("../../media/pistol.jpg"));
               m_gunNode->setParent(camera);
return true;
               }
          case KEY_KEY_2:{
               smgr->addToDeletionQueue(m_gunNode);
               UziMesh = smgr->getMesh("../../media/uzi.3ds");
               m_gunNode = smgr->addAnimatedMeshSceneNode(UziMesh,NULL);
               m_gunNode->setMaterialFlag(video::EMF_LIGHTING, false);
               m_gunNode->setMaterialTexture(0, driver->getTexture("../../media/uzi.jpg"));
               m_gunNode->setParent(camera);
return true;
               }
          case KEY_KEY_3:{
               smgr->addToDeletionQueue(m_gunNode);
               UziMesh = smgr->getMesh("../../media/smach.3ds");
               m_gunNode = smgr->addAnimatedMeshSceneNode(UziMesh,NULL);
               m_gunNode->setMaterialFlag(video::EMF_LIGHTING, false);
               m_gunNode->setMaterialTexture(0, driver->getTexture("../../media/smach.jpg"));
               m_gunNode->setParent(camera);
return true;
               }
}
}
return false;
if you return true, you tell the system (cam) that there is nothing more to do... ;)
And see the return false is outside the if statement !!!
while(!asleep) sheep++;
IrrExtensions:Image
http://abusoft.g0dsoft.com
try Stendhal a MORPG written in Java
execute
Posts: 14
Joined: Wed Nov 22, 2006 7:48 pm

Post by execute »

Alright Thank you. ^^

Ok, now both movement AND keys work, (saves me a lot of work). Also I added Crouch and Jump features, which kind of work, I kinda used the x^2 idea since it creates a parabola, it would make a more realistic jump effect. So I looped that, but I guess I must experiment to make it look good:

Code: Select all

KEY_SPACE:
 for(int i = 1.0f; i < 10.0f; i++){
   vertex3df v = camera->getPosition();
   v.Y += i*i;
 }
 for(int c = 9.0f; i > 0.0f; i++){
   vertex3df xc = camera->getPosition();
   xc.Y -= i*i;
 } 
 return true;
It isn't perfect but it sorta works.

Also I added the collision response to the camera, which now when first loaded acts a little wierd... (like as if it has some sort of boundary in beginning) but after moving around a bit, the boundary disappears, and I am able to move around my map WITH GRAVITY AND NO CLIPPING THRU WALLS. Damn the collision detection is awesome + easy.

Whats left? Shooting, which I am kinda working on, which i sort of have an idea. Also some 2D images like showing ammo, cursor, etc... And finally, adding enemy targets, which I will get models (wish I knew a good 3D model designer to help or a free source of models, or I might have to learn 3Dstudiomax overnight.), the bullet holes, and the detection that an enemy is shot (but i guess I'll figure all that out soon enuf).
Acki
Posts: 3496
Joined: Tue Jun 29, 2004 12:04 am
Location: Nobody's Place (Venlo NL)
Contact:

Post by Acki »

I'm glad you got it without reinventing the wheel !!! :lol:

You should have a look at the tutorials first, so you'll see how things can be done with Irrlicht...

For shooting the collision tutorial should help you, and for the HUD have a look at the UserInterface and 2DGraphics tutorials...

gl
while(!asleep) sheep++;
IrrExtensions:Image
http://abusoft.g0dsoft.com
try Stendhal a MORPG written in Java
execute
Posts: 14
Joined: Wed Nov 22, 2006 7:48 pm

Post by execute »

I loooked at the collision tutorial, there is notihng about bullets, im thinking of using aabox3d and getBoundingBox but I dont know how to compare vertex3dfs or aabox3ds... But I am gonna try and figure that out.

for userinterface, HUD, i'm sure putting up 2dimages is good enough, i'll take a look at tutorials.
Post Reply