ISceneNodeControllerAnimator v0.1

Post those lines of code you feel like sharing or find what you require for your project here; or simply use them as tutorials.
switch_case
Posts: 34
Joined: Sat Mar 08, 2008 12:46 pm
Location: Germany, FFM
Contact:

Post by switch_case »

this is what i mean
damn, my bad english... :P

...i just read the article about the matrices, it is fine, but hard to understand at the first reading, espacially if your english isn't that good. but it helped, thanks to halifax.
if life could only be written in C++...
so much features, money++, remove_childs(), choose parents, life = new life, and no more <IDIOT> templates !
if you're looking for an nerdy coding language: http://lolcode.com/
MasterGod
Posts: 2061
Joined: Fri May 25, 2007 8:06 pm
Location: Israel
Contact:

Post by MasterGod »

Halifax wrote:Well that fact that you aren't locking the cursor should not be desired. Especially since you can't constantly keep rotating because your mouse goes outside the window.

At least a method to lock the cursor would be good.
Good idea, I'll add that. Thanks.
Image
Dev State: Abandoned (For now..)
Requirements Analysis Doc: ~87%
UML: ~0.5%
Halifax
Posts: 1424
Joined: Sun Apr 29, 2007 10:40 pm
Location: $9D95

Post by Halifax »

No problem, I aim to help switch_case, and MasterGod.
TheQuestion = 2B || !2B
MasterGod
Posts: 2061
Joined: Fri May 25, 2007 8:06 pm
Location: Israel
Contact:

Post by MasterGod »

Ok I've added the lock/unlock methods:

ISceneNodeControllerAnimator.hpp:

Code: Select all

// Copyright (c) 2007-2008 Tomer Nosrati
// This file is part of the "NUSoftware Game Engine".
// For conditions of distribution and use, see copyright notice in nge.hpp

#pragma once
#ifndef __I_SCENE_NODE_CONTROLLER_ANIMATOR_H_
#define __I_SCENE_NODE_CONTROLLER_ANIMATOR_H_

#include "irrlicht.h"

using namespace irr;
using namespace irr::core;
using namespace irr::gui;
using namespace irr::io;
using namespace irr::scene;

//! Special scene node animator for doing automatic movement in 3D space.
/*! This scene node animator can be attached to any scene node modifying it in that
way, that it can move freely in 3D space, rotate with mouse input and move/strafe with
keyboard input.	*/
class ISceneNodeControllerAnimator : public ISceneNodeAnimator, public IEventReceiver
{
public:
	//! Destructor
	virtual ~ISceneNodeControllerAnimator() {}

	//! Animates a scene node.
	//! \param node: Node to animate.
	//! \param timeMs: Current time in milli seconds.
	virtual void animateNode(ISceneNode* node, u32 timeMs) = 0;

	//! called if an event happened.
	virtual bool OnEvent(const SEvent& event) = 0;

	virtual void lockMouseCursor() = 0;

	virtual void unlockMouseCursor() = 0;

	//! Returns if the input receiver of the animator is currently enabled. 
	virtual bool isInputReceiverEnabled() = 0;

	//! Disables or enables the animator to get key or mouse inputs. 
	virtual void setInputReceiverEnabled(bool enabled) = 0;

	//! Returns if the scene node could move vertically or not
	virtual bool isVerticalMovementEnabled() = 0;

	//! Sets if the scene node could move vertically or not
	virtual void setVerticalMovementEnabled(bool enabled) = 0;

	//! Get the animator's movement speed
	virtual f32 getMoveSpeed() const = 0;

	//! Get the animator's rotation speed
	virtual f32 getRotateSpeed() const = 0;

	//! Set the animator's movement speed
	virtual void setMoveSpeed(f32 speed) = 0;

	//! Set the animator's rotation speed
	virtual void setRotateSpeed(f32 speed) = 0;

	//! Set should the rotation on both X and Y axes be inverted
	virtual void invertRotation(bool X, bool Y) = 0;

