diff --git a/doc/examples/particles/.gitignore b/doc/examples/particles/.gitignore index e3c6f9654..e56e5624d 100644 --- a/doc/examples/particles/.gitignore +++ b/doc/examples/particles/.gitignore @@ -71,3 +71,7 @@ !**/ios/**/default.pbxuser !**/ios/**/default.perspectivev3 !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages + +.flutter-plugins-dependencies +macos +test diff --git a/doc/examples/particles/lib/main.dart b/doc/examples/particles/lib/main.dart index e681c02a8..aa59a502c 100644 --- a/doc/examples/particles/lib/main.dart +++ b/doc/examples/particles/lib/main.dart @@ -217,7 +217,7 @@ class MyGame extends BaseGame { return Particle.generate( count: 5, generator: (i) => MovingParticle( - curve: Interval(.2, .6, curve: Curves.easeInOutCubic), + curve: const Interval(.2, .6, curve: Curves.easeInOutCubic), to: randomCellOffset() * .5, child: CircleParticle( radius: 5 + rnd.nextDouble() * 5, diff --git a/doc/examples/sprites/.gitignore b/doc/examples/sprites/.gitignore index 3274b351d..6a66cc27d 100644 --- a/doc/examples/sprites/.gitignore +++ b/doc/examples/sprites/.gitignore @@ -70,7 +70,5 @@ !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages macos - test - .flutter-plugins-dependencies diff --git a/example/.gitignore b/example/.gitignore index c7143c389..9fd4653bf 100644 --- a/example/.gitignore +++ b/example/.gitignore @@ -71,3 +71,6 @@ build/ !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages .flutter-plugins-dependencies + +macos +test diff --git a/lib/box2d/box2d_game.dart b/lib/box2d/box2d_game.dart index 1c2224420..04d620b09 100644 --- a/lib/box2d/box2d_game.dart +++ b/lib/box2d/box2d_game.dart @@ -2,7 +2,7 @@ import 'dart:ui'; import 'package:flame/box2d/box2d_component.dart'; import 'package:flame/components/component.dart'; -import 'package:flame/game.dart'; +import 'package:flame/game/base_game.dart'; class Box2DGame extends BaseGame { final Box2DComponent box; diff --git a/lib/components/composed_component.dart b/lib/components/composed_component.dart index b7349f2b6..ee7c3656d 100644 --- a/lib/components/composed_component.dart +++ b/lib/components/composed_component.dart @@ -2,7 +2,7 @@ import 'dart:ui'; import 'package:flame/components/mixins/has_game_ref.dart'; import 'package:flame/components/mixins/tapable.dart'; -import 'package:flame/game.dart'; +import 'package:flame/game/base_game.dart'; import 'package:ordered_set/comparing.dart'; import 'package:ordered_set/ordered_set.dart'; diff --git a/lib/game.dart b/lib/game.dart index c14f75e20..362d3d1bd 100644 --- a/lib/game.dart +++ b/lib/game.dart @@ -1,2 +1,3 @@ // Keeping compatible with earlier versions of Flame export './game/game.dart'; +export './game/base_game.dart'; diff --git a/lib/game/base_game.dart b/lib/game/base_game.dart new file mode 100644 index 000000000..a8de361f7 --- /dev/null +++ b/lib/game/base_game.dart @@ -0,0 +1,194 @@ +import 'dart:math' as math; +import 'dart:ui'; + +import 'package:flame/components/composed_component.dart'; +import 'package:flutter/gestures.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/widgets.dart' hide WidgetBuilder; +import 'package:flutter/foundation.dart'; +import 'package:ordered_set/comparing.dart'; +import 'package:ordered_set/ordered_set.dart'; + +import '../components/component.dart'; +import '../components/mixins/has_game_ref.dart'; +import '../components/mixins/tapable.dart'; +import '../position.dart'; +import '../gestures.dart'; +import 'game.dart'; + + +/// This is a more complete and opinionated implementation of Game. +/// +/// It still needs to be subclasses to add your game logic, but the [update], [render] and [resize] methods have default implementations. +/// This is the recommended structure to use for most games. +/// It is based on the Component system. +abstract class BaseGame extends Game with TapDetector { + /// The list of components to be updated and rendered by the base game. + OrderedSet components = + OrderedSet(Comparing.on((c) => c.priority())); + + /// Components added by the [addLater] method + final List _addLater = []; + + /// Current screen size, updated every resize via the [resize] method hook + Size size; + + /// Camera position; every non-HUD component is translated so that the camera position is the top-left corner of the screen. + Position camera = Position.empty(); + + /// List of deltas used in debug mode to calculate FPS + final List _dts = []; + + Iterable get _tapableComponents => + components.where((c) => c is Tapable).cast(); + + @override + void onTapCancel() { + _tapableComponents.forEach((c) => c.handleTapCancel()); + } + + @override + void onTapDown(TapDownDetails details) { + _tapableComponents.forEach((c) => c.handleTapDown(details)); + } + + @override + void onTapUp(TapUpDetails details) { + _tapableComponents.forEach((c) => c.handleTapUp(details)); + } + + /// This method is called for every component added, both via [add] and [addLater] methods. + /// + /// You can use this to setup your mixins, pre-calculate stuff on every component, or anything you desire. + /// By default, this calls the first time resize for every component, so don't forget to call super.preAdd when overriding. + @mustCallSuper + void preAdd(Component c) { + if (debugMode() && c is PositionComponent) { + c.debugMode = true; + } + + // first time resize + if (size != null) { + c.resize(size); + } + + if (c is HasGameRef) { + (c as HasGameRef).gameRef = this; + } + + if (c is ComposedComponent) { + c.components.forEach(preAdd); + } + + c.onMount(); + } + + /// Adds a new component to the components list. + /// + /// Also calls [preAdd], witch in turn sets the current size on the component (because the resize hook won't be called until a new resize happens). + void add(Component c) { + preAdd(c); + components.add(c); + } + + /// Registers a component to be added on the components on the next tick. + /// + /// Use this to add components in places where a concurrent issue with the update method might happen. + /// Also calls [preAdd] for the component added, immediately. + void addLater(Component c) { + preAdd(c); + _addLater.add(c); + } + + /// This implementation of render basically calls [renderComponent] for every component, making sure the canvas is reset for each one. + /// + /// You can override it further to add more custom behaviour. + /// Beware of however you are rendering components if not using this; you must be careful to save and restore the canvas to avoid components messing up with each other. + @override + void render(Canvas canvas) { + canvas.save(); + components.forEach((comp) => renderComponent(canvas, comp)); + canvas.restore(); + } + + /// This renders a single component obeying BaseGame rules. + /// + /// It translates the camera unless hud, call the render method and restore the canvas. + /// This makes sure the canvas is not messed up by one component and all components render independently. + void renderComponent(Canvas canvas, Component c) { + if (!c.loaded()) { + return; + } + if (!c.isHud()) { + canvas.translate(-camera.x, -camera.y); + } + c.render(canvas); + canvas.restore(); + canvas.save(); + } + + /// This implementation of update updates every component in the list. + /// + /// It also actually adds the components that were added by the [addLater] method, and remove those that are marked for destruction via the [Component.destroy] method. + /// You can override it further to add more custom behaviour. + @override + void update(double t) { + components.addAll(_addLater); + _addLater.clear(); + + components.forEach((c) => c.update(t)); + components.removeWhere((c) => c.destroy()).forEach((c) => c.onDestroy()); + } + + /// This implementation of resize passes the resize call along to every component in the list, enabling each one to make their decisions as how to handle the resize. + /// + /// It also updates the [size] field of the class to be used by later added components and other methods. + /// You can override it further to add more custom behaviour, but you should seriously consider calling the super implementation as well. + @override + @mustCallSuper + void resize(Size size) { + this.size = size; + components.forEach((c) => c.resize(size)); + } + + /// Returns whether this [Game] is in debug mode or not. + /// + /// Returns `false` by default. Override to use the debug mode. + /// In debug mode, the [recordDt] method actually records every `dt` for statistics. + /// Then, you can use the [fps] method to check the game FPS. + /// You can also use this value to enable other debug behaviors for your game, like bounding box rendering, for instance. + bool debugMode() => false; + + /// This is a hook that comes from the RenderBox to allow recording of render times and statistics. + @override + void recordDt(double dt) { + if (debugMode()) { + _dts.add(dt); + } + } + + /// Returns the average FPS for the last [average] measures. + /// + /// The values are only saved if in debug mode (override [debugMode] to use this). + /// Selects the last [average] dts, averages then, and returns the inverse value. + /// So it's technically updates per second, but the relation between updates and renders is 1:1. + /// Returns 0 if empty. + double fps([int average = 1]) { + final List dts = _dts.sublist(math.max(0, _dts.length - average)); + if (dts.isEmpty) { + return 0.0; + } + final double dtSum = dts.reduce((s, t) => s + t); + final double averageDt = dtSum / average; + return 1 / averageDt; + } + + /// Returns the current time in seconds with microseconds precision. + /// + /// This is compatible with the `dt` value used in the [update] method. + double currentTime() { + return DateTime.now().microsecondsSinceEpoch.toDouble() / + Duration.microsecondsPerSecond; + } +} + diff --git a/lib/game/embedded_game_widget.dart b/lib/game/embedded_game_widget.dart new file mode 100644 index 000000000..a66494313 --- /dev/null +++ b/lib/game/embedded_game_widget.dart @@ -0,0 +1,38 @@ +import 'package:flutter/rendering.dart'; +import 'package:flutter/widgets.dart' hide WidgetBuilder; + +import '../position.dart'; + +import 'game_render_box.dart'; +import 'game.dart'; + +/// This a widget to embed a game inside the Widget tree. You can use it in pair with [SimpleGame] or any other more complex [Game], as desired. +/// +/// It handles for you positioning, size constraints and other factors that arise when your game is embedded within the component tree. +/// Provided it with a [Game] instance for your game and the optional size of the widget. +/// Creating this without a fixed size might mess up how other components are rendered with relation to this one in the tree. +/// You can bind Gesture Recognizers immediately around this to add controls to your widgets, with easy coordinate conversions. +class EmbeddedGameWidget extends LeafRenderObjectWidget { + final Game game; + final Position size; + + EmbeddedGameWidget(this.game, {this.size}); + + @override + RenderBox createRenderObject(BuildContext context) { + return RenderConstrainedBox( + child: GameRenderBox(context, game), + additionalConstraints: + BoxConstraints.expand(width: size?.x, height: size?.y)); + } + + @override + void updateRenderObject( + BuildContext context, RenderConstrainedBox renderBox) { + renderBox + ..child = GameRenderBox(context, game) + ..additionalConstraints = + BoxConstraints.expand(width: size?.x, height: size?.y); + } +} + diff --git a/lib/game/game.dart b/lib/game/game.dart index 3c2f25c72..e477533e8 100644 --- a/lib/game/game.dart +++ b/lib/game/game.dart @@ -1,25 +1,14 @@ -import 'dart:math' as math; import 'dart:ui'; import 'dart:async'; -import 'package:flame/components/composed_component.dart'; -import 'package:flutter/gestures.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter/widgets.dart' hide WidgetBuilder; import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; -import 'package:ordered_set/comparing.dart'; -import 'package:ordered_set/ordered_set.dart'; -import '../components/component.dart'; -import '../components/mixins/has_game_ref.dart'; -import '../components/mixins/tapable.dart'; -import '../position.dart'; -import '../gestures.dart'; import '../keyboard.dart'; -import 'game_loop.dart'; import 'widget_builder.dart'; /// Represents a generic game. @@ -55,7 +44,7 @@ abstract class Game { void lifecycleStateChange(AppLifecycleState state) {} /// Used for debugging - void _recordDt(double dt) {} + void recordDt(double dt) {} /// Returns the game widget. Put this in your structure to start rendering and updating the game. /// You can add it directly to the runApp method or inside your widget structure (if you use vanilla screens and widgets). @@ -95,13 +84,13 @@ abstract class Game { bool runOnCreation = true; /// Pauses the engine game loop execution - void pauseEngine() => _pauseEngineFn?.call(); + void pauseEngine() => pauseEngineFn?.call(); /// Resumes the engine game loop execution - void resumeEngine() => _resumeEngineFn?.call(); + void resumeEngine() => resumeEngineFn?.call(); - VoidCallback _pauseEngineFn; - VoidCallback _resumeEngineFn; + VoidCallback pauseEngineFn; + VoidCallback resumeEngineFn; } class OverlayWidget { @@ -127,289 +116,4 @@ mixin HasWidgetsOverlay on Game { } } -/// This is a more complete and opinionated implementation of Game. -/// -/// It still needs to be subclasses to add your game logic, but the [update], [render] and [resize] methods have default implementations. -/// This is the recommended structure to use for most games. -/// It is based on the Component system. -abstract class BaseGame extends Game with TapDetector { - /// The list of components to be updated and rendered by the base game. - OrderedSet components = - OrderedSet(Comparing.on((c) => c.priority())); - /// Components added by the [addLater] method - final List _addLater = []; - - /// Current screen size, updated every resize via the [resize] method hook - Size size; - - /// Camera position; every non-HUD component is translated so that the camera position is the top-left corner of the screen. - Position camera = Position.empty(); - - /// List of deltas used in debug mode to calculate FPS - final List _dts = []; - - Iterable get _tapableComponents => - components.where((c) => c is Tapable).cast(); - - @override - void onTapCancel() { - _tapableComponents.forEach((c) => c.handleTapCancel()); - } - - @override - void onTapDown(TapDownDetails details) { - _tapableComponents.forEach((c) => c.handleTapDown(details)); - } - - @override - void onTapUp(TapUpDetails details) { - _tapableComponents.forEach((c) => c.handleTapUp(details)); - } - - /// This method is called for every component added, both via [add] and [addLater] methods. - /// - /// You can use this to setup your mixins, pre-calculate stuff on every component, or anything you desire. - /// By default, this calls the first time resize for every component, so don't forget to call super.preAdd when overriding. - @mustCallSuper - void preAdd(Component c) { - if (debugMode() && c is PositionComponent) { - c.debugMode = true; - } - - // first time resize - if (size != null) { - c.resize(size); - } - - if (c is HasGameRef) { - (c as HasGameRef).gameRef = this; - } - - if (c is ComposedComponent) { - c.components.forEach(preAdd); - } - - c.onMount(); - } - - /// Adds a new component to the components list. - /// - /// Also calls [preAdd], witch in turn sets the current size on the component (because the resize hook won't be called until a new resize happens). - void add(Component c) { - preAdd(c); - components.add(c); - } - - /// Registers a component to be added on the components on the next tick. - /// - /// Use this to add components in places where a concurrent issue with the update method might happen. - /// Also calls [preAdd] for the component added, immediately. - void addLater(Component c) { - preAdd(c); - _addLater.add(c); - } - - /// This implementation of render basically calls [renderComponent] for every component, making sure the canvas is reset for each one. - /// - /// You can override it further to add more custom behaviour. - /// Beware of however you are rendering components if not using this; you must be careful to save and restore the canvas to avoid components messing up with each other. - @override - void render(Canvas canvas) { - canvas.save(); - components.forEach((comp) => renderComponent(canvas, comp)); - canvas.restore(); - } - - /// This renders a single component obeying BaseGame rules. - /// - /// It translates the camera unless hud, call the render method and restore the canvas. - /// This makes sure the canvas is not messed up by one component and all components render independently. - void renderComponent(Canvas canvas, Component c) { - if (!c.loaded()) { - return; - } - if (!c.isHud()) { - canvas.translate(-camera.x, -camera.y); - } - c.render(canvas); - canvas.restore(); - canvas.save(); - } - - /// This implementation of update updates every component in the list. - /// - /// It also actually adds the components that were added by the [addLater] method, and remove those that are marked for destruction via the [Component.destroy] method. - /// You can override it further to add more custom behaviour. - @override - void update(double t) { - components.addAll(_addLater); - _addLater.clear(); - - components.forEach((c) => c.update(t)); - components.removeWhere((c) => c.destroy()).forEach((c) => c.onDestroy()); - } - - /// This implementation of resize passes the resize call along to every component in the list, enabling each one to make their decisions as how to handle the resize. - /// - /// It also updates the [size] field of the class to be used by later added components and other methods. - /// You can override it further to add more custom behaviour, but you should seriously consider calling the super implementation as well. - @override - @mustCallSuper - void resize(Size size) { - this.size = size; - components.forEach((c) => c.resize(size)); - } - - /// Returns whether this [Game] is in debug mode or not. - /// - /// Returns `false` by default. Override to use the debug mode. - /// In debug mode, the [_recordDt] method actually records every `dt` for statistics. - /// Then, you can use the [fps] method to check the game FPS. - /// You can also use this value to enable other debug behaviors for your game, like bounding box rendering, for instance. - bool debugMode() => false; - - /// This is a hook that comes from the RenderBox to allow recording of render times and statistics. - @override - void _recordDt(double dt) { - if (debugMode()) { - _dts.add(dt); - } - } - - /// Returns the average FPS for the last [average] measures. - /// - /// The values are only saved if in debug mode (override [debugMode] to use this). - /// Selects the last [average] dts, averages then, and returns the inverse value. - /// So it's technically updates per second, but the relation between updates and renders is 1:1. - /// Returns 0 if empty. - double fps([int average = 1]) { - final List dts = _dts.sublist(math.max(0, _dts.length - average)); - if (dts.isEmpty) { - return 0.0; - } - final double dtSum = dts.reduce((s, t) => s + t); - final double averageDt = dtSum / average; - return 1 / averageDt; - } - - /// Returns the current time in seconds with microseconds precision. - /// - /// This is compatible with the `dt` value used in the [update] method. - double currentTime() { - return DateTime.now().microsecondsSinceEpoch.toDouble() / - Duration.microsecondsPerSecond; - } -} - -/// This is a helper implementation of a [BaseGame] designed to allow to easily create a game with a single component. -/// -/// This is useful to add sprites, animations and other Flame components "directly" to your non-game Flutter widget tree, when combined with [EmbeddedGameWidget]. -class SimpleGame extends BaseGame { - SimpleGame(Component c) { - add(c); - } -} - -/// This a widget to embed a game inside the Widget tree. You can use it in pair with [SimpleGame] or any other more complex [Game], as desired. -/// -/// It handles for you positioning, size constraints and other factors that arise when your game is embedded within the component tree. -/// Provided it with a [Game] instance for your game and the optional size of the widget. -/// Creating this without a fixed size might mess up how other components are rendered with relation to this one in the tree. -/// You can bind Gesture Recognizers immediately around this to add controls to your widgets, with easy coordinate conversions. -class EmbeddedGameWidget extends LeafRenderObjectWidget { - final Game game; - final Position size; - - EmbeddedGameWidget(this.game, {this.size}); - - @override - RenderBox createRenderObject(BuildContext context) { - return RenderConstrainedBox( - child: GameRenderBox(context, game), - additionalConstraints: - BoxConstraints.expand(width: size?.x, height: size?.y)); - } - - @override - void updateRenderObject( - BuildContext context, RenderConstrainedBox renderBox) { - renderBox - ..child = GameRenderBox(context, game) - ..additionalConstraints = - BoxConstraints.expand(width: size?.x, height: size?.y); - } -} - -class GameRenderBox extends RenderBox with WidgetsBindingObserver { - BuildContext context; - Game game; - GameLoop gameLoop; - - GameRenderBox(this.context, this.game) { - gameLoop = GameLoop(gameLoopCallback); - } - - @override - bool get sizedByParent => true; - - @override - void performResize() { - super.performResize(); - game.resize(constraints.biggest); - } - - @override - void attach(PipelineOwner owner) { - super.attach(owner); - game.onAttach(); - - game._pauseEngineFn = gameLoop.pause; - game._resumeEngineFn = gameLoop.resume; - - if (game.runOnCreation) { - gameLoop.scheduleTick(); - } - - _bindLifecycleListener(); - } - - @override - void detach() { - super.detach(); - game.onDetach(); - gameLoop.unscheduleTick(); - _unbindLifecycleListener(); - } - - void gameLoopCallback(double dt) { - if (!attached) { - return; - } - game._recordDt(dt); - game.update(dt); - markNeedsPaint(); - } - - @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 _bindLifecycleListener() { - WidgetsBinding.instance.addObserver(this); - } - - void _unbindLifecycleListener() { - WidgetsBinding.instance.removeObserver(this); - } - - @override - void didChangeAppLifecycleState(AppLifecycleState state) { - game.lifecycleStateChange(state); - } -} diff --git a/lib/game/game_render_box.dart b/lib/game/game_render_box.dart new file mode 100644 index 000000000..b814ae544 --- /dev/null +++ b/lib/game/game_render_box.dart @@ -0,0 +1,82 @@ +import 'dart:ui'; + +import 'package:flutter/gestures.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/scheduler.dart'; +import 'package:flutter/widgets.dart' hide WidgetBuilder; + +import 'game_loop.dart'; +import 'game.dart'; + +class GameRenderBox extends RenderBox with WidgetsBindingObserver { + BuildContext context; + Game game; + GameLoop gameLoop; + + GameRenderBox(this.context, this.game) { + gameLoop = GameLoop(gameLoopCallback); + } + + @override + bool get sizedByParent => true; + + @override + void performResize() { + super.performResize(); + game.resize(constraints.biggest); + } + + @override + void attach(PipelineOwner owner) { + super.attach(owner); + game.onAttach(); + + game.pauseEngineFn = gameLoop.pause; + game.resumeEngineFn = gameLoop.resume; + + if (game.runOnCreation) { + gameLoop.scheduleTick(); + } + + _bindLifecycleListener(); + } + + @override + void detach() { + super.detach(); + game.onDetach(); + gameLoop.unscheduleTick(); + _unbindLifecycleListener(); + } + + void gameLoopCallback(double dt) { + if (!attached) { + return; + } + game.recordDt(dt); + game.update(dt); + markNeedsPaint(); + } + + @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 _bindLifecycleListener() { + WidgetsBinding.instance.addObserver(this); + } + + void _unbindLifecycleListener() { + WidgetsBinding.instance.removeObserver(this); + } + + @override + void didChangeAppLifecycleState(AppLifecycleState state) { + game.lifecycleStateChange(state); + } +} \ No newline at end of file diff --git a/lib/game/simple_game.dart b/lib/game/simple_game.dart new file mode 100644 index 000000000..e020122b4 --- /dev/null +++ b/lib/game/simple_game.dart @@ -0,0 +1,12 @@ +import 'package:flame/components/component.dart'; + +import 'base_game.dart'; + +/// This is a helper implementation of a [BaseGame] designed to allow to easily create a game with a single component. +/// +/// This is useful to add sprites, animations and other Flame components "directly" to your non-game Flutter widget tree, when combined with [EmbeddedGameWidget]. +class SimpleGame extends BaseGame { + SimpleGame(Component c) { + add(c); + } +} diff --git a/lib/game/widget_builder.dart b/lib/game/widget_builder.dart index 45d5fcd0a..d26eed9f0 100644 --- a/lib/game/widget_builder.dart +++ b/lib/game/widget_builder.dart @@ -1,5 +1,6 @@ import 'package:flutter/widgets.dart'; import '../gestures.dart'; +import 'embedded_game_widget.dart'; import 'game.dart'; class WidgetBuilder { @@ -9,70 +10,53 @@ class WidgetBuilder { return GestureDetector( // Taps onTap: game is TapDetector ? () => (game as TapDetector).onTap() : null, - onTapCancel: game is TapDetector - ? () => (game as TapDetector).onTapCancel() - : null, - onTapDown: game is TapDetector - ? (TapDownDetails d) => (game as TapDetector).onTapDown(d) - : null, - onTapUp: game is TapDetector - ? (TapUpDetails d) => (game as TapDetector).onTapUp(d) - : null, + onTapCancel: game is TapDetector ? () => (game as TapDetector).onTapCancel() : null, + onTapDown: + game is TapDetector ? (TapDownDetails d) => (game as TapDetector).onTapDown(d) : null, + onTapUp: game is TapDetector ? (TapUpDetails d) => (game as TapDetector).onTapUp(d) : null, // Secondary taps onSecondaryTapDown: game is SecondaryTapDetector - ? (TapDownDetails d) => - (game as SecondaryTapDetector).onSecondaryTapDown(d) + ? (TapDownDetails d) => (game as SecondaryTapDetector).onSecondaryTapDown(d) : null, onSecondaryTapUp: game is SecondaryTapDetector - ? (TapUpDetails d) => - (game as SecondaryTapDetector).onSecondaryTapUp(d) + ? (TapUpDetails d) => (game as SecondaryTapDetector).onSecondaryTapUp(d) : null, onSecondaryTapCancel: game is SecondaryTapDetector ? () => (game as SecondaryTapDetector).onSecondaryTapCancel() : null, // Double tap - onDoubleTap: game is DoubleTapDetector - ? () => (game as DoubleTapDetector).onDoubleTap() - : null, + onDoubleTap: + game is DoubleTapDetector ? () => (game as DoubleTapDetector).onDoubleTap() : null, // Long presses - onLongPress: game is LongPressDetector - ? () => (game as LongPressDetector).onLongPress() - : null, + onLongPress: + game is LongPressDetector ? () => (game as LongPressDetector).onLongPress() : null, onLongPressStart: game is LongPressDetector - ? (LongPressStartDetails d) => - (game as LongPressDetector).onLongPressStart(d) + ? (LongPressStartDetails d) => (game as LongPressDetector).onLongPressStart(d) : null, onLongPressMoveUpdate: game is LongPressDetector - ? (LongPressMoveUpdateDetails d) => - (game as LongPressDetector).onLongPressMoveUpdate(d) - : null, - onLongPressUp: game is LongPressDetector - ? () => (game as LongPressDetector).onLongPressUp() + ? (LongPressMoveUpdateDetails d) => (game as LongPressDetector).onLongPressMoveUpdate(d) : null, + onLongPressUp: + game is LongPressDetector ? () => (game as LongPressDetector).onLongPressUp() : null, onLongPressEnd: game is LongPressDetector - ? (LongPressEndDetails d) => - (game as LongPressDetector).onLongPressEnd(d) + ? (LongPressEndDetails d) => (game as LongPressDetector).onLongPressEnd(d) : null, // Vertical drag onVerticalDragDown: game is VerticalDragDetector - ? (DragDownDetails d) => - (game as VerticalDragDetector).onVerticalDragDown(d) + ? (DragDownDetails d) => (game as VerticalDragDetector).onVerticalDragDown(d) : null, onVerticalDragStart: game is VerticalDragDetector - ? (DragStartDetails d) => - (game as VerticalDragDetector).onVerticalDragStart(d) + ? (DragStartDetails d) => (game as VerticalDragDetector).onVerticalDragStart(d) : null, onVerticalDragUpdate: game is VerticalDragDetector - ? (DragUpdateDetails d) => - (game as VerticalDragDetector).onVerticalDragUpdate(d) + ? (DragUpdateDetails d) => (game as VerticalDragDetector).onVerticalDragUpdate(d) : null, onVerticalDragEnd: game is VerticalDragDetector - ? (DragEndDetails d) => - (game as VerticalDragDetector).onVerticalDragEnd(d) + ? (DragEndDetails d) => (game as VerticalDragDetector).onVerticalDragEnd(d) : null, onVerticalDragCancel: game is VerticalDragDetector ? () => (game as VerticalDragDetector).onVerticalDragCancel() @@ -80,20 +64,16 @@ class WidgetBuilder { // Horizontal drag onHorizontalDragDown: game is HorizontalDragDetector - ? (DragDownDetails d) => - (game as HorizontalDragDetector).onHorizontalDragDown(d) + ? (DragDownDetails d) => (game as HorizontalDragDetector).onHorizontalDragDown(d) : null, onHorizontalDragStart: game is HorizontalDragDetector - ? (DragStartDetails d) => - (game as HorizontalDragDetector).onHorizontalDragStart(d) + ? (DragStartDetails d) => (game as HorizontalDragDetector).onHorizontalDragStart(d) : null, onHorizontalDragUpdate: game is HorizontalDragDetector - ? (DragUpdateDetails d) => - (game as HorizontalDragDetector).onHorizontalDragUpdate(d) + ? (DragUpdateDetails d) => (game as HorizontalDragDetector).onHorizontalDragUpdate(d) : null, onHorizontalDragEnd: game is HorizontalDragDetector - ? (DragEndDetails d) => - (game as HorizontalDragDetector).onHorizontalDragEnd(d) + ? (DragEndDetails d) => (game as HorizontalDragDetector).onHorizontalDragEnd(d) : null, onHorizontalDragCancel: game is HorizontalDragDetector ? () => (game as HorizontalDragDetector).onHorizontalDragCancel() @@ -101,38 +81,29 @@ class WidgetBuilder { // Force presses onForcePressStart: game is ForcePressDetector - ? (ForcePressDetails d) => - (game as ForcePressDetector).onForcePressStart(d) + ? (ForcePressDetails d) => (game as ForcePressDetector).onForcePressStart(d) : null, onForcePressPeak: game is ForcePressDetector - ? (ForcePressDetails d) => - (game as ForcePressDetector).onForcePressPeak(d) + ? (ForcePressDetails d) => (game as ForcePressDetector).onForcePressPeak(d) : null, onForcePressUpdate: game is ForcePressDetector - ? (ForcePressDetails d) => - (game as ForcePressDetector).onForcePressUpdate(d) + ? (ForcePressDetails d) => (game as ForcePressDetector).onForcePressUpdate(d) : null, onForcePressEnd: game is ForcePressDetector - ? (ForcePressDetails d) => - (game as ForcePressDetector).onForcePressEnd(d) + ? (ForcePressDetails d) => (game as ForcePressDetector).onForcePressEnd(d) : null, // Pan - onPanDown: game is PanDetector - ? (DragDownDetails d) => (game as PanDetector).onPanDown(d) - : null, - onPanStart: game is PanDetector - ? (DragStartDetails d) => (game as PanDetector).onPanStart(d) - : null, + onPanDown: + game is PanDetector ? (DragDownDetails d) => (game as PanDetector).onPanDown(d) : null, + onPanStart: + game is PanDetector ? (DragStartDetails d) => (game as PanDetector).onPanStart(d) : null, onPanUpdate: game is PanDetector ? (DragUpdateDetails d) => (game as PanDetector).onPanUpdate(d) : null, - onPanEnd: game is PanDetector - ? (DragEndDetails d) => (game as PanDetector).onPanEnd(d) - : null, - onPanCancel: game is PanDetector - ? () => (game as PanDetector).onPanCancel() - : null, + onPanEnd: + game is PanDetector ? (DragEndDetails d) => (game as PanDetector).onPanEnd(d) : null, + onPanCancel: game is PanDetector ? () => (game as PanDetector).onPanCancel() : null, // Scales onScaleStart: game is ScaleDetector @@ -147,9 +118,7 @@ class WidgetBuilder { child: Container( color: game.backgroundColor(), - child: Directionality( - textDirection: TextDirection.ltr, - child: EmbeddedGameWidget(game))), + child: Directionality(textDirection: TextDirection.ltr, child: EmbeddedGameWidget(game))), ); } } @@ -185,8 +154,7 @@ class _OverlayGameWidgetState extends State { Widget build(BuildContext context) { return Directionality( textDirection: TextDirection.ltr, - child: - Stack(children: [widget.gameChild, ..._overlays.values.toList()])); + child: Stack(children: [widget.gameChild, ..._overlays.values.toList()])); } } @@ -197,7 +165,6 @@ class OverlayWidgetBuilder extends WidgetBuilder { Widget build(Game game) { final container = super.build(game); - return OverlayGameWidget( - gameChild: container, game: game, key: UniqueKey()); + return OverlayGameWidget(gameChild: container, game: game, key: UniqueKey()); } } diff --git a/lib/util.dart b/lib/util.dart index fff13fc24..1c03ab6af 100644 --- a/lib/util.dart +++ b/lib/util.dart @@ -6,9 +6,10 @@ import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart' as widgets; import 'animation.dart'; +import 'game/embedded_game_widget.dart'; +import 'game/simple_game.dart'; import 'sprite.dart'; import 'components/animation_component.dart'; -import 'game.dart'; import 'position.dart'; /// Some utilities that did not fit anywhere else. diff --git a/test/composed_component_test.dart b/test/composed_component_test.dart index 09c414e9f..d60e98d6d 100644 --- a/test/composed_component_test.dart +++ b/test/composed_component_test.dart @@ -4,10 +4,10 @@ import 'package:flame/components/composed_component.dart'; import 'package:flame/components/mixins/has_game_ref.dart'; import 'package:flame/components/mixins/resizable.dart'; import 'package:flame/components/mixins/tapable.dart'; +import 'package:flame/game/base_game.dart'; import 'package:flutter/gestures.dart'; import 'package:test/test.dart'; -import 'package:flame/game.dart'; import 'package:flame/components/component.dart'; class MyGame extends BaseGame {} diff --git a/test/has_game_ref_test.dart b/test/has_game_ref_test.dart index 39f069771..d9f241d5c 100644 --- a/test/has_game_ref_test.dart +++ b/test/has_game_ref_test.dart @@ -1,9 +1,9 @@ import 'dart:ui'; import 'package:flame/components/mixins/has_game_ref.dart'; +import 'package:flame/game/base_game.dart'; import 'package:test/test.dart'; -import 'package:flame/game.dart'; import 'package:flame/components/component.dart'; class MyGame extends BaseGame { diff --git a/test/resizable_test.dart b/test/resizable_test.dart index 6576e1283..c4d427db1 100644 --- a/test/resizable_test.dart +++ b/test/resizable_test.dart @@ -1,8 +1,8 @@ import 'dart:ui'; +import 'package:flame/game/base_game.dart'; import 'package:test/test.dart'; -import 'package:flame/game.dart'; import 'package:flame/components/component.dart'; import 'package:flame/components/mixins/resizable.dart';