-
-
Notifications
You must be signed in to change notification settings - Fork 934
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Component visibility (HasVisibility mixin) (#2681)
This PR introduces a new HasVisibility mixin on Component. It prevents the renderTree method from progressing if the isVisible property is false. It therefore prevents the component and all it's children from rendering. The purpose of this mixin is to allow showing and hiding a component without removing it from the tree. An important note is that the component (and all it's children) will still be on the tree. They will continue to receive update events, and all other lifecycle events. If the user has implemented input such as tap events, or collision detection, or any other interactivity, this will continue to operate without affect (unless it relies on the render step - such as per-pixel collision detection). This is expected behaviour. If it is not desired, the user needs to account for it (by checking isVisible in their code) or someone needs to create another mixin for HasEnabled or HasActive which would prevent these other actions 😁 I am very happy to make changes, take suggestions, etc!
- Loading branch information
1 parent
158fc34
commit 76405da
Showing
7 changed files
with
205 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
30 changes: 30 additions & 0 deletions
30
examples/lib/stories/components/has_visibility_example.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import 'dart:async'; | ||
|
||
import 'package:flame/components.dart' hide Timer; | ||
import 'package:flame/game.dart'; | ||
|
||
class HasVisibilityExample extends FlameGame { | ||
static const String description = ''' | ||
In this example we use the `HasVisibility` mixin to toggle the | ||
visibility of a component without removing it from the parent | ||
component. | ||
This is a non-interactive example. | ||
'''; | ||
|
||
@override | ||
Future<void> onLoad() async { | ||
final flameLogoComponent = LogoComponent(await loadSprite('flame.png')); | ||
add(flameLogoComponent); | ||
|
||
// Toggle visibility every second | ||
const oneSecDuration = Duration(seconds: 1); | ||
Timer.periodic( | ||
oneSecDuration, | ||
(Timer t) => flameLogoComponent.isVisible = !flameLogoComponent.isVisible, | ||
); | ||
} | ||
} | ||
|
||
class LogoComponent extends SpriteComponent with HasVisibility { | ||
LogoComponent(Sprite sprite) : super(sprite: sprite, size: sprite.srcSize); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
32 changes: 32 additions & 0 deletions
32
packages/flame/lib/src/components/mixins/has_visibility.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import 'package:flame/components.dart'; | ||
import 'package:flutter/material.dart'; | ||
|
||
/// A mixin that allows a component visibility to be toggled | ||
/// without removing it from the tree. Visibility affects | ||
/// the component and all it's children/descendants. | ||
/// | ||
/// Set [isVisible] to false to prevent the component and all | ||
/// it's children from being rendered. | ||
/// | ||
/// The component will still respond as if it is on the tree, | ||
/// including lifecycle and other events, but will simply | ||
/// not render itself or it's children. | ||
/// | ||
/// If you are adding a custom implementation of the | ||
/// [renderTree] method, make sure to wrap your render code | ||
/// in a conditional. i.e.: | ||
/// ``` | ||
/// if (isVisible) { | ||
/// // Custom render code here | ||
/// } | ||
/// ``` | ||
mixin HasVisibility on Component { | ||
bool isVisible = true; | ||
|
||
@override | ||
void renderTree(Canvas canvas) { | ||
if (isVisible) { | ||
super.renderTree(canvas); | ||
} | ||
} | ||
} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
59 changes: 59 additions & 0 deletions
59
packages/flame/test/components/mixins/has_visibility_test.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import 'dart:ui'; | ||
|
||
import 'package:flame/components.dart'; | ||
import 'package:flame_test/flame_test.dart'; | ||
import 'package:flutter/material.dart'; | ||
import 'package:flutter_test/flutter_test.dart'; | ||
|
||
import '../../_resources/load_image.dart'; | ||
|
||
void main() { | ||
group('HasVisibility', () { | ||
testGolden( | ||
'Render a Component with isVisible set to false', | ||
(game) async { | ||
game.add(MyComponent()..mySprite.isVisible = false); | ||
}, | ||
size: Vector2(300, 400), | ||
goldenFile: '../../_goldens/visibility_test_1.png', | ||
); | ||
}); | ||
} | ||
|
||
class MySpriteComponent extends PositionComponent with HasVisibility { | ||
late final Sprite sprite; | ||
|
||
@override | ||
Future<void> onLoad() async { | ||
sprite = Sprite(await loadImage('flame.png')); | ||
} | ||
|
||
@override | ||
void render(Canvas canvas) { | ||
sprite.render(canvas, anchor: Anchor.center); | ||
} | ||
} | ||
|
||
/// This component contains a [MySpriteComponent]. It first | ||
/// renders a rectangle, and then the children will render. | ||
/// In this test the visibility of [mySprite] is set to | ||
/// false, so only the rectangle is expected to be rendered. | ||
class MyComponent extends PositionComponent { | ||
MyComponent() : super(size: Vector2(300, 400)) { | ||
mySprite = MySpriteComponent()..position = Vector2(150, 200); | ||
add(mySprite); | ||
} | ||
late final MySpriteComponent mySprite; | ||
|
||
@override | ||
void render(Canvas canvas) { | ||
canvas.drawRect( | ||
Rect.fromLTRB(25, 25, size.x - 25, size.y - 25), | ||
Paint() | ||
..color = const Color(0xffffffff) | ||
..style = PaintingStyle.stroke | ||
..strokeWidth = 2, | ||
); | ||
super.render(canvas); | ||
} | ||
} |