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.