RTS 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
Haddayn
Posts: 4
Joined: Mon Apr 28, 2014 4:49 am

RTS Camera Animator

Post by Haddayn »

Hey there. Here is some code I'd like to share. This is an animator for RTS-style camera. I didn't like the http://irrlicht.sourceforge.net/forum/v ... =9&t=17066 RTSCamera implementation (since it is kind of outdated), so I wrote my own.

It is still unfinished, but useable. On my todo list are adding possibility to rotate camera along up axis, and adding possibility to zoom/pan camera around cursor.

Code: Select all

 
        // Controls :
        // Mouse middle + Mouse move = move camera
        // Mouse pointer X/Y at border  = move camera
        // Mouse wheel up/down = zoom camera
 
Usage:

Code: Select all

 
    irr::scene::ICameraSceneNode* node = smgr->addCameraSceneNode(0, irr::core::vector3df(0,0,0), irr::core::vector3df(0,0,0));
    irr::scene::ISceneNodeAnimatorCameraRTS* animator = new irr::scene::CSceneNodeAnimatorCameraRTS(device->getCursorControl(),device->getTimer()); 
    node->addAnimator(animator);
    animator->drop();
 
ISceneNodeAnimator.h

Code: Select all

 
#ifndef __I_SCENE_NODE_ANIMATOR_CAMERA_RTS_H_INCLUDED__
#define __I_SCENE_NODE_ANIMATOR_CAMERA_RTS_H_INCLUDED__
 
 
namespace irr
{
 
namespace scene
{
    class ISceneNodeAnimator;
 
    //! A scene node animator for RTS-style camera
 
    class ISceneNodeAnimatorCameraRTS : public ISceneNodeAnimator
    {
    public:
 
        //! Returns the speed of movement
        virtual f32 getMoveSpeed() const = 0;
 
        //! Sets the speed of movement
        virtual void setMoveSpeed(f32 moveSpeed) = 0;
 
        //! Returns the rotation speed
        virtual f32 getRotateSpeed() const = 0;
 
        //! Set the rotation speed
        virtual void setRotateSpeed(f32 rotateSpeed) = 0;
 
        //! Returns the zoom speed
        virtual f32 getZoomSpeed() const = 0;
 
        //! Set the zoom speed
        virtual void setZoomSpeed(f32 zoomSpeed) = 0;
 
        //! Returns the camera zoom
        virtual f32 getZoom() const = 0;
 
        //! Set the camera zoom
        virtual void setZoom(f32 multiplier) = 0;
 
        //! Returns the current distance, i.e. orbit radius
        virtual f32 getDistance() const = 0;
 
        //! Set the distance
        virtual void setDistance(f32 dist) = 0;
        
        //! Get the camera angle
        virtual f32 getAngle() const = 0;
 
        //! Set the camera angle
        virtual void setAngle(f32 a) = 0;
 
        //! Get the camera angle for close zoom
        virtual f32 getAngleClose() const = 0;
 
        //! Set the camera angle
        virtual void setAngleClose(f32 a) = 0;
    };
 
} // end namespace scene
} // end namespace irr
 
#endif //__I_SCENE_NODE_ANIMATOR_CAMERA_RTS_H_INCLUDED__
 
CSceneNodeAnimatorCameraRTS.h

Code: Select all

 
// This is an extension for the "Irrlicht Engine".
// See copyright notice in irrlicht.h
 
#ifndef __C_SCENE_NODE_ANIMATOR_CAMERA_RTS_H_INCLUDED__
#define __C_SCENE_NODE_ANIMATOR_CAMERA_RTS_H_INCLUDED__
 
#include "irrlicht.h"
#include "ISceneNodeAnimatorCameraRTS.h"
 
namespace irr
{
 
namespace gui
{
    class ICursorControl;
}
 
namespace scene
{
 
    //! Scene node animator for RTS cameras
    class CSceneNodeAnimatorCameraRTS : public ISceneNodeAnimatorCameraRTS
    {
    public:
 
