Hướng 
dẫn dùng CameraRPG
1) Class quản lý bàn phím + mouse ảo
Hôm 
nay mình Up lên tệp tin cKeyBoard.h dùng để quản lý bàn phím ảo. 
Cách dùng 
của nó sẽ được cụ thể trong tệp tin main.cpp phần dùng CameraRPG
////////////////
#include 
 
using namespace irr; 
extern bool 
keys[KEY_KEY_CODES_COUNT ]; 
class TKeyClass : public IEventReceiver 
{ 
public: 
TKeyClass() 
{ 
for (int i=0;ikeys[i]=0; 
} 
~TKeyClass(){}; 
virtual bool OnEvent(SEvent event) 
{ 
if(event.EventType == irr::EET_KEY_INPUT_EVENT) 
{ 
keys[event.KeyInput.Key] = event.KeyInput.PressedDown; 
return false; 
} 
if (event.EventType==irr::EET_MOUSE_INPUT_EVENT) 
{ 
keys[irr::KEY_LBUTTON]= (event.MouseInput.Event==EMIE_LMOUSE_PRESSED_DOWN) ; 
keys[irr::KEY_RBUTTON]= (event.MouseInput.Event==EMIE_RMOUSE_PRESSED_DOWN) ; 
//keys[irr::KEY_XBUTTON1]=(event.MouseInput.Event==EMIE_MOUSE_MOVED); 
//keys[irr::KEY_MBUTTON]= (event.MouseInput.Event==EMIE_MOUSE_WHEEL); 
return false; 
} 
return false; 
} 
}; 
2)Tệp tin main.cpp 
dùng để thực thi hướng dẫn tạo CameraRPG 
/////////////////////////
/* 
This tutorial will briefly show how to use the 
terrain renderer of Irrlicht. It will also 
show the terrain renderer 
triangle selector to be able to do collision detection with 
terrain.
Note that the Terrain Renderer in Irrlicht is 
based on Spintz' GeoMipMapSceneNode, lots 
of thanks go to him. 
DeusXL 
provided a new elegant simple solution for building larger area on small 
heightmaps 
-> terrain smoothing. 
In the beginning there is nothing 
special. We include the needed header files and create 
an event listener to 
listen if the user presses the 'W' key so we can switch to wireframe 
mode 
and if he presses 'D' we toggle to material between solid and detail mapped. 
*/ 
#include  
#include "cKeyBoard.h" 
using 
namespace irr; 
using namespace core; 
using namespace scene; 
using 
namespace video; 
using namespace io; 
using namespace gui;
#pragma comment(lib, "Irrlicht.lib") 
bool 
keys[KEY_KEY_CODES_COUNT ]; 
int cZoom = 80; 
int cOffset = 
180,cNewOffset=180; 
float cUpdir = -10; 
int cRotation = 0; 
int 
oldScore =0; 
bool isActive = false; 
ICameraSceneNode* camera; 
IAnimatedMeshSceneNode* character; 
/* 
The start of the main function 
starts like in most other example. We ask the user 
for the desired renderer 
and start it up. 
*/ 
int main() 
{ 
// let user select driver type 
video::E_DRIVER_TYPE driverType = video::EDT_DIRECT3D9; 
IrrlichtDevice* 
device = createDevice(driverType, core::dimension2d(640, 480)); 
if (device == 0) 
return 1; // could not create selected driver. 
/* 
First, we add standard stuff to the scene: A nice irrlicht engine 
logo, 
a small help text, a user controlled camera, and we disable 
the mouse 
cursor. 
*/ 
video::IVideoDriver* driver = device->getVideoDriver(); 
scene::ISceneManager* smgr = device->getSceneManager(); 
gui::IGUIEnvironment* env = device->getGUIEnvironment();
driver->setTextureCreationFlag(video::ETCF_ALWAYS_32_BIT, 
true);
// add irrlicht logo 
env->addImage(driver->getTexture("../../irrlicht-1.3.1/media/irrlichtlogo2.png"), 
core::position2d(10,10));
//set other font 
env->getSkin()->setFont(env->getFont("../../irrlicht-1.3.1/media/fontlucida.png"));
// add some help text 
gui::IGUIStaticText* 
text = env->addStaticText( 
L"Press 'W' to change wireframe mode\nPress 
'D' to toggle detail map\nPress (Up,Left,Right) arrow to cotrol character", 
core::rect(10,420,300,475), true, true, 0, -1, true);
// add camera 
camera = 
smgr->addCameraSceneNode();
camera->setPosition(core::vector3df(1900*2,255*2,3700*2)); 
camera->setTarget(core::vector3df(2397*2,343*2,2700*2)); 
camera->setFarValue(12000.0f); 
//add main character 
character = 
smgr->addAnimatedMeshSceneNode( 
smgr->getMesh("../../irrlicht-1.3.1/media/faerie.md2"),0,-1, 
vector3df(2397*2,343*5,2700*2),vector3df(0, 0, 0),vector3df(1.0f, 1.0f, 
1.0f),false); 
character->setMaterialTexture(0,driver->getTexture("../../irrlicht-1.3.1/media/Faerie5.bmp")); 
character->setMaterialFlag(video::EMF_LIGHTING, false); 
character->setMD2Animation(EMAT_STAND); 
// disable mouse cursor 
//device->getCursorControl()->setVisible(false); 
/* 
Here 
comes the terrain renderer scene node: We add it just like any 
other scene 
node to the scene using ISceneManager::addTerrainSceneNode(). 
The only 
parameter we use is a file name to the heightmap we use. A heightmap 
is 
simply a gray scale texture. The terrain renderer loads it and creates 
the 
3D terrain from it. 
To make the terrain look more big, we change the scale 
factor of it to (40, 4.4, 40). 
Because we don't have any dynamic lights in 
the scene, we switch off the lighting, 
and we set the file 
terrain-texture.jpg as texture for the terrain and 
detailmap3.jpg as second 
texture, called detail map. At last, we set 
the scale values for the 
texture: The first texture will be repeated only one time over 
the whole 
terrain, and the second one (detail map) 20 times. 
*/
// add terrain scene node 
scene::ITerrainSceneNode* terrain = smgr->addTerrainSceneNode( 
"../../irrlicht-1.3.1/media/terrain-heightmap.bmp", 
0, // parent node 
-1, // node id 
core::vector3df(0.f, 0.f, 0.f), // position 
core::vector3df(0.f, 0.f, 0.f), // rotation 
core::vector3df(40.f, 4.4f, 
40.f), // scale 
video::SColor ( 255, 255, 255, 255 ), // vertexColor, 
5, 
// maxLOD 
scene::ETPS_17, // patchSize 
4 // smoothFactor 
);
terrain->setMaterialFlag(video::EMF_LIGHTING, 
false);
terrain->setMaterialTexture(1, 
driver->getTexture("../../irrlicht-1.3.1/media/terrain-texture.jpg")); 
terrain->setMaterialTexture(0, 
driver->getTexture("../../irrlicht-1.3.1/media/detailmap3.jpg")); 
terrain->setMaterialType(video::EMT_DETAIL_MAP);
terrain->scaleTexture(10.0f, 1.0f); 
//terrain->setDebugDataVisible ( true );
/* 
To be able to do collision with the 
terrain, we create a triangle selector. 
If you want to know what triangle 
selectors do, just take a look into the 
collision tutorial. The terrain 
triangle selector works together with the 
terrain. To demonstrate this, we 
create a collision response animator 
and attach it to the camera, so that 
the camera will not be able to fly 
through the terrain. 
*/
// create triangle selector for the terrain 
scene::ITriangleSelector* selector 
= 
smgr->createTerrainTriangleSelector(terrain, 0); 
terrain->setTriangleSelector(selector); 
selector->drop();
// create collision response animator and 
attach it to the main character 
aabbox3df box = 
character->getBoundingBox(); 
vector3df radius = box.MaxEdge; 
radius.X 
*=10; radius.Y *=4; radius.Z *=10; 
scene::ISceneNodeAnimator* anim = 
smgr->createCollisionResponseAnimator( 
selector, character,radius, 
core::vector3df(0,-1.0f,0), 
radius); 
character->addAnimator(anim); 
anim->drop(); 
/* 
To make the 
user be able to switch between normal and wireframe mode, we create 
an 
instance of the event reciever from above and let Irrlicht know about it. In 
addition, we add the skybox which we already used in lots of Irrlicht 
examples. 
*/ 
// create event receiver 
TKeyClass receiver; 
device->setEventReceiver(&receiver); 
// create skybox 
driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false); 
smgr->addSkyBoxSceneNode( 
driver->getTexture("../../irrlicht-1.3.1/media/irrlicht2_up.jpg"), 
driver->getTexture("../../irrlicht-1.3.1/media/irrlicht2_dn.jpg"), 
driver->getTexture("../../irrlicht-1.3.1/media/irrlicht2_lf.jpg"), 
driver->getTexture("../../irrlicht-1.3.1/media/irrlicht2_rt.jpg"), 
driver->getTexture("../../irrlicht-1.3.1/media/irrlicht2_ft.jpg"), 
driver->getTexture("../../irrlicht-1.3.1/media/irrlicht2_bk.jpg")); 
driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, true); 
/* 
That's it, draw everything. Now you know how to use terrain in Irrlicht. 
*/ 
///////////- khëi t¹o biÕn Camera ///////////// 
cZoom =80; 
cOffset = 0; 
cUpdir =0; 
/////////////////////// 
int lastFPS = 
-1; 
while(device->run()) 
if (device->isWindowActive()) 
{ 
driver->beginScene(true, true, 0 ); 
smgr->drawAll(); 
env->drawAll(); 
driver->endScene(); 
//////////// - RPG camera 
vector3df p =character->getPosition();//box.getCenter(); 
vector3df r 
= character->getRotation(); 
if (smgr->getActiveCamera()==camera) 
{ 
camera->setTarget(core::vector3df(p.X,p.Y+cUpdir,p.Z)); 
camera->setPosition(core::vector3df(( -1 * cZoom * cosf( -1 * ( r.Y + 
cRotation +cOffset ) *core::DEGTORAD ) ) + p.X, 
p.Y+50,( -1 * cZoom * sinf( 
-1 * ( r.Y+cRotation + cOffset ) * core::DEGTORAD ) ) + p.Z)); 
} 
/////////// 
if (keys[KEY_KEY_W]) 
{ 
terrain->setMaterialFlag(video::EMF_WIREFRAME, 
!terrain->getMaterial(0).Wireframe); 
terrain->setMaterialFlag(video::EMF_POINTCLOUD, false); 
keys[KEY_KEY_W] = false; 
} 
if (keys[KEY_KEY_P]) 
{ 
terrain->setMaterialFlag(video::EMF_POINTCLOUD, 
!terrain->getMaterial(0).PointCloud); 
terrain->setMaterialFlag(video::EMF_WIREFRAME, false); 
keys[KEY_KEY_P] = false; 
} 
if (keys[KEY_KEY_D]) 
{ 
terrain->setMaterialType(terrain->getMaterial(0).MaterialType == 
video::EMT_SOLID ? 
video::EMT_DETAIL_MAP : video::EMT_SOLID); 
keys[KEY_KEY_D] = false; 
} 
if (keys[KEY_ESCAPE]) 
device->closeDevice(); 
//////////////// - Control the Character - 
////////////// 
if (keys[KEY_UP]) // di chuyen toi 
{ 
p.X = p.X + ( 
cos((r.Y+cRotation) * core::DEGTORAD )*10.0f ); 
p.Z = p.Z - ( 
sin((r.Y+cRotation) * core::DEGTORAD )*10.0f ); 
character->setPosition(p); 
if (!isActive) 
{ 
character->setMD2Animation(EMAT_RUN );//di toi 
isActive = true; //cho 
biet nhan vat dang hoat dong 
} 
} 
if (keys[KEY_LEFT]) // queo trai 
{ 
int goc = 1; 
if (r.Y>goc) r.Y -= goc; 
else r.Y =360; 
character->setRotation(r); 
} 
if (keys[KEY_RIGHT]) // queo phai 
{ 
int goc = 1; 
if (r.Y<360-goc br="br" goc="goc" r.y="r.y">else r.Y =0; 
character->setRotation(r); 
} 
//kiem tra phim bam 
bool 
keypressed = false; 
for (int i=0;iif ((!keypressed)&&(isActive)) //neu khong co 
phim bam 
{ 
character->setMD2Animation(EMAT_STAND); 
isActive = 
false; 
} 
//keys[KEY_UP] = false; 
/////////////////////////////////////////////////////////////////////// 
// display frames per second in window title 
int fps = 
driver->getFPS(); 
if (lastFPS != fps) 
{ 
core::stringw str = 
L"Terrain Renderer - Irrlicht Engine ["; 
str += driver->getName(); 
str += "] FPS:"; 
str += fps; 
// Also print terrain height of current 
camera position 
// We can use camera position because terrain is located at 
coordinate origin 
str += " Height: "; 
str += 
terrain->getHeight(camera->getAbsolutePosition().X, 
camera->getAbsolutePosition().Z); 
device->setWindowCaption(str.c_str()); 
lastFPS = fps; 
} 
} 
device->drop(); 
return 0; 
}360-goc>
3) Các bạn tự tạo 
project và chỉnh lại các đường dẫn cho phù hợp nhé. Chúc các bạn thành 
công!