JavaFX 画布双缓冲 [英] JavaFX Canvas Double Buffering

查看:35
本文介绍了JavaFX 画布双缓冲的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 JavaFX 在 Java 中复制经典游戏 Pong.我使用 java.util.Timer、java.util.TimerTask 作为游戏循环和 JavaFX 的 Canvas 进行渲染.有没有办法向画布添加双缓冲,使动画不闪烁?或者我应该以不同的方式处理这个问题?波纹管是代码.我删除了其中一些我认为不相关的部分,因为代码大约有 200 行长.

I am replicating a classic game, Pong, in Java using JavaFX. I am using java.util.Timer, java.util.TimerTask for the game loop and JavaFX's Canvas for rendering. Is there a way to add double buffering to the Canvas so the animation doesn't flicker? Or should I approach this differently? Bellow is the code. I removed some parts of it, that I think are irrelevant, since the code is around 200 lines long.

Canvas canvas = new Canvas(stageW, stageH);
GraphicsContext gc;

public void start(Stage stage) throws Exception {
    Group root = new Group();

    gc = canvas.getGraphicsContext2D();

    Timer loop = new Timer();

    root.getChildren().add(canvas);

    loop.schedule(new GameLoop(), 0, 1000 / 60);

    stage.setScene(new Scene(root,stageW, stageH));
    stage.show();
}

public class GameLoop extends TimerTask {
    @Override
    public void run() {
        draw(gc);
        collisionDetect();
        ball.move();
    }
}

public void draw() {
    gc.setFill(Color.BLACK);
    gc.fillRect(0, 0, stageW, stageH);

    gc.setFill(Color.WHITE);
    gc.fillRect(lBat.getX(), lBat.getY(), lBat.getW(), lBat.getH());
    gc.fillRect(rBat.getX(), rBat.getY(), rBat.getW(), rBat.getH());
    gc.fillRect(ball.getX(), ball.getY(), ball.getW(), ball.getH());
}

推荐答案

你应该以不同的方式这样做.

You should do this differently.

  1. 定时器运行自己的线程.此任务不需要额外的线程.
  2. 您正在 JavaFX 应用程序线程之外对显示的画布执行修改(您不应在 JavaFX 线程之外修改场景中的对象).
  3. JavaFX 有一个基于 脉冲.此计时器称为 AnimationTimer,您应该使用那个.
  4. 您不需要双缓冲.
  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.

其他更高级别的工具,例如 TimelineTransitions 也可以使用,但它们主要用于场景图对象,您目前的实现基于 Canvas 不太适合他们.

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.

您不需要双重缓冲画布,因为 JavaFX 架构是一种延迟绘图架构.您发出绘图命令并调用 api 以调整 JavaFX 应用程序线程上的场景图,然后,完成后,您放弃对 JavaFX 应用程序线程的控制.JavaFX 将在内部计算出需要渲染的内容,并使用其内部渲染技术对查看的图像发出更新,该技术仅绘制完整的场景(或修补脏位).画布内部实现有一个命令队列,每个帧都会刷新该队列以呈现对画布的任何更改,因此您不会获得部分更新.

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.

此外,如果您有一个像 Pong 这样的基于物理的游戏,您可能想要引入一些概念,例如应用于移动物体(例如球)的速度,并在动画计时器的每次回调中更新物体位置(这种技术在下面的弹跳球演示中进行了演示).

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:

示例 AnimationTimer 代码(来自链接的弹跳球演示):

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

这篇关于JavaFX 画布双缓冲的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