        //! Constructor
    CSceneNodeAnimatorCameraRTS(gui::ICursorControl* cursor, ITimer* timer, f32 distance=36.055, f32 angle=0.9828, f32 angle_close=0.5880, 
        f32 translateSpeed = 0.01f, f32 rotateSpeed = 0.1f, f32 zoomSpeed=0.1f);
 
        //! Destructor
        virtual ~CSceneNodeAnimatorCameraRTS();
 
        //! 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
        virtual f32 getMoveSpeed() const;
 
        //! Sets the speed of movement
        virtual void setMoveSpeed(f32 moveSpeed);
 
        //! Returns the rotation speed
        virtual f32 getRotateSpeed() const;
 
        //! Set the rotation speed
        virtual void setRotateSpeed(f32 rotateSpeed);
 
        //! Returns the zoom speed
        virtual f32 getZoomSpeed() const;
 
        //! Set the zoom speed
        virtual void setZoomSpeed(f32 zoomSpeed);
 
        //! Returns the camera zoom
        virtual f32 getZoom() const;
 
        //! Set the camera zoom
        virtual void setZoom(f32 multiplier);
 
        //! Returns the current distance, i.e. orbit radius
        virtual f32 getDistance() const;
 
        //! Set the distance
        virtual void setDistance(f32 dist);
        
        //! Get the camera angle
        virtual f32 getAngle() const;
 
        //! Set the camera angle
        virtual void setAngle(f32 a);
 
        //! Get the camera angle for close zoom
        virtual f32 getAngleClose() const;
 
        //! Set the camera angle
        virtual void setAngleClose(f32 a);
        
        //! 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);
 
    private:
        void allKeysUp();
        void animate();
        bool isMouseKeyDown(s32 key) const;
 
        bool MouseKeys[3];
        //bool MouseMiddleDown;
        enum MOUSE_KEY
        {
            MOUSE_KEY_RIGHT,
            MOUSE_KEY_MIDDLE,
            MOUSE_KEY_LEFT
        };
        
        gui::ICursorControl *CursorControl;
 
    ITimer* Timer;
        
    u32 LastUpdate;
 
        f32 distance;
        f32 angle;
        f32 angle_close;
 
        core::position2df MousePos;
        core::position2df MousePos_old;
 
 
        f32 ZoomSpeed;
        f32 RotateSpeed;
        f32 TranslateSpeed; 
 
        
        f32 MinZoom;
        f32 NewZoom;
        f32 CurrentZoom;
        f32 MaxZoom;
        
        f32 RotZ;
        f32 MaxRotZ;
 
        bool Zooming;
        bool Rotating;
        bool Scrolling;
        bool Scroll_lock;
        bool Dragging;
    };
 
} // end namespace scene
} // end namespace irr
 
#endif//__C_SCENE_NODE_ANIMATOR_CAMERA_RTS_H_INCLUDED__
 
CSceneNodeAnimatorCameraRTS.cpp

Code: Select all

 
#include "CSceneNodeAnimatorCameraRTS.h"
#include "math.h"
 
namespace irr
{
namespace scene
{
    
    CSceneNodeAnimatorCameraRTS::CSceneNodeAnimatorCameraRTS(gui::ICursorControl* cursor, f32 distance, f32 angle, f32 angle_close, 
        f32 translateSpeed, f32 rotateSpeed, f32 zoomSpeed) 
        : CursorControl(cursor), MousePos(0.5f, 0.5f), MousePos_old(0.5f, 0.5f), 
        ZoomSpeed(zoomSpeed), RotateSpeed(rotateSpeed), TranslateSpeed(translateSpeed),
    Zooming(false), Rotating(false), Scrolling(false), Scroll_lock(false), Dragging(false), 
    MinZoom(0.2f), MaxZoom(5.f), NewZoom(1.0f), CurrentZoom(1.0f), RotZ(0.0f),
    distance(), angle(angle), angle_close(angle_close)
 
