Line data Source code
1 : import 'dart:ui'; 2 : 3 : import 'package:flutter/gestures.dart'; 4 : import 'package:flutter/rendering.dart'; 5 : import 'package:flutter/scheduler.dart'; 6 : import 'package:flutter/widgets.dart' hide WidgetBuilder; 7 : 8 : import '../extensions/size.dart'; 9 : import 'game.dart'; 10 : import 'game_loop.dart'; 11 : 12 : // ignore: prefer_mixin 13 : class GameRenderBox extends RenderBox with WidgetsBindingObserver { 14 : BuildContext buildContext; 15 : Game game; 16 : GameLoop? gameLoop; 17 : 18 2 : GameRenderBox(this.buildContext, this.game) { 19 8 : WidgetsBinding.instance!.addTimingsCallback(game.onTimingsCallback); 20 : } 21 : 22 2 : @override 23 : bool get isRepaintBoundary => true; 24 : 25 0 : @override 26 : void performResize() { 27 0 : super.performResize(); 28 0 : game.onResize(constraints.biggest.toVector2()); 29 : } 30 : 31 2 : @override 32 : void attach(PipelineOwner owner) { 33 2 : super.attach(owner); 34 4 : game.attach(owner, this); 35 : 36 6 : final gameLoop = this.gameLoop = GameLoop(gameLoopCallback); 37 : 38 6 : game.pauseEngineFn = gameLoop.pause; 39 6 : game.resumeEngineFn = gameLoop.resume; 40 : 41 4 : if (game.runOnCreation) { 42 2 : gameLoop.start(); 43 : } 44 : 45 2 : _bindLifecycleListener(); 46 : } 47 : 48 2 : @override 49 : void detach() { 50 2 : super.detach(); 51 4 : game.detach(); 52 4 : gameLoop?.dispose(); 53 2 : gameLoop = null; 54 2 : _unbindLifecycleListener(); 55 : } 56 : 57 2 : void gameLoopCallback(double dt) { 58 2 : if (!attached) { 59 : return; 60 : } 61 4 : game.update(dt); 62 2 : markNeedsPaint(); 63 : } 64 : 65 1 : @override 66 : void performLayout() { 67 3 : size = constraints.biggest; 68 : } 69 : 70 2 : @override 71 : void paint(PaintingContext context, Offset offset) { 72 4 : context.canvas.save(); 73 8 : context.canvas.translate(offset.dx, offset.dy); 74 6 : game.render(context.canvas); 75 4 : context.canvas.restore(); 76 : } 77 : 78 2 : void _bindLifecycleListener() { 79 4 : WidgetsBinding.instance!.addObserver(this); 80 : } 81 : 82 2 : void _unbindLifecycleListener() { 83 4 : WidgetsBinding.instance!.removeObserver(this); 84 : } 85 : 86 0 : @override 87 : void didChangeAppLifecycleState(AppLifecycleState state) { 88 0 : game.lifecycleStateChange(state); 89 : } 90 : 91 0 : @override 92 0 : Size computeDryLayout(BoxConstraints constraints) => constraints.biggest; 93 : }