Writing a good acceleration function in Jmonkey

Edit: you beat me to it… so my post below is no longer valid.



Ok, I did miss that.



The little bits of code you’ve shown should work, I guess.



Where does your input come from? What did the debug lines I suggested print?

I need to look at my code again. The function makes sense, somehow debugging it was a little bit confusing which made me think there’s something major I need to change in it.



I’ll take a look at my code and report back.

ah!! endPosition is not the destination!!! its in fact the currentPosition!!!!!


Are you saying that this statement is correct? cz I take it back :) endPosition is being passed as the destination.


now the trace giving us the input is the following generated from a 100% working code:
[java]
time 0.6572779653234996
accelerate Car_1 to x = 0.725 y = 0.434 z = 0.0 duration = 1.3s initialSpeed = 0.0 accelerationRate = 1.0
time 1.9572779653234997
coast Car_1 x = 29.766 y =17.844 z = 0.0 duration = 26.045715034886744s
time 28.002993000210243
accelerate Car_1 x = 30.491 y = 18.278 z = 0.0 duration = 1.3 initialSpeed = 1.3000000000000003s accelerationRate = -1.0
[/java]

1- first issue the car reaches a max speed of 1.02m/s instead of 1.3 before coasting, it should be reach vmax (1.3)
2- 2nd issue is that the deceleration is not ending in the right place. Obviously there's minor miscalculations occuring somewhere

Note that the accelerationFactor was static at 0.8 and I replaced it with acceleration (thought would be more accurate) however acceleration doesn't look smooth now (meaning speed -= tpf * acceleration;) instead of (speed -= tpf * accelerationFactor); // this will get me a max final speed after acceleartion of 1.15 (still not 1.3)

In other words for issue no 1,



speed += tpf * acceleration;



is not enough to reach the max acceleration although it should. v = v0 + at if a is 1.3 v should be 1.3 at time 1.3s

This is the whole class:



[java]

import com.jme3.animation.LoopMode;

import com.jme3.app.Application;

import com.jme3.asset.AssetManager;

import com.jme3.cinematic.Cinematic;

import com.jme3.cinematic.events.AbstractCinematicEvent;

import com.jme3.export.InputCapsule;

import com.jme3.export.JmeExporter;

import com.jme3.export.JmeImporter;

import com.jme3.export.OutputCapsule;

import com.jme3.math.FastMath;

import com.jme3.math.Vector3f;

import com.jme3.scene.Spatial;

import com.kiva.sim.animation.Jme3Cinematics;

import java.io.IOException;

import java.util.logging.Level;

import java.util.logging.Logger;



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 float value = 0;

private float maxSpeed;

private float acceleration;

private float previousSpeed;

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

//private float = 0;

// 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) {

this.endPosition = endPosition;

this.spatial = spatial;

spatialName = spatial.getName();

}







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

float acceleration, float previousSpeed, float maxSpeed,

LoopMode loopMode)

{

super(initialDuration, loopMode);

this.endPosition = endPosition;

this.spatial = spatial;

//this.accelerationFactor = accelerationFactor;

this.acceleration = acceleration;

this.maxSpeed = maxSpeed;

this.previousSpeed = previousSpeed;

this.spatialName = spatial.getName();

speed = previousSpeed; // speed is a protected variable in cinemtics events

}





@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() {

// do nothing

}



@Override

public void onPlay() {

if (playState != playState.Paused) {

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

}

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



spatial.setLocalTranslation(endPosition);

}



}



@Override

public void onStop() {

value = 0;



}







@Override

public void onUpdate(float tpf) {



// to be synchronized with setTime()

if (spatial != null)

{

// time = myApp.time;

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



// acceleration using tpf, acceleration, and Cinematics speed

if(acceleration > epsilon)

{

System.out.println("Accelerated Speed: "+speed);

//System.out.println("Acceleration: "+acceleration);

speed += tpf * acceleration;// * myApp.getAnimationSpeed();



// if final speed exceeds max speed

if( speed > maxSpeed ) // no reason for epsilon here

{

speed = maxSpeed;

}

}



// deceleration using tpf, acceleration, and Cinematics speed

else if(acceleration < -epsilon)

{

System.out.println("Reduced Speed: "+speed);

//System.out.println("Deceleration: "+acceleration);

speed -= tpf * acceleration;// * myApp.getAnimationSpeed();



// if speed becomes negative

if( speed < -maxSpeed) // minSpeed = -maxSpeed

{

speed = -maxSpeed;

}



}



if( FastMath.abs(speed) < 0.01 )

{

speed = 0;

//System.out.println("STOP SPEED");

}



System.out.println("Final SPEED"+speed);

}





if (spatial != null) {

Vector3f dir = endPosition.subtract( startPosition );

dir.normalize();

Vector3f velocity = dir.mult( speed * tpf );

Vector3f pos = spatial.getLocalTranslation();

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

}

}



@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]

@nehon can u take a look? maybe we can fix it and put it up with the rest of the cinematic tracks. I think it could be important to have an AccelerateTrack right?

@garnaout said:
@nehon can u take a look? maybe we can fix it and put it up with the rest of the cinematic tracks. I think it could be important to have an AccelerateTrack right?

No that won't be in the engine. PositionTrack, RotationTrack and ScaleTrack are deprecated for a reason. This should be handled with the SpatialAnimation system.
For now there is a AnimationFactory that computes the animation by linearly interpolating between keyframed positions. The way to go would be to add some easeIn / easeOut support to this interpolation.

For your problem, you're still using tpf, that could be the cause of the imprecision, use the time attribute of the AbstractCinematicEvent.
Didn't we already went through this?
I'm sorry but i have no time to look more into your code, i'm already fiddling with my own project and the engine support/dev.

@nehon thanks for all your help I definitely appreciate it. The thing is if you go back to the previous post (where we went over this) you still haven’t replied to my question ( see http://hub.jmonkeyengine.org/groups/general-2/forum/topic/jme3-cinemtics-speeding-up-the-animation/?topic_page=3&num=15 ) - setTime() didn’t work for me.



again thanks for the help