Is there an accuracy problem in the cinematics’ positioning?

so what you’re saying is leave Everything the same except replace time with my own timer? I’m gonna give it a shot. Never played around with the system timer.



thanks

So i’m going with your approach although I am not completely sure it’s gonna be more accurate, the issue I am having is that getElapsedTime() does not give me the right elapsed time :S



[java]



public class AccelerateTrack extends AbstractCinematicEvent {



private static final Logger log = Logger.getLogger(AccelerateTrack.class.getName());

private Vector3f startPosition;

private Vector3f endPosition;

private Spatial spatial;

private String spatialName = “”;

private double value = 0;

private double maxSpeed;

private double currentSpeed;

private double acceleration;

private double previousSpeed;

float epsilon = 0.001f; // used to compare floats accurately

float animationSpeed;

double prevDisp;



//my own timer

private long startTimer = 0;

private long stopTimer = 0;

private long elapsed = 0;

boolean running = false;



// create an instance of the Simpleapplication inside Jme3Cinematics

private Jme3Cinematics myApp = Jme3Cinematics.getApp();



// reads the asset manager initialized in Jme3Cinematics

private AssetManager assetManager = myApp.getAssetManager();





public AccelerateTrack(Spatial spatial, Vector3f endPosition, double initialDuration,

double acceleration, double previousSpeed, double maxSpeed,

LoopMode loopMode)

{

super((float) initialDuration, loopMode);

this.endPosition = endPosition;

this.spatial = spatial;

this.acceleration = acceleration;

this.maxSpeed = maxSpeed;

this.previousSpeed = previousSpeed;

this.spatialName = spatial.getName();

currentSpeed = previousSpeed;

startTimer = System.currentTimeMillis();

}





@Override

public void initEvent(Application app, Cinematic cinematic) {

super.initEvent(app, cinematic);

if (spatial == null) {



spatial = cinematic.getScene().getChild(spatialName);

if (spatial == null) {

} else {

log.log(Level.WARNING, “spatial {0} not found in the scene”, spatialName);

}

}

}





@Override

public void onPause() {

running = false;

}



@Override

public void onPlay() {

if (playState != playState.Paused) {

startPosition = spatial.getWorldTranslation().clone();

}





if (initialDuration == 0 && spatial != null) {



spatial.setLocalTranslation(endPosition);

}



startTimer = System.currentTimeMillis();

running = true;

System.out.println(“Acceleration track called”);

System.out.println("Syst time: "+startTimer);





elapsed = 0; // reset timer

//startTimer = 0;



//printElapsedTime();



}



@Override

public void onStop() {

value = 0;

running = false;



}





@Override

public void onUpdate(float tpf) {





// to be synchronized with setTime()

if (spatial != null)

{

// the animation speed (e.g. 2x)

animationSpeed = myApp.getAnimationSpeed();



// if positive acceleration

if(acceleration > epsilon)

{

currentSpeed = (getElapsedTime() * acceleration) * animationSpeed;





// limit speed to a max speed

if( currentSpeed > maxSpeed * animationSpeed )

{

currentSpeed = maxSpeed ;

}



}



// if negative acceleration (or deceleration)

else if(acceleration < -epsilon)

{

currentSpeed = (previousSpeed * animationSpeed) + ( getElapsedTime() * (acceleration) * animationSpeed);

}

}



// the exact current position is x(t) = x(0) + v(0)*t + 1/2(at^2)

// which is the integral of the current speed - previousPosition

if (spatial != null) {



Vector3f dir = endPosition.subtract( startPosition );

dir.normalize();

Vector3f velocity = dir.mult( (float) (currentSpeed * tpf + acceleration * tpf * tpf * 0.5f) );

Vector3f pos = spatial.getLocalTranslation();

spatial.setLocalTranslation( pos.add(velocity) );



}

}







//elaspsed time in seconds

private long getElapsedTime() {

long elapsed;

if (running) {

elapsed = (System.currentTimeMillis() - startTimer)/1000;



System.out.println("system time: "+ System.currentTimeMillis());

System.out.println("sstartTimer "+ startTimer);

}

else {

elapsed = (stopTimer - startTimer)/1000;

}



System.out.println("Elapsed Time "+elapsed);

return elapsed;

}









@Override

public void write(JmeExporter ex) throws IOException {

super.write(ex);

OutputCapsule oc = ex.getCapsule(this);

oc.write(spatialName, “spatialName”, “”);

oc.write(endPosition, “endPosition”, null);

}



@Override

public void read(JmeImporter im) throws IOException {

super.read(im);

InputCapsule ic = im.getCapsule(this);

spatialName = ic.readString(“spatialName”, “”);

endPosition = (Vector3f) ic.readSavable(“endPosition”, null);

}



}

[/java]

I really think the issue is in the function where I am advancing the spatial. I shouldn’t be advancing using tpf but using time or my own timer. tpf is the reason of the problem. @androlo wrote this function which I think could be a start (however at the moment it is less accurate than my current function)



@androlo’s function

[java]// the exact current position is x(t) = x(0) + v(0)*t + 1/2(at^2)

// which is the integral of the current speed - previousPosition

if (spatial != null) {

Vector3f dir = endPosition.subtract( startPosition );

dir.normalize();

double disp = currentSpeed * time * 0.5f;

Vector3f velocity = dir.mult((float) (disp - prevDisp));

prevDisp = disp;

Vector3f pos = spatial.getLocalTranslation();

spatial.setLocalTranslation( pos.add(velocity) );

}[/java]



current function

[java]// the exact current position is x(t) = x(0) + v(0)*t + 1/2(at^2)

// which is the integral of the current speed - previousPosition

if (spatial != null) {



Vector3f dir = endPosition.subtract( startPosition );

dir.normalize();

Vector3f velocity = dir.mult( (float) (currentSpeed * tpf + acceleration * tpf * tpf * 0.5f) ); // this is a position

Vector3f pos = spatial.getLocalTranslation();

spatial.setLocalTranslation( pos.add(velocity) );





}[/java]

Okay so I got it figured out by really simplifying it (see below) however now the only issue is that I am not taking time into consideration which means when I speed up the animation things gets messy. How can I find a way around that but using time to get the updated position?



[java]@Override

public void onUpdate(float tpf) {



//value = Math.min(time / initialDuration, 1.0f);

//time = time+ (tpf * speed);



// get spatial acceleration direction

float vx = (float) (currentSpeed * Math.cos(theta));

float vy = (float) (currentSpeed * Math.sin(theta));



// get spatial local translation

Vector3f x0 = spatial.getLocalTranslation();



// get spatial initial speed

Vector3f v0 = new Vector3f(vx, vy, 0);



// get spatial x(t) according to the formula

// x(t) = x0 + v0(t) + 1/2 at^2

// tpf is the delta time here

Vector3f xi = x0.add(v0.mult(tpf));

xi.addLocal(acceleration.mult(0.5f * tpf * tpf));



// update the location of the spatial accordingly

spatial.setLocalTranslation( xi );



// update the current speed for the next update

currentSpeed = currentSpeed + acceleration.x * tpf;



}[/java]

of course a cleaner approach than multiplying xi and currentSpeed by myApp.getAnimationSpeed()

i can’t give a detailed answer as i haven’t tried to implement the same application,

i would try the following, don’t know if it will work for you :

a) i would consider “time” as data. Data is manipulated by YOU, its up to you if it goes forward, backward, how much. I would remove all 3d knowledge from my head and treat it as a plain java application. Ignore “float tpf” as its only a render. Treat time as data, jme as “preview” of data.