diff --git a/.github/workflows/unit.yml b/.github/workflows/unit.yml index 6a93cce93..e86f968b4 100644 --- a/.github/workflows/unit.yml +++ b/.github/workflows/unit.yml @@ -5,9 +5,6 @@ on: - master pull_request: types: [opened,ready_for_review,synchronize] - -env: - flutter_version: "3.13.0" jobs: test-analyze: @@ -25,7 +22,7 @@ jobs: - name: Setup Flutter uses: subosito/flutter-action@v2 with: - flutter-version: ${{ env.flutter_version }} + channel: 'stable' cache: true - run: flutter pub get - run: flutter analyze diff --git a/CHANGELOG.md b/CHANGELOG.md index 9650004ab..0e6b8ada4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# 3.4.0 +- Adds `header` param in `TiledNetworkReader` +- Update Flame to '1.15.0' + # 3.3.0 - `TiledNetworkReader` improvements. Adds support to embedded tileset. - Update Flame to `1.14.0` diff --git a/example/.metadata b/example/.metadata index 790d0ac3d..4ac126a28 100644 --- a/example/.metadata +++ b/example/.metadata @@ -1,11 +1,11 @@ # This file tracks properties of this Flutter project. # Used by Flutter tool to assess capabilities and perform upgrades etc. # -# This file should be version controlled. +# This file should be version controlled and should not be manually edited. version: - revision: 682aa387cfe4fbd71ccd5418b2c2a075729a1c66 - channel: stable + revision: "41456452f29d64e8deb623a3c927524bcf9f111b" + channel: "stable" project_type: app @@ -13,26 +13,11 @@ project_type: app migration: platforms: - platform: root - create_revision: 682aa387cfe4fbd71ccd5418b2c2a075729a1c66 - base_revision: 682aa387cfe4fbd71ccd5418b2c2a075729a1c66 - - platform: android - create_revision: 682aa387cfe4fbd71ccd5418b2c2a075729a1c66 - base_revision: 682aa387cfe4fbd71ccd5418b2c2a075729a1c66 - - platform: ios - create_revision: 682aa387cfe4fbd71ccd5418b2c2a075729a1c66 - base_revision: 682aa387cfe4fbd71ccd5418b2c2a075729a1c66 + create_revision: 41456452f29d64e8deb623a3c927524bcf9f111b + base_revision: 41456452f29d64e8deb623a3c927524bcf9f111b - platform: linux - create_revision: 682aa387cfe4fbd71ccd5418b2c2a075729a1c66 - base_revision: 682aa387cfe4fbd71ccd5418b2c2a075729a1c66 - - platform: macos - create_revision: 682aa387cfe4fbd71ccd5418b2c2a075729a1c66 - base_revision: 682aa387cfe4fbd71ccd5418b2c2a075729a1c66 - - platform: web - create_revision: 682aa387cfe4fbd71ccd5418b2c2a075729a1c66 - base_revision: 682aa387cfe4fbd71ccd5418b2c2a075729a1c66 - - platform: windows - create_revision: 682aa387cfe4fbd71ccd5418b2c2a075729a1c66 - base_revision: 682aa387cfe4fbd71ccd5418b2c2a075729a1c66 + create_revision: 41456452f29d64e8deb623a3c927524bcf9f111b + base_revision: 41456452f29d64e8deb623a3c927524bcf9f111b # User provided section diff --git a/example/lib/pages/mini_games/top_down_game/robot_enemy.dart b/example/lib/pages/mini_games/top_down_game/robot_enemy.dart index ef3828f46..daddcd308 100644 --- a/example/lib/pages/mini_games/top_down_game/robot_enemy.dart +++ b/example/lib/pages/mini_games/top_down_game/robot_enemy.dart @@ -29,17 +29,12 @@ class ZombieEnemy extends RotationEnemy @override void update(double dt) { super.update(dt); - seePlayer( - observed: (player) { - moveTowardsTarget( - target: player, - close: () { - simpleAttackMelee( - damage: 10, - size: Vector2.all(size.y), - animationRight: CommonSpriteSheet.blackAttackEffectRight, - ); - }, + seeAndMoveToPlayer( + closePlayer: (_) { + simpleAttackMelee( + damage: 10, + size: Vector2.all(size.y), + animationRight: CommonSpriteSheet.blackAttackEffectRight, ); }, radiusVision: 128, @@ -51,6 +46,7 @@ class ZombieEnemy extends RotationEnemy minDistance: 32, speed: 20, ); + return false; }, ); } diff --git a/example/pubspec.lock b/example/pubspec.lock index 710b8cc8f..68b783d6e 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -47,7 +47,7 @@ packages: path: ".." relative: true source: path - version: "3.2.0" + version: "3.3.0" boolean_selector: dependency: transitive description: @@ -68,10 +68,10 @@ packages: dependency: transitive description: name: collection - sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a url: "https://pub.dev" source: hosted - version: "1.17.2" + version: "1.18.0" convert: dependency: transitive description: @@ -124,10 +124,10 @@ packages: dependency: transitive description: name: flame - sha256: "61c42b966a6b1f44ee093194e6701d45b14fdda1859c14fe68a39489454bfbd4" + sha256: "2a2352741500ce47823dcf212f06b23e9bdb622454eab90244ee6da58e23b488" url: "https://pub.dev" source: hosted - version: "1.14.0" + version: "1.15.0" flutter: dependency: "direct main" description: flutter @@ -246,10 +246,10 @@ packages: dependency: transitive description: name: meta - sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" + sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.10.0" mime: dependency: transitive description: @@ -539,10 +539,10 @@ packages: dependency: transitive description: name: web - sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 + sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152 url: "https://pub.dev" source: hosted - version: "0.1.4-beta" + version: "0.3.0" web_socket_channel: dependency: transitive description: @@ -568,5 +568,5 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.1.0 <4.0.0" + dart: ">=3.2.0-194.0.dev <4.0.0" flutter: ">=3.13.0" diff --git a/lib/base/listener_game_widget.dart b/lib/base/listener_game_widget.dart index 1c3b7b312..9edc0f36e 100644 --- a/lib/base/listener_game_widget.dart +++ b/lib/base/listener_game_widget.dart @@ -1,4 +1,4 @@ -// ignore_for_file: implementation_imports +// ignore_for_file: implementation_imports, invalid_use_of_internal_member import 'dart:async'; @@ -171,13 +171,13 @@ class ListenerGameWidgetState late T currentGame; Future get loaderFuture => _loaderFuture ??= (() async { - assert(currentGame.hasLayout); - // ignore: invalid_use_of_internal_member - final onLoad = currentGame.onLoadFuture; - if (onLoad != null) { - await onLoad; + final game = currentGame; + assert(game.hasLayout); + await game.load(); + game.mount(); + if (!game.paused) { + game.update(0); } - currentGame.onMount(); })(); Future? _loaderFuture; @@ -236,9 +236,31 @@ class ListenerGameWidgetState _loaderFuture = null; } - void disposeCurrentGame() { + /// Visible for testing for + /// https://github.com/flame-engine/flame/issues/2771. + @visibleForTesting + static void initGameStateListener( + Game currentGame, + void Function() onGameStateChange, + ) { + currentGame.addGameStateListener(onGameStateChange); + + // See https://github.com/flame-engine/flame/issues/2771 + // for why we aren't using [WidgetsBinding.instance.lifecycleState]. + currentGame.lifecycleStateChange(AppLifecycleState.resumed); + } + + /// [disposeCurrentGame] is called by two flutter events - `didUpdateWidget` + /// and `dispose`. When the parameter [callGameOnDispose] is true, the + /// `currentGame`'s `onDispose` method will be called; otherwise, it will not. + void disposeCurrentGame({bool callGameOnDispose = false}) { currentGame.removeGameStateListener(_onGameStateChange); - currentGame.onRemove(); + currentGame.lifecycleStateChange(AppLifecycleState.paused); + + currentGame.finalizeRemoval(); + if (callGameOnDispose) { + currentGame.onDispose(); + } } @override @@ -274,6 +296,11 @@ class ListenerGameWidgetState KeyEventResult _handleKeyEvent(FocusNode focusNode, RawKeyEvent event) { final game = currentGame; + + if (!_focusNode.hasPrimaryFocus) { + return KeyEventResult.ignored; + } + if (game is KeyboardEvents) { return game.onKeyEvent(event, RawKeyboard.instance.keysPressed); } @@ -305,7 +332,7 @@ class ListenerGameWidgetState ); } - final stackedWidgets = []; + final stackedWidgets = [internalGameWidget]; _addBackground(context, stackedWidgets); _addOverlays(context, stackedWidgets); @@ -313,80 +340,84 @@ class ListenerGameWidgetState final textDir = widget.textDirection ?? TextDirection.ltr; return ClipRect( - child: Stack( - children: [ - Listener( - onPointerDown: currentGame is PointerDetector - ? (currentGame as PointerDetector).onPointerDown - : null, - onPointerMove: currentGame is PointerDetector - ? (currentGame as PointerDetector).onPointerMove - : null, - onPointerUp: currentGame is PointerDetector - ? (currentGame as PointerDetector).onPointerUp - : null, - onPointerCancel: currentGame is PointerDetector - ? (currentGame as PointerDetector).onPointerCancel - : null, - onPointerHover: currentGame is PointerDetector - ? (currentGame as PointerDetector).onPointerHover - : null, - onPointerSignal: currentGame is PointerDetector - ? (currentGame as PointerDetector).onPointerSignal - : null, - child: Focus( - focusNode: _focusNode, - autofocus: widget.autofocus, - descendantsAreFocusable: true, - onKey: _handleKeyEvent, - child: MouseRegion( - cursor: currentGame.mouseCursor, - child: Directionality( - textDirection: textDir, - child: ColoredBox( - color: currentGame.backgroundColor(), - child: LayoutBuilder( - builder: (_, BoxConstraints constraints) { - return _protectedBuild(() { - final size = constraints.biggest.toVector2(); - if (size.isZero()) { + child: Listener( + onPointerDown: currentGame is PointerDetector + ? (currentGame as PointerDetector).onPointerDown + : null, + onPointerMove: currentGame is PointerDetector + ? (currentGame as PointerDetector).onPointerMove + : null, + onPointerUp: currentGame is PointerDetector + ? (currentGame as PointerDetector).onPointerUp + : null, + onPointerCancel: currentGame is PointerDetector + ? (currentGame as PointerDetector).onPointerCancel + : null, + onPointerHover: currentGame is PointerDetector + ? (currentGame as PointerDetector).onPointerHover + : null, + onPointerSignal: currentGame is PointerDetector + ? (currentGame as PointerDetector).onPointerSignal + : null, + child: FocusScope( + child: Focus( + focusNode: _focusNode, + autofocus: widget.autofocus, + descendantsAreFocusable: true, + onKey: _handleKeyEvent, + child: MouseRegion( + cursor: currentGame.mouseCursor, + child: Directionality( + textDirection: textDir, + child: ColoredBox( + color: currentGame.backgroundColor(), + child: LayoutBuilder( + builder: (_, BoxConstraints constraints) { + return _protectedBuild(() { + final size = constraints.biggest.toVector2(); + if (size.isZero()) { + return widget.loadingBuilder?.call(context) ?? + Container(); + } + currentGame.onGameResize(size); + // This should only be called if the game has already been + // loaded (in the case of resizing for example), since + // update otherwise should be called after onMount. + if (!currentGame.paused && currentGame.isAttached) { + currentGame.update(0); + } + return FutureBuilder( + future: loaderFuture, + builder: (_, snapshot) { + if (snapshot.hasError) { + final errorBuilder = widget.errorBuilder; + if (errorBuilder == null) { + throw Error.throwWithStackTrace( + snapshot.error!, + snapshot.stackTrace!, + ); + } else { + return errorBuilder(context, snapshot.error!); + } + } + + if (snapshot.connectionState == + ConnectionState.done) { + return Stack(children: stackedWidgets); + } + return widget.loadingBuilder?.call(context) ?? const SizedBox.expand(); - } - currentGame.onGameResize(size); - return FutureBuilder( - future: loaderFuture, - builder: (_, snapshot) { - if (snapshot.hasError) { - final errorBuilder = widget.errorBuilder; - if (errorBuilder == null) { - throw Error.throwWithStackTrace( - snapshot.error!, - snapshot.stackTrace!, - ); - } else { - return errorBuilder( - context, snapshot.error!); - } - } - if (snapshot.connectionState == - ConnectionState.done) { - return internalGameWidget; - } - return widget.loadingBuilder?.call(context) ?? - const SizedBox.expand(); - }, - ); - }); - }, - ), + }, + ); + }); + }, ), ), ), ), ), - ...stackedWidgets - ], + ), ), ); }); @@ -404,7 +435,6 @@ class ListenerGameWidgetState void _addOverlays(BuildContext context, List stackWidgets) { stackWidgets.addAll( - // ignore: invalid_use_of_internal_member currentGame.overlays.buildCurrentOverlayWidgets(context), ); } diff --git a/lib/mixins/movement.dart b/lib/mixins/movement.dart index f2542b860..1d71f984f 100644 --- a/lib/mixins/movement.dart +++ b/lib/mixins/movement.dart @@ -372,39 +372,41 @@ mixin Movement on GameComponent { return false; } else { if (diffX.abs() > dtDiagonalSpeed && diffY.abs() > dtDiagonalSpeed) { - final speedOnce = dtDiagonalSpeed / dtUpdate; + final minToMOve = dtDiagonalSpeed * 2; + final xOnce = diffX.abs() / dtUpdate; + final yOnce = diffY.abs() / dtUpdate; if (diffX > 0 && diffY > 0) { - if (diffX.abs() < dtDiagonalSpeed * 2) { - moveRightOnce(speed: speedOnce); - } else if (diffY.abs() < dtDiagonalSpeed * 2) { - moveDownOnce(speed: speedOnce); + if (diffX.abs() < minToMOve) { + moveRightOnce(speed: xOnce); + } else if (diffY.abs() < minToMOve) { + moveDownOnce(speed: yOnce); } else { moveDownRight(speed: speed); } return true; } else if (diffX < 0 && diffY > 0) { - if (diffX.abs() < dtDiagonalSpeed * 2) { - moveLeftOnce(speed: speedOnce); - } else if (diffY.abs() < dtDiagonalSpeed * 2) { - moveDownOnce(speed: speedOnce); + if (diffX.abs() < minToMOve) { + moveLeftOnce(speed: xOnce); + } else if (diffY.abs() < minToMOve) { + moveDownOnce(speed: yOnce); } else { moveDownLeft(speed: speed); } return true; } else if (diffX > 0 && diffY < 0) { - if (diffX.abs() < dtDiagonalSpeed * 2) { - moveRightOnce(speed: speedOnce); - } else if (diffY.abs() < dtDiagonalSpeed * 2) { - moveUpOnce(speed: speedOnce); + if (diffX.abs() < minToMOve) { + moveRightOnce(speed: xOnce); + } else if (diffY.abs() < minToMOve) { + moveUpOnce(speed: yOnce); } else { moveUpRight(speed: speed); } return true; } else if (diffX < 0 && diffY < 0) { - if (diffX.abs() < dtDiagonalSpeed * 2) { - moveLeftOnce(speed: speedOnce); - } else if (diffY.abs() < dtDiagonalSpeed * 2) { - moveUpOnce(speed: speedOnce); + if (diffX.abs() < dtSpeed) { + moveLeftOnce(speed: xOnce); + } else if (diffY.abs() < dtSpeed) { + moveUpOnce(speed: yOnce); } else { moveUpLeft(speed: speed); } diff --git a/lib/tiled/reader/tiled_network_reader.dart b/lib/tiled/reader/tiled_network_reader.dart index 0be0749d4..905a87478 100644 --- a/lib/tiled/reader/tiled_network_reader.dart +++ b/lib/tiled/reader/tiled_network_reader.dart @@ -16,11 +16,15 @@ class TiledNetworkReader extends TiledReader { static const _keyImgBase64 = 'base64'; final Uri uri; final TiledCacheProvider cache; + final Map? headers; @override late String basePath; - TiledNetworkReader({required this.uri, TiledCacheProvider? cacheProvider}) - : cache = cacheProvider ?? TiledMemoryCacheProvider() { + TiledNetworkReader({ + required this.uri, + TiledCacheProvider? cacheProvider, + this.headers, + }) : cache = cacheProvider ?? TiledMemoryCacheProvider() { String url = uri.toString(); basePath = url.replaceAll(url.split('/').last, ''); } @@ -93,7 +97,7 @@ class TiledNetworkReader extends TiledReader { if (!_isSuppotedMapFileType(uriKey)) { throw Exception('Invalid TileMap source: only supports json|tmj files'); } - final mapResponse = await http.get(uri); + final mapResponse = await http.get(uri, headers: headers); final map = jsonDecode(mapResponse.body); cache.put(uriKey, map); return TiledMap.fromJson(map); @@ -111,6 +115,7 @@ class TiledNetworkReader extends TiledReader { } else { final tileSetResponse = await http.get( Uri.parse('$basePath$source'), + headers: headers, ); final map = jsonDecode(tileSetResponse.body); cache.put(uriKey, map); @@ -119,13 +124,20 @@ class TiledNetworkReader extends TiledReader { } Future _fetchTilesetImage(String sourceBasePath, String image) async { - final url = '$basePath$sourceBasePath$image'; + String url = '$basePath$sourceBasePath$image'; + if (image.contains('http')) { + url = image; + } + return _loadImage(url); } Future _fetchLayerImage(MapLayer layer) async { if (layer is ImageLayer) { - final url = '$basePath${layer.image}'; + String url = '$basePath${layer.image}'; + if (layer.image.contains('http')) { + url = layer.image; + } return _loadImage(url); } } @@ -137,7 +149,7 @@ class TiledNetworkReader extends TiledReader { String base64 = (await cache.get(url))[_keyImgBase64]; await Flame.images.fromBase64(url, base64); } else { - final response = await http.get(Uri.parse(url)); + final response = await http.get(Uri.parse(url), headers: headers); String img64 = base64Encode(response.bodyBytes); cache.put(url, {_keyImgBase64: img64}); await Flame.images.fromBase64(url, img64); diff --git a/lib/tiled/reader/tiled_reader.dart b/lib/tiled/reader/tiled_reader.dart index 3b4684823..444f34d35 100644 --- a/lib/tiled/reader/tiled_reader.dart +++ b/lib/tiled/reader/tiled_reader.dart @@ -1,5 +1,6 @@ import 'dart:async'; +import 'package:bonfire/tiled/cache_provider/tiled_cache_provider.dart'; import 'package:bonfire/tiled/reader/tiled_asset_reader.dart'; import 'package:bonfire/tiled/reader/tiled_network_reader.dart'; import 'package:tiledjsonreader/map/tiled_map.dart'; @@ -13,7 +14,15 @@ abstract class TiledReader { return TiledAssetReader(asset: asset); } - static TiledReader network(Uri uri) { - return TiledNetworkReader(uri: uri); + static TiledReader network( + Uri uri, { + TiledCacheProvider? cacheProvider, + Map? headers, + }) { + return TiledNetworkReader( + uri: uri, + cacheProvider: cacheProvider, + headers: headers, + ); } } diff --git a/lib/widgets/typewriter/typewriter.dart b/lib/widgets/typewriter/typewriter.dart index ce202650a..b5fcdb9c7 100644 --- a/lib/widgets/typewriter/typewriter.dart +++ b/lib/widgets/typewriter/typewriter.dart @@ -40,7 +40,7 @@ class TypeWriter extends StatefulWidget { /// /// For example, if the text scale factor is 1.5, text will be 50% larger than /// the specified font size. - final double textScaleFactor; + final TextScaler textScaler; /// An optional maximum number of lines for the text to span, wrapping if necessary. /// If the text exceeds the given number of lines, it will be truncated according @@ -75,7 +75,7 @@ class TypeWriter extends StatefulWidget { this.textDirection, this.softWrap = true, this.overflow = TextOverflow.clip, - this.textScaleFactor = 1.0, + this.textScaler = const TextScaler.linear(1), this.maxLines, this.locale, this.strutStyle, @@ -120,7 +120,7 @@ class TypeWriterState extends State { strutStyle: widget.strutStyle, textAlign: widget.textAlign, textDirection: widget.textDirection, - textScaleFactor: widget.textScaleFactor, + textScaler: widget.textScaler, textWidthBasis: widget.textWidthBasis, text: TextSpan( children: snapshot.data, diff --git a/pubspec.lock b/pubspec.lock index e8d681455..e1e23c548 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -45,10 +45,10 @@ packages: dependency: transitive description: name: collection - sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a url: "https://pub.dev" source: hosted - version: "1.17.2" + version: "1.18.0" fake_async: dependency: transitive description: @@ -61,10 +61,10 @@ packages: dependency: "direct main" description: name: flame - sha256: "61c42b966a6b1f44ee093194e6701d45b14fdda1859c14fe68a39489454bfbd4" + sha256: "2a2352741500ce47823dcf212f06b23e9bdb622454eab90244ee6da58e23b488" url: "https://pub.dev" source: hosted - version: "1.14.0" + version: "1.15.0" flutter: dependency: "direct main" description: flutter @@ -127,10 +127,10 @@ packages: dependency: transitive description: name: meta - sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" + sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.10.0" ordered_set: dependency: transitive description: @@ -164,18 +164,18 @@ packages: dependency: transitive description: name: stack_trace - sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.11.1" stream_channel: dependency: transitive description: name: stream_channel - sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" string_scanner: dependency: transitive description: @@ -196,10 +196,10 @@ packages: dependency: transitive description: name: test_api - sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" + sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" url: "https://pub.dev" source: hosted - version: "0.6.0" + version: "0.6.1" tiledjsonreader: dependency: "direct main" description: @@ -228,10 +228,10 @@ packages: dependency: transitive description: name: web - sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 + sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152 url: "https://pub.dev" source: hosted - version: "0.1.4-beta" + version: "0.3.0" sdks: - dart: ">=3.1.0-185.0.dev <4.0.0" + dart: ">=3.2.0-194.0.dev <4.0.0" flutter: ">=3.13.0" diff --git a/pubspec.yaml b/pubspec.yaml index 8830c72cf..004b85d23 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: bonfire description: (RPG maker) Create RPG-style or similar games more simply with Flame. -version: 3.3.0 +version: 3.3.1 homepage: https://bonfire-engine.github.io repository: https://github.com/RafaelBarbosatec/bonfire issue_tracker: https://github.com/RafaelBarbosatec/bonfire/issues @@ -14,7 +14,7 @@ dependencies: flutter: sdk: flutter - flame: ^1.14.0 + flame: ^1.15.0 tiledjsonreader: ^1.3.4 http: ^1.1.0 a_star_algorithm: ^0.3.1