	//! Set should the rotation on the X axis be inverted
	virtual void invertXRotation(bool isInvert) = 0;

	//! Set should the rotation on the Y axis be inverted
	virtual void invertYRotation(bool isInvert) = 0;

	//! Returns whether the rotation on the X axis is inverted or not
	virtual bool isXRotationInverted() const = 0;

	//! Returns whether the rotation on the Y axis is inverted or not
	virtual bool isYRotationInverted() const = 0;
};

#endif // __I_SCENE_NODE_CONTROLLER_ANIMATOR_H_
CSceneNodeControllerAnimator.hpp:

Code: Select all

// Copyright (c) 2007-2008 Tomer Nosrati
// This file is part of the "NUSoftware Game Engine".
// For conditions of distribution and use, see copyright notice in nge.hpp

#pragma once
#ifndef __C_SCENE_NODE_CONTROLLER_ANIMATOR_H_
#define __C_SCENE_NODE_CONTROLLER_ANIMATOR_H_

#include "ISceneNodeControllerAnimator.hpp"

class CSceneNodeControllerAnimator : public ISceneNodeControllerAnimator
{
public:
	//! Constructor
	CSceneNodeControllerAnimator(ISceneManager* smgr, ICursorControl* cur,
		f32 rotateSpeed = 150.f, f32 moveSpeed = 100.f, 
		SKeyMap* keyMapArray = 0, s32 keyMapSize = 0, 
		bool verticalMovement = true);

	//! Destructor
	~CSceneNodeControllerAnimator();

	virtual void animateNode(ISceneNode* node, u32 timeMs);

	virtual bool OnEvent(const SEvent& event);

	virtual void lockMouseCursor();

	virtual void unlockMouseCursor();

	virtual bool isInputReceiverEnabled();

	virtual void setInputReceiverEnabled(bool enabled);

	virtual bool isVerticalMovementEnabled();

	virtual void setVerticalMovementEnabled(bool enabled);

	f32 getMoveSpeed() const;

	f32 getRotateSpeed() const;

	void setMoveSpeed(f32 speed);

	void setRotateSpeed(f32 speed);

	void invertRotation(bool X, bool Y);

	void invertXRotation(bool isInvert);

	void invertYRotation(bool isInvert);

	bool isXRotationInverted() const;

	bool isYRotationInverted() const;

private:
	void allKeysUp();

	//! Binds an action to a key
	struct SCamKeyMap
	{
		SCamKeyMap() {};
		SCamKeyMap(EKEY_ACTION a, EKEY_CODE k) : action(a), keycode(k) {}

		EKEY_ACTION action;
		EKEY_CODE keycode;
	};

	array<SCamKeyMap> m_aKeyMap;

	bool m_CursorKeys[EKA_COUNT];

	ISceneNode* m_pDummySceneNode;

	position2df m_CenterPosition;

	ISceneManager* m_pSceneManager;
	ICursorControl* m_pCursorControl;
	f32 m_MoveSpeed;
	f32 m_RotateSpeed;

	s32 m_LastAnimationTime;

	bool m_RotUp, m_RotDown, m_RotLeft, m_RotRight;

	s32 m_PrevMouseX, m_PrevMouseY;

	bool m_IsInvertX, m_IsInvertY;

	bool m_InputReceiverEnabled;

	bool m_VerticalMovement;

	bool m_IsLocked;
};

#endif // __C_SCENE_NODE_CONTROLLER_ANIMATOR_H_
CSceneNodeControllerAnimator.cpp:

Code: Select all

// Copyright (c) 2007-2008 Tomer Nosrati
// This file is part of the "NUSoftware Game Engine".
// For conditions of distribution and use, see copyright notice in nge.hpp

#include "CSceneNodeControllerAnimator.hpp"

