Witam. Staram się zaprogramować kamerę dla mojej gry. Kamera ma być w stylu RTS, czyli widok z lotu ptaka.
Napisałem już prototyp ale nie wiadomo w którym miejscu obraca mi kamerę o 90 stopni. Próbowałem to naprawić funkcjami cam->setRotation();, ale rotacja nie zadziałała.

image

#include <irrlicht.h>

using namespace irr;	// I don't want to use it irr::

using namespace core;	// also ( irr::core:: )
using namespace scene;	// also ( irr::scene::)
using namespace video;	// also ... 
using namespace io;		// ... 
using namespace gui;	// ...

#include<iostream>
#include<set>

// device
int screenWidth = 1080;
int screenHeight = 720;
int bitsPerPixel = 32;
bool fullscreen = false;
bool stencilbuffer = false;		// Specifies if we want to use the stencil buffer (for drawing shadows)
bool vsync = false;				// Specifies if we want to have vsync enabled, this is only useful in fullscreen mode.
int eventReceiver = 0;			// An object to receive events.We do not want to use this parameter here, and set it to 0.
int cam_x, cam_z;

// clearing screen colors
int clear_r = 48;	int clear_g = 48;	int clear_b = 48;	int clear_a = 256;

// Basic things
IrrlichtDevice* device;
IVideoDriver* driver;
ISceneManager* sceneManager;
IGUIEnvironment* GUI;

// Fonts
IGUIFont* basicFont;
IGUIFont* boldFont;

// Textures
ITexture* TWTexture;

// Model pathfiles
std::string modelPathfile = "Media/TT_RTS_Demo_Character.obj";
std::string modelTexturePathfile = "Media/TT_RTS_Units_blue.png";

// Meshes
IAnimatedMesh* modelMesh;		// mesh

// Animators
IAnimatedMeshSceneNode* animModel1;		// model1
IAnimatedMeshSceneNode* animModel2;		// model2
IAnimatedMeshSceneNode* animModel3;		// model3

// Textures
ITexture* modelTexture;


// Buttons ID's
enum
{
	// World
	GUI_ID_CREATEWORLD, GUI_ID_LOADWORLD, GUI_ID_SAVEWORLD, GUI_ID_GENERATEWORLD,
	// Help
	GUI_ID_TUTORIAL, GUI_ID_INFO
};

float outerRadius = 10.0f;
float innerRadius = outerRadius * 0.866025404f;

class HexTile : public scene::ISceneNode
{

	core::aabbox3d<f32> Box;
	video::S3DVertex Vertices[8];
	video::SMaterial Material;

public:

	HexTile(scene::ISceneNode* parent, scene::ISceneManager* mgr, s32 id)
		: scene::ISceneNode(parent, mgr, id)
	{
		Material.Wireframe = false;
		Material.Lighting = false;
		//Material.setTexture(0,driver->getTexture("Media/grass.png"));

		// verticves of hexagons
		Vertices[0] = video::S3DVertex(0, 0, 0, 0, 0, 0, video::SColor(255, 48, 48, 48), 0, 0);	// CENTER OF HEXTILE
		Vertices[1] = video::S3DVertex(0.0f, 0, outerRadius, 0, 0, 0, video::SColor(255, 128, 48, 48), 0, 0);
		Vertices[2] = video::S3DVertex(innerRadius, 0, outerRadius * 0.5f, 0, 0, 0, video::SColor(255, 128, 48, 48), 0, 0);
		Vertices[3] = video::S3DVertex(innerRadius, 0, -outerRadius * 0.5f, 0, 0, 0, video::SColor(255, 128, 48, 48), 0, 0);
		Vertices[4] = video::S3DVertex(0.0f, 0, -outerRadius, 0, 0, 0, video::SColor(255, 128, 48, 48), 0, 0);
		Vertices[5] = video::S3DVertex(-innerRadius, 0, -outerRadius * 0.5f, 0, 0, 0, video::SColor(255, 128, 48, 48), 0, 0);
		Vertices[6] = video::S3DVertex(-innerRadius, 0, outerRadius * 0.5f, 0, 0, 0, video::SColor(255, 128, 48, 48), 0, 0);
		Vertices[7] = video::S3DVertex(0.0f, 0, outerRadius, 0, 0, 0, video::SColor(255, 128, 48, 48), 0, 0);

		Box.reset(Vertices[0].Pos);
		for (s32 i = 1; i < 7; ++i)
			Box.addInternalPoint(Vertices[i].Pos);
	}

