From 96533d8a394a4f47cca66896714a9f1d786333d5 Mon Sep 17 00:00:00 2001 From: Jochum van der Ploeg Date: Fri, 22 Apr 2022 23:33:58 +0200 Subject: [PATCH 1/7] feat: add `HasParent` to force parent child relations --- doc/flame/components.md | 19 ++++++++++- packages/flame/lib/game.dart | 1 + .../flame/lib/src/game/mixins/has_parent.dart | 13 ++++++++ .../test/game/mixins/has_parent_test.dart | 32 +++++++++++++++++++ 4 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 packages/flame/lib/src/game/mixins/has_parent.dart create mode 100644 packages/flame/test/game/mixins/has_parent_test.dart diff --git a/doc/flame/components.md b/doc/flame/components.md index 36157ece6a8..a797f78f9e6 100644 --- a/doc/flame/components.md +++ b/doc/flame/components.md @@ -158,6 +158,24 @@ available eventually: after they are loaded and mounted. We can only assure that they will appear in the children list in the same order as they were scheduled for addition. +#### Ensuring a component has a given parent + +When a component requires to be added to a specific parent type the +`HasParent` mixin can be used to enforce a strongly typed parent. + +Example: + +```dart +class MyComponent extends Component with HasParent { + Future onLoad() async { + // parent is of type MyParentComponent + print(parent.myValue); + } +} +``` + +If `MyComponent` is added to a component that is not `MyParentComponent` +an assertion error will be thrown stating such. ### Querying child components @@ -279,7 +297,6 @@ Future onLoad() async { Remember that most components that are rendered on the screen are `PositionComponent`s, so this pattern can be used in for example [](#spritecomponent) and [](#spriteanimationcomponent) too. - ### Render PositionComponent When implementing the `render` method for a component that extends `PositionComponent` remember to diff --git a/packages/flame/lib/game.dart b/packages/flame/lib/game.dart index b45ade87e9b..b54bdb202d3 100644 --- a/packages/flame/lib/game.dart +++ b/packages/flame/lib/game.dart @@ -10,6 +10,7 @@ export 'src/game/mixins/fps_counter.dart'; export 'src/game/mixins/game.dart'; export 'src/game/mixins/has_draggables.dart'; export 'src/game/mixins/has_hoverables.dart'; +export 'src/game/mixins/has_parent.dart'; export 'src/game/mixins/has_tappables.dart'; export 'src/game/mixins/loadable.dart'; export 'src/game/mixins/single_game_instance.dart'; diff --git a/packages/flame/lib/src/game/mixins/has_parent.dart b/packages/flame/lib/src/game/mixins/has_parent.dart new file mode 100644 index 00000000000..be85281aa27 --- /dev/null +++ b/packages/flame/lib/src/game/mixins/has_parent.dart @@ -0,0 +1,13 @@ +import '../../../components.dart'; + +/// A mixin that ensures a parent is of the given type [T]. +mixin HasParent on Component { + @override + T get parent => super.parent! as T; + + @override + void onMount() { + assert(super.parent is T, 'Parent must be of type ${T.toString()}'); + super.onMount(); + } +} diff --git a/packages/flame/test/game/mixins/has_parent_test.dart b/packages/flame/test/game/mixins/has_parent_test.dart new file mode 100644 index 00000000000..e3d1e989c67 --- /dev/null +++ b/packages/flame/test/game/mixins/has_parent_test.dart @@ -0,0 +1,32 @@ +import 'package:flame/components.dart'; +import 'package:flame/game.dart'; +import 'package:flutter_test/flutter_test.dart'; + +class ParentComponent extends Component {} + +class DifferentComponent extends Component {} + +class TestComponent extends Component with HasParent {} + +void main() { + group('HasParent', () { + test('successfully sets the parent link', () { + final parent = ParentComponent(); + final component = TestComponent(); + + parent.add(component); + + expect(component.parent, isA()); + expect(component.onMount, returnsNormally); + }); + + test('throws assertion error when the wrong parent is used', () { + final parent = DifferentComponent(); + final component = TestComponent(); + + parent.add(component); + + expect(component.onMount, throwsAssertionError); + }); + }); +} From 8d5c51848aed3918aeb2e0d22bb4e5670a5a1f95 Mon Sep 17 00:00:00 2001 From: Jochum van der Ploeg Date: Sat, 23 Apr 2022 17:05:24 +0200 Subject: [PATCH 2/7] feat: add `HasParent` to force parent child relations --- packages/flame/lib/src/game/mixins/has_parent.dart | 9 ++++++--- .../flame/test/game/mixins/has_parent_test.dart | 14 +++++++------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/packages/flame/lib/src/game/mixins/has_parent.dart b/packages/flame/lib/src/game/mixins/has_parent.dart index be85281aa27..16c495aee51 100644 --- a/packages/flame/lib/src/game/mixins/has_parent.dart +++ b/packages/flame/lib/src/game/mixins/has_parent.dart @@ -1,3 +1,5 @@ +import 'package:flutter/material.dart'; + import '../../../components.dart'; /// A mixin that ensures a parent is of the given type [T]. @@ -6,8 +8,9 @@ mixin HasParent on Component { T get parent => super.parent! as T; @override - void onMount() { - assert(super.parent is T, 'Parent must be of type ${T.toString()}'); - super.onMount(); + @mustCallSuper + Future? addToParent(Component parent) { + assert(parent is T, 'Parent must be of type $T'); + return super.addToParent(parent); } } diff --git a/packages/flame/test/game/mixins/has_parent_test.dart b/packages/flame/test/game/mixins/has_parent_test.dart index e3d1e989c67..a018a9669ef 100644 --- a/packages/flame/test/game/mixins/has_parent_test.dart +++ b/packages/flame/test/game/mixins/has_parent_test.dart @@ -1,5 +1,6 @@ import 'package:flame/components.dart'; import 'package:flame/game.dart'; +import 'package:flame_test/flame_test.dart'; import 'package:flutter_test/flutter_test.dart'; class ParentComponent extends Component {} @@ -10,23 +11,22 @@ class TestComponent extends Component with HasParent {} void main() { group('HasParent', () { - test('successfully sets the parent link', () { + testWithFlameGame('successfully sets the parent link', (game) async { final parent = ParentComponent(); final component = TestComponent(); - parent.add(component); + await parent.add(component); + await game.add(parent); expect(component.parent, isA()); - expect(component.onMount, returnsNormally); }); - test('throws assertion error when the wrong parent is used', () { + testWithFlameGame('throws assertion error when the wrong parent is used', + (game) async { final parent = DifferentComponent(); final component = TestComponent(); - parent.add(component); - - expect(component.onMount, throwsAssertionError); + expect(() => parent.add(component), throwsAssertionError); }); }); } From a5961dec089ef32ff65d06c0b9f0ecde1432d2b5 Mon Sep 17 00:00:00 2001 From: Jochum van der Ploeg Date: Sat, 23 Apr 2022 20:47:15 +0200 Subject: [PATCH 3/7] feat: add `HasParent` to force parent child relations --- doc/flame/components.md | 1 + packages/flame/test/game/mixins/has_parent_test.dart | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/doc/flame/components.md b/doc/flame/components.md index a797f78f9e6..1836a4c27f6 100644 --- a/doc/flame/components.md +++ b/doc/flame/components.md @@ -167,6 +167,7 @@ Example: ```dart class MyComponent extends Component with HasParent { + @override Future onLoad() async { // parent is of type MyParentComponent print(parent.myValue); diff --git a/packages/flame/test/game/mixins/has_parent_test.dart b/packages/flame/test/game/mixins/has_parent_test.dart index a018a9669ef..297e4c65e28 100644 --- a/packages/flame/test/game/mixins/has_parent_test.dart +++ b/packages/flame/test/game/mixins/has_parent_test.dart @@ -26,7 +26,10 @@ void main() { final parent = DifferentComponent(); final component = TestComponent(); - expect(() => parent.add(component), throwsAssertionError); + expect( + () => parent.add(component), + failsAssert('Parent must be of type ParentComponent'), + ); }); }); } From 4c4cd92ad26897d0307b8e3b9463c9144fc516cc Mon Sep 17 00:00:00 2001 From: Jochum van der Ploeg Date: Sat, 23 Apr 2022 20:47:34 +0200 Subject: [PATCH 4/7] Update doc/flame/components.md Co-authored-by: Pasha Stetsenko --- doc/flame/components.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/flame/components.md b/doc/flame/components.md index 1836a4c27f6..a395c80e44a 100644 --- a/doc/flame/components.md +++ b/doc/flame/components.md @@ -175,8 +175,8 @@ class MyComponent extends Component with HasParent { } ``` -If `MyComponent` is added to a component that is not `MyParentComponent` -an assertion error will be thrown stating such. +If you try to add `MyComponent` to a parent that is not `MyParentComponent`, +an assertion error will be thrown. ### Querying child components From 517e8bffd8e435784df9d8a298c3442f0c5fd3be Mon Sep 17 00:00:00 2001 From: Jochum van der Ploeg Date: Tue, 26 Apr 2022 20:32:39 +0200 Subject: [PATCH 5/7] feat: add `ParentIsA` to force parent child relations --- doc/flame/components.md | 4 ++-- packages/flame/lib/game.dart | 2 +- .../flame/lib/src/game/mixins/has_parent.dart | 16 ---------------- .../flame/lib/src/game/mixins/parent_is_a.dart | 13 +++++++++++++ ...as_parent_test.dart => parent_is_a_test.dart} | 4 ++-- 5 files changed, 18 insertions(+), 21 deletions(-) delete mode 100644 packages/flame/lib/src/game/mixins/has_parent.dart create mode 100644 packages/flame/lib/src/game/mixins/parent_is_a.dart rename packages/flame/test/game/mixins/{has_parent_test.dart => parent_is_a_test.dart} (90%) diff --git a/doc/flame/components.md b/doc/flame/components.md index 1836a4c27f6..e0585ff8526 100644 --- a/doc/flame/components.md +++ b/doc/flame/components.md @@ -161,12 +161,12 @@ scheduled for addition. #### Ensuring a component has a given parent When a component requires to be added to a specific parent type the -`HasParent` mixin can be used to enforce a strongly typed parent. +`ParentIsA` mixin can be used to enforce a strongly typed parent. Example: ```dart -class MyComponent extends Component with HasParent { +class MyComponent extends Component with ParentIsA { @override Future onLoad() async { // parent is of type MyParentComponent diff --git a/packages/flame/lib/game.dart b/packages/flame/lib/game.dart index b54bdb202d3..5823eadaec4 100644 --- a/packages/flame/lib/game.dart +++ b/packages/flame/lib/game.dart @@ -10,9 +10,9 @@ export 'src/game/mixins/fps_counter.dart'; export 'src/game/mixins/game.dart'; export 'src/game/mixins/has_draggables.dart'; export 'src/game/mixins/has_hoverables.dart'; -export 'src/game/mixins/has_parent.dart'; export 'src/game/mixins/has_tappables.dart'; export 'src/game/mixins/loadable.dart'; +export 'src/game/mixins/parent_is_a.dart'; export 'src/game/mixins/single_game_instance.dart'; export 'src/game/projector.dart'; export 'src/game/transform2d.dart'; diff --git a/packages/flame/lib/src/game/mixins/has_parent.dart b/packages/flame/lib/src/game/mixins/has_parent.dart deleted file mode 100644 index 16c495aee51..00000000000 --- a/packages/flame/lib/src/game/mixins/has_parent.dart +++ /dev/null @@ -1,16 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../../../components.dart'; - -/// A mixin that ensures a parent is of the given type [T]. -mixin HasParent on Component { - @override - T get parent => super.parent! as T; - - @override - @mustCallSuper - Future? addToParent(Component parent) { - assert(parent is T, 'Parent must be of type $T'); - return super.addToParent(parent); - } -} diff --git a/packages/flame/lib/src/game/mixins/parent_is_a.dart b/packages/flame/lib/src/game/mixins/parent_is_a.dart new file mode 100644 index 00000000000..61c22c7140f --- /dev/null +++ b/packages/flame/lib/src/game/mixins/parent_is_a.dart @@ -0,0 +1,13 @@ +import '../../../components.dart'; + +/// A mixin that ensures a parent is of the given type [T]. +mixin ParentIsA on Component { + @override + T get parent => super.parent! as T; + + @override + void onMount() { + assert(super.parent is T, 'Parent must be of type $T'); + super.onMount(); + } +} diff --git a/packages/flame/test/game/mixins/has_parent_test.dart b/packages/flame/test/game/mixins/parent_is_a_test.dart similarity index 90% rename from packages/flame/test/game/mixins/has_parent_test.dart rename to packages/flame/test/game/mixins/parent_is_a_test.dart index 297e4c65e28..0102deb0ef1 100644 --- a/packages/flame/test/game/mixins/has_parent_test.dart +++ b/packages/flame/test/game/mixins/parent_is_a_test.dart @@ -7,10 +7,10 @@ class ParentComponent extends Component {} class DifferentComponent extends Component {} -class TestComponent extends Component with HasParent {} +class TestComponent extends Component with ParentIsA {} void main() { - group('HasParent', () { + group('ParentIsA', () { testWithFlameGame('successfully sets the parent link', (game) async { final parent = ParentComponent(); final component = TestComponent(); From 6ff3810de76c680c24ba0cdd624cd075558ac6a7 Mon Sep 17 00:00:00 2001 From: Jochum van der Ploeg Date: Tue, 26 Apr 2022 22:06:34 +0200 Subject: [PATCH 6/7] feat: add `ParentIsA` to force parent child relations --- packages/flame/lib/components.dart | 1 + packages/flame/lib/game.dart | 1 - .../lib/src/{game => components}/mixins/parent_is_a.dart | 0 .../{game => components}/mixins/parent_is_a_test.dart | 8 ++++---- 4 files changed, 5 insertions(+), 5 deletions(-) rename packages/flame/lib/src/{game => components}/mixins/parent_is_a.dart (100%) rename packages/flame/test/{game => components}/mixins/parent_is_a_test.dart (82%) diff --git a/packages/flame/lib/components.dart b/packages/flame/lib/components.dart index b669a60fe91..e1d609d425b 100644 --- a/packages/flame/lib/components.dart +++ b/packages/flame/lib/components.dart @@ -14,6 +14,7 @@ export 'src/components/mixins/has_game_ref.dart'; export 'src/components/mixins/has_paint.dart'; export 'src/components/mixins/hoverable.dart'; export 'src/components/mixins/keyboard_handler.dart'; +export 'src/components/mixins/parent_is_a.dart'; export 'src/components/mixins/single_child_particle.dart'; export 'src/components/mixins/tappable.dart'; export 'src/components/nine_tile_box_component.dart'; diff --git a/packages/flame/lib/game.dart b/packages/flame/lib/game.dart index 5823eadaec4..b45ade87e9b 100644 --- a/packages/flame/lib/game.dart +++ b/packages/flame/lib/game.dart @@ -12,7 +12,6 @@ export 'src/game/mixins/has_draggables.dart'; export 'src/game/mixins/has_hoverables.dart'; export 'src/game/mixins/has_tappables.dart'; export 'src/game/mixins/loadable.dart'; -export 'src/game/mixins/parent_is_a.dart'; export 'src/game/mixins/single_game_instance.dart'; export 'src/game/projector.dart'; export 'src/game/transform2d.dart'; diff --git a/packages/flame/lib/src/game/mixins/parent_is_a.dart b/packages/flame/lib/src/components/mixins/parent_is_a.dart similarity index 100% rename from packages/flame/lib/src/game/mixins/parent_is_a.dart rename to packages/flame/lib/src/components/mixins/parent_is_a.dart diff --git a/packages/flame/test/game/mixins/parent_is_a_test.dart b/packages/flame/test/components/mixins/parent_is_a_test.dart similarity index 82% rename from packages/flame/test/game/mixins/parent_is_a_test.dart rename to packages/flame/test/components/mixins/parent_is_a_test.dart index 0102deb0ef1..138f42b375d 100644 --- a/packages/flame/test/game/mixins/parent_is_a_test.dart +++ b/packages/flame/test/components/mixins/parent_is_a_test.dart @@ -1,5 +1,4 @@ import 'package:flame/components.dart'; -import 'package:flame/game.dart'; import 'package:flame_test/flame_test.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -21,13 +20,14 @@ void main() { expect(component.parent, isA()); }); - testWithFlameGame('throws assertion error when the wrong parent is used', - (game) async { + test('throws assertion error when the wrong parent is used', () { final parent = DifferentComponent(); final component = TestComponent(); + parent.add(component); + expect( - () => parent.add(component), + component.onMount, failsAssert('Parent must be of type ParentComponent'), ); }); From 7cc396a4fcbf5c34568c423a3d46f71bf2e8f39f Mon Sep 17 00:00:00 2001 From: Jochum van der Ploeg Date: Wed, 27 Apr 2022 12:13:20 +0200 Subject: [PATCH 7/7] feat: add `ParentIsA` to force parent child relations --- doc/flame/components.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/flame/components.md b/doc/flame/components.md index 5de25c78c32..1921868d9fb 100644 --- a/doc/flame/components.md +++ b/doc/flame/components.md @@ -158,7 +158,7 @@ available eventually: after they are loaded and mounted. We can only assure that they will appear in the children list in the same order as they were scheduled for addition. -#### Ensuring a component has a given parent +### Ensuring a component has a given parent When a component requires to be added to a specific parent type the `ParentIsA` mixin can be used to enforce a strongly typed parent.