JavaFXCanvas双缓冲

JavaFXCanvas双缓冲,java,canvas,javafx,2d-games,double-buffering,Java,Canvas,Javafx,2d Games,Double Buffering,我正在使用JavaFX用Java复制一个经典游戏Pong。我使用java.util.Timer、java.util.TimerTask进行游戏循环,使用JavaFX的画布进行渲染。有没有办法向画布添加双缓冲,使动画不会闪烁?或者我应该以不同的方式来处理这个问题?下面是代码。我删除了其中一些我认为不相关的部分,因为代码大约有200行长 Canvas canvas = new Canvas(stageW, stageH); GraphicsContext gc; public void start

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

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

达到60 fps的最佳方法是使用:

  • 您可以通过服装类来扩展它
  • 您可以使用匿名类立即实现它

  • 一个很好的例子是。

    你应该以不同的方式来做

  • 计时器运行自己的线程。此任务不需要额外的线程
  • 您正在JavaFX应用程序线程之外对显示的画布执行修改(您不应该在JavaFX线程之外修改场景中的对象)
  • JavaFX有一个内置计时器,它基于JavaFX系统为每个帧生成的。这个计时器叫做,你应该用它
  • 你不需要双重缓冲
  • 也可以使用其他更高级别的工具,如或,但它们主要用于场景图对象,并且您当前基于的实现不太适合它们

    您可以考虑将实现从使用画布切换到场景图,这可能会使实现更加简单,但是您可以用任何方式对其进行编码。

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

    此外,如果您有一个基于物理的游戏(如乒乓球),您可能希望引入一些概念,例如应用于移动对象(如球)的速度,并在动画计时器回调的每次迭代中更新对象位置(此技术在下面的反弹球演示中演示)

    您可能有兴趣阅读一些参考资料:

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


    非常感谢,你帮了我很大的忙。谢谢,我想我会改用JavaFX动画,但我会在以后的项目中记住这一点。@silex jewelsea答案是一个很好的解释。。!
     public class AnimationClass extends AnimationTimer {
    
        @Override
        public void handle(long nano) {
          //Code here
        }
    }
    
      new AnimationTimer() {
            @Override
            public void handle(long now) {              
    
            }
        }.start();
    }
    
    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();