well, im receiving some mp with questions about a 3rd person caméra i started in the "beginners help" forum and since the questions are often about things i solved with help of some people or found out, i just share my code and project as it is for now.
its really not finished :
-i dont use external class.
-the zoom is kinda bugued
-there is still the problem about terrain collision i didnt fixed yet (through there is some fix here for exemple)
-no animation yet either (i was working on it when i stopped..)
what does it do :
-load a terrain and spawn a player
-the mouse X axis control the player rotation
-the mouse Y axis control the camera hightness kinda
-the mouse wheel zoom in and out (or is supposed to do so ^^)
-Z,Q,S,D move the player (foward, backward and strafe right and left)
-space for jumping (that help to avoid the terrain bug^when testing..)
-a little black window with FPS.
that's it i think.
i repeat myself but its really not a finished work but maybe that will help people that are bad programmer like me to understand some stuff.
be sure that when all the stuff i want to do are done, i will upload it all for the community but im more into modeling right now or other stuff like mysql so for now i just share that to answer some question i receive in mp.
feel free to use it as you like or to improve it.
dont expect me to answer question about it because if i started it in the 'beginners help" forum, its because im really a beginner...
anyway :
here is my full c::b project so you can take a look (irrlicht 1.4)
update* http://www.fileden.com/files/2006/6/21/80755/Demo3.zip
a little messed up like the first one anyway lol but work with irrlicht 1.7.3
update*2 http://www.fileden.com/files/2006/6/21/ ... _start.zip
it say newton but dont actualy use it, the code is more clean in this version.
beware that in this version i dont use any collision. its actualy my starting point to then use newton as a physic engine if i get it to work someday..
and the full code : (outdated)
(some stuff are in french, sorry for that)
Code: Select all
#include <irrlicht.h>
#include <iostream>
using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;
#pragma comment(lib, "Irrlicht.lib")
//---> DEFINITION <---///////////////////////////////////////////////////////////////////////////
bool keys[KEY_KEY_CODES_COUNT];
position2d<f32> cursor; //position du curseur de la souris
position2d<s32> ScreenCenter; //centre de l'ecran bien que le curseur soit pas d'accord avec ça lol
f32 RotationSpeed= 1.0; //determine la vitesse de rotation du joueur.
f32 playerSpeed= 0.8; //vitesse du joueur
vector3df playerRot; //rotation du joueur
vector3df playerPos; //position du joueur
vector3df cameraPos; //position de la camera
f32 cameraDistance= 100;
///////////////////////////////////////////////////////////////////////////////////////////////////
//---> EVEN RECEIVER <---////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
class MyEventReceiver: public IEventReceiver
{
public: virtual bool OnEvent(const SEvent& event)
{
if (event.EventType == EET_MOUSE_INPUT_EVENT)
{
cursor.X = event.MouseInput.X;
cursor.Y = event.MouseInput.Y;
}
if(event.MouseInput.Event == EMIE_MOUSE_WHEEL)
{
cameraDistance += -event.MouseInput.Wheel* (cameraDistance / 20) * 3;
if(cameraDistance < 10) cameraDistance = 10;
}
if(event.EventType == EET_KEY_INPUT_EVENT)
{
keys[event.KeyInput.Key] = event.KeyInput.PressedDown;
return false;
}
return false;
}
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////// //////////////////////////////////////////////////////
////////////////////////////// MAIN //////////////////////////////////////////////////////
////////////////////////////// //////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////
int main()
{
MyEventReceiver receiver; //initialisation du receiver
IrrlichtDevice* device = createDevice(
EDT_OPENGL, //EDT_SOFTWARE, EDT_NULL, EDT_DIRECT3D8, EDT_DIRECT3D9, EDT_OPENGL
dimension2d<s32>(800, 600),
32,
true, //fullscreen ?
false, false, //?
&receiver); //node receiver
device->setEventReceiver(&receiver); // " " same
if (device == 0)return 1; //exit if creation failed
IVideoDriver* driver = device->getVideoDriver();
ISceneManager* smgr = device->getSceneManager();
ICursorControl* myCursor = device->getCursorControl();
///////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////// //////////////////////////////////////////////////////
////////////////////////////// TERRAIN //////////////////////////////////////////////////////
////////////////////////////// //////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////
ITerrainSceneNode* terrain = smgr->addTerrainSceneNode(
"heightmap/F18.bmp", //heightmap
0, //parent
-1, //ID
vector3df(0.f, 0.f, 0.f), //position
vector3df(0.f, 0.f, 0.f), //rotaton ?
vector3df(500,33, 500), //scaling de la heightmap / taille
SColor(255, 255, 255, 250), //couleur des vertex
5, //detail du node
ETPS_33, //patchsize wth ??
3, //smoothfactor
false); //add terrain node even with empty heightmap
terrain->setMaterialFlag(EMF_LIGHTING, false); //lumière ?
terrain->setMaterialTexture(0, driver->getTexture("terrain/herbe.jpg")); //texture
terrain->setMaterialType(EMT_DETAIL_MAP);
terrain->scaleTexture(600, 48000); //scaling de la texture
//SKYBOX
driver->setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, false); //true ?
smgr->addSkyBoxSceneNode(
driver->getTexture("skybox/siege_up.jpg"), //up
driver->getTexture("skybox/siege_dn.jpg"), //down
driver->getTexture("skybox/siege_lf.jpg"), //left
driver->getTexture("skybox/siege_rt.jpg"), //right
driver->getTexture("skybox/siege_bk.jpg"), //back
driver->getTexture("skybox/siege_ft.jpg")); //front
driver->setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, true); //?
///////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////// ////////////////////////////////////////////////
////////////////////////////// TRIANGLE SELECTOR ////////////////////////////////////////////////
////////////////////////////// ////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////
ISceneNode* terrainNode = 0;
if(terrain)
terrainNode = smgr->addMeshSceneNode(terrain->getMesh());
ITriangleSelector* selector = 0;
if(terrainNode)
{
terrainNode->setPosition(vector3df(-1370,-130,-1400));
selector = smgr->createTerrainTriangleSelector(terrain, 0);
terrainNode->setTriangleSelector(selector);
selector->drop();
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////// ////////////////////////////////////////////////////
////////////////////////////// PLAYER ////////////////////////////////////////////////////
////////////////////////////// ////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////
for(int x=0; x<irr::KEY_KEY_CODES_COUNT; x++) keys[x] = false; //key count
ISceneNode* playerNode = smgr->addEmptySceneNode(); //3rd person
playerNode->setPosition(vector3df(19000, 6000, 37000));
IAnimatedMesh* playerMesh= smgr->getMesh("models/faerie.md2"); //model
IAnimatedMeshSceneNode* visualNode= smgr->addAnimatedMeshSceneNode(playerMesh, playerNode);
if (visualNode)
{
visualNode->setMaterialFlag(EMF_LIGHTING, false);
visualNode->setFrameLoop(0, 159); // 0,310
visualNode->setAnimationSpeed(35);
visualNode->setMaterialTexture(0, driver->getTexture("models/faerie.bmp")); //texture
visualNode->setRotation(core::vector3df(0,90,0)); //player dos a la caméra
}
//COLLISION PLAYER
const aabbox3df& box= playerNode->getBoundingBox();
const f32 height= (box.MaxEdge.Y - box.MinEdge.Y)/ 2.f;
const f32 verticalOffset= -box.MinEdge.Y - box.MaxEdge.Y;
const f32 waist= max_(box.MaxEdge.X - box.MinEdge.X, box.MaxEdge.Z - box.MinEdge.Z)/ 2.f;
ISceneNodeAnimator* anim= smgr->createCollisionResponseAnimator
(
selector, //triangle selector
playerNode, //scene node
vector3df(30,25,30), //ellipsoidRadius //position du perso 30;60;30
vector3df(0,-3,0), //gravity
vector3df(0,0,0), //ellipsoidTranslation
0.0005f //slidingValue
);
playerNode->addAnimator(anim);
anim->drop();
///////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////// ////////////////////////////////////////////////////
////////////////////////////// ANIMATION ////////////////////////////////////////////////////
////////////////////////////// ////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////
bool STAND = false;
if(STAND == true)
{
visualNode->setFrameLoop(0, 159);
}
bool RUN = false;
if(RUN == true)
{
visualNode->setFrameLoop(160, 183);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////// ////////////////////////////////////////////////////
////////////////////////////// CAMERA ////////////////////////////////////////////////////
////////////////////////////// ////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////
ICameraSceneNode* myCamera =
smgr->addCameraSceneNode(
playerNode, //parent
vector3df(0,75,100), //angleX, angleH, distance
playerNode->getPosition(), //vector3df(0,0,0), //look at...
-1); //ID
myCamera->setFarValue(80000); //drawing distance
///////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////// ////////////////////////////////////////////////////
////////////////////////////// CURSOR ////////////////////////////////////////////////////
////////////////////////////// ////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////
myCursor->setVisible(false);
///////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////// ////////////////////////////////////////////////////
////////////////////////////// RENDERING ////////////////////////////////////////////////////
////////////////////////////// ////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////
IGUIEnvironment* guienv = device->getGUIEnvironment();
IGUIStaticText* debug_panel = guienv->addStaticText(L"",rect<s32>(15, 15, 50, 30),true,true,0,-1,false); //100 : L - h
while(device->run())
{
driver->beginScene(true, true, SColor(0,200,200,200));
//--------------------------------------------------------------------------------------------------------
ScreenCenter.X= 400;
ScreenCenter.Y= 300;
playerRot.X=0;
playerRot.Y=playerNode->getRotation().Y+RotationSpeed*(ScreenCenter.X-cursor.X)*-1;
playerRot.Z=0;
cameraPos.X=0;
cameraPos.Y=myCamera->getPosition().Y+/*RotationSpeed*/(ScreenCenter.Y-cursor.Y)*-1;
cameraPos.Z=cameraDistance;//100;
playerPos= playerNode->getPosition();
if(keys[KEY_KEY_S]) //moving back
{
f32 roty_rad = playerRot.Y * PI / 180; // convert to radians
playerPos.Z += playerSpeed * cos(roty_rad);
playerPos.X += playerSpeed * sin(roty_rad);
}
if(keys[KEY_KEY_Z]) //moving foward
{
f32 roty_rad = playerRot.Y * PI / 180; // convert to radians
playerPos.Z -= playerSpeed * cos(roty_rad);
playerPos.X -= playerSpeed * sin(roty_rad);
}
if(keys[KEY_KEY_D]) //strafing right
{
f32 roty_rad = playerRot.Y;
roty_rad -= 90;
roty_rad *= PI / 180;
playerPos.Z += playerSpeed * cos(roty_rad);
playerPos.X += playerSpeed * sin(roty_rad);
}
if(keys[KEY_KEY_Q]) //strafing left
{
f32 roty_rad = playerRot.Y;
roty_rad += 90;
roty_rad *= PI / 180;
playerPos.Z += playerSpeed * cos(roty_rad);
playerPos.X += playerSpeed * sin(roty_rad);
}
if(keys[KEY_SPACE])playerPos.Y = playerPos.Y + 3.5f;
//--------------------------------------------------------------------------------------------------------
myCamera->setTarget(playerNode->getPosition()); //refresh caméra target
myCamera->setPosition(cameraPos);
playerNode->setPosition(playerPos);
playerNode->setRotation(playerRot);
myCursor->setPosition(ScreenCenter); //remise a zéro du cursor
smgr->drawAll();
stringw framerate = driver->getFPS();
debug_panel->setText(stringw(framerate).c_str()); //framerate
debug_panel->setOverrideColor(SColor(255,255,255,255));
debug_panel->setBackgroundColor(SColor(255,0,0,0));
device->getGUIEnvironment()->drawAll();
driver->endScene();
}
device->drop();
return 0;
}