CSceneNodeControllerAnimator::CSceneNodeControllerAnimator(
	ISceneManager* smgr, ICursorControl* cur, 
	f32 rotateSpeed, f32 m_MoveSpeed, SKeyMap* keyMapArray, s32 keyMapSize, 
	bool verticalMovement)
	: m_pSceneManager(smgr), m_pCursorControl(cur),
	m_MoveSpeed(m_MoveSpeed), m_RotateSpeed(rotateSpeed), m_LastAnimationTime(0),
	m_RotUp(false), m_RotDown(false), m_RotLeft(false), m_RotRight(false),
	m_PrevMouseX(0), m_PrevMouseY(0),
	m_IsInvertX(false), m_IsInvertY(false),
	m_InputReceiverEnabled(true), m_VerticalMovement(verticalMovement), m_IsLocked(false)
{
	m_pSceneManager->grab();

	//m_pDummySceneNode = m_pSceneManager->addCubeSceneNode(3.f,0,12);
	m_pDummySceneNode = m_pSceneManager->addEmptySceneNode();

	m_pCursorControl->setPosition(0.5f,0.5f);
	m_CenterPosition = m_pCursorControl->getRelativePosition();

	allKeysUp();

	// create key map
	if (!keyMapArray || !keyMapSize)
	{
		// create default key map
		m_aKeyMap.push_back(SCamKeyMap(EKA_MOVE_FORWARD, KEY_UP));
		m_aKeyMap.push_back(SCamKeyMap(EKA_MOVE_BACKWARD, KEY_DOWN));
		m_aKeyMap.push_back(SCamKeyMap(EKA_STRAFE_LEFT, KEY_LEFT));
		m_aKeyMap.push_back(SCamKeyMap(EKA_STRAFE_RIGHT, KEY_RIGHT));
	}
	else
	{
		// create custom key map
		for (s32 i = 0; i < keyMapSize; i++)
		{
			switch(keyMapArray[i].Action)
			{
			case EKA_MOVE_FORWARD: 
				m_aKeyMap.push_back(SCamKeyMap(EKA_MOVE_FORWARD, keyMapArray[i].KeyCode));
				break;
			case EKA_MOVE_BACKWARD: 
				m_aKeyMap.push_back(SCamKeyMap(EKA_MOVE_BACKWARD, keyMapArray[i].KeyCode));
				break;
			case EKA_STRAFE_LEFT: 
				m_aKeyMap.push_back(SCamKeyMap(EKA_STRAFE_LEFT, keyMapArray[i].KeyCode));
				break;
			case EKA_STRAFE_RIGHT: 
				m_aKeyMap.push_back(SCamKeyMap(EKA_STRAFE_RIGHT, keyMapArray[i].KeyCode));
				break;
			default:
				break;
			} // end switch
		} // end for
	}// end if
}

CSceneNodeControllerAnimator::~CSceneNodeControllerAnimator()
{
	if(m_pSceneManager)
		m_pSceneManager->drop();
}