    {
        if (CursorControl)
        {
            CursorControl->grab();
            MousePos = CursorControl->getRelativePosition();
        }
 
        allKeysUp();
    }
 
    //! destructor
    CSceneNodeAnimatorCameraRTS::~CSceneNodeAnimatorCameraRTS()
    {
        if (CursorControl)
        {
            CursorControl->drop();
        }
    }
 
    bool CSceneNodeAnimatorCameraRTS::OnEvent(const SEvent& event)
    {
        //if (event.EventType != EET_MOUSE_INPUT_EVENT)
        //  return false;
        
        switch(event.EventType)
        {
        case EET_MOUSE_INPUT_EVENT:
            switch(event.MouseInput.Event)
            {
            case EMIE_MMOUSE_PRESSED_DOWN:
                MouseKeys[1] = true;
                break;
            case EMIE_MMOUSE_LEFT_UP:
                MouseKeys[1] = false;
                break;
            case EMIE_MOUSE_MOVED:
                MousePos = CursorControl->getRelativePosition();
                break;
            case EMIE_MOUSE_WHEEL:
                NewZoom -= event.MouseInput.Wheel * ZoomSpeed * (CurrentZoom / (MaxZoom * MinZoom));
                break;
            /*case EMIE_LMOUSE_PRESSED_DOWN:
            case EMIE_RMOUSE_PRESSED_DOWN:
            case EMIE_LMOUSE_LEFT_UP:
            case EMIE_RMOUSE_LEFT_UP:
            case EMIE_LMOUSE_DOUBLE_CLICK:
            case EMIE_RMOUSE_DOUBLE_CLICK:
            case EMIE_MMOUSE_DOUBLE_CLICK:
            case EMIE_LMOUSE_TRIPLE_CLICK:
            case EMIE_RMOUSE_TRIPLE_CLICK:
            case EMIE_MMOUSE_TRIPLE_CLICK:
            case EMIE_COUNT:*/
            default:
                return false;
            }
 
            break;
            
        case EET_KEY_INPUT_EVENT:       
            /*for (u32 i=0; i<KeyMap.size(); ++i)
            {
                if (KeyMap[i].KeyCode == event.KeyInput.Key)
                {
                    CursorKeys[KeyMap[i].Action] = event.KeyInput.PressedDown;
                    return true;
                }
            }
 
            break;*/
 
        default:
            return false;
        }
        return true;
    }
    
    bool CSceneNodeAnimatorCameraRTS::isMouseKeyDown(s32 key) const
    {
        return MouseKeys[key];
    }
    
 
    void CSceneNodeAnimatorCameraRTS::allKeysUp()
    {
        for (s32 i=0; i<3; ++i)
            MouseKeys[i] = false;
    }
 
