Title:修改Irrlicht的FPSCamera默认光标操作
Author:kagula
Date:2012-3-26
环境:
[1]VS2010SP1
[2]Irrlicht1.7.3
正文:
FPSCamera默认移动鼠标就改变视图区域(头转到哪里),现在我们要把它改成
按住鼠标左键,才改变视图区域。
[S1]打开..\irrlicht-1.7.3\source\Irrlicht\CSceneNodeAnimatorCameraFPS.h文件
用下面的源文件内容替换
// Copyright (C) 2002-2010 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h #ifndef __C_SCENE_NODE_ANIMATOR_CAMERA_FPS_H_INCLUDED__ #define __C_SCENE_NODE_ANIMATOR_CAMERA_FPS_H_INCLUDED__ #include "ISceneNodeAnimatorCameraFPS.h" #include "vector2d.h" #include "position2d.h" #include "SKeyMap.h" #include "irrArray.h" namespace irr { namespace gui { class ICursorControl; } namespace scene { //! Special scene node animator for FPS cameras class CSceneNodeAnimatorCameraFPS : public ISceneNodeAnimatorCameraFPS { public: //! Constructor CSceneNodeAnimatorCameraFPS(gui::ICursorControl* cursorControl, f32 rotateSpeed = 100.0f, f32 moveSpeed = .5f, f32 jumpSpeed=0.f, SKeyMap* keyMapArray=0, u32 keyMapSize=0, bool noVerticalMovement=false, bool invertY=false); //! Destructor virtual ~CSceneNodeAnimatorCameraFPS(); //! Animates the scene node, currently only works on cameras virtual void animateNode(ISceneNode* node, u32 timeMs); //! Event receiver virtual bool OnEvent(const SEvent& event); //! Returns the speed of movement in units per second virtual f32 getMoveSpeed() const; //! Sets the speed of movement in units per second virtual void setMoveSpeed(f32 moveSpeed); //! Returns the rotation speed virtual f32 getRotateSpeed() const; //! Set the rotation speed virtual void setRotateSpeed(f32 rotateSpeed); //! Sets the keyboard mapping for this animator //! \param keymap: an array of keyboard mappings, see SKeyMap //! \param count: the size of the keyboard map array virtual void setKeyMap(SKeyMap *map, u32 count); //! Sets whether vertical movement should be allowed. virtual void setVerticalMovement(bool allow); //! Sets whether the Y axis of the mouse should be inverted. /** If enabled then moving the mouse down will cause the camera to look up. It is disabled by default. */ virtual void setInvertMouse(bool invert); //! This animator will receive events when attached to the active camera virtual bool isEventReceiverEnabled() const { return true; } //! Returns the type of this animator virtual ESCENE_NODE_ANIMATOR_TYPE getType() const { return ESNAT_CAMERA_FPS; } //! Creates a clone of this animator. /** Please note that you will have to drop (IReferenceCounted::drop()) the returned pointer once you're done with it. */ virtual ISceneNodeAnimator* createClone(ISceneNode* node, ISceneManager* newManager=0); struct SCamKeyMap { SCamKeyMap() {}; SCamKeyMap(s32 a, EKEY_CODE k) : action(a), keycode(k) {} s32 action; EKEY_CODE keycode; }; //! Sets the keyboard mapping for this animator /** Helper function for the clone method. \param keymap the new keymap array */ void setKeyMap(const core::array<SCamKeyMap>& keymap); private: void allKeysUp(); gui::ICursorControl *CursorControl; f32 MaxVerticalAngle; f32 MoveSpeed; f32 RotateSpeed; f32 JumpSpeed; // -1.0f for inverted mouse, defaults to 1.0f f32 MouseYDirection; s32 LastAnimationTime; core::array<SCamKeyMap> KeyMap; //core::position2d<f32> CenterCursor, CursorPos;//comment by lijun //add by lijun bool m_bLeftPressed; core::position2d<f32> OldCursor, CursorPos; bool CursorKeys[6]; bool firstUpdate; bool NoVerticalMovement; }; } // end namespace scene } // end namespace irr #endif // __C_SCENE_NODE_ANIMATOR_CAMERA_FPS_H_INCLUDED__
[S2]打开..\irrlicht-1.7.3\source\Irrlicht\CSceneNodeAnimatorCameraFPS.cpp文件
用下面的源文件内容替换
// Copyright (C) 2002-2010 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h #include "CSceneNodeAnimatorCameraFPS.h" #include "IVideoDriver.h" #include "ISceneManager.h" #include "Keycodes.h" #include "ICursorControl.h" #include "ICameraSceneNode.h" #include "ISceneNodeAnimatorCollisionResponse.h" namespace irr { namespace scene { //! constructor CSceneNodeAnimatorCameraFPS::CSceneNodeAnimatorCameraFPS(gui::ICursorControl* cursorControl, f32 rotateSpeed, f32 moveSpeed, f32 jumpSpeed, SKeyMap* keyMapArray, u32 keyMapSize, bool noVerticalMovement, bool invertY) : CursorControl(cursorControl), MaxVerticalAngle(88.0f), MoveSpeed(moveSpeed), RotateSpeed(rotateSpeed), JumpSpeed(jumpSpeed), MouseYDirection(invertY ? -1.0f : 1.0f), LastAnimationTime(0), firstUpdate(true), NoVerticalMovement(noVerticalMovement) { #ifdef _DEBUG setDebugName("CCameraSceneNodeAnimatorFPS"); #endif if (CursorControl) CursorControl->grab(); allKeysUp(); // create key map if (!keyMapArray || !keyMapSize) { // create default key map KeyMap.push_back(SCamKeyMap(EKA_MOVE_FORWARD, irr::KEY_UP)); KeyMap.push_back(SCamKeyMap(EKA_MOVE_BACKWARD, irr::KEY_DOWN)); KeyMap.push_back(SCamKeyMap(EKA_STRAFE_LEFT, irr::KEY_LEFT)); KeyMap.push_back(SCamKeyMap(EKA_STRAFE_RIGHT, irr::KEY_RIGHT)); KeyMap.push_back(SCamKeyMap(EKA_JUMP_UP, irr::KEY_KEY_J)); } else { // create custom key map setKeyMap(keyMapArray, keyMapSize); } } //! destructor CSceneNodeAnimatorCameraFPS::~CSceneNodeAnimatorCameraFPS() { if (CursorControl) CursorControl->drop(); } //! It is possible to send mouse and key events to the camera. Most cameras //! may ignore this input, but camera scene nodes which are created for //! example with scene::ISceneManager::addMayaCameraSceneNode or //! scene::ISceneManager::addFPSCameraSceneNode, may want to get this input //! for changing their position, look at target or whatever. bool CSceneNodeAnimatorCameraFPS::OnEvent(const SEvent& evt) { switch(evt.EventType) { case EET_KEY_INPUT_EVENT: for (u32 i=0; i<KeyMap.size(); ++i) { if (KeyMap[i].keycode == evt.KeyInput.Key) { CursorKeys[KeyMap[i].action] = evt.KeyInput.PressedDown; return true; } } break; case EET_MOUSE_INPUT_EVENT: if (evt.MouseInput.Event == EMIE_MOUSE_MOVED) { if(evt.MouseInput.isLeftPressed()==true) { CursorPos = CursorControl->getRelativePosition(); m_bLeftPressed = true; return true; } else { OldCursor = CursorControl->getRelativePosition(); m_bLeftPressed = false; } } break; default: break; } return false; } void CSceneNodeAnimatorCameraFPS::animateNode(ISceneNode* node, u32 timeMs) { if (!node || node->getType() != ESNT_CAMERA) return; ICameraSceneNode* camera = static_cast<ICameraSceneNode*>(node); if (firstUpdate) { camera->updateAbsolutePosition(); if (CursorControl && camera) { CursorControl->setPosition(0.5f, 0.5f); CursorPos = OldCursor = CursorControl->getRelativePosition(); } LastAnimationTime = timeMs; firstUpdate = false; } // If the camera isn't the active camera, and receiving input, then don't process it. if(!camera->isInputReceiverEnabled()) return; scene::ISceneManager * smgr = camera->getSceneManager(); if(smgr && smgr->getActiveCamera() != camera) return; // get time f32 timeDiff = (f32) ( timeMs - LastAnimationTime ); LastAnimationTime = timeMs; // update position core::vector3df pos = camera->getPosition(); // Update rotation core::vector3df target = (camera->getTarget() - camera->getAbsolutePosition()); core::vector3df relativeRotation = target.getHorizontalAngle(); if (CursorControl) { if (CursorPos != OldCursor&&m_bLeftPressed) { relativeRotation.Y -= (OldCursor.X - CursorPos.X) * RotateSpeed; relativeRotation.X -= (OldCursor.Y - CursorPos.Y) * RotateSpeed * MouseYDirection; // X < MaxVerticalAngle or X > 360-MaxVerticalAngle if (relativeRotation.X > MaxVerticalAngle*2 && relativeRotation.X < 360.0f-MaxVerticalAngle) { relativeRotation.X = 360.0f-MaxVerticalAngle; } else if (relativeRotation.X > MaxVerticalAngle && relativeRotation.X < 360.0f-MaxVerticalAngle) { relativeRotation.X = MaxVerticalAngle; } // Do the fix as normal, special case below // reset cursor position to the centre of the window. //CursorControl->setPosition(0.5f, 0.5f); OldCursor = CursorControl->getRelativePosition(); // needed to avoid problems when the event receiver is disabled CursorPos = OldCursor; } } // set target target.set(0,0, core::max_(1.f, pos.getLength())); core::vector3df movedir = target; core::matrix4 mat; mat.setRotationDegrees(core::vector3df(relativeRotation.X, relativeRotation.Y, 0)); mat.transformVect(target); if (NoVerticalMovement) { mat.setRotationDegrees(core::vector3df(0, relativeRotation.Y, 0)); mat.transformVect(movedir); } else { movedir = target; } movedir.normalize(); if (CursorKeys[EKA_MOVE_FORWARD]) pos += movedir * timeDiff * MoveSpeed; if (CursorKeys[EKA_MOVE_BACKWARD]) pos -= movedir * timeDiff * MoveSpeed; // strafing core::vector3df strafevect = target; strafevect = strafevect.crossProduct(camera->getUpVector()); if (NoVerticalMovement) strafevect.Y = 0.0f; strafevect.normalize(); if (CursorKeys[EKA_STRAFE_LEFT]) pos += strafevect * timeDiff * MoveSpeed; if (CursorKeys[EKA_STRAFE_RIGHT]) pos -= strafevect * timeDiff * MoveSpeed; // For jumping, we find the collision response animator attached to our camera // and if it's not falling, we tell it to jump. if (CursorKeys[EKA_JUMP_UP]) { const ISceneNodeAnimatorList& animators = camera->getAnimators(); ISceneNodeAnimatorList::ConstIterator it = animators.begin(); while(it != animators.end()) { if(ESNAT_COLLISION_RESPONSE == (*it)->getType()) { ISceneNodeAnimatorCollisionResponse * collisionResponse = static_cast<ISceneNodeAnimatorCollisionResponse *>(*it); if(!collisionResponse->isFalling()) collisionResponse->jump(JumpSpeed); } it++; } } // write translation camera->setPosition(pos); // write right target target += pos; camera->setTarget(target); } void CSceneNodeAnimatorCameraFPS::allKeysUp() { for (u32 i=0; i<6; ++i) CursorKeys[i] = false; } //! Sets the rotation speed void CSceneNodeAnimatorCameraFPS::setRotateSpeed(f32 speed) { RotateSpeed = speed; } //! Sets the movement speed void CSceneNodeAnimatorCameraFPS::setMoveSpeed(f32 speed) { MoveSpeed = speed; } //! Gets the rotation speed f32 CSceneNodeAnimatorCameraFPS::getRotateSpeed() const { return RotateSpeed; } // Gets the movement speed f32 CSceneNodeAnimatorCameraFPS::getMoveSpeed() const { return MoveSpeed; } //! Sets the keyboard mapping for this animator void CSceneNodeAnimatorCameraFPS::setKeyMap(SKeyMap *map, u32 count) { // clear the keymap KeyMap.clear(); // add actions for (u32 i=0; i<count; ++i) { switch(map[i].Action) { case EKA_MOVE_FORWARD: KeyMap.push_back(SCamKeyMap(EKA_MOVE_FORWARD, map[i].KeyCode)); break; case EKA_MOVE_BACKWARD: KeyMap.push_back(SCamKeyMap(EKA_MOVE_BACKWARD, map[i].KeyCode)); break; case EKA_STRAFE_LEFT: KeyMap.push_back(SCamKeyMap(EKA_STRAFE_LEFT, map[i].KeyCode)); break; case EKA_STRAFE_RIGHT: KeyMap.push_back(SCamKeyMap(EKA_STRAFE_RIGHT, map[i].KeyCode)); break; case EKA_JUMP_UP: KeyMap.push_back(SCamKeyMap(EKA_JUMP_UP, map[i].KeyCode)); break; default: break; } } } //! Sets whether vertical movement should be allowed. void CSceneNodeAnimatorCameraFPS::setVerticalMovement(bool allow) { NoVerticalMovement = !allow; } //! Sets whether the Y axis of the mouse should be inverted. void CSceneNodeAnimatorCameraFPS::setInvertMouse(bool invert) { if (invert) MouseYDirection = -1.0f; else MouseYDirection = 1.0f; } ISceneNodeAnimator* CSceneNodeAnimatorCameraFPS::createClone(ISceneNode* node, ISceneManager* newManager) { CSceneNodeAnimatorCameraFPS * newAnimator = new CSceneNodeAnimatorCameraFPS(CursorControl, RotateSpeed, MoveSpeed, JumpSpeed, 0, 0, NoVerticalMovement); newAnimator->setKeyMap(KeyMap); return newAnimator; } void CSceneNodeAnimatorCameraFPS::setKeyMap(const core::array<SCamKeyMap>& keymap) { KeyMap=keymap; } } // namespace scene } // namespace irr
[S3]重新编译Irrlicht1.7.3即可