0

我正在学习自定义绘画,并且我知道我可以告诉颤振何时重新绘制画布。但是如果我正在开发一款游戏,我认为如果我在每一帧都被调用,那么事情会变得更顺利,这样我就可以更新游戏板上的任何状态,然后进行绘画。这可能吗?

我在想我总是可以从 shouldRepaint() 中返回 true。无论如何都会为每一帧调用我的绘画方法(即每秒60次)?

我也知道有一个飞镖计时器,但我认为它不会与帧同步,所以除非我想要更慢的更新,否则这似乎不是要走的路。

我知道那里有游戏引擎——我的目标是更好地理解颤振,所以我试图自己做一些事情来更好地理解它。

4

1 回答 1

2

如果您正在编写游戏,我强烈建议您为此使用框架,因为它可以处理各种此类事情。

但是,我很感激你试图理解如何做到这一点——这是一个令人钦佩的目标,所以我会尽力解释。

基本上,你需要挂钩到 Flutter 的渲染并改变它的完成方式,因为 Flutter 优化了很多不应该为游戏优化的东西。

返回 true fromshouldRepaint是一个很好的第一步,但实际上你要做的远不止这些。在普通应用程序中,您的 CustomPainter 对象应该是一个常量对象,每次发生更改时都会创建该对象。通常你会使用 AnimationBuilder 之类的东西,并创建一个新的 custompainter,每次都会更新值。然后在 custompainter 的 shouldRepaint 中,将旧 custompainter 的值与新的值进行比较,只有当它们不同时才重绘。

对于一个非常简单的游戏,您可能可以使用一些动画,以及颤振的拖放和按钮等。但是任何复杂的事情可能会更好地在更自定义和更适合游戏的东西中完成。

要了解如何做到这一点,我建议阅读 Flame 的源代码。Flame 是一个轻量级的游戏引擎,在 Flutter 上运行。它实际上将绘图从颤振中抽象出来,取而代之的是一堆游戏“组件”,每个组件都有自己的绘画。请参阅 Flame 的game.dart 文件,因为它是该逻辑所在的位置。

一些相关代码,来自继承 RenderBox 的 GameRenderBox :

  void _scheduleTick() {
    _frameCallbackId = SchedulerBinding.instance.scheduleFrameCallback(_tick);
  }

  void _unscheduleTick() {
    SchedulerBinding.instance.cancelFrameCallbackWithId(_frameCallbackId);
  }

  void _tick(Duration timestamp) {
    if (!attached) {
      return;
    }
    _scheduleTick();
    _update(timestamp);
    markNeedsPaint();
  }

_tick 在每一帧都被调用,然后在下一帧期间重新安排自己。

RenderBox 的渲染函数被覆盖:

  @override
  void paint(PaintingContext context, Offset offset) {
    context.canvas.save();
    context.canvas.translate(
        game.builder.offset.dx + offset.dx, game.builder.offset.dy + offset.dy);
    game.render(context.canvas);
    context.canvas.restore();
  }

这会调用游戏的渲染函数,该函数反过来告诉它的每个组件进行渲染:

  void render(Canvas canvas) {
    canvas.save();
    components.forEach((comp) => renderComponent(canvas, comp));
    canvas.restore();
  }

这更符合游戏通常的做事方式。

于 2019-06-06T22:20:08.697 回答