    //! OnAnimate() is called just before rendering the whole scene.
    void CSceneNodeAnimatorCameraRTS::animateNode(ISceneNode *node, u32 timeMs)
    {
        // Controls :
        // Mouse middle + Mouse move = move camera
        // Mouse pointer X/Y at border  = move camera
        // Mouse wheel up/down = zoom camera
 
        if (!node || node->getType() != ESNT_CAMERA)
            return;
        
        ICameraSceneNode* camera = static_cast<ICameraSceneNode*>(node);
        
        // If the camera isn't the active camera, and receiving input, then don't process it.
        if (!camera->isInputReceiverEnabled())
            return;
 
        scene::ISceneManager * scnmgr = camera->getSceneManager();
        if (scnmgr && scnmgr->getActiveCamera() != camera)
            return;
 
        if (!CursorControl)
        {
            return;
        }
 
        // Camera movement
        core::vector3df pos = camera->getPosition();
        core::vector3df target = camera->getTarget();
        core::vector3df translate(0,0,0);
 
        core::vector3df zoom_vector(0,distance*sin(angle),distance*cos(angle));
        core::vector3df zoom_close(0,zoom_vector.Y - distance*sin(angle_close),zoom_vector.Z - distance*cos(angle_close));
 
        //core::vector3df zoom_close(0,20,30);
        //core::vector3df zoom_point(0,0,0);
            
        if(isMouseKeyDown(MOUSE_KEY_MIDDLE) && !Zooming) //&& !Translating)
        {
            Dragging = true;
 
            if(MousePos != MousePos_old)
            {
                translate.X += TranslateSpeed*(MousePos.X - MousePos_old.X)*scnmgr->getVideoDriver()->getScreenSize().Width   * (CurrentZoom / (MaxZoom * MinZoom));
                translate.Z += TranslateSpeed*(MousePos_old.Y - MousePos.Y)*scnmgr->getVideoDriver()->getScreenSize().Height  * (CurrentZoom / (MaxZoom * MinZoom));
                MousePos_old = MousePos;
            }
 
            if ((MousePos.X < 0.005) || (MousePos.X > 0.995) || (MousePos.Y < 0.005) || (MousePos.Y > 0.995))
            {
                Scroll_lock = true;
            }
        }
        else
        {
            MousePos_old = MousePos;
            Dragging = false;
            if((MousePos.X > 0.005) && (MousePos.X < 0.995) && (MousePos.Y > 0.005) && (MousePos.Y < 0.995))
            {
                Scroll_lock = false;
            }
        }
 
        if(CurrentZoom != NewZoom && !Dragging && !Scrolling)
        {
            if(NewZoom >= MaxZoom)
            {
                NewZoom = MaxZoom;
            }
            else if(NewZoom <= MinZoom)
            {
                NewZoom = MinZoom;
            }
 
            CurrentZoom = NewZoom;
            
        #ifdef _DEBUG
            fprintf(stderr, "DEBUG: CurrentZoom %f\n", CurrentZoom);
        #endif //_DEBUG
 
            /*if(CurrentZoom < 1.f)
            {
                zoom_vector += zoom_close * (1.f - CurrentZoom - MinZoom*(CurrentZoom-1.f));
            }*/
 
            Zooming = true;
        }
        else
        {
            NewZoom = CurrentZoom;
            Zooming = false;
        }
 
        if(!Dragging && !Zooming && !Scroll_lock)
        {
            
        u32 TimeDelta = Timer->getTime() - LastUpdate;
        LastUpdate = Timer->getTime();
 
            if (MousePos.X < 0.005)   //Up
            {   
                translate.X +=  TranslateSpeed * static_cast<irr::f32>(TimeDelta);
            //#ifdef _DEBUG
            //  fprintf(stderr, "DEBUG: MousePos.X %f\n", MousePos.X);
            //#endif //_DEBUG
            }
            else if (MousePos.X > 0.995) //Down
            {
                translate.X -=  TranslateSpeed * static_cast<irr::f32>(TimeDelta);
            //#ifdef _DEBUG
            //  fprintf(stderr, "DEBUG: MousePos.X %f\n", MousePos.X);
            //#endif //_DEBUG
            }
 
            if (MousePos.Y < 0.005)   //Left
            {
                translate.Z -= TranslateSpeed * static_cast<irr::f32>(TimeDelta);
            //#ifdef _DEBUG
            //  fprintf(stderr, "DEBUG: MousePos.Y %f\n", MousePos.Y);
            //#endif //_DEBUG
            }
            else if (MousePos.Y > 0.995) //Right
            {
                translate.Z += TranslateSpeed * static_cast<irr::f32>(TimeDelta);
            //#ifdef _DEBUG
            //  fprintf(stderr, "DEBUG: MousePos.Y %f\n", MousePos.Y);
            //#endif //_DEBUG
            }
 
            if(translate.X + translate.Y == 0)
            {
                Scrolling = false;
            }
            else
            {
                Scrolling = true;
            }
        }
 
 
        target += translate; // + zoom_point;
        pos = target;
 
        if(CurrentZoom < 1.f)
        {
            pos += (zoom_vector * ((CurrentZoom - MinZoom)/(1.f - MinZoom)) + zoom_close * (1-(CurrentZoom - MinZoom)/(1.f - MinZoom)))*CurrentZoom;
        }
        else
        {
            pos += zoom_vector*CurrentZoom;
        }
 
        camera->setPosition(pos);
        camera->setTarget(target);
        //camera->setTarget(translate);
    }
 
