3rd person rpg camera animator

Post those lines of code you feel like sharing or find what you require for your project here; or simply use them as tutorials.
Post Reply
freezzo
Posts: 27
Joined: Thu Mar 08, 2007 6:36 pm
Contact:

3rd person rpg camera animator

Post by freezzo »

Hey all, I have been working on a third person camera that behave like most MMO/RPG style ones out there today:

- Mouse wheel zoom.
- Rotate camera around character with left mouse button.
- Rotate camera up and down with right mouse. Player rotation is handled separately, however camera updates based on the rotation of the player.

I have an issue when I rotate the player outside of the camera and then push the right mouse button, it "snaps" back, which it shouldn't do and I can't quite figure it out. I think I need to update "cameraPosition" based on the new camera location due to the outside player rotation, but can't figure it out. Can anyone help? (Ignore the class names, I have modified the good RTS camera animator for this and haven't updated yet)

Code: Select all

 
#include "CSceneNodeAnimatorRTS.h"
 
using namespace irr;
using namespace core;
using namespace gui;
using namespace io;
using namespace scene;
using namespace video;
 
CSceneNodeAnimatorRTS::CSceneNodeAnimatorRTS(irr::core::vector3df cameraPosition, gui::ICursorControl* cursorControl) : cameraPosition(cameraPosition), cursorControl(cursorControl)
{
    initCam();
}
 
CSceneNodeAnimatorRTS::~CSceneNodeAnimatorRTS()
{
}
 
void CSceneNodeAnimatorRTS::initCam()
{
    activeMouseButton = USE_MOUSE_L;
    
    camera = NULL;
    parent = NULL;
    
    cameraOrbit       = 90.0f;
    
    cameraAngle       = 30.0f;
    cameraAngleMin    = 15.0f;
    cameraAngleMax    = 88.0f;
    
    cameraDistance    = 100.0f;
    cameraDistanceMin = 50.0f;
    cameraDistanceMax = 300.0f;
    
    cameraSpeedMouse  = 5.0f;
    cameraSpeedDrift  = 100.0f;
    cameraSpeedScroll = 5.0f;
    
    cameraMinX        = 0.0f;
    cameraMaxX        = 250.0f;
    cameraMinZ        = 0.0f;
    cameraMaxZ        = 250.0f;
    
    cameraOrbitOld    = 0.0f;
    cameraAngleOld    = 0.0f;
    
    firstTime         = true;
    mouseMoved        = false;
    mouseZoom         = false;
    mouseDownL        = false;
    mouseDownR        = false;
    mouseDownM        = false;
    
    movingCamera      = false;
    rotatingParent    = false;
    
    for (u32 i = 0; i < KEY_KEY_CODES_COUNT; ++i) keyDown[i] = false;
    
    timeThen = 0;
    
    if (cursorControl)
    {
        cursorControl->grab();
        cursor = cursorOld = cursorControl->getRelativePosition();
    }
}
 
bool CSceneNodeAnimatorRTS::OnEvent(const irr::SEvent& event)
{
    switch (event.EventType)
    {
        case EET_KEY_INPUT_EVENT : return OnKeyInputEvent(event);
            
        case EET_MOUSE_INPUT_EVENT :
        {
            switch (event.MouseInput.Event)
            {
                case EMIE_LMOUSE_PRESSED_DOWN : return OnLMousePressedDown(event);
                case EMIE_LMOUSE_LEFT_UP      : return OnLMouseLeftUp(event);
                    
                case EMIE_RMOUSE_PRESSED_DOWN : return OnRMousePressedDown(event);
                case EMIE_RMOUSE_LEFT_UP      : return OnRMouseLeftUp(event);
                    
                case EMIE_MMOUSE_PRESSED_DOWN : return OnMMousePressedDown(event);
                case EMIE_MMOUSE_LEFT_UP      : return OnMMouseLeftUp(event);
                    
                case EMIE_MOUSE_MOVED         : return OnMouseMoved(event);
                case EMIE_MOUSE_WHEEL         : return OnMouseWheel(event);
            }
        }
    }
    
    return false;
}
 
bool CSceneNodeAnimatorRTS::OnKeyInputEvent(const irr::SEvent &e)
{
    keyDown[e.KeyInput.Key] = e.KeyInput.PressedDown;
    return false;
}
 
bool CSceneNodeAnimatorRTS::OnLMousePressedDown(const irr::SEvent &e)
{
    mouseDownL = true;
    
    return CameraMouseButton(e);
}
 
bool CSceneNodeAnimatorRTS::OnLMouseLeftUp(const irr::SEvent &e)
{
    mouseDownL = false;
    return false;
}
 
bool CSceneNodeAnimatorRTS::OnRMousePressedDown(const irr::SEvent &e)
{
    mouseDownR = true;
    
    return CameraMouseButton(e);
}
 
bool CSceneNodeAnimatorRTS::OnRMouseLeftUp(const irr::SEvent &e)
{
    mouseDownR = false;
    return false;
}
 
bool CSceneNodeAnimatorRTS::OnMMousePressedDown(const SEvent &e)
{
    mouseDownM = true;
    
    return CameraMouseButton(e);
}
 
bool CSceneNodeAnimatorRTS::OnMMouseLeftUp(const irr::SEvent &e)
{
    mouseDownM = false;
    return false;
}
 
bool CSceneNodeAnimatorRTS::OnMouseMoved(const irr::SEvent &e)
{
    return CameraMouseMoved(e);
}
 
