The camera has the Y location locked, but can be changed within the code in WASD events.
The mechanics that you include in summary are:
Move with WASD.
Rotate the camera with the cursor.
A light follows the camera.
You need a cube for this to work, you can create it or import this one which only has vertices and no faces (it is invisible to the camera, similar to aabbox3d):
https://www.mediafire.com/file/lgn2meut ... o.b3d/file
Code: Select all
#include <irrlicht.h>
using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
struct TheEventReceiver : public IEventReceiver {
s32 deltaX;
s32 deltaY;
virtual bool OnEvent(const SEvent& event) {
if (event.EventType == EET_MOUSE_INPUT_EVENT) {
s32 mouseX = event.MouseInput.X;
s32 mouseY = event.MouseInput.Y;
deltaX = event.MouseInput.X - prevMouseX;
deltaY = event.MouseInput.Y - prevMouseY;
prevMouseX = event.MouseInput.X;
prevMouseY = event.MouseInput.Y;
if (event.MouseInput.Event == EMIE_MOUSE_MOVED) {
accumulatedDeltaX = deltaX;
accumulatedDeltaY = deltaY;
}
}
if (event.EventType == EET_KEY_INPUT_EVENT) {
KeyIsDown[event.KeyInput.Key] = event.KeyInput.PressedDown;
}
return false;
}
virtual bool IsKeyDown(EKEY_CODE keyCode) const {
return KeyIsDown[keyCode];
}
TheEventReceiver() {
for (u32 i = 0; i < KEY_KEY_CODES_COUNT; ++i)
KeyIsDown[i] = false;
}
s32 getDeltaX() const {
return deltaX;
}
s32 getDeltaY() const {
return deltaY;
}
s32 getAccumulatedDeltaX() const {
return accumulatedDeltaX;
}
s32 getAccumulatedDeltaY() const {
return accumulatedDeltaY;
}
private:
s32 prevMouseX;
s32 prevMouseY;
s32 accumulatedDeltaX;
s32 accumulatedDeltaY;
bool KeyIsDown[KEY_KEY_CODES_COUNT];
};
struct StructWindowResolution
{
s32 Width;
s32 Height;
};
StructWindowResolution WindowResolution;
struct StructDeviceParams
{
video::E_DRIVER_TYPE DriverType;
core::dimension2d<u32> WindowSize;
u32 Bits;
bool Fullscreen;
bool Stencilbuffer;
bool Vsync;
IEventReceiver* EventReceiver;
};
StructDeviceParams DeviceParams;
f32 FieldOfView = 1.0f;
f32 oneF32 = 1.0f;
f32 zeroF32 = 0.0f;
f32 totalDegrees = 360.0f;
const f32 allowedCursorWidthByRadius = 177.95f; // ((640*100)+64)/360
const f32 allowedCursorHeightByRadius = 133.46f; // ((480*100)+48)/360
const s32 allowedCursorWidthLimitMax = 720;
const s32 allowedCursorWidthLimitMin = 80;
const s32 allowedCursorHeightLimitMax = 540;
const s32 allowedCursorHeightLimitMin = 60;
f32 hundred = 100.0f;
vector2df currentCursorPosition;
int main() {
WindowResolution.Width = 800;
WindowResolution.Height = 600;
DeviceParams.DriverType = video::EDT_DIRECT3D9; // Change this according to your preference
DeviceParams.WindowSize = dimension2d<u32>(WindowResolution.Width, WindowResolution.Height);
DeviceParams.Bits = 32;
DeviceParams.Fullscreen = true;
DeviceParams.Stencilbuffer = true;
DeviceParams.Vsync = false;
DeviceParams.EventReceiver = 0;
IrrlichtDevice* device = createDevice(
DeviceParams.DriverType,
DeviceParams.WindowSize,
DeviceParams.Bits,
DeviceParams.Fullscreen,
DeviceParams.Stencilbuffer,
DeviceParams.Vsync,
DeviceParams.EventReceiver
);
if (!device)
return 1;
TheEventReceiver EventReceiver;
device->setEventReceiver(&EventReceiver);
device->setWindowCaption(L"Moving Square in Circular Motion around the Camera");
IVideoDriver* driver = device->getVideoDriver();
ISceneManager* smgr = device->getSceneManager();
ICameraSceneNode* camera = smgr->addCameraSceneNode();
camera->setPosition(vector3df(0, 200, -100));
IAnimatedMesh* mesh = smgr->getMesh("c:/Directory/TheCubeHere.b3d");
IMeshSceneNode* cubeViewMesh = smgr->addMeshSceneNode(mesh);
cubeViewMesh->setPosition(vector3df(0, 40, 0));
gui::ICursorControl* cursorControl = device->getCursorControl();
cursorControl->setVisible(1);
ILightSceneNode* light = smgr->addLightSceneNode(0, vector3df(0, 80, -5), SColorf(1.0f, 1.0f, 1.0f, 1.0f), 10000.0f);
ILogger* logger = device->getLogger();
cubeViewMesh->setRotation(vector3df(0.0f, 0.0f, 0.0f));
s32 lastFPS = -1;
const f32 minLimit = 95.0f;
const f32 maxLimit = 240.0f;
const f32 MoveSpeed = 50.0f;
camera->setFOV(FieldOfView);
u32 lastTime = device->getTimer()->getTime();
while (device->run()) {
if (device->isWindowActive()) {
const u32 currentTime = device->getTimer()->getTime();
const f32 deltaTime = (currentTime - lastTime) / 1000.0f;
lastTime = currentTime;
light->setPosition(camera->getAbsolutePosition());
core::matrix4 cubeTransform = cubeViewMesh->getAbsoluteTransformation();
core::vector3df faceCenter(0, 0, 25.0f);
cubeTransform.transformVect(faceCenter);
camera->setPosition(cubeViewMesh->getPosition());
camera->setTarget(faceCenter);
currentCursorPosition.X = cursorControl->getPosition().X;
currentCursorPosition.Y = cursorControl->getPosition().Y;
s32 PosFcY = currentCursorPosition.Y;
s32 PosFcX = currentCursorPosition.X;
if (currentCursorPosition.X > allowedCursorWidthLimitMax) {
cursorControl->setPosition(allowedCursorWidthLimitMin, PosFcY);
}
if (currentCursorPosition.X < allowedCursorWidthLimitMin) {
cursorControl->setPosition(allowedCursorWidthLimitMax, PosFcY);
}
if (currentCursorPosition.Y > allowedCursorHeightLimitMax) {
cursorControl->setPosition(PosFcX, allowedCursorHeightLimitMin);
}
if (currentCursorPosition.Y < allowedCursorHeightLimitMin) {
cursorControl->setPosition(PosFcX, allowedCursorHeightLimitMax);
}
f32 movAcPX = (currentCursorPosition.X * hundred) / allowedCursorWidthByRadius;
f32 movAcPY = (currentCursorPosition.Y * hundred) / allowedCursorHeightByRadius;
f32 movAcPZ = zeroF32;
movAcPY = fmod(-movAcPY, totalDegrees);
if (movAcPY < zeroF32) {
movAcPY += totalDegrees;
}
movAcPY = core::clamp(movAcPY, minLimit, maxLimit);
cubeViewMesh->setRotation(vector3df(movAcPY, movAcPX, movAcPZ));
//core::stringw messageLog = stringw(cubeViewMesh->getRotation);
//logger->log(messageLog.c_str(), ELL_INFORMATION);
if (EventReceiver.IsKeyDown(KEY_KEY_W)) {
core::vector3df forward = cubeViewMesh->getRotation().rotationToDirection();
forward.Y = zeroF32;
cubeViewMesh->setPosition(cubeViewMesh->getPosition() + forward * MoveSpeed * deltaTime);
}
if (EventReceiver.IsKeyDown(KEY_KEY_S)) {
core::vector3df backward = -cubeViewMesh->getRotation().rotationToDirection();
backward.Y = zeroF32;
cubeViewMesh->setPosition(cubeViewMesh->getPosition() + backward * MoveSpeed * deltaTime);
}
if (EventReceiver.IsKeyDown(KEY_KEY_A)) {
core::vector3df left = cubeViewMesh->getRotation().rotationToDirection().crossProduct(core::vector3df(0, 1, 0));
left.Y = zeroF32;
cubeViewMesh->setPosition(cubeViewMesh->getPosition() + left * MoveSpeed * deltaTime);
}
if (EventReceiver.IsKeyDown(KEY_KEY_D)) {
core::vector3df right = -cubeViewMesh->getRotation().rotationToDirection().crossProduct(core::vector3df(0, 1, 0));
right.Y = zeroF32;
cubeViewMesh->setPosition(cubeViewMesh->getPosition() + right * MoveSpeed * deltaTime);
}
driver->beginScene(true, true, SColor(12, 12, 122, 255));
smgr->drawAll();
driver->endScene();
s32 fps = driver->getFPS();
if (lastFPS != fps) {
core::stringw tmp(L"Camera scene node movement example [");
tmp += driver->getName();
tmp += L"] fps: ";
tmp += fps;
device->setWindowCaption(tmp.c_str());
lastFPS = fps;
}
}
else {
device->yield();
}
}
device->drop();
return 0;
}
It also needs a scene with objects to differentiate the environment and know if you are moving or turning, but you can add that yourself.