3rd person camera #3,267 (C&C needed for newbie)

Post those lines of code you feel like sharing or find what you require for your project here; or simply use them as tutorials.
Tannz0rz
Posts: 35
Joined: Fri May 08, 2009 12:25 am
Location: Orlando FL, USA

Post by Tannz0rz »

It works and all, but all of the position/distance/other values are predefined, so the camera always starts in the same place regardless of the player's position. It's rather inconvenient, but nice job with everything else.
kill56321
Posts: 5
Joined: Thu Oct 22, 2009 2:46 pm

Post by kill56321 »

Hey ultramedia. thanks for this. It's very useful.

But something error in it when I built it.

I'm sorry, I can't show my error message.
but I changed
IrrlichtDevice* device = createDevice(EDT_OPENGL,dimension2d<s32>(800,600),32,false,false,false);

to

IrrlichtDevice* device = createDevice(EDT_OPENGL,dimension2d<u32>(800,600),32,false,false,false);
Bate
Posts: 364
Joined: Sun Nov 01, 2009 11:39 pm
Location: Germany

Post by Bate »

Thanks for the camera, nice one.

However, I found a little issue. The camera "jumps" some pixels (in my case) if you rotate it with the mouse, so it doesn't feel smooth. That is because you lose the float precision by casting into an integer in order to do integer modulo ( % ). To fix that you just have to use float mod:

replace these lines

Code: Select all

cameraOrbit = (f32)((int)(cameraOrbitOld + cursorDelta.X) % 360);
cameraAngle = (f32)((int)(cameraAngleOld + cursorDelta.Y) % 360);
with

Code: Select all

cameraOrbit = fmod( (cameraOrbitOld + cursorDelta.X), 360);
cameraAngle = fmod( (cameraAngleOld + cursorDelta.Y), 360);
and you are all set ;)
jimburnettva
Posts: 13
Joined: Fri Feb 19, 2010 5:07 pm
Contact:

Post by jimburnettva »

Good stuff.

Rei, I got your latest code to compile just fine under Linux and using the latest Irr libs.

One change...
I had to change

sprintf_s(temp,"%d",intToConvert);

to

sprintf(temp,"%d",intToConvert);

Apparently sprintf_s is a mickeysoft thing? Hmmm not sure.

Anyways, works like a charm! Thanks everyone for the info!
sudi
Posts: 1686
Joined: Fri Aug 26, 2005 8:38 pm

Post by sudi »

wow that looks like some nice spagethicode....seriously make a class out of it and maybe even a ISceneNodeAnimator that can be attached to a camera. but that way the code is not ruseable for any real projects...
We're programmers. Programmers are, in their hearts, architects, and the first thing they want to do when they get to a site is to bulldoze the place flat and build something grand. We're not excited by renovation:tinkering,improving,planting flower beds.
paulorr29
Posts: 27
Joined: Fri Aug 27, 2010 8:23 pm
Location: Panama
Contact:

Post by paulorr29 »

thanks !!!! nice camera, very useful to me :D !!
my first app with irrlicht http://youtube.com/watch?v=8OHUgciBT8E
digoxy
Posts: 51
Joined: Wed Feb 17, 2010 3:55 pm
Location: Currently Germany.

Post by digoxy »

How about adding

S = reverse
A = Rotate left
D = Rotate right
Q = Strafe left
E = Strafe right.

That would complete this I think. It works nicely.
Grandma-- / Grandpa --
crysty2k9
Posts: 1
Joined: Fri Dec 17, 2010 12:51 pm

Post by crysty2k9 »

Here is a update code :

Code: Select all

#include <iostream>
#include <Irrlicht.h>

using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;

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

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// SETTINGS /////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// setup key engine objects
IrrlichtDevice* device = createDevice(EDT_OPENGL,dimension2d<u32>(800,600),32,false,false,false);
IVideoDriver* driver = device->getVideoDriver();
ISceneManager* smgr = device->getSceneManager();
IGUIEnvironment* guienv = device->getGUIEnvironment();
ICursorControl* CursorControl;

// keyboard registry
bool keys[irr::KEY_KEY_CODES_COUNT];

// mouse registry
bool mouseDownL;
bool mouseDownM;
bool mouseDownR;
f32 lastWheelMovement;
position2d<f32> cursor;
position2d<f32> cursorOld;
position2d<f32> cursorDelta;
position2d<f32> cursorDeltaOld;

// camera registry
f32 cameraOrbit = 135;
f32 cameraAngle = 35;
f32 cameraDistance = 6;
f32 cameraOrbitOld = 0;
f32 cameraAngleOld = 0;

// player registry
f32 playerX = 12;
f32 playerY = 0;
f32 playerZ = 15;
f32 playerCompass = 0;
f32 playerTurnTo = 0;
f32 playerTurnSpeed = 1;
f32 playerMoveSpeed = 0.01f;

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CLASS : MyEventReceiver //////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