bool CSceneNodeAnimatorRTS::OnMouseWheel(const irr::SEvent &e)
{
    return CameraMouseWheel(e);
}
 
bool CSceneNodeAnimatorRTS::CameraMouseButton(const irr::SEvent &e)
{
    cursorOld.X      = (f32)e.MouseInput.X;
    cursorOld.Y      = (f32)e.MouseInput.Y;
    cursorDelta.X    = 0.0f;
    cursorDelta.Y    = 0.0f;
    cursorDeltaOld.X = 0.0f;
    cursorDeltaOld.Y = 0.0f;
    cameraOrbitOld   = cameraOrbit;
    cameraAngleOld   = cameraAngle;
    
    return false;
}
 
bool CSceneNodeAnimatorRTS::CameraMouseMoved(const irr::SEvent &e)
{
    //if( (activeMouseButton == USE_MOUSE_L && mouseDownL) ||
    //   (activeMouseButton == USE_MOUSE_R && mouseDownR) ||
    //   (activeMouseButton == USE_MOUSE_M && mouseDownM))
    if(mouseDownL || mouseDownR)
    {
        cursor.X = (f32)e.MouseInput.X;
        cursor.Y = (f32)e.MouseInput.Y;
        
        cursorDelta.X = (cursor.X - cursorOld.X) / cameraSpeedMouse;
        cursorDelta.Y = (cursor.Y - cursorOld.Y) / cameraSpeedMouse;
        
        if (cursorDelta.Y > (88.0f - cameraAngleOld))
        {
            cursorOld.Y += (cursorDelta.Y - cursorDeltaOld.Y);
            cursorDelta.Y = 88.0f - cameraAngleOld;
        }
        
        if (cursorDelta.Y < (-88.0f - cameraAngleOld))
        {
            cursorOld.Y += (cursorDelta.Y - cursorDeltaOld.Y);
            cursorDelta.Y = -88.0f - cameraAngleOld;
        }
        
        cursorDeltaOld.X = cursorDelta.X;
        cursorDeltaOld.Y = cursorDelta.Y;
 
        cameraAngle = fmod((cameraAngleOld + cursorDelta.Y), 360.0f);
        if(cameraAngle > cameraAngleMax) cameraAngle = cameraAngleMax;
        if(cameraAngle < cameraAngleMin) cameraAngle = cameraAngleMin;
        
        float tmpOrbit = fmod((cameraOrbitOld + cursorDelta.X), 360.0f);
        
        if(mouseDownL)
        {
            cameraOrbit = tmpOrbit;
        }
    }
    
    return false;
}
 
bool CSceneNodeAnimatorRTS::CameraMouseWheel(const irr::SEvent &e)
{
    cameraDistance -= (e.MouseInput.Wheel * cameraSpeedScroll);
    
    if(cameraDistance < cameraDistanceMin) cameraDistance = cameraDistanceMin;
    if(cameraDistance > cameraDistanceMax) cameraDistance = cameraDistanceMax;
    
    return false;
}
 
void CSceneNodeAnimatorRTS::animateNode(irr::scene::ISceneNode* node, irr::u32 timeMs)
{
    if (!node || node->getType() != ESNT_CAMERA) { return; }
    camera = static_cast<ICameraSceneNode*>(node);
 
    parent = camera->getParent();
    if (!parent)
    {
        return;
    }
    
    if (firstTime)
    {
        camera->setPosition(cameraPosition);
        camera->setTarget(parent->getPosition());
        firstTime = false;
    }
    
    timeDelta = (f32)(timeMs - timeThen) * 0.001f;
    timeThen  = timeMs;
    
    core::vector3df position = cameraPosition;
    core::vector3df rotation = parent->getRotation();
    
    f32 NEWcameraOrbit = cameraOrbit - 90.0f;
    f32 NEWcameraAngle = cameraAngle * -1.0f + 45.0f;
    
    matrix4 m, n;
    
    n.setRotationDegrees(core::vector3df(-NEWcameraAngle, NEWcameraOrbit, 0));
    n.rotateVect(position);
    
    // Perform zooming
    position.setLength(cameraDistance);
    
    camera->setPosition(position);
    camera->setTarget(parent->getPosition());
    camera->updateAbsolutePosition();
}
 
void CSceneNodeAnimatorRTS::setDeadZone(irr::f32 newMinX, irr::f32 newMaxX, irr::f32 newMinZ, irr::f32 newMaxZ)
{
    cameraMinX = newMinX;
    cameraMaxX = newMaxX;
    cameraMinZ = newMinZ;
    cameraMaxZ = newMaxZ;
}
 
void CSceneNodeAnimatorRTS::setCameraPosition(irr::core::vector3df position)
{
    if (camera && parent)
    {
        camera->setPosition(position);
        camera->setTarget(parent->getPosition());
        cameraPosition = position;
    }
}
 
einsteinsci
Posts: 10
Joined: Tue Nov 19, 2013 3:35 am

Re: 3rd person rpg camera animator

Post by einsteinsci »

Do you have a few screenshots/video of it in action? Looks really well-done.
thanhle
Posts: 325
Joined: Wed Jun 12, 2013 8:09 am

Re: 3rd person rpg camera animator

Post by thanhle »

You need to use Matrices or Quaternion to prevent the snap back caused by rotations.
You might need to learn the dot and cross product.

Regards
Post Reply