	virtual void OnRegisterSceneNode()
	{
		if (IsVisible)
			SceneManager->registerNodeForRendering(this);

		ISceneNode::OnRegisterSceneNode();
	}

	virtual void render()
	{
		u16 indices[] = { 0, 1, 2, /**/ 0, 2, 3, /**/ 0, 3, 4, /**/ 0, 4, 5, /**/ 0, 5, 6, /**/ 0, 6, 7 };
		IVideoDriver* driver = SceneManager->getVideoDriver();
		driver->setMaterial(Material);
		driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
		driver->drawVertexPrimitiveList(&Vertices[0], 3, &indices[0], 6, video::EVT_STANDARD, scene::EPT_TRIANGLES, video::EIT_16BIT);

	}

	virtual const core::aabbox3d<f32>& getBoundingBox() const
	{
		return Box;
	}

	virtual u32 getMaterialCount() const
	{
		return 1;
	}

	virtual video::SMaterial& getMaterial(u32 i)
	{
		return Material;
	}
};

class HexMap
{
public:
	std::set < HexTile* > tiles;

	HexMap();
	~HexMap();
	void addTile(HexTile*);
};

HexMap::HexMap()
{
	tiles.clear();
}

HexMap::~HexMap()
{

}

void HexMap::addTile(HexTile* tile)
{
	tiles.insert(tile);
}

void thisIsNotBuildYet()
{
	int rectWidth = 300;
	int rectHeight = 300;
	int x1 = (screenWidth - rectWidth) / 2;
	int x2 = (screenWidth + rectWidth) / 2;
	int y1 = (screenHeight - rectHeight) / 2;
	int y2 = (screenHeight + rectHeight) / 2;

	rect<s32> rectangle = rect<s32>(x1, y1, x2, y2);

	IGUIWindow* window = GUI->addWindow(rectangle);

	const wchar_t* t = L"This section is not build yed";
	IGUIStaticText* text = GUI->addStaticText(t, rect<s32>(0, 20, rectWidth, rectHeight), true, true, window, -1, true);
	text->setTextAlignment(EGUIA_CENTER, EGUIA_CENTER);

}

void createWorld()
{
	std::cout << "created new world" << std::endl;
	thisIsNotBuildYet();

}

void loadWorld()
{
	std::cout << "load world" << std::endl;
	thisIsNotBuildYet();
}

void saveWorld()
{
	std::cout << "save world" << std::endl;
	thisIsNotBuildYet();
}

void generateWorld()
{
	std::cout << "generate world" << std::endl;
	thisIsNotBuildYet();
}

void tutorial()
{
	std::cout << "tutorial" << std::endl;
	thisIsNotBuildYet();
}

void info()
{
	std::cout << "info" << std::endl;

	int rectWidth = 300;
	int rectHeight = 300;
	int x1 = (screenWidth - rectWidth) / 2;
	int x2 = (screenWidth + rectWidth) / 2;
	int y1 = (screenHeight - rectHeight) / 2;
	int y2 = (screenHeight + rectHeight) / 2;

	rect<s32> rectangle = rect<s32>(x1, y1, x2, y2);

	IGUIWindow* window = GUI->addWindow(rectangle);
	const wchar_t* t = L"Program created by tBane";

	IGUIStaticText* text = GUI->addStaticText(t, rect<s32>(0, 20, rectWidth, rectHeight), true, true, window, -1, true);
	text->setTextAlignment(EGUIA_CENTER, EGUIA_CENTER);
}

class MyEventReceiver : public IEventReceiver
{
public:
	bool KeyIsDown[KEY_KEY_CODES_COUNT];

	MyEventReceiver();
	virtual bool OnEvent(const SEvent&);
	virtual bool IsKeyDown(EKEY_CODE);
	bool OnMenuItemSelected(IGUIContextMenu* menu);
};