void CSceneNodeControllerAnimator::animateNode(ISceneNode* node, u32 timeMs)
{
	if (!node)
		return;

	f32 timeDiff = 0.f;

	// for first time
	if(m_LastAnimationTime)
		timeDiff = (f32) ( timeMs - m_LastAnimationTime );

	m_LastAnimationTime = timeMs;

	m_pDummySceneNode->setParent(node);
	m_pDummySceneNode->setPosition(vector3df(0,0,-8.1f));

	vector3df Pos = node->getPosition();
	vector3df PrevPos = Pos;
	vector3df Rot = node->getRotation();
	vector3df PrevRot = Rot;

	vector3df Vel(Pos - m_pDummySceneNode->getAbsolutePosition());

	f32 MovementSpeed = m_MoveSpeed/1000.f * timeDiff;
	f32 RotationSpeed = m_RotateSpeed/100.f;

	Vel.normalize();
	if(m_VerticalMovement)
		Vel.Y *= MovementSpeed;
	else
		Vel.Y = 0.f;
	Vel.X *= MovementSpeed;
	Vel.Z *= MovementSpeed;

	if (m_CursorKeys[EKA_MOVE_FORWARD])
	{
		Pos += Vel;
	}
	if (m_CursorKeys[EKA_MOVE_BACKWARD])
	{
		Pos -= Vel;
	}
	if (m_CursorKeys[EKA_STRAFE_LEFT])
	{
		Pos.X -= MovementSpeed * cos((Rot.Y) * DEGTORAD);
		Pos.Z += MovementSpeed * sin((Rot.Y) * DEGTORAD);
	}
	if (m_CursorKeys[EKA_STRAFE_RIGHT])
	{
		Pos.X += MovementSpeed * cos((Rot.Y) * DEGTORAD);
		Pos.Z -= MovementSpeed * sin((Rot.Y) * DEGTORAD);
	}

	if (m_RotUp)
	{
		Rot.X -= RotationSpeed;
		m_RotUp = false;
	}
	if (m_RotDown)
	{
		Rot.X += RotationSpeed;
		m_RotDown = false;
	}
	if (m_RotLeft)
	{
		Rot.Y -= RotationSpeed;
		m_RotLeft = false;
	}
	if (m_RotRight)
	{
		Rot.Y += RotationSpeed;
		m_RotRight = false;
	}

	node->setPosition(Pos);
	node->setRotation(Rot);

	if(m_IsLocked)
	{
		m_pCursorControl->setPosition(m_CenterPosition);
		m_PrevMouseX = m_pCursorControl->getPosition().X;
		m_PrevMouseY = m_pCursorControl->getPosition().Y;
	}
}

bool CSceneNodeControllerAnimator::OnEvent(const SEvent& event)
{
	if(m_InputReceiverEnabled)
	{
		if(event.EventType == EET_KEY_INPUT_EVENT)
		{
			const u32 cnt = m_aKeyMap.size();
			for(u32 i=0; i<cnt; i++)
				if(m_aKeyMap[i].keycode == event.KeyInput.Key)
				{
					m_CursorKeys[m_aKeyMap[i].action] = event.KeyInput.PressedDown;
				}
		}

		if (event.EventType == EET_MOUSE_INPUT_EVENT)
		{
			switch(event.MouseInput.Event)
			{
			case EMIE_MOUSE_MOVED:
				{
					s32 CurrentX = event.MouseInput.X;
					s32 CurrentY = event.MouseInput.Y;

					if((CurrentX - m_PrevMouseX) > 0)
					{
						if(m_IsInvertY)
						{
							m_RotLeft = true;
							m_RotRight  = false;
						}
						else
						{
							m_RotLeft = false;
							m_RotRight  = true;
						}
					}
					else if((CurrentX - m_PrevMouseX) < 0)
					{
						if(m_IsInvertY)
						{
							m_RotLeft = false;
							m_RotRight  = true;
						}
						else
						{
							m_RotLeft = true;
							m_RotRight  = false;
						}
					}

					if((CurrentY - m_PrevMouseY) > 0)
					{
						if(m_IsInvertX)
						{
							m_RotUp = true;
							m_RotDown  = false;
						}
						else
						{
							m_RotUp = false;
							m_RotDown  = true;
						}
					}
					else if((CurrentY - m_PrevMouseY) < 0)
					{
						if(m_IsInvertX)
						{
							m_RotUp = false;
							m_RotDown  = true;
						}
						else
						{
							m_RotUp = true;
							m_RotDown  = false;
						}
					}

					m_PrevMouseX = CurrentX;
					m_PrevMouseY = CurrentY;

					break;
				}
			}
		}

		return true;
	} // if(m_InputReceiverEnabled)

	return false;
}

void CSceneNodeControllerAnimator::lockMouseCursor()
{
	m_IsLocked = true;
}

void CSceneNodeControllerAnimator::unlockMouseCursor()
{
	m_IsLocked = false;
}

bool CSceneNodeControllerAnimator::isInputReceiverEnabled()
{
	return m_InputReceiverEnabled;
}

