diff --git a/examples/lib/stories/rendering/text_example.dart b/examples/lib/stories/rendering/text_example.dart index 41fc17aab7c..074a26e19ac 100644 --- a/examples/lib/stories/rendering/text_example.dart +++ b/examples/lib/stories/rendering/text_example.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'package:flame/components.dart'; +import 'package:flame/effects.dart'; import 'package:flame/game.dart'; import 'package:flame/palette.dart'; import 'package:flame/text.dart'; @@ -82,6 +83,37 @@ class TextExample extends FlameGame { margins: EdgeInsets.fromLTRB(10, 10, 10, 10), ), ), + TextComponent( + text: 'I fade in and fade out', + anchor: Anchor.topRight, + position: Vector2(size.x - 50, 20), + children: [ + SequenceEffect( + [ + OpacityEffect.fadeOut( + LinearEffectController(1.5), + ), + OpacityEffect.fadeIn( + LinearEffectController(1.5), + ), + ], + infinite: true, + ), + ], + ), + TextComponent( + text: 'I change my color!', + anchor: Anchor.topRight, + position: Vector2(size.x - 50, 50), + children: [ + ColorEffect( + Colors.blue, + InfiniteEffectController( + LinearEffectController(1.5), + ), + ), + ], + ), ], ); } @@ -114,7 +146,7 @@ final _shaded = TextPaint( ); class MyTextBox extends TextBoxComponent { - late Paint paint; + late Paint bgPaint; late Rect bgRect; MyTextBox( @@ -136,25 +168,25 @@ class MyTextBox extends TextBoxComponent { @override Future onLoad() { - paint = Paint(); + bgPaint = Paint(); bgRect = Rect.fromLTWH(0, 0, width, height); size.addListener(() { bgRect = Rect.fromLTWH(0, 0, width, height); }); - paint.color = Colors.white10; + bgPaint.color = Colors.white10; return super.onLoad(); } @override void render(Canvas canvas) { - canvas.drawRect(bgRect, paint); + canvas.drawRect(bgRect, bgPaint); super.render(canvas); } } class MyScrollTextBox extends ScrollTextBoxComponent { - late Paint paint; + late Paint bgPaint; late Rect backgroundRect; MyScrollTextBox( @@ -167,16 +199,16 @@ class MyScrollTextBox extends ScrollTextBoxComponent { @override FutureOr onLoad() { - paint = Paint(); + bgPaint = Paint(); backgroundRect = Rect.fromLTWH(0, 0, width, height); - paint.color = Colors.white10; + bgPaint.color = Colors.white10; return super.onLoad(); } @override void render(Canvas canvas) { - canvas.drawRect(backgroundRect, paint); + canvas.drawRect(backgroundRect, bgPaint); super.render(canvas); } } diff --git a/packages/flame/lib/src/components/mixins/has_paint.dart b/packages/flame/lib/src/components/mixins/has_paint.dart index 48a0ce81744..5942900ff48 100644 --- a/packages/flame/lib/src/components/mixins/has_paint.dart +++ b/packages/flame/lib/src/components/mixins/has_paint.dart @@ -113,6 +113,7 @@ mixin HasPaint on Component /// Shortcut for changing the color of the paint. void setColor(Color color, {T? paintId}) { getPaint(paintId).color = color; + onChanged(); } /// Applies a color filter to the paint which will make @@ -120,6 +121,7 @@ mixin HasPaint on Component /// tinted with the given color. void tint(Color color, {T? paintId}) { getPaint(paintId).colorFilter = ColorFilter.mode(color, BlendMode.srcATop); + onChanged(); } @override @@ -131,6 +133,7 @@ mixin HasPaint on Component for (final paint in _paints.values) { paint.color = paint.color.withValues(alpha: value); } + onChanged(); } @override @@ -158,6 +161,7 @@ mixin HasPaint on Component layerPaint.colorFilter = filter; } } + onChanged(); } /// Creates an [OpacityProvider] for given [paintId] and can be used as @@ -189,6 +193,12 @@ mixin HasPaint on Component includeLayers: includeLayers, ); } + + /// Can be overridden to react when the [paint] object + /// changed! + /// + /// Default implementation is a no-op. + void onChanged() {} } class _ProxyOpacityProvider implements OpacityProvider { diff --git a/packages/flame/lib/src/components/text_component.dart b/packages/flame/lib/src/components/text_component.dart index 3ac38b8dfcb..30a9bb5760f 100644 --- a/packages/flame/lib/src/components/text_component.dart +++ b/packages/flame/lib/src/components/text_component.dart @@ -5,7 +5,8 @@ import 'package:flame/text.dart'; import 'package:flutter/painting.dart'; import 'package:meta/meta.dart'; -class TextComponent extends PositionComponent { +class TextComponent extends PositionComponent + with HasPaint { TextComponent({ String? text, T? textRenderer, @@ -40,9 +41,13 @@ class TextComponent extends PositionComponent { late InlineTextElement _textElement; + void _updateElement() { + _textElement = _textRenderer.format(_text); + } + @internal void updateBounds() { - _textElement = _textRenderer.format(_text); + _updateElement(); final measurements = _textElement.metrics; _textElement.translate(0, measurements.ascent); size.setValues(measurements.width, measurements.height); @@ -52,4 +57,10 @@ class TextComponent extends PositionComponent { void render(Canvas canvas) { _textElement.draw(canvas); } + + @override + void onChanged() { + _textRenderer = _textRenderer.copyWithPaint(paint) as T; + _updateElement(); + } } diff --git a/packages/flame/lib/src/text/renderers/sprite_font_renderer.dart b/packages/flame/lib/src/text/renderers/sprite_font_renderer.dart index a04a0f913cb..0f3b127d199 100644 --- a/packages/flame/lib/src/text/renderers/sprite_font_renderer.dart +++ b/packages/flame/lib/src/text/renderers/sprite_font_renderer.dart @@ -17,6 +17,13 @@ class SpriteFontRenderer extends TextRenderer { } } + SpriteFontRenderer.fromPaint( + this.font, { + required this.paint, + this.scale = 1.0, + this.letterSpacing = 0.0, + }); + final SpriteFont font; final double scale; final double letterSpacing; @@ -56,4 +63,12 @@ class SpriteFontRenderer extends TextRenderer { ), ); } + + @override + TextRenderer copyWithPaint(Paint paint) { + return SpriteFontRenderer.fromPaint( + font, + paint: paint, + ); + } } diff --git a/packages/flame/lib/src/text/renderers/text_paint.dart b/packages/flame/lib/src/text/renderers/text_paint.dart index c9b00070305..1202523cd83 100644 --- a/packages/flame/lib/src/text/renderers/text_paint.dart +++ b/packages/flame/lib/src/text/renderers/text_paint.dart @@ -54,6 +54,17 @@ class TextPaint extends TextRenderer { return _textPainterCache.getValue(text)!; } + @override + TextRenderer copyWithPaint(Paint paint) { + return copyWith( + (style) { + return style.copyWith( + foreground: paint, + ); + }, + ); + } + TextPaint copyWith( TextStyle Function(TextStyle) transform, { TextDirection? textDirection, diff --git a/packages/flame/lib/src/text/renderers/text_renderer.dart b/packages/flame/lib/src/text/renderers/text_renderer.dart index edb295ab0f6..1d442de8757 100644 --- a/packages/flame/lib/src/text/renderers/text_renderer.dart +++ b/packages/flame/lib/src/text/renderers/text_renderer.dart @@ -1,3 +1,5 @@ +import 'dart:ui'; + import 'package:flame/extensions.dart'; import 'package:flame/src/anchor.dart'; import 'package:flame/text.dart'; @@ -11,6 +13,8 @@ abstract class TextRenderer { return format(text).metrics; } + TextRenderer copyWithPaint(Paint paint); + void render( Canvas canvas, String text, diff --git a/packages/flame/test/text/text_renderer_test.dart b/packages/flame/test/text/text_renderer_test.dart index 32c9e5e1ce7..3182c5f4318 100644 --- a/packages/flame/test/text/text_renderer_test.dart +++ b/packages/flame/test/text/text_renderer_test.dart @@ -37,6 +37,11 @@ class _CustomTextRenderer extends TextRenderer { InlineTextElement format(String text) { return _CustomTextElement(); } + + @override + TextRenderer copyWithPaint(Paint paint) { + return _CustomTextRenderer(); + } } class _CustomTextElement extends InlineTextElement { diff --git a/packages/flame_test/lib/src/debug_text_renderer.dart b/packages/flame_test/lib/src/debug_text_renderer.dart index a5be123710e..c04f4aa9c54 100644 --- a/packages/flame_test/lib/src/debug_text_renderer.dart +++ b/packages/flame_test/lib/src/debug_text_renderer.dart @@ -25,6 +25,17 @@ class DebugTextRenderer extends TextRenderer { @override InlineTextElement format(String text) => _DebugTextElement(this, text); + + @override + TextRenderer copyWithPaint(Paint paint) { + return DebugTextRenderer( + color: paint.color, + fontSize: fontSize, + lineHeight: lineHeight, + fontWeight: fontWeight, + fontStyle: fontStyle, + ); + } } class _DebugTextElement extends InlineTextElement {