Обратный вызов флаттера, вызываемый для каждого кадра - PullRequest
0 голосов
/ 06 июня 2019

Я узнаю о нестандартной живописи и понимаю, что могу сказать трепетать, когда перекрашивать холст. Но если я разрабатываю игру, я думаю, что все пошло бы лучше, если бы мне называли каждый кадр, чтобы я мог обновить любое состояние на игровой доске и затем рисовать. Возможно ли это?

Я думал, что всегда могу вернуть true из shouldRepaint (). Будет ли тогда вызываться мой метод рисования для каждого кадра, независимо от того, что (то есть 60 раз в секунду)?

Я также знаю, что есть таймер дротика, но я бы не подумал, что он будет синхронизирован с кадрами, поэтому, если бы я не хотел гораздо более медленного обновления, это, похоже, не тот путь.

Я знаю, что существуют игровые движки - моя цель - лучше понять флаттер, поэтому я пытаюсь сделать что-то сам, чтобы лучше его понять.

1 Ответ

1 голос
/ 07 июня 2019

Если вы пишете игру, я настоятельно рекомендую использовать для этого фреймворк, потому что он позаботится обо всех подобных вещах.

Однако я ценю, что вы пытаетесь понять, как это будет сделано - это замечательная цель, поэтому я постараюсь объяснить.

По сути, вам нужно подключиться к рендерингу флаттера и изменить способ его выполнения, поскольку флаттер оптимизирует многие вещи, которые не обязательно должны быть оптимизированы для игры.

Возвращение true из shouldRepaint - хороший первый шаг, но на самом деле вам нужно сделать гораздо больше. В обычном приложении ваш объект CustomPainter должен быть постоянным объектом, который создается при каждом изменении. Обычно вы используете что-то вроде AnimationBuilder и создаете новый пользовательский интерфейс с обновленными значениями каждый раз. И затем, в customRainaint для custompainter, вы сравниваете значения старых custompainter с новыми и перерисовываете их, только если они отличаются.

Для очень простой игры вам, возможно, удастся избежать использования нескольких анимаций, а также перетаскивания флаттера, кнопок и т.д. к играм.

Чтобы понять, как это можно сделать, я бы рекомендовал прочитать исходный код Flame. Flame - легкий игровой движок, работающий на флаттере. Он на самом деле абстрагирует рисунок от трепетания и вместо этого имеет кучу игровых «компонентов», каждый из которых рисует самостоятельно. Смотрите файл game.dart Flame , где находится эта логика.

Часть соответствующего кода из GameRenderBox, который наследует RenderBox:

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

Это больше соответствует тому, как игры обычно работают.

...