void CSceneNodeControllerAnimator::setInputReceiverEnabled(bool enabled)
{
	m_InputReceiverEnabled = enabled;
}

bool CSceneNodeControllerAnimator::isVerticalMovementEnabled()
{
	return m_VerticalMovement;
}

void CSceneNodeControllerAnimator::setVerticalMovementEnabled(bool enabled)
{
	m_VerticalMovement = enabled;
}

f32 CSceneNodeControllerAnimator::getMoveSpeed() const
{
	return m_MoveSpeed;
}

f32 CSceneNodeControllerAnimator::getRotateSpeed() const
{
	return m_RotateSpeed;
}

void CSceneNodeControllerAnimator::setMoveSpeed(f32 speed)
{
	m_MoveSpeed = speed;
}

void CSceneNodeControllerAnimator::setRotateSpeed(f32 speed)
{
	m_RotateSpeed = speed;
}

void CSceneNodeControllerAnimator::invertRotation(bool X, bool Y)
{
	m_IsInvertX = X;
	m_IsInvertY = Y;
}

void CSceneNodeControllerAnimator::invertXRotation(bool isInvert)
{
	m_IsInvertX = isInvert;
}

void CSceneNodeControllerAnimator::invertYRotation(bool isInvert)
{
	m_IsInvertY = isInvert;
}

bool CSceneNodeControllerAnimator::isXRotationInverted() const
{
	return m_IsInvertX;
}

bool CSceneNodeControllerAnimator::isYRotationInverted() const
{
	return m_IsInvertY;
}

void CSceneNodeControllerAnimator::allKeysUp()
{
	for (s32 i=0; i<EKA_COUNT; i++)
		m_CursorKeys[i] = false;
}
main.cpp:

Code: Select all

#include <irrlicht.h>
#include <iostream>
#include "CSceneNodeControllerAnimator.hpp"

using namespace irr;

#pragma comment(lib, "Irrlicht.lib")

scene::ISceneNode* node = 0;
IrrlichtDevice* device = 0;
ISceneNodeControllerAnimator* anim = 0;

class MyEventReceiver : public IEventReceiver
{
public:
   virtual bool OnEvent(const SEvent& event)
   {
      if(anim)
         return anim->OnEvent(event);

      return false;
   }
};

