Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add ParentIsA to force parent child relations #1566

Merged
merged 10 commits into from
Apr 27, 2022
20 changes: 19 additions & 1 deletion doc/flame/components.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,25 @@ 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
`ParentIsA` mixin can be used to enforce a strongly typed parent.

Example:

```dart
class MyComponent extends Component with ParentIsA<MyParentComponent> {
@override
Future<void> onLoad() async {
wolfenrain marked this conversation as resolved.
Show resolved Hide resolved
// parent is of type MyParentComponent
print(parent.myValue);
}
}
```

If you try to add `MyComponent` to a parent that is not `MyParentComponent`,
an assertion error will be thrown.

### Querying child components

Expand Down Expand Up @@ -305,7 +324,6 @@ Future<void> 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
Expand Down
1 change: 1 addition & 0 deletions packages/flame/lib/components.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down
13 changes: 13 additions & 0 deletions packages/flame/lib/src/components/mixins/parent_is_a.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import '../../../components.dart';

/// A mixin that ensures a parent is of the given type [T].
mixin ParentIsA<T extends Component> 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();
}
}
35 changes: 35 additions & 0 deletions packages/flame/test/components/mixins/parent_is_a_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import 'package:flame/components.dart';
import 'package:flame_test/flame_test.dart';
import 'package:flutter_test/flutter_test.dart';

class ParentComponent extends Component {}

class DifferentComponent extends Component {}

class TestComponent extends Component with ParentIsA<ParentComponent> {}

void main() {
group('ParentIsA', () {
testWithFlameGame('successfully sets the parent link', (game) async {
final parent = ParentComponent();
final component = TestComponent();

await parent.add(component);
await game.add(parent);

expect(component.parent, isA<ParentComponent>());
});

test('throws assertion error when the wrong parent is used', () {
final parent = DifferentComponent();
final component = TestComponent();

parent.add(component);

expect(
component.onMount,
failsAssert('Parent must be of type ParentComponent'),
);
});
});
}