Topic: Smoothly move the M3Object3d with custom behavior

In my maratis project I have invisible Target object, and Camera, which has Follow Target behavior and Looks At target behavior.
I want to move target from my C++ code, thus force Camera follows this object.
I  want to achieve effect of smooth moving the camera.
I create custom MoveTo behavior. Objects are initialized with new position , and the time during which they have to move. (If you familiar with cocos2d actions - I want to realize analogue of CCMoveTo for maratis).
I add behavior to my target object:

 target = scene->getObjectByName("Target");
 float animationDuration = 1.5;
 MoveToBehaviour *moveToBeh = new MoveToBehaviour(target, categoryTargetPosition, animationDuration);
 target->addBehavior( moveToBeh );
// delete behavior after delay
 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, animationDuration*1.1 * NSEC_PER_SEC), dispatch_get_current_queue(), ^{
     target->deleteBehavior(0);
 });

When this code executed, the camera instantly move to new position, without smooth movement.
What I'm doing wrong?
How to do this correctly?
Does MBehavior::update() is called periodically by engine , or should I manually call MBehavior::update() on every frame?

Code of MoveTo behavior class:

#ifndef _MB_MOVETO_H
#define _MB_MOVETO_H

#include <sys/time.h>

class MoveToBehaviour : public MBehavior
{
public:
    // constructors / destructors
    MoveToBehaviour(MObject3d * parentObject, MVector3 _pos, float _tm);
    MoveToBehaviour(MoveToBehaviour & behavior, MObject3d * parentObject);
    ~MoveToBehaviour(void);
private:

    float tm, elapsedTime;
    MVector3 pos;
    MVector3 initialPos;
    struct timeval lastCallTime;
//    M
public:

    // destroy
    void destroy(void);

    // get new
    static MBehavior * getNew(MObject3d * parentObject);

    // get copy
    MBehavior * getCopy(MObject3d * parentObject);

    // name
    static const char * getStaticName(void){ return "MoveTo"; }
    const char * getName(void){ return getStaticName(); }

    // events
    void update(void);
    void runEvent(int param){}

    // variables
    unsigned int getVariablesNumber(void);
    MVariable getVariable(unsigned int id);
};

#endif

.cpp:

#include <MEngine.h>
#include "MoveToBehaviour.h"

/////////////////////////////////////////////////////////////////////////////////////////////////////////
// Init
/////////////////////////////////////////////////////////////////////////////////////////////////////////

MoveToBehaviour::MoveToBehaviour(MObject3d * parentObject, MVector3 _pos, float _tm) :
MBehavior(parentObject),
tm (_tm),
pos (_pos),
elapsedTime (0.0)
{
    gettimeofday(&lastCallTime, NULL);
    initialPos = MVector3();
    if (parentObject) {
        initialPos = parentObject->getPosition();
    }
}

MoveToBehaviour::MoveToBehaviour(MoveToBehaviour & behavior, MObject3d * parentObject) :
MBehavior(parentObject),
tm (behavior.tm),
pos (behavior.pos),
elapsedTime (behavior.elapsedTime),
lastCallTime(behavior.lastCallTime),
initialPos (behavior.initialPos)
{}

MoveToBehaviour::~MoveToBehaviour(void) {}

void MoveToBehaviour::destroy(void)
{
    delete this;
}

MBehavior * MoveToBehaviour::getNew(MObject3d * parentObject)
{
    return new MoveToBehaviour(parentObject, MVector3() , 0.0 );
}

MBehavior * MoveToBehaviour::getCopy(MObject3d * parentObject)
{
    return new MoveToBehaviour(*this, parentObject);
}


/////////////////////////////////////////////////////////////////////////////////////////////////////////
// Variables
/////////////////////////////////////////////////////////////////////////////////////////////////////////

unsigned int MoveToBehaviour::getVariablesNumber(void){
    return 2;
}

MVariable MoveToBehaviour::getVariable(unsigned int id)
{
    switch(id)
    {
    default:
        return MVariable("NULL", NULL, M_VARIABLE_NULL);
    case 0:
        return MVariable("time", &tm, M_VARIABLE_FLOAT);
    case 1:
        return MVariable("moveToPosition", &pos, M_VARIABLE_VEC3);
    }
}


/////////////////////////////////////////////////////////////////////////////////////////////////////////
// Events
/////////////////////////////////////////////////////////////////////////////////////////////////////////

void MoveToBehaviour::update(void)
{
    if (elapsedTime >= tm*1000.0) {
        return;
    }
    
    MEngine * engine = MEngine::getInstance();
    MGame * game = engine->getGame();
    MLevel * level = engine->getLevel();
    MScene * scene = level->getCurrentScene();

    MObject3d * parent = getParentObject();

    long lastMillis = lastCallTime.tv_sec * 1000 + lastCallTime.tv_usec / 1000;
    
    struct timeval tv ;
    gettimeofday(&tv, NULL);
    long millis = (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
    long dt = millis - lastMillis;
    lastCallTime = tv;
    
    MVector3 dpos = (pos - initialPos) * ( ((float)dt) / (tm*1000.0) );
    MVector3 newPosition = parent->getPosition() + dpos;
    parent->setPosition( newPosition );
    parent->updateMatrix();
    
    elapsedTime += dt;
    if (elapsedTime >= tm*1000.0) {
        parent->setPosition( pos );
        parent->updateMatrix();
    }
}

Last edited by Petr (2012-09-07 09:11:50)

Re: Smoothly move the M3Object3d with custom behavior

I've found and fix  the error ,code works now.

Re: Smoothly move the M3Object3d with custom behavior

update is called 60 times/sec

I think the problem is in your algorithm,
and should you not do : 

MVector3 newPosition = initialPos + dpos;

instead of :

MVector3 newPosition = parent->getPosition() + dpos;

Also, to get ticks, use engine->getSystemContext()->getSystemTick() instead of gettimeofday (more portable)

Re: Smoothly move the M3Object3d with custom behavior

I think its ok with  MVector3 newPosition = parent->getPosition() + dpos;   ,
dpos - distance that object moved from last update.

Code works now, but movement is not smooth. its very jerky.
App works very slow.
How can I get current fps from engine? I want to experiment with different effects on/off and different meshes

I will try to use
engine->getSystemContext()->getSystemTick()
also

Re: Smoothly move the M3Object3d with custom behavior

There is no build-in variable for fps, you have to count the frames every seconds,
you can do that in MGame::draw for example, increment a number every frame and when 1 sec is done you'll have fps.

But I'll try to add this feature by default soon.

Re: Smoothly move the M3Object3d with custom behavior

Thanks a lot!