MyEventReceiver::MyEventReceiver()
{
	for (u32 i = 0; i < KEY_KEY_CODES_COUNT; ++i)
		KeyIsDown[i] = false;
}

bool MyEventReceiver::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 true;
	}

	if (event.EventType == EET_GUI_EVENT)
	{
		switch (event.GUIEvent.EventType)
		{
		case EGET_MENU_ITEM_SELECTED:		// main menu events
		{
			IGUIContextMenu* menu = (IGUIContextMenu*)event.GUIEvent.Caller;
			s32 id = menu->getItemCommandId(menu->getSelectedItem());

			if (id == GUI_ID_CREATEWORLD)
				createWorld();

			if (id == GUI_ID_LOADWORLD)
				loadWorld();

			if (id == GUI_ID_SAVEWORLD)
				saveWorld();

			if (id == GUI_ID_GENERATEWORLD)
				generateWorld();

			if (id == GUI_ID_TUTORIAL)
				tutorial();

			if (id == GUI_ID_INFO)
				info();

		}
		break;

		default:
			break;
		}
	}

	return false;
}

bool MyEventReceiver::IsKeyDown(EKEY_CODE keyCode)
{
	return KeyIsDown[keyCode];
}//#include "HexTile.hpp"

int main()
{
	MyEventReceiver receiver;
	// CREATE DEVICE ( OpenGL )
	device = createDevice(EDT_SOFTWARE, dimension2d<u32>(screenWidth, screenHeight), bitsPerPixel, fullscreen, stencilbuffer, vsync, &receiver);

	if (!device)	// if no Device then error
		return 1;

	// GET THE BASIC THINGS
	driver = device->getVideoDriver();			// get the Video Driver
	sceneManager = device->getSceneManager();	// get the Scene
	GUI = device->getGUIEnvironment();			// get the GUI Manager


	// LOAD THE FONTS
	basicFont = device->getGUIEnvironment()->getBuiltInFont();							// get the Default Font
	boldFont = device->getGUIEnvironment()->getFont("media/fonthaettenschweiler.bmp");	// get the Bold Font


	// STYLES FOR GUI
	IGUISkin* GUIskin = GUI->getSkin();
	GUIskin->setFont(boldFont);

	for (s32 i = 0; i < gui::EGDC_COUNT; ++i)
	{
		GUIskin->setColor((EGUI_DEFAULT_COLOR)i, SColor(255, 96, 96, 96));	// coloring the Background
		GUIskin->setColor(EGDC_BUTTON_TEXT, SColor(255, 224, 224, 224));	// coloring the Text
		GUIskin->setColor(EGDC_HIGH_LIGHT_TEXT, SColor(255, 128, 48, 48));	// coloring the Highlighed Text
	}

	// CREATE MAIN MENU
	IGUIContextMenu* menu = GUI->addMenu();
		menu->addItem(L"World", -1, true, true);
		menu->addItem(L"Help", -1, true, true);

	// Create World Menu
	IGUIContextMenu* worldMenu = menu->getSubMenu(0);
		worldMenu->addItem(L"Create World", GUI_ID_CREATEWORLD);
		worldMenu->addItem(L"Load World", GUI_ID_LOADWORLD);
		worldMenu->addItem(L"Save world", GUI_ID_SAVEWORLD);
		worldMenu->addItem(L"Generate World", GUI_ID_GENERATEWORLD);

	// Create Help Menu
	IGUIContextMenu* helpMenu = menu->getSubMenu(1);				
		helpMenu->addItem(L"Tutorial", GUI_ID_TUTORIAL);
		helpMenu->addItem(L"Info", GUI_ID_INFO);

	// LOAD THE "TW Editor Logo"
	TWTexture = driver->getTexture("Media/TW.png");

	// ADD CAMERA
	cam_x = 0;
	cam_z = -40;
	ICameraSceneNode* cam = sceneManager->addCameraSceneNode(0, vector3df(cam_x, 30, cam_z), vector3df(0, 5, 0));
	cam->setFOV(1);
	cam->setTarget(vector3df(cam_x, 30, cam_z));
	

	// CURSOR IS HIDDEN
	device->getCursorControl()->setVisible(true);

	// LOAD THE MODEL 
	modelMesh = sceneManager->getMesh(modelPathfile.c_str());
	if (!modelMesh)
		device->drop();
	
	
	animModel1 = sceneManager->addAnimatedMeshSceneNode(modelMesh);		// Add Model1
		animModel1->setScale(vector3df(10, 10, 10));
		animModel1->setPosition(vector3df(0, 0, 0));
		animModel1->setRotation(vector3df(0, 180, 0));
		animModel1->setMaterialFlag(EMF_LIGHTING, false);
		animModel1->setMD2Animation(scene::EMAT_STAND);
		animModel1->setMaterialTexture(0, driver->getTexture(modelTexturePathfile.c_str()));
	
	animModel2 = sceneManager->addAnimatedMeshSceneNode(modelMesh);		// Add Model2
		animModel2->setScale(vector3df(10, 10, 10));
		animModel2->setPosition(vector3df(20, 0, 0));
		animModel2->setRotation(vector3df(0, 180, 0));
		animModel2->setMaterialFlag(EMF_LIGHTING, false);
		animModel2->setMD2Animation(scene::EMAT_STAND);
		animModel2->setMaterialTexture(0, driver->getTexture(modelTexturePathfile.c_str()));

	animModel3 = sceneManager->addAnimatedMeshSceneNode(modelMesh);		// Add Model3
		animModel3->setScale(vector3df(10, 10, 10));
		animModel3->setPosition(vector3df(40, 0, 0));
		animModel3->setRotation(vector3df(0, 180, 0));
		animModel3->setMaterialFlag(EMF_LIGHTING, false);
		animModel3->setMD2Animation(scene::EMAT_STAND);
		animModel3->setMaterialTexture(0, driver->getTexture(modelTexturePathfile.c_str()));

	// Create HexMap
	HexMap* hexMap = new HexMap();
	float xpos, zpos;
	for( int z=0; z<20; z++)
		for (int x = 0; x < 20; x++)
		{
			HexTile* tile = new HexTile(sceneManager->getRootSceneNode(), sceneManager, 666);

				xpos = float(x) * 2.0f * innerRadius + (z%2)*innerRadius;
				zpos = float(z) * 1.5f * outerRadius;

			tile->setPosition(vector3df(xpos, 0, zpos));
			hexMap->addTile(tile);
		}
	
		
	// MAIN "TW Editor" LOOP 
	while (device->run())
	{
		if (device->isWindowActive())
		{
			
			// UPDATE
			if (receiver.IsKeyDown(irr::KEY_ESCAPE))	// if press ESCAPE then exit
			{
				device->drop();
				return 0;
			}

			if (receiver.IsKeyDown(irr::KEY_KEY_A))	cam_x -= 1.0f;
			if (receiver.IsKeyDown(irr::KEY_KEY_D))	cam_x += 1.0f;
			if (receiver.IsKeyDown(irr::KEY_KEY_W))	cam_z += 1.0f;
			if (receiver.IsKeyDown(irr::KEY_KEY_S))	cam_z -= 1.0f;

			cam->setPosition(vector3df(cam_x, 200, cam_z));
			cam->setTarget(vector3df(cam_x, 30, cam_z));

			// RENDER
			driver->beginScene(true, true, SColor(clear_a, clear_r, clear_g, clear_b));														// clear screen
				sceneManager->drawAll();																										// render scene
				driver->draw2DImage(TWTexture, position2d<s32>(0, screenHeight - 128 - 20), rect<s32>(0, 0, 128, 128));							// render TW Logo
				boldFont->draw(L"TW World Editor v0.1", recti(20, screenHeight - 20, 100, screenHeight), SColor(256, 128, 48, 48), true, true);	// render text on bottom
				GUI->drawAll();																													// render GUI
				position2d<s32> m = device->getCursorControl()->getPosition();																	// render cursor
			driver->endScene();																												// render submit

			// FPS
			int currentFPS = driver->getFPS();
			core::stringw str = L"FPS: ";
			str += currentFPS;
			device->setWindowCaption(str.c_str());
		}
		else
			device->yield();	// if window is inactive not use CPU

	}

	// In the end, delete the Irrlicht device.
	device->drop();
	return 0;
}