Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Avoiding short stutter in animation when loading in/displaying FXML

When loading in a new FXML and setting the center of a BorderPane there is a brief 'freeze' of the application where existing animation, whether from a Timeline, or from a gif in an image view, will stop. I'm using this code to change the centerView:

 @FXML
    public void handleChangeView(ActionEvent event) {
        Task<Parent> loadTask = new Task<>() {
            @Override
            public Parent call() throws IOException {

                String changeButtonID = ((ToggleButton) event.getSource()).getId();
                Parent newOne = getFxmls().get(changeButtonID);

                if (newOne == null) {
                    FXMLLoader loader = new FXMLLoader(getClass().getResource("/view/" + changeButtonID + ".fxml"));
                    newOne = loader.load();
                    getFxmls().put(changeButtonID, newOne);
                }
                return newOne ;
            }
        };

        loadTask.setOnSucceeded(e -> {
                    getMainUI().setCenter(loadTask.getValue());
        });

        loadTask.setOnFailed(e -> loadTask.getException().printStackTrace());

        Thread thread = new Thread(loadTask);
        thread.start();
    }

And while this does the job in keeping the UI responsive in the load time, when the center stage displays for the first time there is a noticable lag. Looking at a CPU profile:

enter image description here

I'm not sure if the delay is from the initialize function running, or the loading of the elements. Here's a gif of the program, you can see the visible delay:

enter image description here

By loading it up in VLC and progresing frame-by-frame the delay looks to be 5 or 6 frames in a 30 fps video, meaning about a 200ms delay which implies the animation freezes for more than the 50ms or so initialize method. (Maybe the entire load method freezes the animation?)

The question is, is it possible to keep the animation smooth during this?

//********* EDIT **********//

So I went through the project and cut out as many methods and classes as possible, reducing the entire game to 6 minimal classes. I STILL have the delay in pressing the character button ('you' button). With such a minimal example I'm lost to what could be wrong. I've uploaded this to google drive for anyone to take a look.

https://drive.google.com/open?id=17A-PB2517bPJc8Dek-yp2wGXsjTyTj1d

like image 287
AlwaysNeedingHelp Avatar asked Jun 17 '18 04:06

AlwaysNeedingHelp


1 Answers

There is nothing "wrong" with your code (at least in regards to this issue).

The issue you are experiencing also has nothing to do with the loading of the FXML (which is very slow and you have correctly handled off FX-Thread).

The stutter happens for These reasons:

  • relativly large hierarchy in character.fxml
  • lots of CSS (delete the main.css and you will notice; the stutter is slightly less prominent)
  • dynamically changing the scene graph (adding/removing Nodes during runtime)

Every time you replace the center of the mainView with some large Node, it causes the JavaFx runtime to completely re-layout and re-style (at least) that node. This happens on the FX-Thread, hence you notice the stutter.

One possible mitigation is a classic game dev technique: Pre-allocating as much as possible. Simply load all necessary FMXLs once during startup and put them into the scene graph. In your click handlers then, change the visibility or (Z-)position of the Nodes you want to show/hide. This is a good use case for a StackPane for example.

I adapted your code a little to demonstrate what I mean: Prototype

Check out these ressources to learn more:

  • http://gameprogrammingpatterns.com/
  • https://stackoverflow.com/a/26537688/1271937
  • https://www.javaworld.com/article/2074652/core-java/javaone-2012-javafx-graphics-tips-and-tricks.html
like image 134
Oliver Jan Krylow Avatar answered Nov 16 '22 04:11

Oliver Jan Krylow