class MyEventReceiver : public IEventReceiver
{
public:
   virtual bool OnEvent(const SEvent& event)
   {
      if(event.EventType == irr::EET_KEY_INPUT_EVENT)
      {
         keys[event.KeyInput.Key] = event.KeyInput.PressedDown;
         return false;
      }

      if (event.EventType == EET_MOUSE_INPUT_EVENT)
        {
         // left mouse button state check
         if(event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN)   mouseDownL = true;
         if(event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP)      mouseDownL = false;

         // middle mouse button state check
         if(event.MouseInput.Event == EMIE_MMOUSE_PRESSED_DOWN)   mouseDownM = true;
         if(event.MouseInput.Event == EMIE_MMOUSE_LEFT_UP)      mouseDownM = false;

         if(event.MouseInput.Event == EMIE_MOUSE_WHEEL)
         {
            cameraDistance -= event.MouseInput.Wheel * (cameraDistance / 20) * 2;
            if(cameraDistance < 6) cameraDistance = 6;
            if(cameraDistance > 12) cameraDistance = 12;
         }

         // right mouse button state check
         if(event.MouseInput.Event == EMIE_RMOUSE_PRESSED_DOWN)
         {
            mouseDownR = true;
            cursorOld.X = (f32)event.MouseInput.X;
            cursorOld.Y = (f32)event.MouseInput.Y;
            cursorDelta.X = 0;
            cursorDelta.Y = 0;
            cursorDeltaOld.X = 0;
            cursorDeltaOld.Y = 0;
            cameraOrbitOld = cameraOrbit;
            cameraAngleOld = cameraAngle;
         }
         if(event.MouseInput.Event == EMIE_RMOUSE_LEFT_UP)      mouseDownR = false;

         // mouse move check
         if(event.MouseInput.Event == EMIE_MOUSE_MOVED)
            {
            // add condition that right mouse button be down
            if(mouseDownR == true){
               cursor.X = (f32)event.MouseInput.X;
               cursor.Y = (f32)event.MouseInput.Y;
               cursorDelta.X = (f32)((cursor.X - cursorOld.X) * 1.0);
               cursorDelta.Y = (f32)((cursor.Y - cursorOld.Y) * 1.0);
            if (cursorDelta.Y > (88 - cameraAngleOld)) {
               cursorOld.Y += (cursorDelta.Y - cursorDeltaOld.Y);
               cursorDelta.Y = 88 - cameraAngleOld;
            }
            if (cursorDelta.Y < (-88 - cameraAngleOld)) {
               cursorOld.Y += (cursorDelta.Y - cursorDeltaOld.Y);
               cursorDelta.Y = -88 - cameraAngleOld;
            }
            cursorDeltaOld.X = cursorDelta.X;
            cursorDeltaOld.Y = cursorDelta.Y;
               cameraOrbit = (f32)((int)(cameraOrbitOld + cursorDelta.X) % 360);
               cameraAngle = (f32)((int)(cameraAngleOld + cursorDelta.Y) % 360);
               if(cameraAngle > 88) cameraAngle = 88;
               if(cameraAngle < 18) cameraAngle = 18;
            }

            }
         return false;

        }

      return false;
   }
};

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CLASS : CMySampleSceneNode ///////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

class CMySampleSceneNode : public ISceneNode
{

   private:
      static const s32 tileResolution = 32;   // how many segments to have down each edge of the tile
      static const s32 cellSize = 2;         // how many units square will each cell of the tile be?

      aabbox3d<f32> Box;     // [A]xis [A]ligned [B]ounding [B]ox in [3D] space
      S3DVertex Vertices[((tileResolution+1) * (tileResolution+1))]; // An array where each cell is of type S3DVertex
      u16 indices[(tileResolution * tileResolution) * 6];   // number of cells * 6 (each cell has two tris, each tri has 3 indices)
      SMaterial Material;    // A material object of type SMaterial
      IVideoDriver *driver;  // A link through to the driver object

   public:

      /////////////////
      // constructor //
      /////////////////

      CMySampleSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id) : ISceneNode(parent, mgr, id)
      {
         // put link to videoDriver into already prepared var of type IVideoDriver
         driver = SceneManager->getVideoDriver();

         // set material settings
         Material.Wireframe = true;
         Material.Lighting = false;
         Material.BackfaceCulling = false;

         // create vertex objects in vertex array

         s32 vIndex = 0;
         for (f32 i=0; i<(tileResolution+1); i++){
            for (f32 j=0; j<(tileResolution+1); j++){
               Vertices[vIndex] = S3DVertex((j*cellSize),0,(i*cellSize), 0,0,1, SColor(255,0,255,255),j,i);
               // std :: cout << vIndex << ":" << j << "," << i << "\n";
               vIndex++;
            }
         }

         // reposition the bounding box to the first vertex
         Box.reset(Vertices[0].Pos);

         // add the defined vertices to Box
         for (s32 i=0; i<vIndex; i++)
            Box.addInternalPoint(Vertices[i].Pos);

         // setup indices
         s32   iIndex = 0;

         for (s32 i=0; i<tileResolution; i++){
            for (s32 j=0; j<tileResolution; j++){

               s32 currentVertex = (i*(tileResolution+1)) + j;

               indices[iIndex + 0] = currentVertex;
               indices[iIndex + 1] = currentVertex+1;
               indices[iIndex + 2] = currentVertex+tileResolution+1;
               indices[iIndex + 3] = currentVertex+1;
               indices[iIndex + 4] = currentVertex+tileResolution+2;
               indices[iIndex + 5] = currentVertex+tileResolution+1;

               iIndex = iIndex + 6;

            }
         }

      }

      /////////////////////////
      // OnRegisterSceneNode //
      /////////////////////////

      virtual void OnRegisterSceneNode()
      {
         if (IsVisible)
            ISceneNode::OnRegisterSceneNode();
      }

      ///////////////
      // OnAnimate //
      ///////////////

      virtual void OnAnimate(u32 timeMs)
      {
         ISceneNode::OnAnimate(timeMs);
      }

      ////////////
      // render //
      ////////////

      virtual void render()
      {
         driver->setMaterial(Material);
         driver->setTransform(ETS_WORLD, AbsoluteTransformation);

         driver->drawIndexedTriangleList(&Vertices[0],(tileResolution+1) * (tileResolution+1),&indices[0],((tileResolution*tileResolution)*2));
      }

      ////////////////////
      // getBoundingBox //
      ////////////////////

      virtual const aabbox3d<f32>& getBoundingBox() const
      {
         return Box;
      }

      //////////////////////
      // getMaterialCount //
      //////////////////////

      virtual u32 getMaterialCount()
      {
         return 1;
      }

      /////////////////
      // getMaterial //
      /////////////////

      virtual SMaterial& getMaterial(s32 i)
      {
         return Material;
      }
};


