JavaFX Canvas Double Buffering

早过忘川 提交于 2019-12-06 11:23:36

You should do this differently.

  1. Timer runs its own thread. You don't need an additional thread for this task.
  2. You are executing modifications to the displayed canvas off of the JavaFX application thread (you should not modify objects in the scene off of the JavaFX thread).
  3. JavaFX has an in-built timer based upon a pulse that is generated for each frame by the JavaFX system. This timer is called an AnimationTimer, you should use that.
  4. You don't need double buffering.

Other higher level facilities such as Timeline or Transitions could also be used, but they are primarily for scene graph objects and you are currently basing your implementation on a Canvas which is not well suited to them.

You could consider switching your implementation from using canvas to the scene graph, which might make the implementation a bit easier, but you can code it either way.

You don't need to double-buffer the canvas as the JavaFX architecture is a delayed drawing architecture. You issue drawing commands and invoke api to adjust the scene graph on the JavaFX application thread, then, when you are done, you relinquish control of the JavaFX application thread. JavaFX will work out internally what needs to be rendered and issue updates to the viewed image using it's internal rendering technology, which just draws complete scenes (or patches the dirty bits). The canvas internal implementation has a command queue which is flushed for each frame to render any changes to the canvas, so you don't get partial updates.

Additionally, given you have a physics based game like Pong, you might want to introduce concepts such as velocity that you apply to moving objects such as the ball and update the object position on each iteration of the callback from the animation timer (this technique is demonstrated in the bouncing ball demo below).

You may be interested in reading a couple of resources:

Sample AnimationTimer code (from the bouncing ball demo linked):

final LongProperty lastUpdateTime = new SimpleLongProperty(0);
final AnimationTimer timer = new AnimationTimer() {
    @Override
    public void handle(long timestamp) {
        if (lastUpdateTime.get() > 0) {
            long elapsedTime = timestamp - lastUpdateTime.get();
            checkCollisions(ballContainer.getWidth(), ballContainer.getHeight());
            updateWorld(elapsedTime);
            frameStats.addFrame(elapsedTime);
        }
        lastUpdateTime.set(timestamp);
    }
};
timer.start();
GOXR3PLUS

The best way to achieve 60 fps is using AnimationTimer:

  1. You can extend it through a costume class

 public class AnimationClass extends AnimationTimer {

    @Override
    public void handle(long nano) {
      //Code here
    }
}
  1. You can implement it instantly with an anonymous class

  new AnimationTimer() {
        @Override
        public void handle(long now) {              

        }
    }.start();
}

A nice example is here.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!