[SOLVED] Jme3 Beginner: Putting a Timer text in my animation

As a quick and dirty hack I use this to print my animation timer on the screen:



[java]

cinematic.addCinematicEvent(0, new AbstractCinematicEvent() {



@Override

public void onPlay() {

}

@Override

public void onUpdate(float tpf) {

counter += tpf;

//System.out.println("Simulation Timer: "+counter); // used for debugging

txt.setText("Simulation Timer: "+ Double.valueOf(String.format(Locale.US, “%1$.5f”, counter)));

}

@Override

public void onStop() {

}



@Override

public void onPause() {

}

});

[/java]



however this stops for some reason at time 10.003 seconds. the way my code is setup is initiate the code above at the beginning and then read from a trace file the other cinematic events.



The question is how can I update the simulation timer text all the time and not let it stop. And I’m curious to know why it’s stopping at time 10 specifically.

Can anyone help me with this?

How are you creating the BitmapText? If you leave the System.out.println() in does it continue to print out even after the bitmap text stops updating?



You may be being hit with a bug in BitmapText. (at least I think it’s still there.)

no I don’t get anything after 10 secs with System.out.println(); I create the BitmapText using the following code:



[java]// print the simulation timer on the animation screen

BitmapFont fnt = assetManager.loadFont(“Interface/Fonts/Default.fnt”);

final BitmapText txt = new BitmapText(fnt, false);

txt.setSize(fnt.getPreferredSize() * 2f);

txt.setLocalTranslation(0, settings.getHeight(), 0); // position of the printed timer

guiNode.attachChild(txt);[/java]

Ok, if you stop getting output even from the system out println then it’s not bitmap text’s fault. I have no idea.



10 seconds seems suspicious… like something is set to do something after 10 seconds but I don’t know anything about cinematics.

AbstractCinematicEvent’s initialDuration is 10 seconds

Exactly, the event last 10 secs, so its update method is not called anymore after 10 sec.

Ok now I know why i’m getting 10 secs however the question remains: Is there a way to setup a simulation timer?

I’m not certain what end result you want with the timer. Is it to show how far along each AbstractCinematicEvent is? Or globally knowing how long the cinematics have been running?

Globally… I want a timer for the animation as a whole

Just do a counter+=tpf in the main application class or a special appstate?

1 Like

As i’m using cinematics I don’t have a main update(tpf). How can I do so with a special appstate?

[java]

public class MyAppState extends AbstractAppState {

float totalTime = 0;

public void update( float tpf ) {

totalTime += tpf;

}

}

[/java]



Then somewhere:

getStateManager().attach( new MyAppState() );

So in my main I added:



[java]// Timer

getStateManager().attach( new MyAppState() );[/java]



and created the class MyAppState adding



[java]@Override

public void update( float tpf ) {

totalTime += tpf;

System.out.println("Sim time: "+totalTime);

}[/java]



however that update() function doesn’t get called

I have to check this because sooooo many people do it wrong:

Is your application extending SimpleApplication like it’s supposed to?



Does your MyAppState do anything different than the one I posted other than its update() method?

1 Like

Yes you were right!


Does your MyAppState do anything different than the one I posted other than its update() method?


I created a MyAppState that implements from appState and I guess the other methods were the problem. Now it works.

Sorry if this may sound too easy but does calling the main function from the update() of MyAppState to pass the new time (see below) a bad and design or will result in poor performance over the long term?


[java]@Override
public void update( float tpf )
{
totalTime += tpf;
//System.out.println("Sim time: "+totalTime);

// send it to Jme3Cinematics - Call updateTimer function to animate the timer
myApp.updateTimer(totalTime);
}[/java]

Yes that would be bad design: heading back to the main app constantly. It would mean you still have your timer code in the main app.

Try to encapsulate all of your timer stuff in your appState. In the initialize method you can grab the rootNode (or create your own node and attach it to the root node) from the main app and add your timer display directly to that, without having to go back to your main app constantly. Then make sure to remove the timer stuff from the node when the appState is detached.

@Sploreg, not sure I understood you very well. I do have the BitmapText created in the main and gets updated from a function also available in the main but gets called from MyAppState.



To do you what you are recommending, I didn’t quite get these 2 parts:



(1)

In the initialize method you can grab the rootNode (or create your own node and attach it to the root node) from the main app and add your timer display directly to that


how can I add a node or modify the rootNode from MyAppState?

and (2)
Then make sure to remove the timer stuff from the node when the appState is detached.


can u explain them please in code or pseudo code?

App states let you put a lot of the main app code that uses the update loop, outside of the main class. This way you can easily remove or disable an app state and not harm your main app.

When your AppState is created, its initialize() method is called. That is where you want to create your bitmap text. Then in the appState’s update, update that bitmap text directly without heading to your main app.

Basically copy all the bitmap text stuff you did to your appState.

https://wiki.jmonkeyengine.org/legacy/doku.php/jme3:advanced:application_states has some good examples.

1 Like

Hmmmm actually that made it worse, I guess i’m doing something wrong (look below at my MyAppState class):



[java]public class MyAppState extends AbstractAppState {



float totalTime = 0;

BitmapText txt;



// 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();



// Node that will hold the rootNode from Jme3Cinemtics (main)

private Node rootNode = new Node(“Root Node”);





@Override

public void initialize(AppStateManager stateManager, Application app) {



// print the simulation timer on the animation screen

BitmapFont fnt = assetManager.loadFont(“Interface/Fonts/Default.fnt”);

txt = new BitmapText(fnt, false);

txt.setSize(fnt.getPreferredSize() * 2f);

//txt.setLocalTranslation(0, settings.getHeight(), 0); // position of the printed timer

txt.setLocalTranslation(0, 0, 0); // position of the printed timer

getRootNode().attachChild(txt);



}



@Override

public void update( float tpf )

{

totalTime += tpf;

System.out.println("Sim time: "+totalTime);



// send it to Jme3Cinematics - Call updateTimer function to animate the timer

//myApp.updateTimer(totalTime);



txt.setText("Simulation Timer: "+ Double.valueOf(String.format(Locale.US, “%1$.5f”, totalTime)));



}





// function that gets the rootNode from the main (Jme3Cinematics)

public Node getRootNode(){

return rootNode;

}

}

[/java]



the issue is now the timer is running in the back ground even if I didn’t initiate the app yet.