/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// FUNCTION : sphericalXYZ //////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

vector3df sphericalXYZ(f32 compassAngle, f32 elevationAngle, f32 radius){

   compassAngle = compassAngle * -1;
   elevationAngle = elevationAngle * -1;

   elevationAngle = elevationAngle + 90;

   f32 x = radius * cos(compassAngle * PI/180.0f ) * sin(elevationAngle * PI/180.0f );
   f32 z = radius * sin(compassAngle * PI/180.0f ) * sin(elevationAngle * PI/180.0f );
   f32 y = radius * cos(elevationAngle * PI/180.0f );

   vector3df result;
   result.X = x;
   result.Y = y;
   result.Z = z;
   return result;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// FUNCTION : int2string ////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

stringw int2string(int intToConvert){
   char temp[50];
   sprintf(temp,"%d",intToConvert);
   return temp;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////        /////////////////////////////////////////////////////////////////////////////////////////////////////////////
////  MAIN  /////////////////////////////////////////////////////////////////////////////////////////////////////////////
////        /////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

int main()
{

   // setup event receiver
   MyEventReceiver rv;
   device->setEventReceiver(&rv);
   for(int x=0; x<irr::KEY_KEY_CODES_COUNT; x++) keys[x] = false;

   // setup screen display elements
   device->setWindowCaption(L"First Game");
   IGUIStaticText* debug_panel = guienv->addStaticText(L"Debug Panel",rect<s32>(5, 5, 200, 200),false,true,0,-1,false);

   // setup the "player"
   ISceneNode* cPivot1 = smgr->addCubeSceneNode(0.5,0,-1,vector3df(playerX,playerY,playerZ));
   cPivot1->setMaterialFlag(video::EMF_LIGHTING, false);

   ISceneNode* cPivot2 = smgr->addCubeSceneNode(2,cPivot1,-1,vector3df(0,1,0));
   cPivot2->setMaterialTexture(0,driver->getTexture("wall.bmp"));
   cPivot2->setMaterialFlag(video::EMF_LIGHTING, false);

   ISceneNode* cPivot3 = smgr->addCubeSceneNode(1,cPivot2,-1,vector3df(0,1.5,0));
   cPivot3->setMaterialTexture(0,driver->getTexture("wall.bmp"));
   cPivot3->setMaterialFlag(video::EMF_LIGHTING, false);

   ISceneNode* cPivot4 = smgr->addCubeSceneNode(1,cPivot2,-1,vector3df(0,0,1.5));
   cPivot4->setMaterialTexture(0,driver->getTexture("wall.bmp"));
   cPivot4->setMaterialFlag(video::EMF_LIGHTING, false);

   ISceneNode* cPivot5 = smgr->addCubeSceneNode(0.5,cPivot2,-1,vector3df(0,0,2.2));
   cPivot5->setMaterialTexture(0,driver->getTexture("wall.bmp"));
   cPivot5->setMaterialFlag(video::EMF_LIGHTING, false);

   ISceneNode* cPivot6 = smgr->addCubeSceneNode(0.5,cPivot2,-1,vector3df(1.25,0.7,0.7));
   cPivot6->setMaterialTexture(0,driver->getTexture("wall.bmp"));
   cPivot6->setMaterialFlag(video::EMF_LIGHTING, false);

   ISceneNode* cPivot7 = smgr->addCubeSceneNode(0.5,cPivot2,-1,vector3df(1.25,-0.7,0.7));
   cPivot7->setMaterialTexture(0,driver->getTexture("wall.bmp"));
   cPivot7->setMaterialFlag(video::EMF_LIGHTING, false);


   ISceneNode* cPivot8 = smgr->addCubeSceneNode(0.5,cPivot2,-1,vector3df(-1.25,0.7,0.7));
   cPivot8->setMaterialTexture(0,driver->getTexture("wall.bmp"));
   cPivot8->setMaterialFlag(video::EMF_LIGHTING, false);

   ISceneNode* cPivot9 = smgr->addCubeSceneNode(0.5,cPivot2,-1,vector3df(-1.25,-0.7,0.7));
   cPivot9->setMaterialTexture(0,driver->getTexture("wall.bmp"));
   cPivot9->setMaterialFlag(video::EMF_LIGHTING, false);

   ISceneNode* cPivot10 = smgr->addCubeSceneNode(0.7,cPivot2,-1,vector3df(0,-0.6,-1.25));
   cPivot10->setMaterialTexture(0,driver->getTexture("wall.bmp"));
   cPivot10->setMaterialFlag(video::EMF_LIGHTING, false);

   // setup the camera
   ICameraSceneNode* myCamera = smgr->addCameraSceneNode(cPivot1, sphericalXYZ(cameraOrbit,cameraAngle,cameraDistance), cPivot1->getPosition());

   // create references to our custom nodes
   CMySampleSceneNode* myNode = new CMySampleSceneNode(smgr->getRootSceneNode(),smgr,1);
   myNode->setPosition(vector3df(0,0,0));

   /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
   // DEVICE : main loop ///////////////////////////////////////////////////////////////////////////////////////////////////
   /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

   while(device->run()) {

      /////////////////////////
      // keyboard management //
      /////////////////////////

      // system keys
      if(keys[KEY_ESCAPE]){
         device->closeDevice();
      }

      // player keys

      if(keys[KEY_KEY_W]){

         // player movement vector
         vector3df playerStep = sphericalXYZ(cameraOrbit,0,playerMoveSpeed);
         playerX -= playerStep.X;
         playerY -= playerStep.Y;
         playerZ -= playerStep.Z;

         // player rotation brain torture

         playerTurnTo = cameraOrbit - 90;
         if(playerTurnTo < 0) playerTurnTo += 360;
         if(playerTurnTo >= 360) playerTurnTo -= 360;

         if(playerCompass < 0) playerCompass += 360;
         if(playerCompass >= 360) playerCompass -= 360;

         f32 playerTurnDir = 0;
         f32 playerTurnDelta = 0;

         if(playerCompass > playerTurnTo)
         {
            if(playerCompass - playerTurnTo < 180){
               playerTurnDir = -1;
               playerTurnDelta = playerCompass - playerTurnTo;
            } else {
               playerTurnDir = 1;
               playerTurnDelta = (360 - playerCompass) + playerTurnTo;
            }
         }

         if(playerCompass < playerTurnTo)
         {
            if(playerTurnTo - playerCompass < 180){
               playerTurnDir = 1;
               playerTurnDelta = playerTurnTo - playerCompass;
            } else {
               playerTurnDir = -1;
               playerTurnDelta = (360 - playerTurnTo) + playerCompass;
            }
         }

         f32 playerTurnAmount;

         if(playerTurnDelta < playerTurnSpeed){
            playerTurnAmount = playerTurnDelta;
         } else {
            playerTurnAmount = playerTurnSpeed;
         }
         playerCompass += (playerTurnAmount * playerTurnDir);

         cPivot1->setPosition(vector3df(playerX,playerY,playerZ));
         cPivot2->setRotation(vector3df(0,playerCompass,0));
         myCamera->setTarget(vector3df(playerX,playerY,playerZ));
      }

      if(keys[KEY_KEY_S]){

         // player movement vector
         vector3df playerStep = sphericalXYZ(cameraOrbit,0,playerMoveSpeed);
         playerX += playerStep.X;
         playerY -= playerStep.Y;
         playerZ += playerStep.Z;

         // player rotation brain torture

         playerTurnTo = cameraOrbit + 90;
         if(playerTurnTo < 0) playerTurnTo += 360;
         if(playerTurnTo >= 360) playerTurnTo -= 360;

         if(playerCompass < 0) playerCompass += 360;
         if(playerCompass >= 360) playerCompass -= 360;

         f32 playerTurnDir = 0;
         f32 playerTurnDelta = 0;

         if(playerCompass > playerTurnTo)
         {
            if(playerCompass - playerTurnTo < 180){
               playerTurnDir = -1;
               playerTurnDelta = playerCompass - playerTurnTo;
            } else {
               playerTurnDir = 1;
               playerTurnDelta = (360 - playerCompass) + playerTurnTo;
            }
         }

         if(playerCompass < playerTurnTo)
         {
            if(playerTurnTo - playerCompass < 180){
               playerTurnDir = 1;
               playerTurnDelta = playerTurnTo - playerCompass;
            } else {
               playerTurnDir = -1;
               playerTurnDelta = (360 - playerTurnTo) + playerCompass;
            }
         }

         f32 playerTurnAmount;

         if(playerTurnDelta < playerTurnSpeed){
            playerTurnAmount = playerTurnDelta;
         } else {
            playerTurnAmount = playerTurnSpeed;
         }
         playerCompass += (playerTurnAmount * playerTurnDir);


         cPivot1->setPosition(vector3df(playerX,playerY,playerZ));
         cPivot2->setRotation(vector3df(0,playerCompass,0));
         myCamera->setTarget(vector3df(playerX,playerY,playerZ));
      }

      if(keys[KEY_KEY_D]){

         // player movement vector
         vector3df playerStep = sphericalXYZ(cameraOrbit,0,playerMoveSpeed);
         playerX -= playerStep.X;
         playerY -= playerStep.Y;
         playerZ += playerStep.Z;

         // player rotation brain torture

         playerTurnTo = cameraOrbit;
         if(playerTurnTo < 0) playerTurnTo += 360;
         if(playerTurnTo >= 360) playerTurnTo -= 360;

         if(playerCompass < 0) playerCompass += 360;
         if(playerCompass >= 360) playerCompass -= 360;

         f32 playerTurnDir = 0;
         f32 playerTurnDelta = 0;

         if(playerCompass > playerTurnTo)
         {
            if(playerCompass - playerTurnTo < 180){
               playerTurnDir = -1;
               playerTurnDelta = playerCompass - playerTurnTo;
            } else {
               playerTurnDir = 1;
               playerTurnDelta = (360 - playerCompass) + playerTurnTo;
            }
         }

         if(playerCompass < playerTurnTo)
         {
            if(playerTurnTo - playerCompass < 180){
               playerTurnDir = 1;
               playerTurnDelta = playerTurnTo - playerCompass;
            } else {
               playerTurnDir = -1;
               playerTurnDelta = (360 - playerTurnTo) + playerCompass;
            }
         }

         f32 playerTurnAmount;

         if(playerTurnDelta < playerTurnSpeed){
            playerTurnAmount = playerTurnDelta;
         } else {
            playerTurnAmount = playerTurnSpeed;
         }
         playerCompass += (playerTurnAmount * playerTurnDir);


         cPivot1->setPosition(vector3df(playerX,playerY,playerZ));
         cPivot2->setRotation(vector3df(0,playerCompass,0));
         myCamera->setTarget(vector3df(playerX,playerY,playerZ));
      }

      if(keys[KEY_KEY_A]){

         // player movement vector
         vector3df playerStep = sphericalXYZ(cameraOrbit,0,playerMoveSpeed);
         playerX += playerStep.X;
         playerY -= playerStep.Y;
         playerZ -= playerStep.Z;

         // player rotation brain torture

         playerTurnTo = cameraOrbit - 180;
         if(playerTurnTo < 0) playerTurnTo += 360;
         if(playerTurnTo >= 360) playerTurnTo -= 360;

         if(playerCompass < 0) playerCompass += 360;
         if(playerCompass >= 360) playerCompass -= 360;

         f32 playerTurnDir = 0;
         f32 playerTurnDelta = 0;

         if(playerCompass > playerTurnTo)
         {
            if(playerCompass - playerTurnTo < 180){
               playerTurnDir = -1;
               playerTurnDelta = playerCompass - playerTurnTo;
            } else {
               playerTurnDir = 1;
               playerTurnDelta = (360 - playerCompass) + playerTurnTo;
            }
         }

         if(playerCompass < playerTurnTo)
         {
            if(playerTurnTo - playerCompass < 180){
               playerTurnDir = 1;
               playerTurnDelta = playerTurnTo - playerCompass;
            } else {
               playerTurnDir = -1;
               playerTurnDelta = (360 - playerTurnTo) + playerCompass;
            }
         }

         f32 playerTurnAmount;

         if(playerTurnDelta < playerTurnSpeed){
            playerTurnAmount = playerTurnDelta;
         } else {
            playerTurnAmount = playerTurnSpeed;
         }
         playerCompass += (playerTurnAmount * playerTurnDir);


         cPivot1->setPosition(vector3df(playerX,playerY,playerZ));
         cPivot2->setRotation(vector3df(0,playerCompass,0));
         myCamera->setTarget(vector3df(playerX,playerY,playerZ));
      }

      // orient camera
      myCamera->setPosition(sphericalXYZ(cameraOrbit,cameraAngle,cameraDistance));

      // debug display
      stringw s(L"FPS : "); s+= int2string(driver->getFPS());
      s += L"\nleft mouse button : "; s+= mouseDownL;
      s += L"\nmiddle mouse button : "; s+= mouseDownM;
      s += L"\nright mouse button : "; s+= mouseDownR;
      s += L"\nlast wheel movement : "; s+= lastWheelMovement;
      s += L"\ncursor x : "; s+= cursor.X;
      s += L"\ncursor y : "; s+= cursor.Y;
      s += L"\ncursorOld x : "; s+= cursorOld.X;
      s += L"\ncursorOld y : "; s+= cursorOld.Y;
      s += L"\ncursorDelta x : "; s+= cursorDelta.X;
      s += L"\ncursorDelta y : "; s+= cursorDelta.Y;
      s += L"\ncamera orbit : "; s+= cameraOrbit;
      s += L"\ncamera angle : "; s+= cameraAngle;
      s += L"\nplayer compass : "; s+= playerCompass;
      s += L"\nplayer turn to : "; s+= playerTurnTo;
      debug_panel->setText(s.c_str());

      //////////////////
      // render scene //
      //////////////////

      driver->beginScene(true, true, SColor(0,120,120,120));

      myNode->render();
      smgr->drawAll();

      guienv->drawAll();

      driver->endScene();
   }

   device->drop();
   return 0;
}
What i update ?

I add rotation with W A S D but there are errors !!! it only works with W and S perfect but if you press A or D you move in that direction but the camera not! Anyone can help me ?
jrlago
Posts: 6
Joined: Sat May 04, 2013 8:36 am

Help with nodes

Post by jrlago »

Hello, first of all sorry for my english, and second thanks to all people that write in this forum, it has alot of really interesting information.

I have a problem with this very cool camera style... i hope someone can helpme.

I think that i have a good implementation but i have a hard problem.

This screenshot show original code in action:
Image

Aparently only have two cubes directed by mouse position... but really have 3 cubes, the first is inside of the second Cpivot1, Cpivot2, Cpivot3 and this first no have rotation.

After implement camera code in my proyect im load a .b3d model and dam! here is the problem:
Image

Code: Select all

 
player = smgr->getMesh("Modelos/Soldado/meshes/soldier_lod0.b3d");
    if (!player) { device->drop(); }
    player_node = smgr->addAnimatedMeshSceneNode(player, 0, -1, core::vector3df(playerX,playerY,playerZ));  
 
    player_node2 = smgr->addAnimatedMeshSceneNode(player, player_node, 1, core::vector3df(0,1,0));
 
        myCamera = smgr->addCameraSceneNode(player_node, sphericalXYZ(cameraOrbit,cameraAngle,cameraDistance), player_node->getPosition());
 
     // ...
      if(keys[KEY_KEY_W]){
      /// ...
       player_node->setPosition(core::vector3df(playerX,playerY,playerZ));   
       player_node2->setRotation(core::vector3df(0,playerCompass,0));
      }
 
player_node2 its a parent of player_node, he runs perfect, like cubes in the example. but i need kill player_node, or hide... but if i set player_node like SetVisible(false) all childs have visibility off and camera lost position.

How can i hide player_node? or some tip for search. code up and code down i invert many ours and i cant find the solution.

Thanks for your attention and your time.
gerdb
Posts: 194
Joined: Wed Dec 02, 2009 8:21 pm
Location: Dresden, Germany

Re: 3rd person camera #3,267 (C&C needed for newbie)

Post by gerdb »

Hi, i rewrote the code myself too to get rid of the globals ( reminded me too much of DarkBasic, that is a no go for C++ )

Also i get a strange behaviour when moving the window, the app simply closes the window, dont know why.

I use 1.8 svn on LinuxMint x64 (Ubuntu), does anybody have the same issue?

Code: Select all

 #include <iostream>
#include <irrlicht.h>
 
using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;
 
#pragma comment(lib, "Irrlicht.lib")
 
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CLASS : MyEventReceiver //////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
class MyEventReceiver : public IEventReceiver
{
private:
    IrrlichtDevice* Device;
 
public:
    // keyboard registry
    bool keys[irr::KEY_KEY_CODES_COUNT];
 
    // mouse registry
    bool mouseDownL;
    bool mouseDownM;
    bool mouseDownR;
    f32 lastWheelMovement;
    position2d<f32> cursor;
    position2d<f32> cursorOld;
    position2d<f32> cursorDelta;
 
    // camera registry
    f32 cameraOrbit;
    f32 cameraAngle;
    f32 cameraDistance;
    f32 cameraOrbitOld;
    f32 cameraAngleOld;
 
    // player registry
    f32 playerX;
    f32 playerY;
    f32 playerZ;
    f32 playerCompass;
    f32 playerTurnTo;
    f32 playerTurnSpeed;
    f32 playerMoveSpeed;
 
public:
    /// constructor
    MyEventReceiver( IrrlichtDevice* device )
        : Device(device), mouseDownL(false), mouseDownM(false), mouseDownR(false), lastWheelMovement(0.f)
        , cursor(0.f,0.f), cursorOld(0.f,0.f), cursorDelta(0.f,0.f), cameraOrbit(45.f), cameraAngle(0.f)
        , cameraDistance(30.f), cameraOrbitOld(0.f), cameraAngleOld(0.f), playerX(0.f), playerY(0.f), playerZ(0.f)
        , playerCompass(30.f), playerTurnTo(0.f), playerTurnSpeed(1.f), playerMoveSpeed(0.01f)
    {
        for(u32 i=0; i<KEY_KEY_CODES_COUNT; i++)
            keys[i] = false;
 
        if (Device)
            Device->setEventReceiver( this );
    }
 
    /// destructor
    virtual ~MyEventReceiver()
    {
        // empty
    }
 
    virtual bool OnEvent(const SEvent& event)
    {
        if(event.EventType == irr::EET_KEY_INPUT_EVENT)
        {
            keys[event.KeyInput.Key] = event.KeyInput.PressedDown;
            return false;
        }
 
        if (event.EventType == EET_MOUSE_INPUT_EVENT)
        {
            // left mouse button state check
            if(event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN)   mouseDownL = true;
            if(event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP)      mouseDownL = false;
 
            // middle mouse button state check
            if(event.MouseInput.Event == EMIE_MMOUSE_PRESSED_DOWN)   mouseDownM = true;
            if(event.MouseInput.Event == EMIE_MMOUSE_LEFT_UP)      mouseDownM = false;
 
            if(event.MouseInput.Event == EMIE_MOUSE_WHEEL)
            {
                cameraDistance -= event.MouseInput.Wheel * (cameraDistance / 20) * 2;
                if(cameraDistance < 10) cameraDistance = 10;
                if(cameraDistance > 100) cameraDistance = 100;
            }
 
            // right mouse button state check
            if(event.MouseInput.Event == EMIE_RMOUSE_PRESSED_DOWN)
            {
                mouseDownR = true;
                cursorOld.X = event.MouseInput.X;
                cursorOld.Y = event.MouseInput.Y;
                cursorDelta.X = 0;
                cursorDelta.Y = 0;
                cameraOrbitOld = cameraOrbit;
                cameraAngleOld = cameraAngle;
            }
            if(event.MouseInput.Event == EMIE_RMOUSE_LEFT_UP)      mouseDownR = false;
 
            // mouse move check
            if(event.MouseInput.Event == EMIE_MOUSE_MOVED)
            {
                // add condition that right mouse button be down
                if(mouseDownR == true)
                {
                    cursor.X = event.MouseInput.X;
                    cursor.Y = event.MouseInput.Y;
                    cursorDelta.X = cursor.X - cursorOld.X;
                    cursorDelta.Y = cursor.Y - cursorOld.Y;
                    if(cursorDelta.Y > 100) cursorDelta.Y = 100;
                    if(cursorDelta.Y < -100) cursorDelta.Y = -100;
                    cameraOrbit = (int)(cameraOrbitOld + cursorDelta.X) % 360;
                    cameraAngle = (int)(cameraAngleOld + cursorDelta.Y) % 360;
                    if(cameraAngle > 88) cameraAngle = 88;
                    if(cameraAngle < -88) cameraAngle = -88;
                }
 
            }
            return false;
 
        }
 
        return false;
    }
};
 
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CLASS : CMySampleSceneNode ///////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
class CMySampleSceneNode : public ISceneNode
{
 
private:
    static const s32 tileResolution = 32;   // how many segments to have down each edge of the tile
    static const s32 cellSize = 2;         // how many units square will each cell of the tile be?
 
    aabbox3d<f32> Box;     // [A]xis [A]ligned [B]ounding [B]ox in [3D] space
    S3DVertex Vertices[((tileResolution+1) * (tileResolution+1))]; // An array where each cell is of type S3DVertex
    u16 indices[(tileResolution * tileResolution) * 6];   // number of cells * 6 (each cell has two tris, each tri has 3 indices)
    SMaterial Material;    // A material object of type SMaterial
    IVideoDriver *driver;  // A link through to the driver object
 
public:
 
    /////////////////
    // constructor //
    /////////////////
 
    CMySampleSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id) : ISceneNode(parent, mgr, id)
    {
        // put link to videoDriver into already prepared var of type IVideoDriver
        IVideoDriver* driver = SceneManager->getVideoDriver();
 
        // set material settings
        Material.Wireframe = true;
        Material.Lighting = false;
        Material.BackfaceCulling = false;
 
        // create vertex objects in vertex array
 
        s32 vIndex = 0;
        for (f32 i=0; i<(tileResolution+1); i++)
        {
            for (f32 j=0; j<(tileResolution+1); j++)
            {
                Vertices[vIndex] = S3DVertex((j*cellSize),0,(i*cellSize), 0,0,1, SColor(255,0,255,255),j,i);
                // std :: cout << vIndex << ":" << j << "," << i << "\n";
                vIndex++;
            }
        }
 
        // reposition the bounding box to the first vertex
        Box.reset(Vertices[0].Pos);
 
        // add the defined vertices to Box
        for (s32 i=0; i<vIndex; i++)
            Box.addInternalPoint(Vertices[i].Pos);
 
        // setup indices
        s32   iIndex = 0;
 
        for (s32 i=0; i<tileResolution; i++)
        {
            for (s32 j=0; j<tileResolution; j++)
            {
 
                s32 currentVertex = (i*(tileResolution+1)) + j;
 
                indices[iIndex + 0] = currentVertex;
                indices[iIndex + 1] = currentVertex+1;
                indices[iIndex + 2] = currentVertex+tileResolution+1;
                indices[iIndex + 3] = currentVertex+1;
                indices[iIndex + 4] = currentVertex+tileResolution+2;
                indices[iIndex + 5] = currentVertex+tileResolution+1;
 
                iIndex = iIndex + 6;
 
            }
        }
 
    }
 
    /////////////////////////
    // OnRegisterSceneNode //
    /////////////////////////
 
    virtual void OnRegisterSceneNode()
    {
        if (IsVisible)
            ISceneNode::OnRegisterSceneNode();
    }
 
    ///////////////
    // OnAnimate //
    ///////////////
 
    virtual void OnAnimate(u32 timeMs)
    {
        ISceneNode::OnAnimate(timeMs);
    }
 
    ////////////
    // render //
    ////////////
 
    virtual void render()
    {
        IVideoDriver * driver = SceneManager->getVideoDriver();
        driver->setMaterial(Material);
        driver->setTransform(ETS_WORLD, AbsoluteTransformation);
 
        driver->drawIndexedTriangleList(&Vertices[0],(tileResolution+1) * (tileResolution+1),&indices[0],((tileResolution*tileResolution)*2));
    }
 
    ////////////////////
    // getBoundingBox //
    ////////////////////
 
    virtual const aabbox3d<f32>& getBoundingBox() const
    {
        return Box;
    }
 
    //////////////////////
    // getMaterialCount //
    //////////////////////
 
    virtual u32 getMaterialCount()
    {
        return 1;
    }
 
    /////////////////
    // getMaterial //
    /////////////////
 
    virtual SMaterial& getMaterial(s32 i)
    {
        return Material;
    }
};
 
 
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// FUNCTION : sphericalXYZ //////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
vector3df sphericalXYZ(f32 compassAngle, f32 elevationAngle, f32 radius)
{
 
    compassAngle = compassAngle * -1;
    elevationAngle = elevationAngle * -1;
 
    elevationAngle = elevationAngle + 90;
 
    f32 x = radius * cos(compassAngle * PI/180.0f ) * sin(elevationAngle * PI/180.0f );
    f32 z = radius * sin(compassAngle * PI/180.0f ) * sin(elevationAngle * PI/180.0f );
    f32 y = radius * cos(elevationAngle * PI/180.0f );
 
    vector3df result;
    result.X = x;
    result.Y = y;
    result.Z = z;
    return result;
}
 
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////        /////////////////////////////////////////////////////////////////////////////////////////////////////////////
////  MAIN  /////////////////////////////////////////////////////////////////////////////////////////////////////////////
////        /////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
int main()
{
    // setup key engine objects
    IrrlichtDevice* device = createDevice(EDT_OPENGL,dimension2d<u32>(800,600),24,false,false,false);
 
    if (!device)
    {
        return -1;
    }
 
    // setup event receiver
    MyEventReceiver rv(device);
 
    IVideoDriver* driver = device->getVideoDriver();
    ISceneManager* smgr = device->getSceneManager();
    IGUIEnvironment* guienv = device->getGUIEnvironment();
    ICursorControl* CursorControl = device->getCursorControl();
 
    // setup screen display elements
    device->setWindowCaption(L"Irrlicht Custom Scene Node!");
    IGUIStaticText* debug_panel = guienv->addStaticText(L"Hello World",rect<s32>(5, 5, 200, 200),false,true,0,-1,false);
 
    // setup the "player"
    ISceneNode* cPivot1 = smgr->addCubeSceneNode(0.5,0,-1,vector3df(rv.playerX,rv.playerY,rv.playerZ));
    cPivot1->setMaterialTexture(0,driver->getTexture("media/wall.bmp"));
    cPivot1->setMaterialFlag(video::EMF_LIGHTING, false);
 
    ISceneNode* cPivot2 = smgr->addCubeSceneNode(2,cPivot1,-1,vector3df(0,1,0));
    cPivot2->setMaterialTexture(0,driver->getTexture("media/wall.bmp"));
    cPivot2->setMaterialFlag(video::EMF_LIGHTING, false);
 
    ISceneNode* cPivot3 = smgr->addCubeSceneNode(1,cPivot2,-1,vector3df(0,0,2));
    cPivot3->setMaterialTexture(0,driver->getTexture("media/wall.bmp"));
    cPivot3->setMaterialFlag(video::EMF_LIGHTING, false);
 
    // setup the camera
    ICameraSceneNode* myCamera = smgr->addCameraSceneNode(cPivot1, sphericalXYZ(rv.cameraOrbit,rv.cameraAngle,rv.cameraDistance), cPivot1->getPosition());
 
    // create references to our custom nodes
    CMySampleSceneNode* myNode = new CMySampleSceneNode(smgr->getRootSceneNode(),smgr,1);
    myNode->setPosition(vector3df(0,0,0));
 
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // DEVICE : main loop ///////////////////////////////////////////////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
 
 
    while(device->run() && device->isWindowActive())
    {
 
        /////////////////////////
        // keyboard management //
        /////////////////////////
 
        // system keys
        if(rv.keys[KEY_ESCAPE])
        {
            device->closeDevice();
        }
 
        // player keys
 
        if(rv.keys[KEY_KEY_W])
        {
 
            // player movement vector
            vector3df playerStep = sphericalXYZ(rv.cameraOrbit,0.f,rv.playerMoveSpeed);
            rv.playerX -= playerStep.X;
            rv.playerY -= playerStep.Y;
            rv.playerZ -= playerStep.Z;
 
            // player rotation brain torture
 
            rv.playerTurnTo = rv.cameraOrbit - 90.f;
            if(rv.playerTurnTo < 0.f) rv.playerTurnTo += 360.f;
            if(rv.playerTurnTo >= 360.f) rv.playerTurnTo -= 360.f;
 
            if(rv.playerCompass < 0.f) rv.playerCompass = rv.playerCompass + 360.f;
            if(rv.playerCompass >= 360.f) rv.playerCompass = rv.playerCompass - 360.f;
 
            f32 playerTurnDir = 0.f;
            f32 playerTurnDelta = 0.f;
 
            if(rv.playerCompass > rv.playerTurnTo)
            {
                if(rv.playerCompass - rv.playerTurnTo < 180.f)
                {
                    playerTurnDir = -1.f;
                    playerTurnDelta = rv.playerCompass - rv.playerTurnTo;
                }
                else
                {
                    playerTurnDir = 1.f;
                    playerTurnDelta = (360.f - rv.playerCompass) + rv.playerTurnTo;
                }
            }
 
            if(rv.playerCompass < rv.playerTurnTo)
            {
                if(rv.playerTurnTo - rv.playerCompass < 180.f)
                {
                    playerTurnDir = 1;
                    playerTurnDelta = rv.playerTurnTo - rv.playerCompass;
                }
                else
                {
                    playerTurnDir = -1;
                    playerTurnDelta = (360.f - rv.playerTurnTo) + rv.playerCompass;
                }
            }
 
            f32 playerTurnAmount;
 
            if(playerTurnDelta < rv.playerTurnSpeed)
            {
                playerTurnAmount = playerTurnDelta;
            }
            else
            {
                playerTurnAmount = rv.playerTurnSpeed;
            }
            rv.playerCompass += (playerTurnAmount * playerTurnDir);
 
 
            cPivot1->setPosition(vector3df(rv.playerX,rv.playerY,rv.playerZ));
            cPivot2->setRotation(vector3df(0,rv.playerCompass,0));
            myCamera->setTarget(vector3df(rv.playerX,rv.playerY,rv.playerZ));
        }
 
        // orient camera
        myCamera->setPosition(sphericalXYZ(rv.cameraOrbit,rv.cameraAngle,rv.cameraDistance));
 
        // debug display
        stringw txt(L"FPS : ");
        txt += driver->getFPS();
        txt += L"\n";
        txt += L"left mouse button : ";
        txt += rv.mouseDownL;
        txt += L"\n";
        txt += L"middle mouse button : ";
        txt += rv.mouseDownM;
        txt += L"\n";
        txt += L"right mouse button : ";
        txt += rv.mouseDownR;
        txt += L"\n";
        txt += L"last wheel movement : ";
        txt += rv.lastWheelMovement;
        txt += L"\n";
        txt += L"cursor x : ";
        txt += rv.cursor.X;
        txt += L"\n";
        txt += L"cursor y : ";
        txt += rv.cursor.Y;
        txt += L"\n";
        txt += L"cursorOld x : ";
        txt += rv.cursorOld.X;
        txt += L"\n";
        txt += L"cursorOld y : ";
        txt += rv.cursorOld.Y;
        txt += L"\n";
        txt += L"cursorDelta x : ";
        txt += rv.cursorDelta.X;
        txt += L"\n";
        txt += L"cursorDelta y : ";
        txt += rv.cursorDelta.Y;
        txt += L"\n";
        txt += L"camera orbit : ";
        txt += rv.cameraOrbit;
        txt += L"\n";
        txt += L"camera angle : ";
        txt += rv.cameraAngle;
        txt += L"\n";
        txt += L"player compass : ";
        txt += rv.playerCompass;
        txt += L"\n";
        txt += L"player turn to : ";
        txt += rv.playerTurnTo;
        txt += L"\n";
 
        debug_panel->setText( txt.c_str());
 
        //////////////////
        // render scene //
        //////////////////
 
        driver->beginScene(true, true, SColor(0,120,120,120));
 
        myNode->render();
        smgr->drawAll();
 
        guienv->drawAll();
 
        driver->endScene();
    }
 
    device->drop();
    return 0;
}
 
 
have fun
jrlago
Posts: 6
Joined: Sat May 04, 2013 8:36 am

Re: 3rd person camera #3,267 (C&C needed for newbie)

Post by jrlago »

hello, my complier is vc10, program window run fine when move... i don't know...

to show better the problem that i have:

Code: Select all

// setup the "player"
    ISceneNode* cPivot1 = smgr->addCubeSceneNode(0.5,0,-1,vector3df(rv.playerX,rv.playerY,rv.playerZ)); 
if you change scale "0.5" to for example "2"... main cube cpivot1 no rotate.

Code: Select all

    ISceneNode* cPivot1 = smgr->addCubeSceneNode(2.0,0,-1,vector3df(rv.playerX,rv.playerY,rv.playerZ));
do you know how i can make rotate it or hide...
thanks for your reply
jrlago
Posts: 6
Joined: Sat May 04, 2013 8:36 am

Re: 3rd person camera #3,267 (C&C needed for newbie)

Post by jrlago »

solved, i was offuscated... smgr->addEmptySceneNode(); ftw!!! ;)
Post Reply