    //! Returns the speed of movement
    f32 CSceneNodeAnimatorCameraRTS::getMoveSpeed() const
    {
        return TranslateSpeed;
    }
 
    //! Sets the speed of movement
    void CSceneNodeAnimatorCameraRTS::setMoveSpeed(f32 speed)
    {
        TranslateSpeed = speed;
    }
 
    //! Returns the rotation speed
    f32 CSceneNodeAnimatorCameraRTS::getRotateSpeed() const
    {
        return RotateSpeed;
    }
 
    //! Set the rotation speed
    void CSceneNodeAnimatorCameraRTS::setRotateSpeed(f32 speed)
    {
        RotateSpeed = speed;
    }
 
    //! Returns the zoom speed
    f32 CSceneNodeAnimatorCameraRTS::getZoomSpeed() const
    {
        return ZoomSpeed;
    }
 
    //! Set the zoom speed
    void CSceneNodeAnimatorCameraRTS::setZoomSpeed(f32 speed)
    {
        ZoomSpeed = speed;
    }
 
    //! Returns the camera zoom
    f32 CSceneNodeAnimatorCameraRTS::getZoom() const
    {
        return CurrentZoom;
    }
 
    //! Set the camera zoom
    void CSceneNodeAnimatorCameraRTS::setZoom(f32 multiplier)
    {
        if(multiplier < MaxZoom)
        {
            CurrentZoom = MaxZoom;
        }
        else if(multiplier > MinZoom)
        {
            CurrentZoom = MinZoom;
        }
        else            
        {
            CurrentZoom = multiplier;
        }
    }
 
    //! Returns the current distance, i.e. orbit radius
    f32 CSceneNodeAnimatorCameraRTS::getDistance() const
    {
        return distance;
    }
 
    //! Set the distance
    void CSceneNodeAnimatorCameraRTS::setDistance(f32 dist)
    {
        distance = dist;
    }
        
    //! Get the camera angle
    f32 CSceneNodeAnimatorCameraRTS::getAngle() const
    {
        return angle;
    }
 
    //! Set the camera angle
    void CSceneNodeAnimatorCameraRTS::setAngle(f32 a)
    {
        angle = a;
    }
 
    //! Get the camera angle for close zoom
    f32 CSceneNodeAnimatorCameraRTS::getAngleClose() const
    {
        return angle_close;
    }
 
    //! Set the camera angle
    void CSceneNodeAnimatorCameraRTS::setAngleClose(f32 a)
    {
        angle_close = a;
    }
 
 
    ISceneNodeAnimator* CSceneNodeAnimatorCameraRTS::createClone(ISceneNode* node, ISceneManager* newManager)
    {
        CSceneNodeAnimatorCameraRTS * newAnimator =
            new CSceneNodeAnimatorCameraRTS(CursorControl, RotateSpeed, ZoomSpeed, TranslateSpeed);
        return newAnimator;
    }
} // end namespace scene
} // end namespace irr
 
at35z
Posts: 7
Joined: Sat Apr 12, 2014 12:12 pm
Location: HU

Re: RTS Camera Animator

Post by at35z »

I'll give it a try, thanks for sharing it! :)
Wodzu
Posts: 27
Joined: Wed May 07, 2014 5:41 pm

Re: RTS Camera Animator

Post by Wodzu »

Hi, thanks for sharing but this code does not work.

It misses some ITimer parameters, for example in the constructor. But even after fixing the code I was not able to see anything through the camera, perhaps a small example with camera looking at something would be helpful.

Regards.
Post Reply