feat: Added glow effect using maskFilter (#2129)

This commit is contained in:
Dipak Prajapati
2022-10-29 22:14:15 +05:30
committed by GitHub
parent 2fbf11d441
commit bcecd3c1bd
9 changed files with 181 additions and 6 deletions

View File

@ -431,6 +431,30 @@ Currently this effect can only be applied to components that have a `HasPaint` m
uses multiple paints, the effect can target any individual color using the `paintId` parameter.
### GlowEffect
This effect will apply the glowing shade around target relative to the specified
`glow-strength`. The color of shade will be targets paint color. For example, the following effect
will apply the glowing shade around target by strength of `10`:
```{flutter-app}
:sources: ../flame/examples
:page: glow_effect
:show: widget code infobox
:width: 180
:height: 160
```
```dart
final effect = GlowEffect(
10.0,
EffectController(duration: 3),
);
```
Currently this effect can only be applied to components that have a `HasPaint` mixin.
### `SequenceEffect`
This effect can be used to run multiple other effects one after another. The constituent effects

View File

@ -0,0 +1,29 @@
import 'package:flame/components.dart';
import 'package:flame/effects.dart';
import 'package:flame/game.dart';
import 'package:flutter/material.dart';
class GlowEffectExample extends FlameGame {
@override
Future<void> onLoad() async {
final paint = Paint()..color = const Color(0xff39FF14);
add(
CircleComponent(
radius: size.y / 4,
position: size / 2,
anchor: Anchor.center,
paint: paint,
)..add(
GlowEffect(
10.0,
EffectController(
duration: 2,
infinite: true,
),
),
),
);
}
}

View File

@ -10,6 +10,7 @@ import 'package:doc_flame_examples/decorator_rotate3d.dart';
import 'package:doc_flame_examples/decorator_shadow3d.dart';
import 'package:doc_flame_examples/decorator_tint.dart';
import 'package:doc_flame_examples/drag_events.dart';
import 'package:doc_flame_examples/glow_effect.dart';
import 'package:doc_flame_examples/move_along_path_effect.dart';
import 'package:doc_flame_examples/move_by_effect.dart';
import 'package:doc_flame_examples/move_to_effect.dart';
@ -67,6 +68,7 @@ void main() {
'rive_example': RiveExampleGame.new,
'ray_cast': RayCastExample.new,
'ray_trace': RayTraceExample.new,
'glow_effect': GlowEffectExample.new,
'remove_effect': RemoveEffectGame.new,
'color_effect': ColorEffectExample.new,
};

View File

@ -0,0 +1,39 @@
import 'package:flame/components.dart';
import 'package:flame/effects.dart';
import 'package:flame/game.dart';
import 'package:flame/input.dart';
import 'package:flutter/material.dart';
void main() {
runApp(GameWidget(game: GlowEffectExample()));
}
class GlowEffectExample extends FlameGame with TapDetector {
static const String description = '''
In this example we show how the `GlowEffect` can be used.
''';
@override
Future<void> onLoad() async {
final paint = Paint()
..color = const Color(0xff39FF14)
..style = PaintingStyle.stroke;
add(
CircleComponent(
radius: 50,
position: Vector2(300, 400),
paint: paint,
)..add(
GlowEffect(
10.0,
EffectController(
duration: 3,
reverseDuration: 1.5,
infinite: true,
),
),
),
);
}
}

View File

@ -21,6 +21,7 @@ export 'src/effects/controllers/speed_effect_controller.dart';
export 'src/effects/controllers/zigzag_effect_controller.dart';
export 'src/effects/effect.dart';
export 'src/effects/effect_target.dart';
export 'src/effects/glow_effect.dart';
export 'src/effects/move_along_path_effect.dart';
export 'src/effects/move_by_effect.dart';
export 'src/effects/move_effect.dart';

View File

@ -3,6 +3,7 @@ import 'dart:ui';
import 'package:flame/components.dart';
import 'package:flame/effects.dart';
import 'package:flame/src/effects/provider_interfaces.dart';
import 'package:flame/src/palette.dart';
import 'package:meta/meta.dart';
@ -14,8 +15,11 @@ import 'package:meta/meta.dart';
/// [T], that can be omitted if the component only has one paint.
/// [paintLayers] paints should be drawn in list order during the render. The
/// main Paint is the first element.
mixin HasPaint<T extends Object> on Component implements OpacityProvider {
mixin HasPaint<T extends Object> on Component
implements OpacityProvider, PaintProvider {
late final Map<T, Paint> _paints = {};
@override
Paint paint = BasicPalette.white.paint();
@internal

View File

@ -0,0 +1,29 @@
import 'dart:ui';
import 'package:flame/effects.dart';
import 'package:flame/src/effects/provider_interfaces.dart';
/// Change the MaskFilter on Paint of a component over time.
///
/// This effect applies incremental changes to the MaskFilter on Paint of a
/// component and requires that any other effect or update logic applied to the
/// same component also used incremental updates.
class GlowEffect extends Effect with EffectTarget<PaintProvider> {
GlowEffect(this.strength, super.controller, {this.style = BlurStyle.outer});
final BlurStyle style;
final double strength;
@override
void apply(double progress) {
final _value = strength * progress;
target.paint.maskFilter = MaskFilter.blur(style, _value);
}
@override
void reset() {
super.reset();
target.paint.maskFilter = null;
}
}

View File

@ -1,3 +1,5 @@
import 'dart:ui';
import 'package:flame/components.dart';
/// Interface for a component that can be affected by move effects.
@ -64,3 +66,11 @@ abstract class OpacityProvider {
double get opacity;
set opacity(double value);
}
/// Interface for a component that can be affected by Paint effects.
///
/// See [HasPaint] for an example implementation.
abstract class PaintProvider {
Paint get paint;
set paint(Paint value);
}

View File

@ -0,0 +1,37 @@
import 'package:flame/components.dart';
import 'package:flame/effects.dart';
import 'package:flame_test/flame_test.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
group('GlowEffect', () {
testWithFlameGame('can apply to component having HasPaint', (game) async {
final component = _PaintComponent();
await game.ensureAdd(component);
await component.add(
GlowEffect(1, EffectController(duration: 1)),
);
game.update(0);
expect(component.children.length, 1);
expect(component.paint.maskFilter, isNotNull);
expect(
component.paint.maskFilter.toString(),
'MaskFilter.blur(BlurStyle.outer, 0.0)',
);
game.update(1);
expect(
component.paint.maskFilter.toString(),
'MaskFilter.blur(BlurStyle.outer, 1.0)',
);
});
});
}
class _PaintComponent extends Component with HasPaint {}