diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a8bcd64d..128148d9c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ ## [next] - Outsourcing SVG support to an external package + - Adding MemoryCache class + - Fixing games crashes on Web + - Update tiled dependency to 0.6.0 (objects' properties are now double) ## 0.23.0 - Add Joystick Component diff --git a/doc/examples/debug/lib/main.dart b/doc/examples/debug/lib/main.dart index 7139eebe1..5fb0639d5 100644 --- a/doc/examples/debug/lib/main.dart +++ b/doc/examples/debug/lib/main.dart @@ -48,7 +48,7 @@ class AndroidComponent extends SpriteComponent with Resizable { } class MyGame extends BaseGame { - final fpsTextConfig = const TextConfig(color: const Color(0xFFFFFFFF)); + final fpsTextConfig = TextConfig(color: const Color(0xFFFFFFFF)); @override bool debugMode() => true; diff --git a/doc/examples/flare/lib/main.dart b/doc/examples/flare/lib/main.dart index 36310713f..af5dda162 100644 --- a/doc/examples/flare/lib/main.dart +++ b/doc/examples/flare/lib/main.dart @@ -16,8 +16,7 @@ void main() { } class MyGame extends BaseGame with TapDetector { - final TextConfig fpsTextConfig = - const TextConfig(color: const Color(0xFFFFFFFF)); + final TextConfig fpsTextConfig = TextConfig(color: const Color(0xFFFFFFFF)); final paint = Paint()..color = const Color(0xFFE5E5E5E5); final List _animations = ["Stand", "Wave", "Jump", "Dance"]; diff --git a/doc/examples/particles/lib/main.dart b/doc/examples/particles/lib/main.dart index aa59a502c..4f5608ab7 100644 --- a/doc/examples/particles/lib/main.dart +++ b/doc/examples/particles/lib/main.dart @@ -43,7 +43,7 @@ class MyGame extends BaseGame { final Random rnd = Random(); final StepTween steppedTween = StepTween(begin: 0, end: 5); final trafficLight = TrafficLightComponent(); - final TextConfig fpsTextConfig = const TextConfig( + final TextConfig fpsTextConfig = TextConfig( color: const Color(0xFFFFFFFF), ); diff --git a/doc/examples/text/lib/main.dart b/doc/examples/text/lib/main.dart index c10090dee..037c8df67 100644 --- a/doc/examples/text/lib/main.dart +++ b/doc/examples/text/lib/main.dart @@ -19,8 +19,7 @@ TextConfig tiny = regular.withFontSize(12.0); class MyTextBox extends TextBoxComponent { MyTextBox(String text) - : super(text, - config: tiny, boxConfig: const TextBoxConfig(timePerChar: 0.05)); + : super(text, config: tiny, boxConfig: TextBoxConfig(timePerChar: 0.05)); @override void drawBackground(Canvas c) { diff --git a/doc/examples/timer/lib/main.dart b/doc/examples/timer/lib/main.dart index dcb8e7d25..0e1dad562 100644 --- a/doc/examples/timer/lib/main.dart +++ b/doc/examples/timer/lib/main.dart @@ -33,8 +33,7 @@ class GameWidget extends StatelessWidget { } class RenderedTimeComponent extends TimerComponent { - final TextConfig textConfig = - const TextConfig(color: const Color(0xFFFFFFFF)); + final TextConfig textConfig = TextConfig(color: const Color(0xFFFFFFFF)); RenderedTimeComponent(Timer timer) : super(timer); @@ -58,8 +57,7 @@ class MyBaseGame extends BaseGame with TapDetector, DoubleTapDetector { } class MyGame extends Game with TapDetector { - final TextConfig textConfig = - const TextConfig(color: const Color(0xFFFFFFFF)); + final TextConfig textConfig = TextConfig(color: const Color(0xFFFFFFFF)); Timer countdown; Timer interval; diff --git a/lib/components/text_box_component.dart b/lib/components/text_box_component.dart index c2180f29a..02e9be5e8 100644 --- a/lib/components/text_box_component.dart +++ b/lib/components/text_box_component.dart @@ -15,7 +15,7 @@ class TextBoxConfig { final double timePerChar; final double dismissDelay; - const TextBoxConfig({ + TextBoxConfig({ this.maxWidth = 200.0, this.margin = 8.0, this.timePerChar = 0.0, @@ -46,11 +46,13 @@ class TextBoxComponent extends PositionComponent with Resizable { TextBoxConfig get boxConfig => _boxConfig; - TextBoxComponent(String text, - {TextConfig config = const TextConfig(), - TextBoxConfig boxConfig = const TextBoxConfig()}) { - _boxConfig = boxConfig; - _config = config; + TextBoxComponent( + String text, { + TextConfig config, + TextBoxConfig boxConfig, + }) { + _boxConfig = boxConfig ?? TextBoxConfig(); + _config = config ?? TextConfig(); _text = text; _lines = []; text.split(' ').forEach((word) { diff --git a/lib/components/text_component.dart b/lib/components/text_component.dart index e21b732ad..4e52ca28b 100644 --- a/lib/components/text_component.dart +++ b/lib/components/text_component.dart @@ -27,8 +27,8 @@ class TextComponent extends PositionComponent { _updateBox(); } - TextComponent(this._text, {TextConfig config = const TextConfig()}) { - _config = config; + TextComponent(this._text, {TextConfig config}) { + _config = config ?? TextConfig(); _updateBox(); } diff --git a/lib/memory_cache.dart b/lib/memory_cache.dart new file mode 100644 index 000000000..4c5d46e7a --- /dev/null +++ b/lib/memory_cache.dart @@ -0,0 +1,27 @@ +import 'dart:collection'; + +/// Simple class to cache values on the cache +/// +class MemoryCache { + final LinkedHashMap _cache = LinkedHashMap(); + final int cacheSize; + + MemoryCache({this.cacheSize = 10}); + + void setValue(K key, V value) { + if (!_cache.containsKey(key)) { + _cache[key] = value; + + while (_cache.length > cacheSize) { + final k = _cache.keys.first; + _cache.remove(k); + } + } + } + + V getValue(K key) => _cache[key]; + + bool containsKey(K key) => _cache.containsKey(key); + + int get size => _cache.length; +} diff --git a/lib/text_config.dart b/lib/text_config.dart index 9f9bdcfa8..088b62805 100644 --- a/lib/text_config.dart +++ b/lib/text_config.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart' as material; import 'position.dart'; import 'anchor.dart'; +import 'memory_cache.dart'; /// A Text Config contains all typographical information required to render texts; i.e., font size and color, family, etc. /// @@ -52,10 +53,13 @@ class TextConfig { /// For proper fonts of languages like Hebrew or Arabic, replace this with [TextDirection.rtl]. final TextDirection textDirection; + final MemoryCache _textPainterCache = + MemoryCache(); + /// Creates a constant [TextConfig] with sensible defaults. /// /// Every parameter can be specified. - const TextConfig({ + TextConfig({ this.fontSize = 24.0, this.color = const Color(0xFF000000), this.fontFamily = 'Arial', @@ -93,22 +97,26 @@ class TextConfig { /// However, you probably want to use the [render] method witch already renders for you considering the anchor. /// That way, you don't need to perform the math for yourself. material.TextPainter toTextPainter(String text) { - final material.TextStyle style = material.TextStyle( - color: color, - fontSize: fontSize, - fontFamily: fontFamily, - ); - final material.TextSpan span = material.TextSpan( - style: style, - text: text, - ); - final material.TextPainter tp = material.TextPainter( - text: span, - textAlign: textAlign, - textDirection: textDirection, - ); - tp.layout(); - return tp; + if (!_textPainterCache.containsKey(text)) { + final material.TextStyle style = material.TextStyle( + color: color, + fontSize: fontSize, + fontFamily: fontFamily, + ); + final material.TextSpan span = material.TextSpan( + style: style, + text: text, + ); + final material.TextPainter tp = material.TextPainter( + text: span, + textAlign: textAlign, + textDirection: textDirection, + ); + tp.layout(); + + _textPainterCache.setValue(text, tp); + } + return _textPainterCache.getValue(text); } /// Creates a new [TextConfig] changing only the [fontSize]. diff --git a/pubspec.yaml b/pubspec.yaml index c4ab2a89d..459788ab8 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -11,7 +11,7 @@ dependencies: path_provider: ^1.6.0 box2d_flame: ^0.4.6 synchronized: ^2.1.0 - tiled: ^0.5.0 + tiled: ^0.6.0 convert: ^2.0.1 flare_flutter: ^2.0.1 meta: ^1.1.8 diff --git a/test/memory_cache_test.dart b/test/memory_cache_test.dart new file mode 100644 index 000000000..bf4cf6473 --- /dev/null +++ b/test/memory_cache_test.dart @@ -0,0 +1,31 @@ +import 'package:test/test.dart'; + +import 'package:flame/memory_cache.dart'; + +void main() { + group('MemoryCache', () { + test('basic cache addition', () { + final cache = MemoryCache(); + cache.setValue(0, 'bla'); + expect(cache.getValue(0), 'bla'); + }); + + test('contains key', () { + final cache = MemoryCache(); + cache.setValue(0, 'bla'); + expect(cache.containsKey(0), true); + expect(cache.containsKey(1), false); + }); + + test('cache size', () { + final cache = MemoryCache(cacheSize: 1); + cache.setValue(0, 'bla'); + cache.setValue(1, 'ble'); + expect(cache.containsKey(0), false); + expect(cache.containsKey(1), true); + expect(cache.getValue(0), null); + expect(cache.getValue(1), 'ble'); + expect(cache.size, 1); + }); + }); +}