int main()
{
   video::E_DRIVER_TYPE driverType = video::EDT_DIRECT3D9;

   printf("Please select the driver you want for this example:\n"\
      " (a) Direct3D 9.0c\n (b) Direct3D 8.1\n (c) OpenGL 1.5\n"\
      " (d) Software Renderer\n (e) Burning's Software Renderer\n"\
      " (f) NullDevice\n (otherKey) exit\n\n");

   char i;
   std::cin >> i;

   switch(i)
   {
   case 'a': driverType = video::EDT_DIRECT3D9;break;
   case 'b': driverType = video::EDT_DIRECT3D8;break;
   case 'c': driverType = video::EDT_OPENGL;   break;
   case 'd': driverType = video::EDT_SOFTWARE; break;
   case 'e': driverType = video::EDT_BURNINGSVIDEO;break;
   case 'f': driverType = video::EDT_NULL;     break;
   default: return 0;
   }   

   // create device
   MyEventReceiver receiver;

   IrrlichtDevice* device = createDevice( driverType, core::dimension2d<s32>(640, 480),
      32, false, false, false, &receiver);

   if (device == 0)
      return 1; // could not create selected driver.


   video::IVideoDriver* driver = device->getVideoDriver();
   scene::ISceneManager* smgr = device->getSceneManager();

   device->getFileSystem()->addZipFileArchive("map-20kdm2.pk3");
   scene::IAnimatedMesh* lvl_mesh = smgr->getMesh("20kdm2.bsp");
   scene::ISceneNode* lvl_node = 0;

   if (lvl_mesh)
      lvl_node = smgr->addOctTreeSceneNode(lvl_mesh->getMesh(0), 0, -1, 128);

   if (lvl_node)
      lvl_node->setPosition(core::vector3df(-1300,-144,-1249));

   node = smgr->addCubeSceneNode();
   node->setPosition(vector3df(15,0,25.f));

   if (node)
   {
      node->setMaterialTexture(0, driver->getTexture("t351sml.jpg"));
      node->setMaterialFlag(video::EMF_LIGHTING, false);

      SKeyMap keyMap[8];
      keyMap[0].Action = EKA_MOVE_FORWARD;
      keyMap[0].KeyCode = KEY_UP;
      keyMap[1].Action = EKA_MOVE_FORWARD;
      keyMap[1].KeyCode = KEY_KEY_W;

      keyMap[2].Action = EKA_MOVE_BACKWARD;
      keyMap[2].KeyCode = KEY_DOWN;
      keyMap[3].Action = EKA_MOVE_BACKWARD;
      keyMap[3].KeyCode = KEY_KEY_S;

      keyMap[4].Action = EKA_STRAFE_LEFT;
      keyMap[4].KeyCode = KEY_LEFT;
      keyMap[5].Action = EKA_STRAFE_LEFT;
      keyMap[5].KeyCode = KEY_KEY_A;

      keyMap[6].Action = EKA_STRAFE_RIGHT;
      keyMap[6].KeyCode = KEY_RIGHT;
      keyMap[7].Action = EKA_STRAFE_RIGHT;
      keyMap[7].KeyCode = KEY_KEY_D;


      anim = new CSceneNodeControllerAnimator(smgr, device->getCursorControl(), 150.f,100.f,keyMap,8);
	  anim->lockMouseCursor();
      node->addAnimator(anim);
      anim->drop();
   }

   IAnimatedMeshSceneNode* forwardArrow = smgr->addAnimatedMeshSceneNode(smgr->addArrowMesh(
      "forward",
      video::SColor(255,255,255,0),
      video::SColor(255,255,0,0),
      4,
      8,
      8.f,
      0.3f,
      0.05f,
      1.3f));
   forwardArrow->setMaterialFlag(video::EMF_LIGHTING, false);
   forwardArrow->setParent(node);
   forwardArrow->setRotation(vector3df(90.f,0.f,0.f));
   forwardArrow->setPosition(vector3df(0.f,0.f,8.f));

   scene::ICameraSceneNode * cam = smgr->addCameraSceneNode();
   device->getCursorControl()->setVisible(true);
   
   /*
   // 3rd Person Camera
   cam->setParent(node);
   cam->setPosition(vector3df(0.f, 20.f, -40.f));*/
   

   //   Add a colorful irrlicht logo
   device->getGUIEnvironment()->addImage(
      driver->getTexture("irrlichtlogoalpha2.tga"),
      core::position2d<s32>(10,10));

   int lastFPS = -1;

   while(device->run())
   {
      cam->setTarget(node->getPosition());
      driver->beginScene(true, true, video::SColor(255,113,113,133));

      smgr->drawAll();
      device->getGUIEnvironment()->drawAll();

      driver->endScene();

      int fps = driver->getFPS();

      if (lastFPS != fps)
      {
         core::stringw tmp(L"Movement Example - Irrlicht Engine [");
         tmp += driver->getName();
         tmp += L"] fps: ";
         tmp += fps;

         device->setWindowCaption(tmp.c_str());
         lastFPS = fps;
      }
   }

   device->drop();

   return 0;
}
Little Note:
Previously if you were moving, the mouse cursor was locked into the center of the screen.
Now by default it is not, no matter if you move or just rotate. To lock use anim->lockMouseCursor(); which will mean no matter what as long as this animator is alive the cursor will be at the center.
To unlock: anim->unlockMouseCursor();
Image
Dev State: Abandoned (For now..)
Requirements Analysis Doc: ~87%
UML: ~0.5%
Post Reply