@
blAaarg dude, you have a gift of explaining
![Smile :)](./images/smilies/icon_smile.gif)
I particularly enjoyed that horse and carrot example (do horses eat carrots though?.. humn...) A bundle of thanks... no.. actually... a huge, gigantic, collosal bundle of thanks!
![Smile :)](./images/smilies/icon_smile.gif)
(now figure out where you gonna put it
![Wink :wink:](./images/smilies/icon_wink.gif)
)
ok, so.. using your tips, I managed to do the forward/backward movement correctly.
Code: Select all
if(receiver.IsKeyDown(KEY_UP))
{
camPosition += camMovement;
camTarget += camMovement;
camera->setPosition(camPosition);
camera->setTarget(camTarget);
}
else if(receiver.IsKeyDown(KEY_DOWN))
{
camPosition -= camMovement;
camTarget -= camMovement;
camera->setPosition(camPosition);
camera->setTarget(camTarget);
}
Next step was to implement rotation of the camera, which I attempted to do as follows:
Code: Select all
if(receiver.IsKeyDown(KEY_LEFT))
{
camRotation.Y -= ROTATION_SPEED * frameDeltaTime;
camera->setRotation(camRotation);
}
else if(receiver.IsKeyDown(KEY_RIGHT))
{
camRotation.Y += ROTATION_SPEED * frameDeltaTime;
camera->setRotation(camRotation);
}
and it actually worked ( keeping camera->bindTargetAndRotation(true);
)
So, now I could move forward/backward as well as rotate. But the problem was, if I'm moving, I could'nt rotate and vice versa. I wanted to be able to rotate
while moving, so I could just choose which way to go using only 4 arrow keys and nothing else.
So I added a little trick by defining two boolean variables inside the game loop :
Code: Select all
bool moving = 0;
bool rotating = 0;
and then modifying the above code like this:
Code: Select all
if(receiver.IsKeyDown(KEY_LEFT))
{
if(!moving){
camRotation.Y -= ROTATION_SPEED * frameDeltaTime;
rotating= true;
camera->setRotation(camRotation);
}
}
else if(receiver.IsKeyDown(KEY_RIGHT))
{
if(!moving){
camRotation.Y += ROTATION_SPEED * frameDeltaTime;
rotating= true;
camera->setRotation(camRotation);
}
}
if(receiver.IsKeyDown(KEY_UP))
{
if(!rotating){
camPosition += camMovement;
camTarget += camMovement;
moving = true;
camera->setPosition(camPosition);
camera->setTarget(camTarget);
}
}
else if(receiver.IsKeyDown(KEY_DOWN))
{
if(!rotating){
camPosition -= camMovement;
camTarget -= camMovement;
moving = true;
camera->setPosition(camPosition);
camera->setTarget(camTarget);
}
}
This has the net effect that while I am moving, I can rotate left or right by a single press of of a key and as soon as I unpress the key I start moving again.
![Very Happy :D](./images/smilies/icon_biggrin.gif)
This is probably not the right way of achieveing this, so if someone can advise a better way I'd be grateful.
Notice though that I have flipped the code-blocks of checking LEFT/ RIGHT with UP/DOWN. If you check the UP/DOWN
first, this would have the effect that you can move while rotating, but in this way, I can rotate while moving
I hae also added collision detection so its possible to actually move around the map without going through the walls.
There is however a wierd problem with this. If you aremoving downwards, i.e. if for example you are moving down the stairs and you try to rotate at the same time, boom, the camera falls on its face
![Smile :)](./images/smilies/icon_smile.gif)
Somehow, it seems if the camera position is changing vertically and you try to rotate, it's target changes towards the direction it was falling. Can't figure out why is that or how to correct it. Any ideas are welcome.
Here's the completye code. If you run it then go up the stairs and while comming down the stairs try to rotate, you'd see what I mean. (hehehe, while writing this, I realized that if you were to try doing that in real life, i.e. try to "rotate" while climbing down the stairs, you'd most probably end up on your face too, so the camera is just immitaing real-life
![Very Happy :D](./images/smilies/icon_biggrin.gif)
ROFL)
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;
#ifdef _IRR_WINDOWS_
#pragma comment(lib, "Irrlicht.lib")
#pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")
#endif
float cam_rotate=0;
float node_rotate=0;
// event reciever
class MyEventReceiver : public IEventReceiver
{
public:
// This is the one method that we have to implement
virtual bool OnEvent(const SEvent& event)
{
// Remember whether each key is down or up
if (event.EventType == irr::EET_KEY_INPUT_EVENT)
KeyIsDown[event.KeyInput.Key] = event.KeyInput.PressedDown;
return false;
}
// This is used to check whether a key is being held down
virtual bool IsKeyDown(EKEY_CODE keyCode) const
{
return KeyIsDown[keyCode];
}
MyEventReceiver()
{
for (u32 i=0; i<KEY_KEY_CODES_COUNT; ++i)
KeyIsDown[i] = false;
}
private:
// We use this array to store the current state of each key
bool KeyIsDown[KEY_KEY_CODES_COUNT];
};
int main()
{
// create device
MyEventReceiver receiver;
IrrlichtDevice* device = createDevice(EDT_OPENGL,
dimension2d<u32>(1024, 768), 16, false, false, false, &receiver);
if (device == 0)
return 1; // could not create selected driver.
IVideoDriver* driver = device->getVideoDriver();
ISceneManager* smgr = device->getSceneManager();
//Make the room
device->getFileSystem()->addZipFileArchive("map-20kdm2.pk3");
scene::IAnimatedMesh* mesh = smgr->getMesh("20kdm2.bsp");
scene::ISceneNode* room = smgr->addOctreeSceneNode(mesh->getMesh(0));
room->setPosition(core::vector3df(-1300,-144,-1249));
//Set triangle selector
scene::ITriangleSelector* selector = 0;
selector = smgr->createOctreeTriangleSelector(mesh->getMesh(0), room, 128);
room->setTriangleSelector(selector);
selector->drop();
//Set up camera
ICameraSceneNode *camera = smgr->addCameraSceneNode();
camera->setPosition(vector3df(0,10,0));
camera->bindTargetAndRotation(true);
//Set collision for camera
scene::ISceneNodeAnimator *collision = smgr->createCollisionResponseAnimator(
selector,camera,core::vector3df(20,60,20),
core::vector3df(0,-2,0),
core::vector3df(0,0,0),
0.0005f);
camera->addAnimator(collision);
collision->drop();
int lastFPS = -1;
// In order to do framerate independent movement, we have to know
// how long it was since the last frame
u32 then = device->getTimer()->getTime();
// This is the movemen speed in units per second.
const f32 MOVEMENT_SPEED = 50.0f;
const f32 ROTATION_SPEED = 30.0f; // how fast camera rotates
while(device->run())
{
bool moving = 0;
bool rotating = 0;
// Work out a frame delta time.
const u32 now = device->getTimer()->getTime();
const f32 frameDeltaTime = (f32)(now - then) / 1000.f; // Time in seconds
then = now;
core::vector3df camPosition = camera->getPosition();
core::vector3df camRotation = camera->getRotation();
// get the 'position' of the thing that the camera (node) is pointed at
core::vector3df camTarget = camera->getTarget();
// figure out the 'direction' vector that describes the relative position of the camera to it's target:
core::vector3df camDirection = camTarget - camPosition;
// scale the direction vector for frame-rate independent speed:
core::vector3df camMovement = camDirection.normalize();
camMovement = camMovement * MOVEMENT_SPEED * frameDeltaTime;
/* Check if keys UP, DOWN, LEFT or RIGHT are being held down, and move the
camre around respectively. */
if(receiver.IsKeyDown(KEY_LEFT))
{
if(!moving){
camRotation.Y -= ROTATION_SPEED * frameDeltaTime;
rotating= true;
camera->setRotation(camRotation);
}
}
else if(receiver.IsKeyDown(KEY_RIGHT))
{
if(!moving){
camRotation.Y += ROTATION_SPEED * frameDeltaTime;
rotating= true;
camera->setRotation(camRotation);
}
}
if(receiver.IsKeyDown(KEY_UP))
{
if(!rotating){
camPosition += camMovement;
camTarget += camMovement;
moving = true;
camera->setPosition(camPosition);
camera->setTarget(camTarget);
}
}
else if(receiver.IsKeyDown(KEY_DOWN))
{
if(!rotating){
camPosition -= camMovement;
camTarget -= camMovement;
moving = true;
camera->setPosition(camPosition);
camera->setTarget(camTarget);
}
}
driver->beginScene(true, true, 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"FP Camera Example (%s)(fps:%d)(Cam:%2.2f %2.2f %2.2f) (Tar:%f %f %f)",driver->getName(), fps,camera->getPosition().X,camera->getPosition().Y, camera->getPosition().Z, camera->getTarget().X, camera->getTarget().Y, camera->getTarget().Z);
device->setWindowCaption(tmp);
//device->setWindowCaption(tmp.c_str());
lastFPS = fps;
}
}// end While
/*
In the end, delete the Irrlicht device.
*/
device->drop();
return 0;
}
Honestly, such a simple kind of camera node should be available in Irrlicht by default, because you dont need tens of keys or a combination of keys and mouse to manouver, just four arrow keys provide all the manouvering, plain and simple!
cheers!