diff --git a/doc/examples/debug/lib/main.dart b/doc/examples/debug/lib/main.dart index 80f12ddf5..410d21724 100644 --- a/doc/examples/debug/lib/main.dart +++ b/doc/examples/debug/lib/main.dart @@ -5,14 +5,16 @@ import 'package:flame/components/sprite_component.dart'; import 'package:flame/components/mixins/resizable.dart'; import 'package:flame/text_config.dart'; -import 'package:flutter/material.dart'; +import 'package:flutter/material.dart' hide Image; + +import 'dart:ui'; void main() async { + Flame.initializeWidget(); await Flame.util.initialDimensions(); final myGame = MyGame(); runApp(myGame.widget); - myGame.start(); } class AndroidComponent extends SpriteComponent with Resizable { @@ -20,7 +22,7 @@ class AndroidComponent extends SpriteComponent with Resizable { int xDirection = 1; int yDirection = 1; - AndroidComponent() : super.square(100, 'android.png'); + AndroidComponent(Image image) : super.square(100, image); @override void update(double dt) { @@ -56,17 +58,20 @@ class MyGame extends BaseGame { @override bool recordFps() => true; - void start() { - final android = AndroidComponent(); + @override + Future onLoad() async { + final androidImage = await images.load('android.png'); + + final android = AndroidComponent(androidImage); android.x = 100; android.y = 400; - final android2 = AndroidComponent(); + final android2 = AndroidComponent(androidImage); android2.x = 100; android2.y = 400; android2.yDirection = -1; - final android3 = AndroidComponent(); + final android3 = AndroidComponent(androidImage); android3.x = 100; android3.y = 400; android3.xDirection = -1; diff --git a/doc/examples/layers/lib/main.dart b/doc/examples/layers/lib/main.dart index 818869073..813ea2b51 100644 --- a/doc/examples/layers/lib/main.dart +++ b/doc/examples/layers/lib/main.dart @@ -7,15 +7,11 @@ import 'package:flame/flame.dart'; import 'dart:ui'; void main() async { - WidgetsFlutterBinding.ensureInitialized(); + Flame.initializeWidget(); await Flame.util.fullScreen(); - final playerSprite = await Sprite.loadSprite('player.png'); - final enemySprite = await Sprite.loadSprite('enemy.png'); - final backgroundSprite = await Sprite.loadSprite('background.png'); - - runApp(LayerGame(playerSprite, enemySprite, backgroundSprite).widget); + runApp(LayerGame().widget); } class GameLayer extends DynamicLayer { @@ -56,14 +52,15 @@ class BackgroundLayer extends PreRenderedLayer { } class LayerGame extends Game { - Sprite playerSprite; - Sprite enemySprite; - Sprite backgroundSprite; - Layer gameLayer; Layer backgroundLayer; - LayerGame(this.playerSprite, this.enemySprite, this.backgroundSprite) { + @override + Future onLoad() async { + final playerSprite = Sprite(await images.load('player.png')); + final enemySprite = Sprite(await images.load('enemy.png')); + final backgroundSprite = Sprite(await images.load('background.png')); + gameLayer = GameLayer(playerSprite, enemySprite); backgroundLayer = BackgroundLayer(backgroundSprite); } diff --git a/doc/examples/nine_tile_box/lib/main.dart b/doc/examples/nine_tile_box/lib/main.dart index 2690d9b9d..ddee5c599 100644 --- a/doc/examples/nine_tile_box/lib/main.dart +++ b/doc/examples/nine_tile_box/lib/main.dart @@ -17,8 +17,11 @@ class MyGame extends Game { Size size; NineTileBox nineTileBox; - MyGame(this.size) { - final sprite = Sprite('nine-box.png'); + MyGame(this.size); + + @override + Future onLoad() async { + final sprite = Sprite(await images.load('nine-box.png')); nineTileBox = NineTileBox(sprite, tileSize: 8, destTileSize: 24); } diff --git a/doc/examples/particles/lib/main.dart b/doc/examples/particles/lib/main.dart index 893b79c31..59f47dc97 100644 --- a/doc/examples/particles/lib/main.dart +++ b/doc/examples/particles/lib/main.dart @@ -65,6 +65,12 @@ class MyGame extends BaseGame { Timer.periodic(sceneDuration, (_) => spawnParticles()); } + @override + Future onLoad() async { + await images.load('zap.png'); + await images.load('boom3.png'); + } + /// Showcases various different uses of [Particle] /// and its derivatives void spawnParticles() { @@ -295,7 +301,7 @@ class MyGame extends BaseGame { Particle imageParticle() { return ImageParticle( size: const Size.square(24), - image: Flame.images.loadedFiles['zap.png'].loadedImage, + image: images.fromCache('zap.png'), ); } @@ -385,7 +391,7 @@ class MyGame extends BaseGame { /// Flame's [Sprite] into the effect. Particle spriteParticle() { return SpriteParticle( - sprite: Sprite('zap.png'), + sprite: Sprite(images.fromCache('zap.png')), size: Position.fromOffset(cellSize * .5), ); } @@ -524,12 +530,11 @@ class MyGame extends BaseGame { const columns = 8; const rows = 8; const frames = columns * rows; - const imagePath = 'boom3.png'; - final spriteImage = Flame.images.loadedFiles[imagePath].loadedImage; + final spriteImage = images.fromCache('boom3.png'); final spritesheet = SpriteSheet( rows: rows, columns: columns, - imageName: imagePath, + image: spriteImage, textureWidth: spriteImage.width ~/ columns, textureHeight: spriteImage.height ~/ rows, ); @@ -543,19 +548,8 @@ class MyGame extends BaseGame { } Future loadGame() async { - Size gameSize; - WidgetsFlutterBinding.ensureInitialized(); - - await Future.wait([ - Flame.util.initialDimensions().then((size) => gameSize = size), - Flame.images.loadAll(const [ - 'zap.png', - - /// Credits to Stumpy Strust from - /// https://opengameart.org/content/explosion-sheet - 'boom3.png', - ]), - ]); + Flame.initializeWidget(); + final gameSize = await Flame.util.initialDimensions(); return MyGame(screenSize: gameSize); } diff --git a/lib/images.dart b/lib/assets/images.dart similarity index 62% rename from lib/images.dart rename to lib/assets/images.dart index 75903d5e8..42bf1ff77 100644 --- a/lib/images.dart +++ b/lib/assets/images.dart @@ -6,14 +6,21 @@ import 'dart:convert' show base64; import 'package:flame/flame.dart'; class Images { - Map loadedFiles = {}; + final Map _loadedFiles = {}; void clear(String fileName) { - loadedFiles.remove(fileName); + _loadedFiles.remove(fileName); } void clearCache() { - loadedFiles.clear(); + _loadedFiles.clear(); + } + + Image fromCache(String fileName) { + final image = _loadedFiles[fileName]; + assert(image?.loadedImage != null, + 'Tried to access an inexistent entry on cache "$fileName"'); + return image.loadedImage; } Future> loadAll(List fileNames) async { @@ -21,17 +28,17 @@ class Images { } Future load(String fileName) async { - if (!loadedFiles.containsKey(fileName)) { - loadedFiles[fileName] = ImageAssetLoader(_fetchToMemory(fileName)); + if (!_loadedFiles.containsKey(fileName)) { + _loadedFiles[fileName] = _ImageAssetLoader(_fetchToMemory(fileName)); } - return await loadedFiles[fileName].retreive(); + return await _loadedFiles[fileName].retreive(); } Future fromBase64(String fileName, String base64) async { - if (!loadedFiles.containsKey(fileName)) { - loadedFiles[fileName] = ImageAssetLoader(_fetchFromBase64(base64)); + if (!_loadedFiles.containsKey(fileName)) { + _loadedFiles[fileName] = _ImageAssetLoader(_fetchFromBase64(base64)); } - return await loadedFiles[fileName].retreive(); + return await _loadedFiles[fileName].retreive(); } Future _fetchFromBase64(String base64Data) async { @@ -53,8 +60,8 @@ class Images { } } -class ImageAssetLoader { - ImageAssetLoader(this.future); +class _ImageAssetLoader { + _ImageAssetLoader(this.future); Image loadedImage; Future future; diff --git a/lib/flame.dart b/lib/flame.dart index 64ed74c19..af1eba37a 100644 --- a/lib/flame.dart +++ b/lib/flame.dart @@ -6,7 +6,7 @@ import 'package:flutter/widgets.dart'; import 'flame_audio.dart'; import 'bgm.dart'; -import 'images.dart'; +import 'assets/images.dart'; import 'assets_cache.dart'; import 'util.dart'; diff --git a/lib/game/game.dart b/lib/game/game.dart index 46791ef7e..172196112 100644 --- a/lib/game/game.dart +++ b/lib/game/game.dart @@ -7,10 +7,11 @@ import 'package:flutter/widgets.dart' hide WidgetBuilder; import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; -import '../keyboard.dart'; - import 'widget_builder.dart'; +import '../keyboard.dart'; +import '../assets/images.dart'; + /// Represents a generic game. /// /// Subclass this to implement the [update] and [render] methods. @@ -19,6 +20,8 @@ abstract class Game { // Widget Builder for this Game final builder = WidgetBuilder(); + final images = Images(); + /// Returns the game background color. /// By default it will return a black color. /// It cannot be changed at runtime, because the game widget does not get rebuild when this value changes. @@ -78,6 +81,8 @@ abstract class Game { if (this is KeyboardEvents) { RawKeyboard.instance.removeListener(_handleKeyEvent); } + + images.clearCache(); } /// Flag to tell the game loop if it should start running upon creation diff --git a/lib/spritesheet.dart b/lib/spritesheet.dart index c3b550db7..49c1390e5 100644 --- a/lib/spritesheet.dart +++ b/lib/spritesheet.dart @@ -14,38 +14,6 @@ class SpriteSheet { List> _sprites; SpriteSheet({ - @required String imageName, - @required this.textureWidth, - @required this.textureHeight, - @required this.columns, - @required this.rows, - }) { - _sprites = List.generate( - rows, - (y) => List.generate( - columns, - (x) => _mapImagePath(imageName, textureWidth, textureHeight, x, y), - ), - ); - } - - Sprite _mapImagePath( - String imageName, - int textureWidth, - int textureHeight, - int x, - int y, - ) { - return Sprite( - imageName, - x: (x * textureWidth).toDouble(), - y: (y * textureHeight).toDouble(), - width: textureWidth.toDouble(), - height: textureHeight.toDouble(), - ); - } - - SpriteSheet.fromImage({ @required Image image, @required this.textureWidth, @required this.textureHeight, @@ -56,19 +24,19 @@ class SpriteSheet { rows, (y) => List.generate( columns, - (x) => _mapImage(image, textureWidth, textureHeight, x, y), + (x) => _mapImagePath(image, textureWidth, textureHeight, x, y), ), ); } - Sprite _mapImage( + Sprite _mapImagePath( Image image, int textureWidth, int textureHeight, int x, int y, ) { - return Sprite.fromImage( + return Sprite( image, x: (x * textureWidth).toDouble(), y: (y * textureHeight).toDouble(),