// Copyright (C) 2002-2007 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h #include "CCameraFPSSceneNode.h" #include "IVideoDriver.h" #include "ISceneManager.h" #include "os.h" #include "Keycodes.h" namespace irr { namespace scene { const f32 MAX_VERTICAL_ANGLE = 88.0f; //! constructor CCameraFPSSceneNode::CCameraFPSSceneNode(ISceneNode* parent, ISceneManager* mgr, gui::ICursorControl* cursorControl, s32 id, f32 rotateSpeed , f32 moveSpeed,f32 jumpSpeed, SKeyMap* keyMapArray, s32 keyMapSize, bool noVerticalMovement) : CCameraSceneNode(parent, mgr, id), CursorControl(cursorControl), MoveSpeed(moveSpeed), RotateSpeed(rotateSpeed), JumpSpeed(jumpSpeed), firstUpdate(true), LastAnimationTime(0), NoVerticalMovement(noVerticalMovement) { #ifdef _DEBUG setDebugName("CCameraFPSSceneNode"); #endif if (CursorControl) CursorControl->grab(); MoveSpeed /= 1000.0f; recalculateViewArea(); allKeysUp(); // create key map if (!keyMapArray || !keyMapSize) { // create default key map KeyMap.push_back(SCamKeyMap(0, irr::KEY_UP)); KeyMap.push_back(SCamKeyMap(1, irr::KEY_DOWN)); KeyMap.push_back(SCamKeyMap(2, irr::KEY_LEFT)); KeyMap.push_back(SCamKeyMap(3, irr::KEY_RIGHT)); KeyMap.push_back(SCamKeyMap(4, irr::KEY_KEY_J)); } else { // create custom key map for (s32 i=0; idrop(); } //! 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 CCameraFPSSceneNode::OnEvent(SEvent event) { if (event.EventType == EET_KEY_INPUT_EVENT) { const u32 cnt = KeyMap.size(); for (u32 i=0; i::Iterator ait = Animators.begin(); for (; ait != Animators.end(); ++ait) (*ait)->animateNode(this, timeMs); updateAbsolutePosition(); Target = getPosition() + TargetVector; core::list::Iterator it = Children.begin(); for (; it != Children.end(); ++it) (*it)->OnAnimate(timeMs); } void CCameraFPSSceneNode::animate( u32 timeMs ) { const u32 camIsMe = SceneManager->getActiveCamera() == this; if (firstUpdate) { if (CursorControl && camIsMe) { CursorControl->setPosition(0.5f, 0.5f); CenterCursor = CursorControl->getRelativePosition(); } LastAnimationTime = os::Timer::getTime(); firstUpdate = false; } // get time. only operate on valid camera f32 timeDiff = 0.f; if ( camIsMe ) { timeDiff = (f32) ( timeMs - LastAnimationTime ); LastAnimationTime = timeMs; } // update position core::vector3df pos = getPosition(); // Update rotation // if (InputReceiverEnabled) { Target.set(0,0,1); if (CursorControl && InputReceiverEnabled && camIsMe ) { core::position2d cursorpos = CursorControl->getRelativePosition(); if (!core::equals(cursorpos.X, CenterCursor.X) || !core::equals(cursorpos.Y, CenterCursor.Y)) { RelativeRotation.X *= -1.0f; RelativeRotation.Y *= -1.0f; RelativeRotation.Y += (0.5f - cursorpos.X) * RotateSpeed; RelativeRotation.X = core::clamp ( RelativeRotation.X + (0.5f - cursorpos.Y) * RotateSpeed, -MAX_VERTICAL_ANGLE, +MAX_VERTICAL_ANGLE ); RelativeRotation.X *= -1.0f; RelativeRotation.Y *= -1.0f; CursorControl->setPosition(0.5f, 0.5f); CenterCursor = CursorControl->getRelativePosition(); } } // set target core::matrix4 mat; mat.setRotationDegrees(core::vector3df( RelativeRotation.X, RelativeRotation.Y, 0)); mat.transformVect(Target); core::vector3df movedir = Target; if (NoVerticalMovement) movedir.Y = 0.f; movedir.normalize(); if (InputReceiverEnabled && camIsMe) { if (CursorKeys[0]) pos += movedir * timeDiff * MoveSpeed; if (CursorKeys[1]) pos -= movedir * timeDiff * MoveSpeed; // strafing core::vector3df strafevect = Target; strafevect = strafevect.crossProduct(UpVector); if (NoVerticalMovement) strafevect.Y = 0.0f; strafevect.normalize(); if (CursorKeys[2]) pos += strafevect * timeDiff * MoveSpeed; if (CursorKeys[3]) pos -= strafevect * timeDiff * MoveSpeed; // jumping ( need's a gravity , else it's a fly to the World-UpVector ) if (CursorKeys[4]) { pos += UpVector * timeDiff * JumpSpeed; } } // write translation setPosition(pos); } // write right target TargetVector = Target; Target += pos; } void CCameraFPSSceneNode::allKeysUp() { for (s32 i=0; i<6; ++i) CursorKeys[i] = false; } //! sets the look at target of the camera //! \param pos: Look at target of the camera. void CCameraFPSSceneNode::setTarget(const core::vector3df& tgt) { updateAbsolutePosition(); core::vector3df vect = tgt - getAbsolutePosition(); vect = vect.getHorizontalAngle(); RelativeRotation.X = vect.X; RelativeRotation.Y = vect.Y; if (RelativeRotation.X > MAX_VERTICAL_ANGLE) RelativeRotation.X -= 360.0f; } //! Disables or enables the camera to get key or mouse inputs. void CCameraFPSSceneNode::setInputReceiverEnabled(bool enabled) { // So we don't skip when we return from a non-enabled mode and the // mouse cursor is now not in the middle of the screen if( !InputReceiverEnabled && enabled ) firstUpdate = true; InputReceiverEnabled = enabled; } //! Sets the rotation speed void CCameraFPSSceneNode::setRotateSpeed(const f32 speed) { RotateSpeed = speed; } //! Sets the movement speed void CCameraFPSSceneNode::setMoveSpeed(const f32 speed) { MoveSpeed = speed; } //! Gets the rotation speed f32 CCameraFPSSceneNode::getRotateSpeed() { return RotateSpeed; } // Gets the movement speed f32 CCameraFPSSceneNode::getMoveSpeed() { return MoveSpeed; } } // end namespace } // end namespace