Если вы пишете игру, я настоятельно рекомендую использовать для этого фреймворк, потому что он позаботится обо всех подобных вещах.
Однако я ценю, что вы пытаетесь понять, как это будет сделано - это замечательная цель, поэтому я постараюсь объяснить.
По сути, вам нужно подключиться к рендерингу флаттера и изменить способ его выполнения, поскольку флаттер оптимизирует многие вещи, которые не обязательно должны быть оптимизированы для игры.
Возвращение 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();
}
Это больше соответствует тому, как игры обычно работают.