Camera movement with addCameraSceneNode

A forum to store posts deemed exceptionally wise and useful
Post Reply
Noiecity
Posts: 92
Joined: Wed Aug 23, 2023 7:22 pm
Contact:

Camera movement with addCameraSceneNode

Post by Noiecity »

This tutorial teaches, through the code, how to move through addCameraSceneNode with the WASD keys, the code is very basic and there are still many mechanics missing, which I decided not to add to make the code more readable, these mechanics are crouching, jumping, third person view, movement on the surface, etc.

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;
}
The original code was different, so the code still needs to be accommodated.

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.

:mrgreen: :mrgreen:
**
If you are looking for people with whom to develop your game, even to try functionalities, I can help you, free and in an anonymous way if necessary. You can send me a private message.

https://www.artstation.com/noiecty
**
Post Reply