diff --git a/doc/README.md b/doc/README.md index d9ec7b3eed5..5a86a49dcfb 100644 --- a/doc/README.md +++ b/doc/README.md @@ -116,7 +116,7 @@ class Player extends SpriteComponent { @override Future onLoad() async { - sprite = await Sprite.load('player.png'); + sprite = await Sprite.load('assets/images/player.png'); } } ``` @@ -151,7 +151,7 @@ class Player extends SpriteComponent with TapCallbacks { @override Future onLoad() async { - sprite = await Sprite.load('player.png'); + sprite = await Sprite.load('assets/images/player.png'); } @override diff --git a/doc/bridge_packages/flame_audio/audio.md b/doc/bridge_packages/flame_audio/audio.md index c10fcb070ac..ee65a132d05 100644 --- a/doc/bridge_packages/flame_audio/audio.md +++ b/doc/bridge_packages/flame_audio/audio.md @@ -33,20 +33,20 @@ Then you have the following methods at your disposal: import 'package:flame_audio/flame_audio.dart'; // For shorter reused audio clips, like sound effects -FlameAudio.play('explosion.mp3'); +FlameAudio.play('assets/audio/explosion.mp3'); // For looping an audio file -FlameAudio.loop('music.mp3'); +FlameAudio.loop('assets/audio/music.mp3'); // For playing a longer audio file -FlameAudio.playLongAudio('music.mp3'); +FlameAudio.playLongAudio('assets/audio/music.mp3'); // For looping a longer audio file -FlameAudio.loopLongAudio('music.mp3'); +FlameAudio.loopLongAudio('assets/audio/music.mp3'); // For background music that should be paused/played when the pausing/resuming // the game -FlameAudio.bgm.play('music.mp3'); +FlameAudio.bgm.play('assets/audio/music.mp3'); ``` The difference between the `play/loop` and `playLongAudio/loopLongAudio` is that `play/loop` makes @@ -89,14 +89,17 @@ are requested; therefore, the first time you play each mp3 you might get a delay pre-load your audios, just use: ```dart -await FlameAudio.audioCache.load('explosion.mp3'); +await FlameAudio.audioCache.load('assets/audio/explosion.mp3'); ``` You can load all your audios in the beginning in your game's `onLoad` method so that they always play smoothly. To load multiple audio files, use the `loadAll` method: ```dart -await FlameAudio.audioCache.loadAll(['explosion.mp3', 'music.mp3']); +await FlameAudio.audioCache.loadAll([ + 'assets/audio/explosion.mp3', + 'assets/audio/music.mp3', +]); ``` Finally, you can use the `clear` method to remove a file that has been loaded into the cache: diff --git a/doc/bridge_packages/flame_audio/audio_pool.md b/doc/bridge_packages/flame_audio/audio_pool.md index e0bf1574bd3..ce7ecc605cb 100644 --- a/doc/bridge_packages/flame_audio/audio_pool.md +++ b/doc/bridge_packages/flame_audio/audio_pool.md @@ -45,7 +45,7 @@ Future loadSounds() async { // Create a pool with minimum 1 player and maximum 2 players // This automatically uses Flame's global audio cache AudioPool explosionSoundPool = await FlameAudio.createPool( - 'explosion.mp3', + 'assets/audio/explosion.mp3', minPlayers: 1, maxPlayers: 2, ); @@ -144,13 +144,13 @@ class MyGame extends FlameGame { Future onLoad() async { // Load sound effects into audio pools laserSound = await FlameAudio.createPool( - 'laser.mp3', + 'assets/audio/laser.mp3', minPlayers: 3, maxPlayers: 6, ); explosionSound = await FlameAudio.createPool( - 'explosion.mp3', + 'assets/audio/explosion.mp3', minPlayers: 2, maxPlayers: 4, ); diff --git a/doc/bridge_packages/flame_audio/bgm.md b/doc/bridge_packages/flame_audio/bgm.md index 14d48ee0520..51d9703258e 100644 --- a/doc/bridge_packages/flame_audio/bgm.md +++ b/doc/bridge_packages/flame_audio/bgm.md @@ -29,7 +29,7 @@ To play a looping background music track, run: ```dart import 'package:flame_audio/flame_audio.dart'; -FlameAudio.bgm.play('adventure-track.mp3'); +FlameAudio.bgm.play('assets/audio/adventure-track.mp3'); ``` You must have an appropriate folder structure and add the files to the `pubspec.yaml` file, as @@ -61,11 +61,11 @@ You can pass an additional optional `double` parameter which is the `volume` (de Examples: ```dart -FlameAudio.bgm.play('music/boss-fight/level-382.mp3'); +FlameAudio.bgm.play('assets/audio/music/boss-fight/level-382.mp3'); ``` ```dart -FlameAudio.bgm.play('music/world-map.mp3', volume: .25); +FlameAudio.bgm.play('assets/audio/music/world-map.mp3', volume: .25); ``` diff --git a/doc/bridge_packages/flame_fire_atlas/fire_atlas.md b/doc/bridge_packages/flame_fire_atlas/fire_atlas.md index 601c223f331..2709fccd9f0 100644 --- a/doc/bridge_packages/flame_fire_atlas/fire_atlas.md +++ b/doc/bridge_packages/flame_fire_atlas/fire_atlas.md @@ -52,11 +52,11 @@ import 'package:flame_fire_atlas/flame_fire_atlas.dart'; // Load the atlas from your assets // file at assets/atlas.fa -final atlas = await FireAtlas.loadAsset('atlas.fa'); +final atlas = await FireAtlas.loadAsset('assets/atlas.fa'); //or when inside a game instance, the loadFireAtlas can be used: // file at assets/atlas.fa -final atlas = await loadFireAtlas('atlas.fa'); +final atlas = await loadFireAtlas('assets/atlas.fa'); // Get a Sprite with the given key. FireAtlas.getSprite('sprite_name') @@ -75,7 +75,7 @@ class ExampleGame extends FlameGame { @override Future onLoad() async { - _atlas = await loadFireAtlas('atlas.fa'); + _atlas = await loadFireAtlas('assets/atlas.fa'); add( SpriteComponent( diff --git a/doc/bridge_packages/flame_svg/svg.md b/doc/bridge_packages/flame_svg/svg.md index 22e9c912674..3f53d69141f 100644 --- a/doc/bridge_packages/flame_svg/svg.md +++ b/doc/bridge_packages/flame_svg/svg.md @@ -18,7 +18,7 @@ To use it just import the `Svg` class from `'package:flame_svg/flame_svg.dart'`, following snippet to render it on the canvas: ```dart -final svgInstance = await Svg.load('android.svg'); +final svgInstance = await Svg.load('assets/android.svg'); final position = Vector2(100, 100); final size = Vector2(300, 300); @@ -32,7 +32,7 @@ or use the `SvgComponent` and add it to the component tree: class MyGame extends FlameGame { @override Future onLoad() async { - final svgInstance = await Svg.load('android.svg'); + final svgInstance = await Svg.load('assets/android.svg'); final size = Vector2.all(100); final position = Vector2.all(100); final svgComponent = SvgComponent( diff --git a/doc/bridge_packages/flame_texturepacker/flame_texturepacker.md b/doc/bridge_packages/flame_texturepacker/flame_texturepacker.md index 16169612a82..431cdd52df0 100644 --- a/doc/bridge_packages/flame_texturepacker/flame_texturepacker.md +++ b/doc/bridge_packages/flame_texturepacker/flame_texturepacker.md @@ -48,7 +48,7 @@ class MyGame extends FlameGame { @override Future onLoad() async { // Load the texture atlas - final atlas = await atlasFromAssets('atlas_map.atlas'); + final atlas = await atlasFromAssets('assets/images/atlas_map.atlas'); // Use the atlas to get sprites final sprite = atlas.findSpriteByName('robot_jump')!; @@ -109,7 +109,7 @@ names contain any of the whitelist strings will be loaded: ```dart final atlas = await TexturePackerAtlas.load( - 'atlas_map.atlas', + 'assets/images/atlas_map.atlas', whiteList: [ 'robot_walk' ] ); ``` @@ -124,21 +124,19 @@ TexturePacker can trim transparent pixels from sprites to save space. By default ```dart final atlas = await TexturePackerAtlas.load( - 'atlas_map.atlas', + 'assets/images/atlas_map.atlas', useOriginalSize: false, // Use the trimmed/packed size instead ); ``` -### Custom Asset Prefix +### Atlas Location -If your ``.atlas`` data file is not stored in the default `images` directory: +The ``.atlas`` path is a full asset path, so the file can live anywhere. Page textures listed +inside the atlas are resolved relative to the atlas's own directory: ```dart -final atlas = await atlasFromAssets( - 'atlas_map.atlas', - assetsPrefix: 'custom_path', -); +final atlas = await atlasFromAssets('assets/atlases/atlas_map.atlas'); ``` diff --git a/doc/bridge_packages/flame_tiled/flame_tiled.md b/doc/bridge_packages/flame_tiled/flame_tiled.md index ce5fe081404..0df13dddc48 100644 --- a/doc/bridge_packages/flame_tiled/flame_tiled.md +++ b/doc/bridge_packages/flame_tiled/flame_tiled.md @@ -10,7 +10,7 @@ To use this, ```dart final component = await TiledComponent.load( - 'my_map.tmx', + 'assets/tiles/my_map.tmx', Vector2.all(32), ); @@ -80,7 +80,7 @@ resizing the original tileset images so that when packed they fit with the limit ```dart final component = await TiledComponent.load( - 'my_map.tmx', + 'assets/tiles/my_map.tmx', Vector2.all(32), atlasMaxX: 9216, atlasMaxY: 9216, @@ -106,7 +106,7 @@ where the sum of their dimensions are in the thousands. ```dart final component = await TiledComponent.load( - 'my_map.tmx', + 'assets/tiles/my_map.tmx', Vector2.all(32), ignoreFlip: true, ); diff --git a/doc/flame/components/parallax_component.md b/doc/flame/components/parallax_component.md index bd30a536dba..3936ecd4a58 100644 --- a/doc/flame/components/parallax_component.md +++ b/doc/flame/components/parallax_component.md @@ -16,8 +16,8 @@ The simplest `ParallaxComponent` is created like this: @override Future onLoad() async { final parallaxComponent = await loadParallaxComponent([ - ParallaxImageData('bg.png'), - ParallaxImageData('trees.png'), + ParallaxImageData('assets/images/bg.png'), + ParallaxImageData('assets/images/trees.png'), ]); add(parallaxComponent); } @@ -30,8 +30,8 @@ class MyParallaxComponent extends ParallaxComponent { @override Future onLoad() async { parallax = await game.loadParallax([ - ParallaxImageData('bg.png'), - ParallaxImageData('trees.png'), + ParallaxImageData('assets/images/bg.png'), + ParallaxImageData('assets/images/trees.png'), ]); } } @@ -86,19 +86,19 @@ Advanced example: ```dart final images = [ loadParallaxImage( - 'stars.jpg', + 'assets/images/stars.jpg', repeat: ImageRepeat.repeat, alignment: Alignment.center, fill: LayerFill.width, ), loadParallaxImage( - 'planets.jpg', + 'assets/images/planets.jpg', repeat: ImageRepeat.repeatY, alignment: Alignment.bottomLeft, fill: LayerFill.none, ), loadParallaxImage( - 'dust.jpg', + 'assets/images/dust.jpg', repeat: ImageRepeat.repeatX, alignment: Alignment.topRight, fill: LayerFill.height, diff --git a/doc/flame/components/sprite_components.md b/doc/flame/components/sprite_components.md index aee17c50fc4..25e4e25f794 100644 --- a/doc/flame/components/sprite_components.md +++ b/doc/flame/components/sprite_components.md @@ -20,7 +20,7 @@ class MyGame extends FlameGame { @override Future onLoad() async { - final sprite = await Sprite.load('player.png'); + final sprite = await Sprite.load('assets/images/player.png'); final size = Vector2.all(128.0); final player = SpriteComponent(size: size, sprite: sprite); @@ -72,7 +72,7 @@ Future onLoad() async { stepTime: 0.1, ); this.player = SpriteAnimationComponent.fromFrameData( - await images.load('player.png'), + await images.load('assets/images/player.png'), data, ); } diff --git a/doc/flame/components/utility_components.md b/doc/flame/components/utility_components.md index 1a348e457ab..cec641d1e81 100644 --- a/doc/flame/components/utility_components.md +++ b/doc/flame/components/utility_components.md @@ -87,7 +87,7 @@ rendered in the game: ```dart @override Future onLoad() async { - final svg = await Svg.load('android.svg'); + final svg = await Svg.load('assets/android.svg'); final android = SvgComponent.fromSvg( svg, position: Vector2.all(100), @@ -108,7 +108,7 @@ A simple example on how to use it: ```dart // Creates a tileset, the block ids are automatically assigned sequentially // starting at 0, from left to right and then top to bottom. -final tilesetImage = await images.load('tileset.png'); +final tilesetImage = await images.load('assets/images/tileset.png'); final tileset = SpriteSheet(image: tilesetImage, srcSize: Vector2.all(32)); // Each element is a block id, -1 means nothing final matrix = [[0, 1, 0], [1, 0, 0], [1, 1, 1]]; diff --git a/doc/flame/examples/lib/ember.dart b/doc/flame/examples/lib/ember.dart index 68208b59c88..dfa81d2e9f0 100644 --- a/doc/flame/examples/lib/ember.dart +++ b/doc/flame/examples/lib/ember.dart @@ -16,7 +16,7 @@ class EmberPlayer extends SpriteAnimationComponent with TapCallbacks { @override Future onLoad() async { animation = SpriteAnimation.fromFrameData( - await Flame.images.load('ember.png'), + await Flame.images.load('assets/images/ember.png'), SpriteAnimationData.sequenced( amount: 4, textureSize: Vector2.all(16), diff --git a/doc/flame/game.md b/doc/flame/game.md index bc895426c46..be7eef4ccd5 100644 --- a/doc/flame/game.md +++ b/doc/flame/game.md @@ -32,7 +32,7 @@ class MyCrate extends SpriteComponent { @override Future onLoad() async { - sprite = await Sprite.load('crate.png'); + sprite = await Sprite.load('assets/images/crate.png'); } } diff --git a/doc/flame/inputs/other_inputs.md b/doc/flame/inputs/other_inputs.md index 926ca63c20a..6b069fea8bd 100644 --- a/doc/flame/inputs/other_inputs.md +++ b/doc/flame/inputs/other_inputs.md @@ -22,7 +22,7 @@ class MyGame extends FlameGame { @override Future onLoad() async { super.onLoad(); - final image = await images.load('joystick.png'); + final image = await images.load('assets/images/joystick.png'); final sheet = SpriteSheet.fromColumnsAndRows( image: image, columns: 6, @@ -60,7 +60,7 @@ class Player extends SpriteComponent with HasGameReference { @override Future onLoad() async { - sprite = await game.loadSprite('layers/player.png'); + sprite = await game.loadSprite('assets/images/layers/player.png'); position = game.size / 2; } diff --git a/doc/flame/migration.md b/doc/flame/migration.md index 0cd8e7450b1..59c1bcea8c9 100644 --- a/doc/flame/migration.md +++ b/doc/flame/migration.md @@ -7,6 +7,168 @@ major versions of Flame, together with the steps required to migrate your code. ## Migrating from v1.38.0 to v2.0.0 +### Asset prefix removed + +`Images` and `AssetsCache` no longer prepend anything to the paths you give them. `Images` used to +prepend `assets/images/` and `AssetsCache` used to prepend `assets/`, both configurable through a +`prefix` property. That property is gone, along with the `prefix` constructor argument. + +Every asset is now addressed by its full path, exactly as declared in the `pubspec.yaml`: + +```dart +// Before +await Flame.images.load('player.png'); +final level = await Flame.assets.readJson('levels/level1.json'); + +// After +await Flame.images.load('assets/images/player.png'); +final level = await Flame.assets.readJson('assets/levels/level1.json'); +``` + +This applies to everything that loads through those caches, including `Sprite.load`, +`SpriteAnimation.load`, `SpriteBatch.load`, `Game.loadSprite`, `Game.loadSpriteAnimation`, the +`Parallax` loaders and `ParallaxImageData`/`ParallaxAnimationData`, and the `.asset` constructors of +`SpriteWidget`, `SpriteAnimationWidget`, `NineTileBoxWidget` and `SpriteButton`. + +If you relied on a custom prefix, there is nothing to replace it with, and nothing to configure: +just write the paths you actually want. + +```dart +// Before +Flame.images.prefix = 'gfx/'; +await Flame.images.load('player.png'); + +// After +await Flame.images.load('gfx/player.png'); +``` + + +#### Cache keys are now the full path + +The path is also the key the asset is cached under, so anything that reads the cache by key needs +the same full path: + +```dart +// Before +await Flame.images.load('player.png'); +final image = Flame.images.fromCache('player.png'); + +// After +await Flame.images.load('assets/images/player.png'); +final image = Flame.images.fromCache('assets/images/player.png'); +``` + +This affects `Images.fromCache`, `Images.containsKey`, `Images.clear`, `Images.keys`, +`AssetsCache.fromCache` and `AssetsCache.clear`. It also affects `SpriteBatch`, whose internal +`imageKey` is derived from the path you loaded with. + +One consequence is a bug fix: `Images.load` now includes the package in the cache key, matching what +`AssetsCache` already did. Previously, loading the same filename from two different packages +collided on one key and the second load silently returned the first package's image. + + +#### `loadAllImages` and `loadAllFromPattern` require a directory + +These two methods used the prefix both to filter the asset manifest and to strip it back off the +resulting keys. They now take a required `directory` argument instead, and cache entries under their +full manifest path. Pass an empty string to scan the whole bundle. + +```dart +// Before +await Flame.images.loadAllImages(); + +// After +await Flame.images.loadAllImages(directory: 'assets/images/'); +``` + + +#### `flame_audio` + +The global `AudioCache` is now created with an empty prefix, so audio paths are full paths too. +`FlameAudio.updatePrefix()` has been removed, as there is no longer a prefix to update. + +```dart +// Before +FlameAudio.play('explosion.mp3'); +FlameAudio.bgm.play('music/theme.mp3'); + +// After +FlameAudio.play('assets/audio/explosion.mp3'); +FlameAudio.bgm.play('assets/audio/music/theme.mp3'); +``` + + +#### `flame_tiled` + +The `prefix` argument is gone from `TiledComponent.load`, `RenderableTiledMap.fromFile`, +`RenderableTiledMap.fromString` and `FlameTsxProvider.parse`. The map's file name is now a full +path, and the assertion that it must not contain path separators has been removed. + +External `.tsx` tilesets are resolved relative to the map's own directory, derived from that path. +`RenderableTiledMap.fromString` has no path to derive from, so its `prefix` argument became +`tsxDirectory`. + +Watch out for these two, since they change behavior without failing to compile: +`RenderableTiledMap.fromString`'s `tsxDirectory` and `FlameTsxProvider.parse`'s third argument both +default to `''` now, where the old `prefix` defaulted to `assets/tiles/`. If you call either +directly and rely on that default, pass the directory explicitly. + +Tileset and image-layer sources are resolved against a new `imagesDirectory` argument, which +defaults to `assets/images/` and so preserves the previous behavior. + +```dart +// Before +await TiledComponent.load('map.tmx', Vector2.all(16)); +await TiledComponent.load( + 'map.tmx', + Vector2.all(16), + prefix: 'assets/maps/', +); + +// After +await TiledComponent.load('assets/tiles/map.tmx', Vector2.all(16)); +await TiledComponent.load('assets/maps/map.tmx', Vector2.all(16)); +``` + +Note that `TiledAtlas` cache keys are now scoped by `imagesDirectory`, so a key that was +`tiles.png` is now `assets/images/tiles.png`. + + +#### `flame_texturepacker` + +The `assetsPrefix` argument is gone from `atlasFromAssets`, `TexturePackerAtlas.load` and +`TexturePackerAtlas.loadAtlas`. The atlas path is a full path, and page textures listed inside the +atlas are resolved relative to the atlas's own directory. + +```dart +// Before +final atlas = await atlasFromAssets('atlas_map.atlas'); + +// After +final atlas = await atlasFromAssets('assets/images/atlas_map.atlas'); +``` + + +#### `flame_sprite_fusion` + +The `tilemapPrefix` argument is gone from `SpriteFusionTilemapComponent.load`. Both `mapJsonFile` +and `spriteSheetFile` are now full paths. + +```dart +// Before +await SpriteFusionTilemapComponent.load( + mapJsonFile: 'map.json', + spriteSheetFile: 'spritesheet.png', +); + +// After +await SpriteFusionTilemapComponent.load( + mapJsonFile: 'assets/tiles/map.json', + spriteSheetFile: 'assets/images/spritesheet.png', +); +``` + + ### `VerticalDragDetector` and `HorizontalDragDetector` removed Both game-level mixins have been removed, with no direct replacement in Flame. diff --git a/doc/flame/rendering/images.md b/doc/flame/rendering/images.md index ca64196691c..24c3d8d8f51 100644 --- a/doc/flame/rendering/images.md +++ b/doc/flame/rendering/images.md @@ -24,15 +24,21 @@ Flutter has a handful of types related to images, and converting everything prop asset to an `Image` that can be drawn on Canvas is a bit convoluted. This class allows you to obtain an `Image` that can be drawn on the `Canvas` using the `drawImageRect` method. -It automatically caches any image loaded by filename, so you can safely call it many times. - -The methods for loading and clearing the cache are: `load`, `loadAll`, `clear` and `clearCache`. +Images are addressed by their full asset path, exactly as declared in the `pubspec.yaml`, for +example `assets/images/player.png`. Nothing is prepended for you, and that same path is the key the +image is cached under, so you can safely call `load` many times. + +The methods for loading and clearing the cache are: `load`, `loadAll`, `loadAllImages`, +`loadAllFromPattern`, `clear` and `clearCache`. The two `loadAll*` methods scan the asset manifest +and take a required `directory` to scope the search, for example +`loadAllImages(directory: 'assets/images/')`. They return `Future`s for loading the images. These futures must be awaited for before the images can be used in any way. If you do not want to await these futures right away, you can initiate multiple `load()` operations and then await for all of them at once using `Images.ready()` method. -To synchronously retrieve a previously cached image, the `fromCache` method can be used. If an image -with that key was not previously loaded, it will throw an exception. +To synchronously retrieve a previously cached image, the `fromCache` method can be used, passing the +same full path you loaded it with. If an image with that key was not previously loaded, it will +throw an exception. To add an already loaded image to the cache, the `add` method can be used and you can set the key that the image should have in the cache. You can retrieve all the keys in the cache using the `keys` @@ -51,7 +57,7 @@ It can manually be used by instantiating it: ```dart import 'package:flame/cache.dart'; final imagesLoader = Images(); -Image image = await imagesLoader.load('yourImage.png'); +Image image = await imagesLoader.load('assets/images/yourImage.png'); ``` But Flame also offers two ways of using this class without instantiating it yourself. @@ -68,7 +74,7 @@ import 'package:flame/flame.dart'; import 'package:flame/sprite.dart'; // inside an async context -Image image = await Flame.images.load('player.png'); +Image image = await Flame.images.load('assets/images/player.png'); final playerSprite = Sprite(image); ``` @@ -92,7 +98,7 @@ class MyGame extends Game { @override Future onLoad() async { // Note that you could also use Sprite.load for this. - final playerImage = await images.load('player.png'); + final playerImage = await images.load('assets/images/player.png'); player = Sprite(playerImage); } } @@ -108,13 +114,13 @@ class MyGame extends Game { @override Future onLoad() async { // other loads omitted - await images.load('bullet.png'); + await images.load('assets/images/bullet.png'); } void shoot() { // This is just an example, in your game you probably don't want to // instantiate new [Sprite] objects every time you shoot. - final bulletSprite = Sprite(images.fromCache('bullet.png')); + final bulletSprite = Sprite(images.fromCache('assets/images/bullet.png')); _bullets.add(bulletSprite); } } @@ -157,7 +163,7 @@ image that that sprite represents. For example, this will create a sprite representing the whole image of the file passed: ```dart -final image = await images.load('player.png'); +final image = await images.load('assets/images/player.png'); Sprite player = Sprite(image); ``` @@ -165,7 +171,7 @@ You can also specify the coordinates in the original image where the sprite is l you to use sprite sheets and reduce the number of images in memory, for example: ```dart -final image = await images.load('player.png'); +final image = await images.load('assets/images/player.png'); final playerFrame = Sprite( image, srcPosition: Vector2(32.0, 0), @@ -179,7 +185,7 @@ the full width/height of the source image). The `Sprite` class has a render method, that allows you to render the sprite onto a `Canvas`: ```dart -final image = await images.load('block.png'); +final image = await images.load('assets/images/block.png'); Sprite block = Sprite(image); // in your render method @@ -219,7 +225,7 @@ is a double value that represents the amount of bleeding to be applied to the ed For example, if you do: ```dart -final image = await images.load('player.png'); +final image = await images.load('assets/images/player.png'); final playerFrame = Sprite( image, srcPosition: Vector2(32.0, 0), @@ -265,7 +271,7 @@ since it then renders an image that only contains the selected area. Example of using a `RasterSpriteComponent`: ```dart -final sprite = await Sprite.load('flame.png'); +final sprite = await Sprite.load('assets/images/flame.png'); final rasterSpriteComponent = RasterSpriteComponent( sprite: sprite, size: Vector2.all(16.0), @@ -278,7 +284,7 @@ loaded. If you need to rasterize a sprite manually, you can use the `Sprite.rasterize` method: ```dart -final image = await images.load('player.png'); +final image = await images.load('assets/images/player.png'); final playerFrame = Sprite( image, srcPosition: Vector2(32.0, 0), @@ -407,8 +413,8 @@ JSON data. To use this feature you will need to export the Sprite Sheet's JSON d something like the following snippet: ```dart -final image = await images.load('chopper.png'); -final jsonData = await assets.readJson('chopper.json'); +final image = await images.load('assets/images/chopper.png'); +final jsonData = await assets.readJson('assets/chopper.json'); final animation = SpriteAnimation.fromAsepriteData(image, jsonData); ``` diff --git a/doc/flame/rendering/layers.md b/doc/flame/rendering/layers.md index 4c32552c88d..c8640fffe4b 100644 --- a/doc/flame/rendering/layers.md +++ b/doc/flame/rendering/layers.md @@ -175,11 +175,11 @@ class MyGame extends FlameGame { add(root); // Add some children. - final background1Sprite = Sprite(await images.load('background1.png')); + final background1Sprite = Sprite(await images.load('assets/images/background1.png')); background1 = SpriteComponent(sprite: background1Sprite); root.add(background1); - final background2Sprite = Sprite(await images.load('background2.png')); + final background2Sprite = Sprite(await images.load('assets/images/background2.png')); background2 = SpriteComponent(sprite: background2Sprite); root.add(background2); diff --git a/doc/flame/rendering/particles.md b/doc/flame/rendering/particles.md index 373b662b5b7..372422ca721 100644 --- a/doc/flame/rendering/particles.md +++ b/doc/flame/rendering/particles.md @@ -190,7 +190,7 @@ renderer: CircleParticleRenderer(softness: 0.8, blendMode: BlendMode.plus), Draws every particle as a `Sprite` (or a whole image), also fully batched: ```dart -renderer: SpriteParticleRenderer.fromImage(await images.load('spark.png')), +renderer: SpriteParticleRenderer.fromImage(await images.load('assets/images/spark.png')), renderer: SpriteParticleRenderer(sprite), // a region of a sprite sheet ``` diff --git a/doc/flame/structure.md b/doc/flame/structure.md index 32896090343..64e4ba651f5 100644 --- a/doc/flame/structure.md +++ b/doc/flame/structure.md @@ -5,8 +5,13 @@ tile maps for levels. Organizing these files consistently ensures that Flame's b (and Flutter's own [asset system](https://docs.flutter.dev/ui/assets/assets-and-images)) can find them without extra configuration. +Every Flame loader takes the **full path** of the asset, exactly as you declared it in your +`pubspec.yaml`. Nothing is prepended for you, so the string you write is the string that gets +loaded. + Flame has a proposed structure for your project that includes the standard Flutter `assets` -directory in addition to some children: `audio`, `images` and `tiles`. +directory in addition to some children: `audio`, `images` and `tiles`. It is only a convention, +not a requirement. If using the following example code: @@ -14,21 +19,21 @@ If using the following example code: class MyGame extends FlameGame { @override Future onLoad() async { - await FlameAudio.play('explosion.mp3'); + await FlameAudio.play('assets/audio/explosion.mp3'); // Load some images - await Flame.images.load('player.png'); - await Flame.images.load('enemy.png'); - - // Or load all images in your images folder - await Flame.images.loadAllImages(); + await Flame.images.load('assets/images/player.png'); + await Flame.images.load('assets/images/enemy.png'); + + // Or load every image in a directory + await Flame.images.loadAllImages(directory: 'assets/images/'); - final map1 = await TiledComponent.load('level.tmx', tileSize); + final map1 = await TiledComponent.load('assets/tiles/level.tmx', tileSize); } } ``` -The following file structure is where Flame would expect to find the files: +The following file structure matches those paths: ```text . @@ -57,11 +62,17 @@ flutter: - assets/tiles/level.tmx ``` -If you want to change this structure, this is possible by using the `prefix` parameter and creating -your instances of `AssetsCache`, `Images`, and `AudioCache`, instead of using the -global ones provided by Flame. +You are free to use any structure you like. Because every path is given in full, laying your +assets out differently needs no configuration at all, just different strings: + +```dart +await Flame.images.load('gfx/sprites/player.png'); +``` + +Note that the path is also the key the asset is cached under, so `Flame.images.fromCache` and +`Images.containsKey` take that same full path. -Additionally, `AssetsCache` and `Images` can receive a custom +`AssetsCache` and `Images` can receive a custom [`AssetBundle`](https://api.flutter.dev/flutter/services/AssetBundle-class.html). This can be used to make Flame look for assets in a different location other than the `rootBundle`, like the file system for example. diff --git a/doc/tutorials/basic_shader/step1.md b/doc/tutorials/basic_shader/step1.md index 58cf2033429..417b0d083d8 100644 --- a/doc/tutorials/basic_shader/step1.md +++ b/doc/tutorials/basic_shader/step1.md @@ -38,7 +38,7 @@ import 'package:flame/components.dart'; class SwordSprite extends SpriteComponent { @override Future onLoad() async { - sprite = await Sprite.load('sword.png'); + sprite = await Sprite.load('assets/images/sword.png'); size = sprite!.srcSize; } } @@ -86,7 +86,7 @@ class OutlinedSwordSprite extends PostProcessComponent { class SwordSprite extends SpriteComponent { @override Future onLoad() async { - sprite = await Sprite.load('sword.png'); + sprite = await Sprite.load('assets/images/sword.png'); size = sprite!.srcSize; } } diff --git a/doc/tutorials/basic_shader/step4.md b/doc/tutorials/basic_shader/step4.md index f7c96101024..a42b26343ef 100644 --- a/doc/tutorials/basic_shader/step4.md +++ b/doc/tutorials/basic_shader/step4.md @@ -111,7 +111,7 @@ class OutlinedSwordSprite extends PostProcessComponent class SwordSprite extends SpriteComponent { @override Future onLoad() async { - sprite = await Sprite.load('sword.png'); + sprite = await Sprite.load('assets/images/sword.png'); size = sprite!.srcSize; } } diff --git a/doc/tutorials/klondike/app/lib/step2/klondike_game.dart b/doc/tutorials/klondike/app/lib/step2/klondike_game.dart index 6d5985f9c1a..a6c88a66097 100644 --- a/doc/tutorials/klondike/app/lib/step2/klondike_game.dart +++ b/doc/tutorials/klondike/app/lib/step2/klondike_game.dart @@ -16,7 +16,7 @@ class KlondikeGame extends FlameGame { @override Future onLoad() async { - await Flame.images.load('klondike-sprites.png'); + await Flame.images.load('assets/images/klondike-sprites.png'); final stock = Stock() ..size = cardSize @@ -59,7 +59,7 @@ class KlondikeGame extends FlameGame { Sprite klondikeSprite(double x, double y, double width, double height) { return Sprite( - Flame.images.fromCache('klondike-sprites.png'), + Flame.images.fromCache('assets/images/klondike-sprites.png'), srcPosition: Vector2(x, y), srcSize: Vector2(width, height), ); diff --git a/doc/tutorials/klondike/app/lib/step3/klondike_game.dart b/doc/tutorials/klondike/app/lib/step3/klondike_game.dart index cf076631b6f..d1b43769255 100644 --- a/doc/tutorials/klondike/app/lib/step3/klondike_game.dart +++ b/doc/tutorials/klondike/app/lib/step3/klondike_game.dart @@ -19,7 +19,7 @@ class KlondikeGame extends FlameGame { @override Future onLoad() async { - await Flame.images.load('klondike-sprites.png'); + await Flame.images.load('assets/images/klondike-sprites.png'); final stock = Stock() ..size = cardSize @@ -75,7 +75,7 @@ class KlondikeGame extends FlameGame { Sprite klondikeSprite(double x, double y, double width, double height) { return Sprite( - Flame.images.fromCache('klondike-sprites.png'), + Flame.images.fromCache('assets/images/klondike-sprites.png'), srcPosition: Vector2(x, y), srcSize: Vector2(width, height), ); diff --git a/doc/tutorials/klondike/app/lib/step4/klondike_game.dart b/doc/tutorials/klondike/app/lib/step4/klondike_game.dart index bc02b9a3bda..2b1d1e815c2 100644 --- a/doc/tutorials/klondike/app/lib/step4/klondike_game.dart +++ b/doc/tutorials/klondike/app/lib/step4/klondike_game.dart @@ -23,7 +23,7 @@ class KlondikeGame extends FlameGame { @override Future onLoad() async { - await Flame.images.load('klondike-sprites.png'); + await Flame.images.load('assets/images/klondike-sprites.png'); final stock = StockPile(position: Vector2(cardGap, cardGap)); final waste = WastePile( @@ -80,7 +80,7 @@ class KlondikeGame extends FlameGame { Sprite klondikeSprite(double x, double y, double width, double height) { return Sprite( - Flame.images.fromCache('klondike-sprites.png'), + Flame.images.fromCache('assets/images/klondike-sprites.png'), srcPosition: Vector2(x, y), srcSize: Vector2(width, height), ); diff --git a/doc/tutorials/klondike/app/lib/step5/klondike_game.dart b/doc/tutorials/klondike/app/lib/step5/klondike_game.dart index 3b982575a08..83731ce11c8 100644 --- a/doc/tutorials/klondike/app/lib/step5/klondike_game.dart +++ b/doc/tutorials/klondike/app/lib/step5/klondike_game.dart @@ -42,7 +42,7 @@ class KlondikeGame extends FlameGame { Sprite klondikeSprite(double x, double y, double width, double height) { return Sprite( - Flame.images.fromCache('klondike-sprites.png'), + Flame.images.fromCache('assets/images/klondike-sprites.png'), srcPosition: Vector2(x, y), srcSize: Vector2(width, height), ); diff --git a/doc/tutorials/klondike/app/lib/step5/klondike_world.dart b/doc/tutorials/klondike/app/lib/step5/klondike_world.dart index 0bdf7f8cca2..d9cf8cb2977 100644 --- a/doc/tutorials/klondike/app/lib/step5/klondike_world.dart +++ b/doc/tutorials/klondike/app/lib/step5/klondike_world.dart @@ -27,7 +27,7 @@ class KlondikeWorld extends World with HasGameReference { @override Future onLoad() async { - await Flame.images.load('klondike-sprites.png'); + await Flame.images.load('assets/images/klondike-sprites.png'); stock.position = Vector2(cardGap, topGap); waste.position = Vector2(cardSpaceWidth + cardGap, topGap); diff --git a/doc/tutorials/klondike/step2.md b/doc/tutorials/klondike/step2.md index 2d5cd5e0927..b2e9e1e5a42 100644 --- a/doc/tutorials/klondike/step2.md +++ b/doc/tutorials/klondike/step2.md @@ -21,7 +21,7 @@ import 'package:flame/flame.dart'; class KlondikeGame extends FlameGame { @override Future onLoad() async { - await Flame.images.load('klondike-sprites.png'); + await Flame.images.load('assets/images/klondike-sprites.png'); } } ``` @@ -47,7 +47,7 @@ sprite sheet: ```dart Sprite klondikeSprite(double x, double y, double width, double height) { return Sprite( - Flame.images.fromCache('klondike-sprites.png'), + Flame.images.fromCache('assets/images/klondike-sprites.png'), srcPosition: Vector2(x, y), srcSize: Vector2(width, height), ); diff --git a/doc/tutorials/platformer/app/lib/actors/ember.dart b/doc/tutorials/platformer/app/lib/actors/ember.dart index 642198f5f95..08449c3268e 100644 --- a/doc/tutorials/platformer/app/lib/actors/ember.dart +++ b/doc/tutorials/platformer/app/lib/actors/ember.dart @@ -30,7 +30,7 @@ class EmberPlayer extends SpriteAnimationComponent @override Future onLoad() async { animation = SpriteAnimation.fromFrameData( - game.images.fromCache('ember.png'), + game.images.fromCache('assets/images/ember.png'), SpriteAnimationData.sequenced( amount: 4, textureSize: Vector2.all(16), diff --git a/doc/tutorials/platformer/app/lib/actors/water_enemy.dart b/doc/tutorials/platformer/app/lib/actors/water_enemy.dart index 769c9845a36..d5d774efd42 100644 --- a/doc/tutorials/platformer/app/lib/actors/water_enemy.dart +++ b/doc/tutorials/platformer/app/lib/actors/water_enemy.dart @@ -19,7 +19,7 @@ class WaterEnemy extends SpriteAnimationComponent @override Future onLoad() async { animation = SpriteAnimation.fromFrameData( - game.images.fromCache('water_enemy.png'), + game.images.fromCache('assets/images/water_enemy.png'), SpriteAnimationData.sequenced( amount: 2, textureSize: Vector2.all(16), diff --git a/doc/tutorials/platformer/app/lib/ember_quest.dart b/doc/tutorials/platformer/app/lib/ember_quest.dart index ccd9b0cc503..0c3d7fe23f5 100644 --- a/doc/tutorials/platformer/app/lib/ember_quest.dart +++ b/doc/tutorials/platformer/app/lib/ember_quest.dart @@ -28,13 +28,13 @@ class EmberQuestGame extends FlameGame Future onLoad() async { //debugMode = true; // Uncomment to see the bounding boxes await images.loadAll([ - 'block.png', - 'ember.png', - 'ground.png', - 'heart_half.png', - 'heart.png', - 'star.png', - 'water_enemy.png', + 'assets/images/block.png', + 'assets/images/ember.png', + 'assets/images/ground.png', + 'assets/images/heart_half.png', + 'assets/images/heart.png', + 'assets/images/star.png', + 'assets/images/water_enemy.png', ]); camera.viewfinder.anchor = Anchor.topLeft; diff --git a/doc/tutorials/platformer/app/lib/objects/ground_block.dart b/doc/tutorials/platformer/app/lib/objects/ground_block.dart index 860190245fd..d9686a64604 100644 --- a/doc/tutorials/platformer/app/lib/objects/ground_block.dart +++ b/doc/tutorials/platformer/app/lib/objects/ground_block.dart @@ -22,7 +22,7 @@ class GroundBlock extends SpriteComponent @override Future onLoad() async { - final groundImage = game.images.fromCache('ground.png'); + final groundImage = game.images.fromCache('assets/images/ground.png'); sprite = Sprite(groundImage); position = Vector2( (gridPosition.x * size.x) + xOffset, diff --git a/doc/tutorials/platformer/app/lib/objects/platform_block.dart b/doc/tutorials/platformer/app/lib/objects/platform_block.dart index 7a2df7843f4..f14d6568658 100644 --- a/doc/tutorials/platformer/app/lib/objects/platform_block.dart +++ b/doc/tutorials/platformer/app/lib/objects/platform_block.dart @@ -17,7 +17,7 @@ class PlatformBlock extends SpriteComponent @override Future onLoad() async { - final platformImage = game.images.fromCache('block.png'); + final platformImage = game.images.fromCache('assets/images/block.png'); sprite = Sprite(platformImage); position = Vector2( (gridPosition.x * size.x) + xOffset, diff --git a/doc/tutorials/platformer/app/lib/objects/star.dart b/doc/tutorials/platformer/app/lib/objects/star.dart index 312ca70a733..98311119bab 100644 --- a/doc/tutorials/platformer/app/lib/objects/star.dart +++ b/doc/tutorials/platformer/app/lib/objects/star.dart @@ -18,7 +18,7 @@ class Star extends SpriteComponent with HasGameReference { @override Future onLoad() async { - final starImage = game.images.fromCache('star.png'); + final starImage = game.images.fromCache('assets/images/star.png'); sprite = Sprite(starImage); position = Vector2( (gridPosition.x * size.x) + xOffset + (size.x / 2), diff --git a/doc/tutorials/platformer/app/lib/overlays/heart.dart b/doc/tutorials/platformer/app/lib/overlays/heart.dart index a19893d3e74..9a176e3700a 100644 --- a/doc/tutorials/platformer/app/lib/overlays/heart.dart +++ b/doc/tutorials/platformer/app/lib/overlays/heart.dart @@ -25,12 +25,12 @@ class HeartHealthComponent extends SpriteGroupComponent Future onLoad() async { await super.onLoad(); final availableSprite = await game.loadSprite( - 'heart.png', + 'assets/images/heart.png', srcSize: Vector2.all(32), ); final unavailableSprite = await game.loadSprite( - 'heart_half.png', + 'assets/images/heart_half.png', srcSize: Vector2.all(32), ); diff --git a/doc/tutorials/platformer/app/lib/overlays/hud.dart b/doc/tutorials/platformer/app/lib/overlays/hud.dart index e2c1cc9d0f6..ee1eb1523e3 100644 --- a/doc/tutorials/platformer/app/lib/overlays/hud.dart +++ b/doc/tutorials/platformer/app/lib/overlays/hud.dart @@ -32,7 +32,7 @@ class Hud extends PositionComponent with HasGameReference { ); add(_scoreTextComponent); - final starSprite = await game.loadSprite('star.png'); + final starSprite = await game.loadSprite('assets/images/star.png'); add( SpriteComponent( sprite: starSprite, diff --git a/doc/tutorials/platformer/step_2.md b/doc/tutorials/platformer/step_2.md index df3b788711d..76a8c96abe2 100644 --- a/doc/tutorials/platformer/step_2.md +++ b/doc/tutorials/platformer/step_2.md @@ -46,13 +46,13 @@ class EmberQuestGame extends FlameGame { @override Future onLoad() async { await images.loadAll([ - 'block.png', - 'ember.png', - 'ground.png', - 'heart_half.png', - 'heart.png', - 'star.png', - 'water_enemy.png', + 'assets/images/block.png', + 'assets/images/ember.png', + 'assets/images/ground.png', + 'assets/images/heart_half.png', + 'assets/images/heart.png', + 'assets/images/star.png', + 'assets/images/water_enemy.png', ]); } @@ -62,8 +62,8 @@ class EmberQuestGame extends FlameGame { As I mentioned in the [assets](step_1.md#assets) section, we are using multiple individual image files and for performance reasons, we should leverage Flame's built-in caching system which will only load the files once, but allow us to access them as many times as needed without an impact to -the game. `await images.loadAll()` takes a list of the file names that are found in `assets/images` -and loads them to cache. +the game. `await images.loadAll()` takes a list of full asset paths and loads them into the cache, +keyed by those same paths. ## Scaffolding @@ -103,13 +103,13 @@ class EmberQuestGame extends FlameGame { @override Future onLoad() async { await images.loadAll([ - 'block.png', - 'ember.png', - 'ground.png', - 'heart_half.png', - 'heart.png', - 'star.png', - 'water_enemy.png', + 'assets/images/block.png', + 'assets/images/ember.png', + 'assets/images/ground.png', + 'assets/images/heart_half.png', + 'assets/images/heart.png', + 'assets/images/star.png', + 'assets/images/water_enemy.png', ]); // Everything in this tutorial assumes that the position @@ -141,7 +141,7 @@ class EmberPlayer extends SpriteAnimationComponent @override void onLoad() { animation = SpriteAnimation.fromFrameData( - game.images.fromCache('ember.png'), + game.images.fromCache('assets/images/ember.png'), SpriteAnimationData.sequenced( amount: 4, textureSize: Vector2.all(16), @@ -154,8 +154,9 @@ class EmberPlayer extends SpriteAnimationComponent This file uses the `HasGameRef` mixin which allows us to reach back to `ember_quest.dart` and leverage any of the variables or methods that are defined in the game class. You can see this in -use with the line `game.images.fromCache('ember.png')`. Earlier, we loaded all the files into -cache, so to use that file now, we call `fromCache` so it can be leveraged by the `SpriteAnimation`. +use with the line `game.images.fromCache('assets/images/ember.png')`. Earlier, we loaded all the +files into cache, so to use that file now, we call `fromCache` so it can be leveraged by the +`SpriteAnimation`. The `EmberPlayer` class is extending a `SpriteAnimationComponent` which allows us to define animation as well as position it accordingly in our game world. When we construct this class, the default size of `Vector2.all(64)` is defined as the size of Ember in our game world should be 64x64. @@ -179,13 +180,13 @@ class EmberQuestGame extends FlameGame { @override Future onLoad() async { await images.loadAll([ - 'block.png', - 'ember.png', - 'ground.png', - 'heart_half.png', - 'heart.png', - 'star.png', - 'water_enemy.png', + 'assets/images/block.png', + 'assets/images/ember.png', + 'assets/images/ground.png', + 'assets/images/heart_half.png', + 'assets/images/heart.png', + 'assets/images/star.png', + 'assets/images/water_enemy.png', ]); camera.viewfinder.anchor = Anchor.topLeft; diff --git a/doc/tutorials/platformer/step_3.md b/doc/tutorials/platformer/step_3.md index bcf9190e704..6aa0534bffd 100644 --- a/doc/tutorials/platformer/step_3.md +++ b/doc/tutorials/platformer/step_3.md @@ -287,13 +287,13 @@ as: @override Future onLoad() async { await images.loadAll([ - 'block.png', - 'ember.png', - 'ground.png', - 'heart_half.png', - 'heart.png', - 'star.png', - 'water_enemy.png', + 'assets/images/block.png', + 'assets/images/ember.png', + 'assets/images/ground.png', + 'assets/images/heart_half.png', + 'assets/images/heart.png', + 'assets/images/star.png', + 'assets/images/water_enemy.png', ]); camera.viewfinder.anchor = Anchor.topLeft; @@ -394,7 +394,7 @@ Now we just need to finish the `onLoad` method. So make your `onLoad` method loo ```dart @override void onLoad() { - final platformImage = game.images.fromCache('block.png'); + final platformImage = game.images.fromCache('assets/images/block.png'); sprite = Sprite(platformImage); position = Vector2((gridPosition.x * size.x) + xOffset, game.size.y - (gridPosition.y * size.y), diff --git a/doc/tutorials/platformer/step_4.md b/doc/tutorials/platformer/step_4.md index e84f72f21d7..720b951f843 100644 --- a/doc/tutorials/platformer/step_4.md +++ b/doc/tutorials/platformer/step_4.md @@ -30,7 +30,7 @@ class Star extends SpriteComponent @override void onLoad() { - final starImage = game.images.fromCache('star.png'); + final starImage = game.images.fromCache('assets/images/star.png'); sprite = Sprite(starImage); position = Vector2( (gridPosition.x * size.x) + xOffset + (size.x / 2), @@ -122,7 +122,7 @@ class WaterEnemy extends SpriteAnimationComponent @override void onLoad() { animation = SpriteAnimation.fromFrameData( - game.images.fromCache('water_enemy.png'), + game.images.fromCache('assets/images/water_enemy.png'), SpriteAnimationData.sequenced( amount: 2, textureSize: Vector2.all(16), @@ -215,7 +215,7 @@ class GroundBlock extends SpriteComponent with HasGameReference @override void onLoad() { - final groundImage = game.images.fromCache('ground.png'); + final groundImage = game.images.fromCache('assets/images/ground.png'); sprite = Sprite(groundImage); position = Vector2( gridPosition.x * size.x + xOffset, @@ -346,7 +346,7 @@ class GroundBlock extends SpriteComponent with HasGameReference @override void onLoad() { - final groundImage = game.images.fromCache('ground.png'); + final groundImage = game.images.fromCache('assets/images/ground.png'); sprite = Sprite(groundImage); position = Vector2( gridPosition.x * size.x + xOffset, diff --git a/doc/tutorials/platformer/step_6.md b/doc/tutorials/platformer/step_6.md index 533f2cee05b..aa7f9d6d9e5 100644 --- a/doc/tutorials/platformer/step_6.md +++ b/doc/tutorials/platformer/step_6.md @@ -43,12 +43,12 @@ class HeartHealthComponent extends SpriteGroupComponent Future onLoad() async { await super.onLoad(); final availableSprite = await game.loadSprite( - 'heart.png', + 'assets/images/heart.png', srcSize: Vector2.all(32), ); final unavailableSprite = await game.loadSprite( - 'heart_half.png', + 'assets/images/heart_half.png', srcSize: Vector2.all(32), ); @@ -116,7 +116,7 @@ class Hud extends PositionComponent with HasGameReference { ); add(_scoreTextComponent); - final starSprite = await game.loadSprite('star.png'); + final starSprite = await game.loadSprite('assets/images/star.png'); add( SpriteComponent( sprite: starSprite, diff --git a/doc/tutorials/platformer/step_7.md b/doc/tutorials/platformer/step_7.md index b845a789f3f..13ec3d24eae 100644 --- a/doc/tutorials/platformer/step_7.md +++ b/doc/tutorials/platformer/step_7.md @@ -177,13 +177,13 @@ Open `lib/ember_quest.dart` and add / update the following code: @override Future onLoad() async { await images.loadAll([ - 'block.png', - 'ember.png', - 'ground.png', - 'heart_half.png', - 'heart.png', - 'star.png', - 'water_enemy.png', + 'assets/images/block.png', + 'assets/images/ember.png', + 'assets/images/ground.png', + 'assets/images/heart_half.png', + 'assets/images/heart.png', + 'assets/images/star.png', + 'assets/images/water_enemy.png', ]); camera.viewfinder.anchor = Anchor.topLeft; diff --git a/doc/tutorials/space_shooter/app/lib/step2/main.dart b/doc/tutorials/space_shooter/app/lib/step2/main.dart index 36e0e45c3ea..ccf93ed2031 100644 --- a/doc/tutorials/space_shooter/app/lib/step2/main.dart +++ b/doc/tutorials/space_shooter/app/lib/step2/main.dart @@ -34,7 +34,7 @@ class Player extends SpriteComponent with HasGameReference { Future onLoad() async { await super.onLoad(); - sprite = await game.loadSprite('player-sprite.png'); + sprite = await game.loadSprite('assets/images/player-sprite.png'); position = game.size / 2; anchor = Anchor.center; diff --git a/doc/tutorials/space_shooter/app/lib/step3/main.dart b/doc/tutorials/space_shooter/app/lib/step3/main.dart index 68bafad1093..00a0a5ac3b0 100644 --- a/doc/tutorials/space_shooter/app/lib/step3/main.dart +++ b/doc/tutorials/space_shooter/app/lib/step3/main.dart @@ -16,9 +16,9 @@ class SpaceShooterGame extends FlameGame with PanDetector { Future onLoad() async { final parallax = await loadParallaxComponent( [ - ParallaxImageData('stars_0.png'), - ParallaxImageData('stars_1.png'), - ParallaxImageData('stars_2.png'), + ParallaxImageData('assets/images/stars_0.png'), + ParallaxImageData('assets/images/stars_1.png'), + ParallaxImageData('assets/images/stars_2.png'), ], baseVelocity: Vector2(0, -5), repeat: ImageRepeat.repeat, @@ -49,7 +49,7 @@ class Player extends SpriteAnimationComponent await super.onLoad(); animation = await game.loadSpriteAnimation( - 'player.png', + 'assets/images/player.png', SpriteAnimationData.sequenced( amount: 4, stepTime: 0.2, diff --git a/doc/tutorials/space_shooter/app/lib/step4/main.dart b/doc/tutorials/space_shooter/app/lib/step4/main.dart index a67071908e6..85a18a192fd 100644 --- a/doc/tutorials/space_shooter/app/lib/step4/main.dart +++ b/doc/tutorials/space_shooter/app/lib/step4/main.dart @@ -16,9 +16,9 @@ class SpaceShooterGame extends FlameGame with PanDetector { Future onLoad() async { final parallax = await loadParallaxComponent( [ - ParallaxImageData('stars_0.png'), - ParallaxImageData('stars_1.png'), - ParallaxImageData('stars_2.png'), + ParallaxImageData('assets/images/stars_0.png'), + ParallaxImageData('assets/images/stars_1.png'), + ParallaxImageData('assets/images/stars_2.png'), ], baseVelocity: Vector2(0, -5), repeat: ImageRepeat.repeat, @@ -61,7 +61,7 @@ class Player extends SpriteAnimationComponent await super.onLoad(); animation = await game.loadSpriteAnimation( - 'player.png', + 'assets/images/player.png', SpriteAnimationData.sequenced( amount: 4, stepTime: 0.2, @@ -117,7 +117,7 @@ class Bullet extends SpriteAnimationComponent await super.onLoad(); animation = await game.loadSpriteAnimation( - 'bullet.png', + 'assets/images/bullet.png', SpriteAnimationData.sequenced( amount: 4, stepTime: 0.2, diff --git a/doc/tutorials/space_shooter/app/lib/step5/main.dart b/doc/tutorials/space_shooter/app/lib/step5/main.dart index 0a4088b5e3c..819cb872c38 100644 --- a/doc/tutorials/space_shooter/app/lib/step5/main.dart +++ b/doc/tutorials/space_shooter/app/lib/step5/main.dart @@ -17,9 +17,9 @@ class SpaceShooterGame extends FlameGame with PanDetector { Future onLoad() async { final parallax = await loadParallaxComponent( [ - ParallaxImageData('stars_0.png'), - ParallaxImageData('stars_1.png'), - ParallaxImageData('stars_2.png'), + ParallaxImageData('assets/images/stars_0.png'), + ParallaxImageData('assets/images/stars_1.png'), + ParallaxImageData('assets/images/stars_2.png'), ], baseVelocity: Vector2(0, -5), repeat: ImageRepeat.repeat, @@ -72,7 +72,7 @@ class Player extends SpriteAnimationComponent await super.onLoad(); animation = await game.loadSpriteAnimation( - 'player.png', + 'assets/images/player.png', SpriteAnimationData.sequenced( amount: 4, stepTime: 0.2, @@ -128,7 +128,7 @@ class Bullet extends SpriteAnimationComponent await super.onLoad(); animation = await game.loadSpriteAnimation( - 'bullet.png', + 'assets/images/bullet.png', SpriteAnimationData.sequenced( amount: 4, stepTime: 0.2, @@ -165,7 +165,7 @@ class Enemy extends SpriteAnimationComponent await super.onLoad(); animation = await game.loadSpriteAnimation( - 'enemy.png', + 'assets/images/enemy.png', SpriteAnimationData.sequenced( amount: 4, stepTime: 0.2, diff --git a/doc/tutorials/space_shooter/app/lib/step6/main.dart b/doc/tutorials/space_shooter/app/lib/step6/main.dart index 606d27353dc..be9fee82344 100644 --- a/doc/tutorials/space_shooter/app/lib/step6/main.dart +++ b/doc/tutorials/space_shooter/app/lib/step6/main.dart @@ -19,9 +19,9 @@ class SpaceShooterGame extends FlameGame Future onLoad() async { final parallax = await loadParallaxComponent( [ - ParallaxImageData('stars_0.png'), - ParallaxImageData('stars_1.png'), - ParallaxImageData('stars_2.png'), + ParallaxImageData('assets/images/stars_0.png'), + ParallaxImageData('assets/images/stars_1.png'), + ParallaxImageData('assets/images/stars_2.png'), ], baseVelocity: Vector2(0, -5), repeat: ImageRepeat.repeat, @@ -74,7 +74,7 @@ class Player extends SpriteAnimationComponent await super.onLoad(); animation = await game.loadSpriteAnimation( - 'player.png', + 'assets/images/player.png', SpriteAnimationData.sequenced( amount: 4, stepTime: 0.2, @@ -130,7 +130,7 @@ class Bullet extends SpriteAnimationComponent await super.onLoad(); animation = await game.loadSpriteAnimation( - 'bullet.png', + 'assets/images/bullet.png', SpriteAnimationData.sequenced( amount: 4, stepTime: 0.2, @@ -173,7 +173,7 @@ class Enemy extends SpriteAnimationComponent await super.onLoad(); animation = await game.loadSpriteAnimation( - 'enemy.png', + 'assets/images/enemy.png', SpriteAnimationData.sequenced( amount: 4, stepTime: 0.2, @@ -225,7 +225,7 @@ class Explosion extends SpriteAnimationComponent await super.onLoad(); animation = await game.loadSpriteAnimation( - 'explosion.png', + 'assets/images/explosion.png', SpriteAnimationData.sequenced( amount: 6, stepTime: 0.1, diff --git a/doc/tutorials/space_shooter/step_2.md b/doc/tutorials/space_shooter/step_2.md index db39b6ec050..378d9321e5f 100644 --- a/doc/tutorials/space_shooter/step_2.md +++ b/doc/tutorials/space_shooter/step_2.md @@ -108,7 +108,7 @@ class SpaceShooterGame extends FlameGame with PanDetector { Future? onLoad() async { await super.onLoad(); - final playerSprite = await loadSprite('player-sprite.png'); + final playerSprite = await loadSprite('assets/images/player-sprite.png'); player = Player() ..sprite = playerSprite ..x = size.x / 2 @@ -163,7 +163,7 @@ class Player extends SpriteComponent with HasGameReference { Future onLoad() async { await super.onLoad(); - sprite = await game.loadSprite('player-sprite.png'); + sprite = await game.loadSprite('assets/images/player-sprite.png'); position = game.size / 2; } diff --git a/doc/tutorials/space_shooter/step_3.md b/doc/tutorials/space_shooter/step_3.md index 43c1f631b2b..828ab8321ee 100644 --- a/doc/tutorials/space_shooter/step_3.md +++ b/doc/tutorials/space_shooter/step_3.md @@ -40,7 +40,7 @@ class Player extends SpriteAnimationComponent await super.onLoad(); animation = await game.loadSpriteAnimation( - 'player.png', + 'assets/images/player.png', SpriteAnimationData.sequenced( amount: 4, stepTime: .2, @@ -106,9 +106,9 @@ class SpaceShooterGame extends FlameGame with PanDetector { Future onLoad() async { final parallax = await loadParallaxComponent( [ - ParallaxImageData('stars_0.png'), - ParallaxImageData('stars_1.png'), - ParallaxImageData('stars_2.png'), + ParallaxImageData('assets/images/stars_0.png'), + ParallaxImageData('assets/images/stars_1.png'), + ParallaxImageData('assets/images/stars_2.png'), ], baseVelocity: Vector2(0, -5), repeat: ImageRepeat.repeat, diff --git a/doc/tutorials/space_shooter/step_4.md b/doc/tutorials/space_shooter/step_4.md index 3520d9b263a..2ffdf0de3af 100644 --- a/doc/tutorials/space_shooter/step_4.md +++ b/doc/tutorials/space_shooter/step_4.md @@ -27,7 +27,7 @@ class Bullet extends SpriteAnimationComponent await super.onLoad(); animation = await game.loadSpriteAnimation( - 'bullet.png', + 'assets/images/bullet.png', SpriteAnimationData.sequenced( amount: 4, stepTime: .2, diff --git a/doc/tutorials/space_shooter/step_5.md b/doc/tutorials/space_shooter/step_5.md index 75f1e8b0ebc..09387d6569e 100644 --- a/doc/tutorials/space_shooter/step_5.md +++ b/doc/tutorials/space_shooter/step_5.md @@ -27,7 +27,7 @@ class Enemy extends SpriteAnimationComponent await super.onLoad(); animation = await game.loadSpriteAnimation( - 'enemy.png', + 'assets/images/enemy.png', SpriteAnimationData.sequenced( amount: 4, stepTime: .2, diff --git a/doc/tutorials/space_shooter/step_6.md b/doc/tutorials/space_shooter/step_6.md index e9c0bbcff35..aa0c4351f93 100644 --- a/doc/tutorials/space_shooter/step_6.md +++ b/doc/tutorials/space_shooter/step_6.md @@ -125,7 +125,7 @@ class Explosion extends SpriteAnimationComponent await super.onLoad(); animation = await game.loadSpriteAnimation( - 'explosion.png', + 'assets/images/explosion.png', SpriteAnimationData.sequenced( amount: 6, stepTime: .1, diff --git a/examples/games/rogue_shooter/lib/components/bullet_component.dart b/examples/games/rogue_shooter/lib/components/bullet_component.dart index 9618a9dbd55..f909f2a0737 100644 --- a/examples/games/rogue_shooter/lib/components/bullet_component.dart +++ b/examples/games/rogue_shooter/lib/components/bullet_component.dart @@ -15,7 +15,7 @@ class BulletComponent extends SpriteAnimationComponent Future onLoad() async { add(CircleHitbox()); animation = await game.loadSpriteAnimation( - 'rogue_shooter/bullet.png', + 'assets/images/rogue_shooter/bullet.png', SpriteAnimationData.sequenced( stepTime: 0.2, amount: 4, diff --git a/examples/games/rogue_shooter/lib/components/enemy_component.dart b/examples/games/rogue_shooter/lib/components/enemy_component.dart index 24102580003..3e707ce8b81 100644 --- a/examples/games/rogue_shooter/lib/components/enemy_component.dart +++ b/examples/games/rogue_shooter/lib/components/enemy_component.dart @@ -14,7 +14,7 @@ class EnemyComponent extends SpriteAnimationComponent @override Future onLoad() async { animation = await game.loadSpriteAnimation( - 'rogue_shooter/enemy.png', + 'assets/images/rogue_shooter/enemy.png', SpriteAnimationData.sequenced( stepTime: 0.2, amount: 4, diff --git a/examples/games/rogue_shooter/lib/components/explosion_component.dart b/examples/games/rogue_shooter/lib/components/explosion_component.dart index 3a35e4fd1e6..c02ac455b59 100644 --- a/examples/games/rogue_shooter/lib/components/explosion_component.dart +++ b/examples/games/rogue_shooter/lib/components/explosion_component.dart @@ -12,7 +12,7 @@ class ExplosionComponent extends SpriteAnimationComponent @override Future onLoad() async { animation = await game.loadSpriteAnimation( - 'rogue_shooter/explosion.png', + 'assets/images/rogue_shooter/explosion.png', SpriteAnimationData.sequenced( stepTime: 0.1, amount: 6, diff --git a/examples/games/rogue_shooter/lib/components/player_component.dart b/examples/games/rogue_shooter/lib/components/player_component.dart index 9e1759e0822..2f9f7ee6b60 100644 --- a/examples/games/rogue_shooter/lib/components/player_component.dart +++ b/examples/games/rogue_shooter/lib/components/player_component.dart @@ -24,7 +24,7 @@ class PlayerComponent extends SpriteAnimationComponent ), ); animation = await game.loadSpriteAnimation( - 'rogue_shooter/player.png', + 'assets/images/rogue_shooter/player.png', SpriteAnimationData.sequenced( stepTime: 0.2, amount: 4, diff --git a/examples/games/rogue_shooter/lib/components/star_background_creator.dart b/examples/games/rogue_shooter/lib/components/star_background_creator.dart index c6d12bed268..37c25e9b270 100644 --- a/examples/games/rogue_shooter/lib/components/star_background_creator.dart +++ b/examples/games/rogue_shooter/lib/components/star_background_creator.dart @@ -17,7 +17,7 @@ class StarBackGroundCreator extends Component @override Future onLoad() async { spriteSheet = SpriteSheet.fromColumnsAndRows( - image: await game.images.load('rogue_shooter/stars.png'), + image: await game.images.load('assets/images/rogue_shooter/stars.png'), rows: 4, columns: 4, ); diff --git a/examples/games/trex/lib/trex_game.dart b/examples/games/trex/lib/trex_game.dart index bccc5cefed2..105ee36e670 100644 --- a/examples/games/trex/lib/trex_game.dart +++ b/examples/games/trex/lib/trex_game.dart @@ -49,7 +49,7 @@ class TRexGame extends FlameGame @override Future onLoad() async { - spriteImage = await Flame.images.load('trex.png'); + spriteImage = await Flame.images.load('assets/images/trex.png'); add(horizon); add(player); add(gameOverPanel); diff --git a/examples/lib/commons/ember.dart b/examples/lib/commons/ember.dart index 88b2a87e11d..4bd58654950 100644 --- a/examples/lib/commons/ember.dart +++ b/examples/lib/commons/ember.dart @@ -14,7 +14,7 @@ class Ember extends SpriteAnimationComponent @override Future onLoad() async { animation = await game.loadSpriteAnimation( - 'animations/ember.png', + 'assets/images/animations/ember.png', SpriteAnimationData.sequenced( amount: 3, textureSize: Vector2.all(16), diff --git a/examples/lib/stories/animations/animation_group_example.dart b/examples/lib/stories/animations/animation_group_example.dart index 3e4b38be8cc..d4e95f590ba 100644 --- a/examples/lib/stories/animations/animation_group_example.dart +++ b/examples/lib/stories/animations/animation_group_example.dart @@ -23,7 +23,7 @@ class AnimationGroupExample extends FlameGame with TapCallbacks { @override Future onLoad() async { final running = await loadSpriteAnimation( - 'animations/robot.png', + 'assets/images/animations/robot.png', SpriteAnimationData.sequenced( amount: 8, stepTime: 0.2, @@ -31,7 +31,7 @@ class AnimationGroupExample extends FlameGame with TapCallbacks { ), ); final idle = await loadSpriteAnimation( - 'animations/robot-idle.png', + 'assets/images/animations/robot-idle.png', SpriteAnimationData.sequenced( amount: 4, stepTime: 0.4, diff --git a/examples/lib/stories/animations/aseprite_example.dart b/examples/lib/stories/animations/aseprite_example.dart index aef17b1636e..fa2116c486a 100644 --- a/examples/lib/stories/animations/aseprite_example.dart +++ b/examples/lib/stories/animations/aseprite_example.dart @@ -9,8 +9,10 @@ class AsepriteExample extends FlameGame { @override Future onLoad() async { - final image = await images.load('animations/chopper.png'); - final jsonData = await assets.readJson('images/animations/chopper.json'); + final image = await images.load('assets/images/animations/chopper.png'); + final jsonData = await assets.readJson( + 'assets/images/animations/chopper.json', + ); final animation = SpriteAnimation.fromAsepriteData(image, jsonData); final spriteSize = Vector2.all(200); final animationComponent = SpriteAnimationComponent( diff --git a/examples/lib/stories/animations/basic_animation_example.dart b/examples/lib/stories/animations/basic_animation_example.dart index b699a03f0ea..2320461177c 100644 --- a/examples/lib/stories/animations/basic_animation_example.dart +++ b/examples/lib/stories/animations/basic_animation_example.dart @@ -21,10 +21,10 @@ class BasicAnimationsWorld extends World with TapCallbacks, HasGameReference { @override Future onLoad() async { - creature = await game.images.load('animations/creature.png'); + creature = await game.images.load('assets/images/animations/creature.png'); final animation = await game.loadSpriteAnimation( - 'animations/chopper.png', + 'assets/images/animations/chopper.png', SpriteAnimationData.sequenced( amount: 4, textureSize: Vector2.all(48), diff --git a/examples/lib/stories/bridge_libraries/audio/basic_audio_example.dart b/examples/lib/stories/bridge_libraries/audio/basic_audio_example.dart index 38500d828d3..6e4566f85c2 100644 --- a/examples/lib/stories/bridge_libraries/audio/basic_audio_example.dart +++ b/examples/lib/stories/bridge_libraries/audio/basic_audio_example.dart @@ -31,7 +31,7 @@ class BasicAudioExample extends FlameGame { @override Future onLoad() async { pool = await FlameAudio.createPool( - 'sfx/fire_2.mp3', + 'assets/audio/sfx/fire_2.mp3', minPlayers: 3, maxPlayers: 4, ); @@ -76,11 +76,11 @@ class BasicAudioExample extends FlameGame { void startBgmMusic() { FlameAudio.bgm.initialize(); - FlameAudio.bgm.play('music/bg_music.ogg'); + FlameAudio.bgm.play('assets/audio/music/bg_music.ogg'); } void fireOne() { - FlameAudio.play('sfx/fire_1.mp3'); + FlameAudio.play('assets/audio/sfx/fire_1.mp3'); } void fireTwo() { diff --git a/examples/lib/stories/bridge_libraries/flame_forge2d/animated_body_example.dart b/examples/lib/stories/bridge_libraries/flame_forge2d/animated_body_example.dart index f6578b5d03b..207d8748eb7 100644 --- a/examples/lib/stories/bridge_libraries/flame_forge2d/animated_body_example.dart +++ b/examples/lib/stories/bridge_libraries/flame_forge2d/animated_body_example.dart @@ -30,7 +30,7 @@ class AnimatedBodyWorld extends Forge2DWorld @override Future onLoad() async { await super.onLoad(); - chopper = await Flame.images.load('animations/chopper.png'); + chopper = await Flame.images.load('assets/images/animations/chopper.png'); animation = SpriteAnimation.fromFrameData( chopper, diff --git a/examples/lib/stories/bridge_libraries/flame_forge2d/sprite_body_example.dart b/examples/lib/stories/bridge_libraries/flame_forge2d/sprite_body_example.dart index a2837c81ef4..a05475e7572 100644 --- a/examples/lib/stories/bridge_libraries/flame_forge2d/sprite_body_example.dart +++ b/examples/lib/stories/bridge_libraries/flame_forge2d/sprite_body_example.dart @@ -47,7 +47,7 @@ class Pizza extends BodyComponent { @override Future onLoad() async { await super.onLoad(); - final sprite = await game.loadSprite('pizza.png'); + final sprite = await game.loadSprite('assets/images/pizza.png'); renderBody = false; add( SpriteComponent( diff --git a/examples/lib/stories/bridge_libraries/flame_jenny/components/button_row.dart b/examples/lib/stories/bridge_libraries/flame_jenny/components/button_row.dart index 52524946d88..9b24da87ee1 100644 --- a/examples/lib/stories/bridge_libraries/flame_jenny/components/button_row.dart +++ b/examples/lib/stories/bridge_libraries/flame_jenny/components/button_row.dart @@ -19,7 +19,7 @@ class ButtonRow extends PositionComponent { void showNextButton(Function() onNextButtonPressed) { removeButtons(); final nextButton = DialogueButton( - assetPath: 'green_button_sqr.png', + assetPath: 'assets/images/green_button_sqr.png', text: 'Next', position: Vector2(size.x / 2, 0), onPressed: () { @@ -38,7 +38,7 @@ class ButtonRow extends PositionComponent { removeButtons(); final optionButtons = [ DialogueButton( - assetPath: 'green_button_sqr.png', + assetPath: 'assets/images/green_button_sqr.png', text: option1.text, position: Vector2(size.x / 4, 0), onPressed: () { @@ -47,7 +47,7 @@ class ButtonRow extends PositionComponent { }, ), DialogueButton( - assetPath: 'red_button_sqr.png', + assetPath: 'assets/images/red_button_sqr.png', text: option2.text, position: Vector2(size.x * 3 / 4, 0), onPressed: () { @@ -61,7 +61,7 @@ class ButtonRow extends PositionComponent { void showCloseButton(Function() onClose) { final closeButton = DialogueButton( - assetPath: 'green_button_sqr.png', + assetPath: 'assets/images/green_button_sqr.png', text: 'Close', onPressed: () => onClose(), position: Vector2(size.x / 2, 0), diff --git a/examples/lib/stories/bridge_libraries/flame_jenny/components/dialogue_box.dart b/examples/lib/stories/bridge_libraries/flame_jenny/components/dialogue_box.dart index 24fe2286675..c05482d8823 100644 --- a/examples/lib/stories/bridge_libraries/flame_jenny/components/dialogue_box.dart +++ b/examples/lib/stories/bridge_libraries/flame_jenny/components/dialogue_box.dart @@ -13,7 +13,7 @@ class DialogueBoxComponent extends SpriteComponent with HasGameReference { position = Vector2(game.size.x / 2, 96); anchor = Anchor.center; sprite = await Sprite.load( - 'dialogue_box.png', + 'assets/images/dialogue_box.png', srcSize: spriteSize, ); addAll([buttonRow, textBox]); diff --git a/examples/lib/stories/camera_and_viewport/fixed_resolution_example.dart b/examples/lib/stories/camera_and_viewport/fixed_resolution_example.dart index 276a28405ca..f34ac63a1d0 100644 --- a/examples/lib/stories/camera_and_viewport/fixed_resolution_example.dart +++ b/examples/lib/stories/camera_and_viewport/fixed_resolution_example.dart @@ -70,7 +70,9 @@ class FixedResolutionWorld extends World @override Future onLoad() async { - final flameSprite = await game.loadSprite('layers/player.png'); + final flameSprite = await game.loadSprite( + 'assets/images/layers/player.png', + ); add(Background()); add( diff --git a/examples/lib/stories/camera_and_viewport/follow_component_example.dart b/examples/lib/stories/camera_and_viewport/follow_component_example.dart index ad4e2647ad9..7124c3ee01c 100644 --- a/examples/lib/stories/camera_and_viewport/follow_component_example.dart +++ b/examples/lib/stories/camera_and_viewport/follow_component_example.dart @@ -191,7 +191,7 @@ class Rock extends SpriteComponent with HasGameReference, TapCallbacks { @override Future onLoad() async { - sprite = await game.loadSprite('nine-box.png'); + sprite = await game.loadSprite('assets/images/nine-box.png'); paint = Paint()..color = Colors.white; add(RectangleHitbox()); } diff --git a/examples/lib/stories/camera_and_viewport/static_components_example.dart b/examples/lib/stories/camera_and_viewport/static_components_example.dart index f44f7c6da76..f9512c81b3a 100644 --- a/examples/lib/stories/camera_and_viewport/static_components_example.dart +++ b/examples/lib/stories/camera_and_viewport/static_components_example.dart @@ -74,8 +74,10 @@ class _StaticComponentWorld extends World late SpriteComponent player; @override Future onLoad() async { - final playerSprite = await game.loadSprite('layers/player.png'); - final flameSprite = await game.loadSprite('flame.png'); + final playerSprite = await game.loadSprite( + 'assets/images/layers/player.png', + ); + final flameSprite = await game.loadSprite('assets/images/flame.png'); final visibleSize = game.camera.visibleWorldRect.toVector2(); add(player = SpriteComponent(sprite: playerSprite, anchor: Anchor.center)); addAll([ @@ -130,11 +132,11 @@ class MyParallaxComponent extends ParallaxComponent { Future onLoad() async { parallax = await game.loadParallax( [ - ParallaxImageData('parallax/bg.png'), - ParallaxImageData('parallax/mountain-far.png'), - ParallaxImageData('parallax/mountains.png'), - ParallaxImageData('parallax/trees.png'), - ParallaxImageData('parallax/foreground-trees.png'), + ParallaxImageData('assets/images/parallax/bg.png'), + ParallaxImageData('assets/images/parallax/mountain-far.png'), + ParallaxImageData('assets/images/parallax/mountains.png'), + ParallaxImageData('assets/images/parallax/trees.png'), + ParallaxImageData('assets/images/parallax/foreground-trees.png'), ], baseVelocity: Vector2(0, 0), velocityMultiplierDelta: Vector2(1.8, 1.0), diff --git a/examples/lib/stories/camera_and_viewport/zoom_example.dart b/examples/lib/stories/camera_and_viewport/zoom_example.dart index 05e0c07c74d..b8d0306ee29 100644 --- a/examples/lib/stories/camera_and_viewport/zoom_example.dart +++ b/examples/lib/stories/camera_and_viewport/zoom_example.dart @@ -11,7 +11,7 @@ class ZoomExample extends FlameGame @override Future onLoad() async { - final flameSprite = await loadSprite('flame.png'); + final flameSprite = await loadSprite('assets/images/flame.png'); world.add( SpriteComponent( diff --git a/examples/lib/stories/collision_detection/collidable_animation_example.dart b/examples/lib/stories/collision_detection/collidable_animation_example.dart index 4c6af8dc589..f9a5ef477f2 100644 --- a/examples/lib/stories/collision_detection/collidable_animation_example.dart +++ b/examples/lib/stories/collision_detection/collidable_animation_example.dart @@ -71,7 +71,7 @@ class AnimatedComponent extends SpriteAnimationComponent @override Future onLoad() async { animation = await game.loadSpriteAnimation( - 'bomb_ptero.png', + 'assets/images/bomb_ptero.png', SpriteAnimationData.sequenced( amount: 4, stepTime: 0.2, diff --git a/examples/lib/stories/collision_detection/quadtree_example.dart b/examples/lib/stories/collision_detection/quadtree_example.dart index 9c1716fd77c..de00dcc8efd 100644 --- a/examples/lib/stories/collision_detection/quadtree_example.dart +++ b/examples/lib/stories/collision_detection/quadtree_example.dart @@ -56,13 +56,13 @@ Press T button to toggle player to collide with other objects. final random = Random(); final spriteBrick = await Sprite.load( - 'retro_tiles.png', + 'assets/images/retro_tiles.png', srcPosition: Vector2.all(0), srcSize: Vector2.all(tileSize), ); final spriteWater = await Sprite.load( - 'retro_tiles.png', + 'assets/images/retro_tiles.png', srcPosition: Vector2(0, tileSize), srcSize: Vector2.all(tileSize), ); @@ -216,7 +216,7 @@ class Player extends SpriteComponent @override Future onLoad() async { sprite = await Sprite.load( - 'retro_tiles.png', + 'assets/images/retro_tiles.png', srcSize: Vector2.all(tileSize), srcPosition: Vector2(tileSize * 3, tileSize), ); diff --git a/examples/lib/stories/components/debug_example.dart b/examples/lib/stories/components/debug_example.dart index ecde44ff4d9..cb805556b17 100644 --- a/examples/lib/stories/components/debug_example.dart +++ b/examples/lib/stories/components/debug_example.dart @@ -13,7 +13,7 @@ class DebugExample extends FlameGame { @override Future onLoad() async { - final flameLogo = await loadSprite('flame.png'); + final flameLogo = await loadSprite('assets/images/flame.png'); final flame1 = LogoComponent(flameLogo); flame1.x = 100; diff --git a/examples/lib/stories/components/has_visibility_example.dart b/examples/lib/stories/components/has_visibility_example.dart index d44f8f5fc01..f9dd10bb514 100644 --- a/examples/lib/stories/components/has_visibility_example.dart +++ b/examples/lib/stories/components/has_visibility_example.dart @@ -13,7 +13,9 @@ class HasVisibilityExample extends FlameGame { @override Future onLoad() async { - final flameLogoComponent = LogoComponent(await loadSprite('flame.png')); + final flameLogoComponent = LogoComponent( + await loadSprite('assets/images/flame.png'), + ); add(flameLogoComponent); // Toggle visibility every second diff --git a/examples/lib/stories/components/keys_example.dart b/examples/lib/stories/components/keys_example.dart index 984809c29df..66427ca6e96 100644 --- a/examples/lib/stories/components/keys_example.dart +++ b/examples/lib/stories/components/keys_example.dart @@ -73,9 +73,9 @@ class KeysExampleGame extends FlameGame { FutureOr onLoad() async { await super.onLoad(); - final knight = await loadSprite('knight.png'); - final mage = await loadSprite('mage.png'); - final ranger = await loadSprite('ranger.png'); + final knight = await loadSprite('assets/images/knight.png'); + final mage = await loadSprite('assets/images/mage.png'); + final ranger = await loadSprite('assets/images/ranger.png'); addAll([ SelectableClass( diff --git a/examples/lib/stories/components/look_at_example.dart b/examples/lib/stories/components/look_at_example.dart index 1c6a71a3b50..92cdf736146 100644 --- a/examples/lib/stories/components/look_at_example.dart +++ b/examples/lib/stories/components/look_at_example.dart @@ -30,7 +30,7 @@ class LookAtExample extends FlameGame<_TapWorld> @override Future onLoad() async { final spriteSheet = SpriteSheet( - image: await images.load('animations/chopper.png'), + image: await images.load('assets/images/animations/chopper.png'), srcSize: Vector2.all(48), ); diff --git a/examples/lib/stories/components/look_at_smooth_example.dart b/examples/lib/stories/components/look_at_smooth_example.dart index 9cc7f811fe1..0b94b1d4f80 100644 --- a/examples/lib/stories/components/look_at_smooth_example.dart +++ b/examples/lib/stories/components/look_at_smooth_example.dart @@ -29,7 +29,7 @@ class LookAtSmoothExample extends FlameGame { @override Future onLoad() async { final spriteSheet = SpriteSheet( - image: await images.load('animations/chopper.png'), + image: await images.load('assets/images/animations/chopper.png'), srcSize: Vector2.all(48), ); diff --git a/examples/lib/stories/components/time_scale_example.dart b/examples/lib/stories/components/time_scale_example.dart index a5b2e176c92..be39af48c04 100644 --- a/examples/lib/stories/components/time_scale_example.dart +++ b/examples/lib/stories/components/time_scale_example.dart @@ -42,7 +42,7 @@ class TimeScaleExample extends FlameGame @override Future onLoad() async { final spriteSheet = SpriteSheet( - image: await images.load('animations/chopper.png'), + image: await images.load('assets/images/animations/chopper.png'), srcSize: Vector2.all(48), ); gameSpeedText.position = Vector2(size.x * 0.5, size.y * 0.8); diff --git a/examples/lib/stories/effects/dual_effect_removal_example.dart b/examples/lib/stories/effects/dual_effect_removal_example.dart index e5cff022b66..127c5dfa900 100644 --- a/examples/lib/stories/effects/dual_effect_removal_example.dart +++ b/examples/lib/stories/effects/dual_effect_removal_example.dart @@ -1,66 +1,66 @@ -import 'package:flame/components.dart'; -import 'package:flame/effects.dart'; -import 'package:flame/events.dart'; -import 'package:flame/game.dart'; -import 'package:flutter/material.dart'; - -class DualEffectRemovalExample extends FlameGame with TapCallbacks { - static const String description = ''' - In this example we show how a dual effect can be used and removed. - To remove an effect, tap anywhere on the screen and the first tap will - remove the OpacityEffect and the second tap removes the ColorEffect. - In this example, when an effect is removed the component is reset to - the state (the part of the state that was affected by the running effect) - that it had before the effect started running. - '''; - - late ColorEffect colorEffect; - late OpacityEffect opacityEffect; - - @override - Future onLoad() async { - final mySprite = SpriteComponent( - sprite: await loadSprite('flame.png'), - position: Vector2(50, 50), - ); - - add(mySprite); - - final colorController = EffectController( - duration: 2, - reverseDuration: 2, - infinite: true, - ); - colorEffect = ColorEffect( - Colors.blue, - colorController, - opacityTo: 0.8, - ); - mySprite.add(colorEffect); - - final opacityController = EffectController( - duration: 1, - reverseDuration: 1, - infinite: true, - ); - opacityEffect = OpacityEffect.fadeOut(opacityController); - mySprite.add(opacityEffect); - } - - @override - void onTapDown(_) { - // apply(0) sends the animation to its initial starting state. - // If this isn't called, the effect would be removed and leave the - // component at its current state. - // Hence when you want an effect to be removed and the component to go - // back to how it looked prior to the effect, you must call apply(0) before - // you call removeFromParent(). - if (opacityEffect.isMounted) { - opacityEffect.apply(0); - opacityEffect.removeFromParent(); - } else if (colorEffect.isMounted) { - colorEffect.apply(0); - colorEffect.removeFromParent(); - } - } -} +import 'package:flame/components.dart'; +import 'package:flame/effects.dart'; +import 'package:flame/events.dart'; +import 'package:flame/game.dart'; +import 'package:flutter/material.dart'; + +class DualEffectRemovalExample extends FlameGame with TapCallbacks { + static const String description = ''' + In this example we show how a dual effect can be used and removed. + To remove an effect, tap anywhere on the screen and the first tap will + remove the OpacityEffect and the second tap removes the ColorEffect. + In this example, when an effect is removed the component is reset to + the state (the part of the state that was affected by the running effect) + that it had before the effect started running. + '''; + + late ColorEffect colorEffect; + late OpacityEffect opacityEffect; + + @override + Future onLoad() async { + final mySprite = SpriteComponent( + sprite: await loadSprite('assets/images/flame.png'), + position: Vector2(50, 50), + ); + + add(mySprite); + + final colorController = EffectController( + duration: 2, + reverseDuration: 2, + infinite: true, + ); + colorEffect = ColorEffect( + Colors.blue, + colorController, + opacityTo: 0.8, + ); + mySprite.add(colorEffect); + + final opacityController = EffectController( + duration: 1, + reverseDuration: 1, + infinite: true, + ); + opacityEffect = OpacityEffect.fadeOut(opacityController); + mySprite.add(opacityEffect); + } + + @override + void onTapDown(_) { + // apply(0) sends the animation to its initial starting state. + // If this isn't called, the effect would be removed and leave the + // component at its current state. + // Hence when you want an effect to be removed and the component to go + // back to how it looked prior to the effect, you must call apply(0) before + // you call removeFromParent(). + if (opacityEffect.isMounted) { + opacityEffect.apply(0); + opacityEffect.removeFromParent(); + } else if (colorEffect.isMounted) { + colorEffect.apply(0); + colorEffect.removeFromParent(); + } + } +} diff --git a/examples/lib/stories/effects/function_effect_example.dart b/examples/lib/stories/effects/function_effect_example.dart index c241360c6ba..c5b0ad47e56 100644 --- a/examples/lib/stories/effects/function_effect_example.dart +++ b/examples/lib/stories/effects/function_effect_example.dart @@ -19,7 +19,7 @@ The robot will switch between running and idle animations over the duration of @override Future onLoad() async { final running = await loadSpriteAnimation( - 'animations/robot.png', + 'assets/images/animations/robot.png', SpriteAnimationData.sequenced( amount: 8, stepTime: 0.2, @@ -27,7 +27,7 @@ The robot will switch between running and idle animations over the duration of ), ); final idle = await loadSpriteAnimation( - 'animations/robot-idle.png', + 'assets/images/animations/robot-idle.png', SpriteAnimationData.sequenced( amount: 4, stepTime: 0.4, diff --git a/examples/lib/stories/effects/opacity_effect_example.dart b/examples/lib/stories/effects/opacity_effect_example.dart index 1df6a844868..2986b0dacd0 100644 --- a/examples/lib/stories/effects/opacity_effect_example.dart +++ b/examples/lib/stories/effects/opacity_effect_example.dart @@ -15,7 +15,7 @@ class OpacityEffectExample extends FlameGame with TapCallbacks { @override Future onLoad() async { - final flameSprite = await loadSprite('flame.png'); + final flameSprite = await loadSprite('assets/images/flame.png'); add( sprite = SpriteComponent( sprite: flameSprite, diff --git a/examples/lib/stories/image/brighten.dart b/examples/lib/stories/image/brighten.dart index ed0b07f9bc9..a74da7ae05d 100644 --- a/examples/lib/stories/image/brighten.dart +++ b/examples/lib/stories/image/brighten.dart @@ -16,7 +16,7 @@ class ImageBrightnessExample extends FlameGame { @override Future onLoad() async { - final image = await images.load('flame.png'); + final image = await images.load('assets/images/flame.png'); final brightenedImage = await image.brighten(brightness / 100); add( diff --git a/examples/lib/stories/image/darken.dart b/examples/lib/stories/image/darken.dart index f3b8d25c777..52a2724c78f 100644 --- a/examples/lib/stories/image/darken.dart +++ b/examples/lib/stories/image/darken.dart @@ -16,7 +16,7 @@ class ImageDarknessExample extends FlameGame { @override Future onLoad() async { - final image = await images.load('flame.png'); + final image = await images.load('assets/images/flame.png'); final darkenedImage = await image.darken(darkness / 100); add( diff --git a/examples/lib/stories/image/resize.dart b/examples/lib/stories/image/resize.dart index 667f5e4cef1..2c0b9b20ff1 100644 --- a/examples/lib/stories/image/resize.dart +++ b/examples/lib/stories/image/resize.dart @@ -14,7 +14,7 @@ class ImageResizeExample extends FlameGame { @override Future onLoad() async { - final image = await images.load('flame.png'); + final image = await images.load('assets/images/flame.png'); final resized = await image.resize(sizeTarget); add( diff --git a/examples/lib/stories/input/joystick_advanced_example.dart b/examples/lib/stories/input/joystick_advanced_example.dart index fc7b1b65fd2..6609b64ed78 100644 --- a/examples/lib/stories/input/joystick_advanced_example.dart +++ b/examples/lib/stories/input/joystick_advanced_example.dart @@ -32,7 +32,7 @@ class JoystickAdvancedExample extends FlameGame with HasCollisionDetection { @override Future onLoad() async { - final image = await images.load('joystick.png'); + final image = await images.load('assets/images/joystick.png'); final sheet = SpriteSheet.fromColumnsAndRows( image: image, columns: 6, @@ -136,7 +136,7 @@ class JoystickAdvancedExample extends FlameGame with HasCollisionDetection { ), ); - final buttonSprites = await images.load('buttons.png'); + final buttonSprites = await images.load('assets/images/buttons.png'); final buttonSheet = SpriteSheet.fromColumnsAndRows( image: buttonSprites, columns: 1, diff --git a/examples/lib/stories/input/joystick_player.dart b/examples/lib/stories/input/joystick_player.dart index 73e22f4eb8a..90f583e4d81 100644 --- a/examples/lib/stories/input/joystick_player.dart +++ b/examples/lib/stories/input/joystick_player.dart @@ -16,7 +16,7 @@ class JoystickPlayer extends SpriteComponent @override Future onLoad() async { - sprite = await game.loadSprite('layers/player.png'); + sprite = await game.loadSprite('assets/images/layers/player.png'); add(RectangleHitbox()); } diff --git a/examples/lib/stories/parallax/advanced_parallax_example.dart b/examples/lib/stories/parallax/advanced_parallax_example.dart index 79d4e9ecd84..0a6d8852514 100644 --- a/examples/lib/stories/parallax/advanced_parallax_example.dart +++ b/examples/lib/stories/parallax/advanced_parallax_example.dart @@ -10,11 +10,11 @@ class AdvancedParallaxExample extends FlameGame { '''; final _layersMeta = { - 'parallax/bg.png': 1.0, - 'parallax/mountain-far.png': 1.5, - 'parallax/mountains.png': 2.3, - 'parallax/trees.png': 3.8, - 'parallax/foreground-trees.png': 6.6, + 'assets/images/parallax/bg.png': 1.0, + 'assets/images/parallax/mountain-far.png': 1.5, + 'assets/images/parallax/mountains.png': 2.3, + 'assets/images/parallax/trees.png': 3.8, + 'assets/images/parallax/foreground-trees.png': 6.6, }; @override diff --git a/examples/lib/stories/parallax/animation_parallax_example.dart b/examples/lib/stories/parallax/animation_parallax_example.dart index 4363d4e8b99..eeafef3900e 100644 --- a/examples/lib/stories/parallax/animation_parallax_example.dart +++ b/examples/lib/stories/parallax/animation_parallax_example.dart @@ -11,13 +11,13 @@ class AnimationParallaxExample extends FlameGame { @override Future onLoad() async { final cityLayer = await loadParallaxLayer( - ParallaxImageData('parallax/city.png'), + ParallaxImageData('assets/images/parallax/city.png'), filterQuality: FilterQuality.none, ); final rainLayer = await loadParallaxLayer( ParallaxAnimationData( - 'parallax/rain.png', + 'assets/images/parallax/rain.png', SpriteAnimationData.sequenced( amount: 4, stepTime: 0.3, @@ -29,7 +29,7 @@ class AnimationParallaxExample extends FlameGame { ); final cloudsLayer = await loadParallaxLayer( - ParallaxImageData('parallax/heavy_clouded.png'), + ParallaxImageData('assets/images/parallax/heavy_clouded.png'), velocityMultiplier: Vector2(4, 0), fill: LayerFill.none, alignment: Alignment.topLeft, diff --git a/examples/lib/stories/parallax/basic_parallax_example.dart b/examples/lib/stories/parallax/basic_parallax_example.dart index d7ce1f54fc4..874edb045fb 100644 --- a/examples/lib/stories/parallax/basic_parallax_example.dart +++ b/examples/lib/stories/parallax/basic_parallax_example.dart @@ -10,11 +10,11 @@ class BasicParallaxExample extends FlameGame { '''; final _imageNames = [ - ParallaxImageData('parallax/bg.png'), - ParallaxImageData('parallax/mountain-far.png'), - ParallaxImageData('parallax/mountains.png'), - ParallaxImageData('parallax/trees.png'), - ParallaxImageData('parallax/foreground-trees.png'), + ParallaxImageData('assets/images/parallax/bg.png'), + ParallaxImageData('assets/images/parallax/mountain-far.png'), + ParallaxImageData('assets/images/parallax/mountains.png'), + ParallaxImageData('assets/images/parallax/trees.png'), + ParallaxImageData('assets/images/parallax/foreground-trees.png'), ]; @override diff --git a/examples/lib/stories/parallax/component_parallax_example.dart b/examples/lib/stories/parallax/component_parallax_example.dart index c11b764fdb7..4078c2a0761 100644 --- a/examples/lib/stories/parallax/component_parallax_example.dart +++ b/examples/lib/stories/parallax/component_parallax_example.dart @@ -26,11 +26,11 @@ class MyParallaxComponent extends ParallaxComponent { Future onLoad() async { parallax = await game.loadParallax( [ - ParallaxImageData('parallax/bg.png'), - ParallaxImageData('parallax/mountain-far.png'), - ParallaxImageData('parallax/mountains.png'), - ParallaxImageData('parallax/trees.png'), - ParallaxImageData('parallax/foreground-trees.png'), + ParallaxImageData('assets/images/parallax/bg.png'), + ParallaxImageData('assets/images/parallax/mountain-far.png'), + ParallaxImageData('assets/images/parallax/mountains.png'), + ParallaxImageData('assets/images/parallax/trees.png'), + ParallaxImageData('assets/images/parallax/foreground-trees.png'), ], baseVelocity: Vector2(20, 0), velocityMultiplierDelta: Vector2(1.8, 1.0), diff --git a/examples/lib/stories/parallax/no_fcs_parallax_example.dart b/examples/lib/stories/parallax/no_fcs_parallax_example.dart index 9c4ab68f2c0..0c288b03e00 100644 --- a/examples/lib/stories/parallax/no_fcs_parallax_example.dart +++ b/examples/lib/stories/parallax/no_fcs_parallax_example.dart @@ -19,11 +19,11 @@ class NoFCSParallaxExample extends Game { Future onLoad() async { parallax = await loadParallax( [ - ParallaxImageData('parallax/bg.png'), - ParallaxImageData('parallax/mountain-far.png'), - ParallaxImageData('parallax/mountains.png'), - ParallaxImageData('parallax/trees.png'), - ParallaxImageData('parallax/foreground-trees.png'), + ParallaxImageData('assets/images/parallax/bg.png'), + ParallaxImageData('assets/images/parallax/mountain-far.png'), + ParallaxImageData('assets/images/parallax/mountains.png'), + ParallaxImageData('assets/images/parallax/trees.png'), + ParallaxImageData('assets/images/parallax/foreground-trees.png'), ], size: size, baseVelocity: Vector2(20, 0), diff --git a/examples/lib/stories/parallax/sandbox_layer_parallax_example.dart b/examples/lib/stories/parallax/sandbox_layer_parallax_example.dart index 0044e545d40..eb1c6ab28a4 100644 --- a/examples/lib/stories/parallax/sandbox_layer_parallax_example.dart +++ b/examples/lib/stories/parallax/sandbox_layer_parallax_example.dart @@ -25,32 +25,32 @@ class SandboxLayerParallaxExample extends FlameGame { @override Future onLoad() async { final bgLayer = await loadParallaxLayer( - ParallaxImageData('parallax/bg.png'), + ParallaxImageData('assets/images/parallax/bg.png'), filterQuality: FilterQuality.none, ); final mountainFarLayer = await loadParallaxLayer( - ParallaxImageData('parallax/mountain-far.png'), + ParallaxImageData('assets/images/parallax/mountain-far.png'), velocityMultiplier: Vector2(1.8, 0), filterQuality: FilterQuality.none, ); final mountainLayer = await loadParallaxLayer( - ParallaxImageData('parallax/mountains.png'), + ParallaxImageData('assets/images/parallax/mountains.png'), velocityMultiplier: Vector2(2.8, 0), filterQuality: FilterQuality.none, ); final treeLayer = await loadParallaxLayer( - ParallaxImageData('parallax/trees.png'), + ParallaxImageData('assets/images/parallax/trees.png'), velocityMultiplier: Vector2(3.8, 0), filterQuality: FilterQuality.none, ); final foregroundTreesLayer = await loadParallaxLayer( - ParallaxImageData('parallax/foreground-trees.png'), + ParallaxImageData('assets/images/parallax/foreground-trees.png'), velocityMultiplier: Vector2(4.8, 0), filterQuality: FilterQuality.none, ); final airplaneLayer = await loadParallaxLayer( ParallaxAnimationData( - 'parallax/airplane.png', + 'assets/images/parallax/airplane.png', SpriteAnimationData.sequenced( amount: 4, stepTime: 0.2, diff --git a/examples/lib/stories/parallax/small_parallax_example.dart b/examples/lib/stories/parallax/small_parallax_example.dart index fda32efc4d6..75a8bdbde4a 100644 --- a/examples/lib/stories/parallax/small_parallax_example.dart +++ b/examples/lib/stories/parallax/small_parallax_example.dart @@ -11,11 +11,11 @@ class SmallParallaxExample extends FlameGame { Future onLoad() async { final component = await loadParallaxComponent( [ - ParallaxImageData('parallax/bg.png'), - ParallaxImageData('parallax/mountain-far.png'), - ParallaxImageData('parallax/mountains.png'), - ParallaxImageData('parallax/trees.png'), - ParallaxImageData('parallax/foreground-trees.png'), + ParallaxImageData('assets/images/parallax/bg.png'), + ParallaxImageData('assets/images/parallax/mountain-far.png'), + ParallaxImageData('assets/images/parallax/mountains.png'), + ParallaxImageData('assets/images/parallax/trees.png'), + ParallaxImageData('assets/images/parallax/foreground-trees.png'), ], size: Vector2.all(200), baseVelocity: Vector2(20, 0), diff --git a/examples/lib/stories/rendering/isometric_tile_map_example.dart b/examples/lib/stories/rendering/isometric_tile_map_example.dart index 9313f891d24..b5989b9b970 100644 --- a/examples/lib/stories/rendering/isometric_tile_map_example.dart +++ b/examples/lib/stories/rendering/isometric_tile_map_example.dart @@ -32,7 +32,9 @@ class IsometricTileMapExample extends FlameGame with MouseMoveCallbacks { @override Future onLoad() async { - final tilesetImage = await images.load('tile_maps/tiles$suffix.png'); + final tilesetImage = await images.load( + 'assets/images/tile_maps/tiles$suffix.png', + ); final tileset = SpriteSheet( image: tilesetImage, srcSize: Vector2.all(srcTileSize), @@ -55,7 +57,9 @@ class IsometricTileMapExample extends FlameGame with MouseMoveCallbacks { ), ); - final selectorImage = await images.load('tile_maps/selector$suffix.png'); + final selectorImage = await images.load( + 'assets/images/tile_maps/selector$suffix.png', + ); add(selector = Selector(destTileSize, selectorImage)); } diff --git a/examples/lib/stories/rendering/layers_example.dart b/examples/lib/stories/rendering/layers_example.dart index f9ff12e9182..8ef6a31b708 100644 --- a/examples/lib/stories/rendering/layers_example.dart +++ b/examples/lib/stories/rendering/layers_example.dart @@ -14,9 +14,15 @@ class LayerExample extends FlameGame { @override Future onLoad() async { - final playerSprite = Sprite(await images.load('layers/player.png')); - final enemySprite = Sprite(await images.load('layers/enemy.png')); - final backgroundSprite = Sprite(await images.load('layers/background.png')); + final playerSprite = Sprite( + await images.load('assets/images/layers/player.png'), + ); + final enemySprite = Sprite( + await images.load('assets/images/layers/enemy.png'), + ); + final backgroundSprite = Sprite( + await images.load('assets/images/layers/background.png'), + ); gameLayer = GameLayer(playerSprite, enemySprite); backgroundLayer = BackgroundLayer(backgroundSprite); diff --git a/examples/lib/stories/rendering/nine_tile_box_custom_grid_example.dart b/examples/lib/stories/rendering/nine_tile_box_custom_grid_example.dart index 975d562d1a1..49212bae8c2 100644 --- a/examples/lib/stories/rendering/nine_tile_box_custom_grid_example.dart +++ b/examples/lib/stories/rendering/nine_tile_box_custom_grid_example.dart @@ -15,7 +15,7 @@ class NineTileBoxCustomGridExample extends FlameGame @override Future onLoad() async { - final sprite = Sprite(await images.load('speech-bubble.png')); + final sprite = Sprite(await images.load('assets/images/speech-bubble.png')); final boxSize = Vector2.all(300); final nineTileBox = NineTileBox.withGrid( sprite, diff --git a/examples/lib/stories/rendering/nine_tile_box_example.dart b/examples/lib/stories/rendering/nine_tile_box_example.dart index 1f4208bbb4d..2a594dc92d4 100644 --- a/examples/lib/stories/rendering/nine_tile_box_example.dart +++ b/examples/lib/stories/rendering/nine_tile_box_example.dart @@ -14,7 +14,7 @@ class NineTileBoxExample extends FlameGame @override Future onLoad() async { - final sprite = Sprite(await images.load('nine-box.png')); + final sprite = Sprite(await images.load('assets/images/nine-box.png')); final boxSize = Vector2.all(300); final nineTileBox = NineTileBox(sprite, destTileSize: 148); add( diff --git a/examples/lib/stories/rendering/particles_example.dart b/examples/lib/stories/rendering/particles_example.dart index 456db2c1a6a..5833a2724c0 100644 --- a/examples/lib/stories/rendering/particles_example.dart +++ b/examples/lib/stories/rendering/particles_example.dart @@ -22,7 +22,7 @@ class ParticlesExample extends FlameGame { @override Future onLoad() async { - final zap = await images.load('zap.png'); + final zap = await images.load('assets/images/zap.png'); final cell = Vector2(size.x / _columns, size.y / _rows); final effects = <(String, PositionComponent)>[ diff --git a/examples/lib/stories/rendering/particles_interactive_example.dart b/examples/lib/stories/rendering/particles_interactive_example.dart index 30f3a087545..f9ced8f56c5 100644 --- a/examples/lib/stories/rendering/particles_interactive_example.dart +++ b/examples/lib/stories/rendering/particles_interactive_example.dart @@ -50,7 +50,7 @@ class ParticlesInteractiveExample extends FlameGame with PanDetector { @override Future onLoad() async { - final zap = await images.load('zap.png'); + final zap = await images.load('assets/images/zap.png'); _emitter = _buildEffect(zap); add(_emitter); } diff --git a/examples/lib/stories/sprites/basic_sprite_example.dart b/examples/lib/stories/sprites/basic_sprite_example.dart index 457e6268ad7..0cb03f40144 100644 --- a/examples/lib/stories/sprites/basic_sprite_example.dart +++ b/examples/lib/stories/sprites/basic_sprite_example.dart @@ -9,7 +9,7 @@ class BasicSpriteExample extends FlameGame { @override Future onLoad() async { - final sprite = await loadSprite('flame.png'); + final sprite = await loadSprite('assets/images/flame.png'); add( SpriteComponent( sprite: sprite, diff --git a/examples/lib/stories/sprites/sprite_batch_bleed_example.dart b/examples/lib/stories/sprites/sprite_batch_bleed_example.dart index 0c20a698960..3b5a04d5239 100644 --- a/examples/lib/stories/sprites/sprite_batch_bleed_example.dart +++ b/examples/lib/stories/sprites/sprite_batch_bleed_example.dart @@ -28,7 +28,7 @@ class SpriteBatchBleedExample extends FlameGame { @override Future onLoad() async { - final spriteBatch = await SpriteBatch.load('retro_tiles.png'); + final spriteBatch = await SpriteBatch.load('assets/images/retro_tiles.png'); const tile1 = Rect.fromLTWH(0, 0, tileSize, tileSize); const tile2 = Rect.fromLTWH(tileSize, 0, tileSize, tileSize); diff --git a/examples/lib/stories/sprites/sprite_batch_example.dart b/examples/lib/stories/sprites/sprite_batch_example.dart index 295f31db9d3..0a1008b3fa7 100644 --- a/examples/lib/stories/sprites/sprite_batch_example.dart +++ b/examples/lib/stories/sprites/sprite_batch_example.dart @@ -13,7 +13,7 @@ class SpriteBatchExample extends FlameGame { @override Future onLoad() async { - final spriteBatch = await SpriteBatch.load('boom.png'); + final spriteBatch = await SpriteBatch.load('assets/images/boom.png'); spriteBatch.add( source: const Rect.fromLTWH(128 * 4.0, 128 * 4.0, 64, 128), diff --git a/examples/lib/stories/sprites/sprite_batch_load_example.dart b/examples/lib/stories/sprites/sprite_batch_load_example.dart index 889e48b9401..05935efce1c 100644 --- a/examples/lib/stories/sprites/sprite_batch_load_example.dart +++ b/examples/lib/stories/sprites/sprite_batch_load_example.dart @@ -27,7 +27,7 @@ class MySpriteBatchComponent extends SpriteBatchComponent @override Future onLoad() async { - final spriteBatch = await game.loadSpriteBatch('boom.png'); + final spriteBatch = await game.loadSpriteBatch('assets/images/boom.png'); this.spriteBatch = spriteBatch; spriteBatch.add( diff --git a/examples/lib/stories/sprites/sprite_group_example.dart b/examples/lib/stories/sprites/sprite_group_example.dart index 0bdea5fe12f..ef2f2510a75 100644 --- a/examples/lib/stories/sprites/sprite_group_example.dart +++ b/examples/lib/stories/sprites/sprite_group_example.dart @@ -27,12 +27,12 @@ class ButtonComponent extends SpriteGroupComponent @override Future onLoad() async { final pressedSprite = await game.loadSprite( - 'buttons.png', + 'assets/images/buttons.png', srcPosition: Vector2(0, 20), srcSize: Vector2(60, 20), ); final unpressedSprite = await game.loadSprite( - 'buttons.png', + 'assets/images/buttons.png', srcSize: Vector2(60, 20), ); diff --git a/examples/lib/stories/sprites/sprite_sheet_example.dart b/examples/lib/stories/sprites/sprite_sheet_example.dart index d58d1d23d97..dd724d15aee 100644 --- a/examples/lib/stories/sprites/sprite_sheet_example.dart +++ b/examples/lib/stories/sprites/sprite_sheet_example.dart @@ -11,7 +11,7 @@ class SpriteSheetExample extends FlameGame { @override Future onLoad() async { final spriteSheet = SpriteSheet( - image: await images.load('sprite_sheet.png'), + image: await images.load('assets/images/sprite_sheet.png'), srcSize: Vector2(16.0, 18.0), ); diff --git a/examples/lib/stories/system/overlays_example.dart b/examples/lib/stories/system/overlays_example.dart index fedf268085c..c03f6ac1f9d 100644 --- a/examples/lib/stories/system/overlays_example.dart +++ b/examples/lib/stories/system/overlays_example.dart @@ -14,7 +14,7 @@ class OverlaysExample extends FlameGame with TapCallbacks { @override Future onLoad() async { final animation = await loadSpriteAnimation( - 'animations/chopper.png', + 'assets/images/animations/chopper.png', SpriteAnimationData.sequenced( amount: 4, textureSize: Vector2.all(48), diff --git a/examples/lib/stories/system/pause_resume_example.dart b/examples/lib/stories/system/pause_resume_example.dart index 26844c6d52f..1fb26048743 100644 --- a/examples/lib/stories/system/pause_resume_example.dart +++ b/examples/lib/stories/system/pause_resume_example.dart @@ -18,7 +18,7 @@ class PauseResumeExample extends FlameGame @override Future onLoad() async { final animation = await loadSpriteAnimation( - 'animations/chopper.png', + 'assets/images/animations/chopper.png', SpriteAnimationData.sequenced( amount: 4, textureSize: Vector2.all(48), diff --git a/examples/lib/stories/system/step_engine_example.dart b/examples/lib/stories/system/step_engine_example.dart index 5e34196dbf9..4b1b5d579fa 100644 --- a/examples/lib/stories/system/step_engine_example.dart +++ b/examples/lib/stories/system/step_engine_example.dart @@ -32,7 +32,7 @@ class StepEngineExample extends FlameGame @override Future onLoad() async { - final carSprite = await Sprite.load('Car.png'); + final carSprite = await Sprite.load('assets/images/Car.png'); final car = SpriteComponent( sprite: carSprite, anchor: Anchor.center, diff --git a/examples/lib/stories/tiled/flame_tiled_animation_example.dart b/examples/lib/stories/tiled/flame_tiled_animation_example.dart index 31c95d29a33..92054ed1e49 100644 --- a/examples/lib/stories/tiled/flame_tiled_animation_example.dart +++ b/examples/lib/stories/tiled/flame_tiled_animation_example.dart @@ -10,7 +10,10 @@ class FlameTiledAnimationExample extends FlameGame { @override Future onLoad() async { - map = await TiledComponent.load('dungeon.tmx', Vector2.all(32)); + map = await TiledComponent.load( + 'assets/tiles/dungeon.tmx', + Vector2.all(32), + ); add(map); } } diff --git a/examples/lib/stories/widgets/nine_tile_box_example.dart b/examples/lib/stories/widgets/nine_tile_box_example.dart index bc11e29bb69..2eb2b065ab1 100644 --- a/examples/lib/stories/widgets/nine_tile_box_example.dart +++ b/examples/lib/stories/widgets/nine_tile_box_example.dart @@ -7,7 +7,7 @@ Widget nineTileBoxBuilder(DashbookContext ctx) { width: ctx.numberProperty('width', 200), height: ctx.numberProperty('height', 200), child: NineTileBoxWidget.asset( - path: 'nine-box.png', + path: 'assets/images/nine-box.png', tileSize: 22, destTileSize: 50, child: const Center( diff --git a/examples/lib/stories/widgets/nine_tile_box_example_with_animation.dart b/examples/lib/stories/widgets/nine_tile_box_example_with_animation.dart index 3444ab4798d..4e00ee261a8 100644 --- a/examples/lib/stories/widgets/nine_tile_box_example_with_animation.dart +++ b/examples/lib/stories/widgets/nine_tile_box_example_with_animation.dart @@ -25,7 +25,7 @@ Widget nineTileBoxBuilderWithAnimation(DashbookContext ctx) { child: NineTileBoxWidget.asset( width: 400, height: 400, - path: 'nine-box.png', + path: 'assets/images/nine-box.png', tileSize: 22, destTileSize: 50, child: const Center( diff --git a/examples/lib/stories/widgets/partial_sprite_widget_example.dart b/examples/lib/stories/widgets/partial_sprite_widget_example.dart index 8cf1a079932..492c90d4505 100644 --- a/examples/lib/stories/widgets/partial_sprite_widget_example.dart +++ b/examples/lib/stories/widgets/partial_sprite_widget_example.dart @@ -11,7 +11,7 @@ Widget partialSpriteWidgetBuilder(DashbookContext ctx) { height: ctx.numberProperty('container height', 200), decoration: BoxDecoration(border: Border.all(color: Colors.amber)), child: SpriteWidget.asset( - path: 'bomb_ptero.png', + path: 'assets/images/bomb_ptero.png', srcPosition: Vector2( ctx.numberProperty('srcPosition.x', 48), ctx.numberProperty('srcPosition.y', 0), diff --git a/examples/lib/stories/widgets/sprite_animation_widget_example.dart b/examples/lib/stories/widgets/sprite_animation_widget_example.dart index cb2f55c9313..fb3cba4d020 100644 --- a/examples/lib/stories/widgets/sprite_animation_widget_example.dart +++ b/examples/lib/stories/widgets/sprite_animation_widget_example.dart @@ -11,7 +11,7 @@ Widget spriteAnimationWidgetBuilder(DashbookContext ctx) { width: ctx.numberProperty('container width', 400), height: ctx.numberProperty('container height', 200), child: SpriteAnimationWidget.asset( - path: 'bomb_ptero.png', + path: 'assets/images/bomb_ptero.png', data: SpriteAnimationData.sequenced( amount: 4, stepTime: 0.2, @@ -39,7 +39,7 @@ Widget spriteAnimationWithSizeWidgetBuilder(DashbookContext ctx) { ctx.numberProperty('width', 400), ctx.numberProperty('height', 200), ), - path: 'bomb_ptero.png', + path: 'assets/images/bomb_ptero.png', data: SpriteAnimationData.sequenced( amount: 4, stepTime: 0.2, diff --git a/examples/lib/stories/widgets/sprite_button_example.dart b/examples/lib/stories/widgets/sprite_button_example.dart index b49dacdfdd2..d8906c34645 100644 --- a/examples/lib/stories/widgets/sprite_button_example.dart +++ b/examples/lib/stories/widgets/sprite_button_example.dart @@ -7,8 +7,8 @@ Widget spriteButtonBuilder(DashbookContext ctx) { return Container( padding: const EdgeInsets.all(20), child: SpriteButton.asset( - path: 'buttons.png', - pressedPath: 'buttons.png', + path: 'assets/images/buttons.png', + pressedPath: 'assets/images/buttons.png', srcPosition: Vector2(0, 0), srcSize: Vector2(60, 20), pressedSrcPosition: Vector2(0, 20), diff --git a/examples/lib/stories/widgets/sprite_widget_example.dart b/examples/lib/stories/widgets/sprite_widget_example.dart index 5ce1e04d185..a4ca319aeaf 100644 --- a/examples/lib/stories/widgets/sprite_widget_example.dart +++ b/examples/lib/stories/widgets/sprite_widget_example.dart @@ -13,7 +13,7 @@ Widget spriteWidgetBuilder(DashbookContext ctx) { height: ctx.numberProperty('container height', 200), decoration: BoxDecoration(border: Border.all(color: Colors.amber)), child: SpriteWidget.asset( - path: 'shield.png', + path: 'assets/images/shield.png', angle: pi / 180 * ctx.numberProperty('angle (deg)', 0), anchor: Anchor.valueOf( ctx.listProperty('anchor', 'center', anchorOptions), @@ -38,7 +38,7 @@ Widget spriteWidgetWithSizeBuilder(DashbookContext ctx) { ctx.numberProperty('width', 400), ctx.numberProperty('height', 200), ), - path: 'shield.png', + path: 'assets/images/shield.png', angle: pi / 180 * ctx.numberProperty('angle (deg)', 0), anchor: Anchor.valueOf( ctx.listProperty('anchor', 'center', anchorOptions), diff --git a/packages/flame/lib/src/cache/assets_cache.dart b/packages/flame/lib/src/cache/assets_cache.dart index e6cd1c645a7..fe3ed2785f2 100644 --- a/packages/flame/lib/src/cache/assets_cache.dart +++ b/packages/flame/lib/src/cache/assets_cache.dart @@ -6,18 +6,15 @@ import 'package:flutter/services.dart' show AssetBundle; /// A class that loads, and caches files. /// -/// It automatically looks for files in the `assets` directory. +/// Files are addressed by their full path, exactly as declared in the +/// `pubspec.yaml`, for example `assets/levels/level1.json`. class AssetsCache { - AssetsCache({ - this.prefix = 'assets/', - AssetBundle? bundle, - }) : bundle = bundle ?? Flame.bundle; + AssetsCache({AssetBundle? bundle}) : bundle = bundle ?? Flame.bundle; /// The [AssetBundle] from which assets are loaded. /// defaults to [Flame.bundle]. AssetBundle bundle; - String prefix; final Map> _files = {}; /// Removes the file from the cache. @@ -33,63 +30,73 @@ class AssetsCache { /// Returns the number of files in the cache. int get cacheCount => _files.length; - /// Reads a file from assets folder. + /// Reads a file from the assets. + /// + /// The [fileName] is the full path of the asset. When a [package] is given, + /// the path is resolved relative to that package's assets. Future readFile(String fileName, {String? package}) async { - final cacheKey = package == null ? fileName : 'packages/$package/$fileName'; - if (!_files.containsKey(cacheKey)) { - _files[cacheKey] = await _readFile(fileName, package: package); + final path = _resolve(fileName, package); + if (!_files.containsKey(path)) { + _files[path] = await _readFile(path); } assert( - _files[cacheKey] is _StringAsset, - '"$cacheKey" was previously loaded as a binary file', + _files[path] is _StringAsset, + '"$path" was previously loaded as a binary file', ); - return (_files[cacheKey]! as _StringAsset).value; + return (_files[path]! as _StringAsset).value; } - /// Reads a binary file from assets folder. + /// Reads a binary file from the assets. + /// + /// The [fileName] is the full path of the asset. When a [package] is given, + /// the path is resolved relative to that package's assets. Future readBinaryFile(String fileName, {String? package}) async { - final cacheKey = package == null ? fileName : 'packages/$package/$fileName'; - if (!_files.containsKey(cacheKey)) { - _files[cacheKey] = await _readBinary(fileName, package: package); + final path = _resolve(fileName, package); + if (!_files.containsKey(path)) { + _files[path] = await _readBinary(path); } assert( - _files[cacheKey] is _BinaryAsset, - '"$cacheKey" was previously loaded as a text file', + _files[path] is _BinaryAsset, + '"$path" was previously loaded as a text file', ); - return (_files[cacheKey]! as _BinaryAsset).value; + return (_files[path]! as _BinaryAsset).value; } - /// Reads a json file from the assets folder. + /// Reads a json file from the assets. + /// + /// The [fileName] is the full path of the asset. When a [package] is given, + /// the path is resolved relative to that package's assets. Future> readJson( String fileName, { String? package, }) async { - final cacheKey = package == null ? fileName : 'packages/$package/$fileName'; - if (!_files.containsKey(cacheKey)) { - _files[cacheKey] = await _readJson(fileName, package: package); + final path = _resolve(fileName, package); + if (!_files.containsKey(path)) { + _files[path] = await _readJson(path); } assert( - _files[cacheKey] is _JsonAsset, - '"$cacheKey" was previously loaded as a different type', + _files[path] is _JsonAsset, + '"$path" was previously loaded as a different type', ); - return (_files[cacheKey]! as _JsonAsset).value; + return (_files[path]! as _JsonAsset).value; } - Future<_StringAsset> _readFile(String fileName, {String? package}) async { - final fullPrefix = package == null ? prefix : 'packages/$package/$prefix'; - final string = await bundle.loadString('$fullPrefix$fileName'); + static String _resolve(String fileName, String? package) => + package == null ? fileName : 'packages/$package/$fileName'; + + Future<_StringAsset> _readFile(String path) async { + final string = await bundle.loadString(path); return _StringAsset(string); } - Future<_BinaryAsset> _readBinary(String fileName, {String? package}) async { - final fullPrefix = package == null ? prefix : 'packages/$package/$prefix'; - final data = await bundle.load('$fullPrefix$fileName'); + Future<_BinaryAsset> _readBinary(String path) async { + final data = await bundle.load(path); final bytes = Uint8List.view(data.buffer); return _BinaryAsset(bytes); } - Future<_JsonAsset> _readJson(String fileName, {String? package}) async { - final string = await _readFile(fileName, package: package); + Future<_JsonAsset> _readJson(String path) async { + final string = await _readFile(path); final json = jsonDecode(string.value) as Map; return _JsonAsset(json); } diff --git a/packages/flame/lib/src/cache/images.dart b/packages/flame/lib/src/cache/images.dart index 5b8fdb5348d..9b12e9398d7 100644 --- a/packages/flame/lib/src/cache/images.dart +++ b/packages/flame/lib/src/cache/images.dart @@ -7,10 +7,7 @@ import 'package:flutter/painting.dart'; import 'package:flutter/services.dart'; class Images { - Images({ - this._prefix = 'assets/images/', - AssetBundle? bundle, - }) : bundle = bundle ?? Flame.bundle; + Images({AssetBundle? bundle}) : bundle = bundle ?? Flame.bundle; final Map _assets = {}; @@ -18,27 +15,6 @@ class Images { /// defaults to [Flame.bundle]. AssetBundle bundle; - /// Path prefix to the project's directory with images. - /// - /// This path is relative to the project's root, and the default prefix is - /// "assets/images/". If necessary, you may change this prefix at any time. - /// A prefix must be a valid directory name and end with "/" (empty prefix is - /// also allowed). - /// - /// The prefix is **not** part of the keys of the images stored in this cache. - /// For example, if you load image `player.png`, then it will be searched at - /// location `prefix + "player.png"` but stored in the cache under the key - /// `"player.png"`. - String get prefix => _prefix; - late String _prefix; - set prefix(String value) { - assert( - value.isEmpty || value.endsWith('/'), - 'Prefix must be empty or end with a "/"', - ); - _prefix = value; - } - /// Adds the [image] into the cache under the key [name]. /// /// The cache will assume the ownership of the [image], and will properly @@ -113,12 +89,18 @@ class Images { return asset!.image!; } - /// Loads the specified image with [fileName] into the cache. - /// By default the key in the cache is the [fileName], if another key is + /// Loads the image at [fileName] into the cache. + /// + /// The [fileName] is the full path of the asset, exactly as declared in the + /// `pubspec.yaml`, for example `assets/images/player.png`. When a [package] + /// is given, the path is resolved relative to that package's assets. + /// + /// By default the key in the cache is the resolved path, if another key is /// desired, specify the optional [key] argument. Future load(String fileName, {String? key, String? package}) { - return (_assets[key ?? fileName] ??= _ImageAsset.future( - _fetchToMemory(fileName, package: package), + final path = _resolve(fileName, package); + return (_assets[key ?? path] ??= _ImageAsset.future( + _fetchToMemory(path), )).retrieveAsync(); } @@ -127,27 +109,35 @@ class Images { return Future.wait(fileNames.map(load)); } - /// Loads all images from the specified (or default) [prefix] into the cache. - Future> loadAllImages() { + /// Loads every image found under [directory] into the cache. + /// + /// The [directory] must be empty, or end with a "/". An empty [directory] + /// matches every asset in the bundle. + Future> loadAllImages({required String directory}) { return loadAllFromPattern( RegExp( r'\.(png|jpg|jpeg|svg|gif|webp|bmp|wbmp)$', caseSensitive: false, ), + directory: directory, ); } - /// Loads all images in the [prefix]ed path that are matching the specified - /// pattern. - Future> loadAllFromPattern(Pattern pattern) async { + /// Loads all images under [directory] that match the specified pattern. + /// + /// Images are cached under their full path, as listed in the asset manifest. + Future> loadAllFromPattern( + Pattern pattern, { + required String directory, + }) async { + assert( + directory.isEmpty || directory.endsWith('/'), + 'directory must be empty or end with a "/"', + ); final manifest = await AssetManifest.loadFromAssetBundle(bundle); - final imagePaths = manifest - .listAssets() - .where((path) { - return path.startsWith(_prefix) && - path.toLowerCase().contains(pattern); - }) - .map((path) => path.replaceFirst(_prefix, '')); + final imagePaths = manifest.listAssets().where((path) { + return path.startsWith(directory) && path.toLowerCase().contains(pattern); + }); return loadAll(imagePaths.toList()); } @@ -174,15 +164,17 @@ class Images { )).retrieveAsync(); } + static String _resolve(String fileName, String? package) => + package == null ? fileName : 'packages/$package/$fileName'; + Future _fetchFromBase64(String base64Data) { final data = base64Data.substring(base64Data.indexOf(',') + 1); final bytes = base64.decode(data); return decodeImageFromList(bytes); } - Future _fetchToMemory(String name, {String? package}) async { - final prefix = package == null ? _prefix : 'packages/$package/$_prefix'; - final data = await bundle.load('$prefix$name'); + Future _fetchToMemory(String path) async { + final data = await bundle.load(path); final bytes = Uint8List.view(data.buffer); return decodeImageFromList(bytes); } diff --git a/packages/flame/lib/src/game/game.dart b/packages/flame/lib/src/game/game.dart index 87d9fdf56e4..1de828cf2e2 100644 --- a/packages/flame/lib/src/game/game.dart +++ b/packages/flame/lib/src/game/game.dart @@ -316,6 +316,9 @@ abstract mixin class Game { /// Utility method to load and cache the image for a sprite based on its /// options. + /// + /// The [path] is the full path of the asset, as declared in the + /// `pubspec.yaml`, for example `assets/images/player.png`. Future loadSprite( String path, { Vector2? srcSize, @@ -331,6 +334,9 @@ abstract mixin class Game { /// Utility method to load and cache the image for a sprite animation based on /// its options. + /// + /// The [path] is the full path of the asset, as declared in the + /// `pubspec.yaml`, for example `assets/images/player.png`. Future loadSpriteAnimation( String path, SpriteAnimationData data, diff --git a/packages/flame/lib/src/parallax.dart b/packages/flame/lib/src/parallax.dart index bf0871b9181..062edaa51a9 100644 --- a/packages/flame/lib/src/parallax.dart +++ b/packages/flame/lib/src/parallax.dart @@ -139,11 +139,14 @@ class ParallaxImage extends ParallaxRenderer { super.filterQuality, }); - /// Takes a path of an image, and optionally arguments for how the image - /// should repeat ([repeat]), which edge it should align with ([alignment]), - /// which axis it should fill the image on ([fill]) and [images] which is the - /// image cache that should be used. If no image cache is set, the global - /// flame cache is used. + /// Takes the full path of an image, and optionally arguments for how the + /// image should repeat ([repeat]), which edge it should align with + /// ([alignment]), which axis it should fill the image on ([fill]) and + /// [images] which is the image cache that should be used. If no image cache + /// is set, the global flame cache is used. + /// + /// The [path] is the full path of the asset, as declared in the + /// `pubspec.yaml`, for example `assets/images/sky.png`. static Future load( String path, { ImageRepeat repeat = ImageRepeat.repeatX, @@ -190,11 +193,14 @@ class ParallaxAnimation extends ParallaxRenderer { super.filterQuality, }) : _animationTicker = animation.createTicker(); - /// Takes a path of an image, a SpriteAnimationData, and optionally arguments - /// for how the image should repeat ([repeat]), which edge it should align - /// with ([alignment]), which axis it should fill the image on ([fill]) and - /// [images] which is the image cache that should be used. If no image cache - /// is set, the global flame cache is used. + /// Takes the full path of an image, a SpriteAnimationData, and optionally + /// arguments for how the image should repeat ([repeat]), which edge it should + /// align with ([alignment]), which axis it should fill the image on ([fill]) + /// and [images] which is the image cache that should be used. If no image + /// cache is set, the global flame cache is used. + /// + /// The [path] is the full path of the asset, as declared in the + /// `pubspec.yaml`, for example `assets/images/clouds.png`. /// /// _IMPORTANT_: This method pre render all the frames of the animation into /// image instances so it can be used inside the parallax. Just keep that in diff --git a/packages/flame/lib/src/sprite.dart b/packages/flame/lib/src/sprite.dart index e9a7bfc9bbd..ff1562daea2 100644 --- a/packages/flame/lib/src/sprite.dart +++ b/packages/flame/lib/src/sprite.dart @@ -29,8 +29,11 @@ class Sprite { this.srcPosition = srcPosition; } - /// Takes a path of an image, a [srcPosition] and [srcSize] and loads the - /// sprite animation. + /// Takes the full path of an image, a [srcPosition] and [srcSize] and loads + /// the sprite. + /// + /// The [src] is the full path of the asset, as declared in the + /// `pubspec.yaml`, for example `assets/images/player.png`. /// When the [images] is omitted, the global [Flame.images] is used. static Future load( String src, { diff --git a/packages/flame/lib/src/sprite_animation.dart b/packages/flame/lib/src/sprite_animation.dart index cfad63ee918..c77e41caa76 100644 --- a/packages/flame/lib/src/sprite_animation.dart +++ b/packages/flame/lib/src/sprite_animation.dart @@ -234,8 +234,11 @@ class SpriteAnimation { ); } - /// Takes a path of an image, a [SpriteAnimationData] and loads the sprite - /// animation. + /// Takes the full path of an image, a [SpriteAnimationData] and loads the + /// sprite animation. + /// + /// The [src] is the full path of the asset, as declared in the + /// `pubspec.yaml`, for example `assets/images/player.png`. /// When the [images] is omitted, the global [Flame.images] is used. static Future load( String src, diff --git a/packages/flame/lib/src/sprite_batch.dart b/packages/flame/lib/src/sprite_batch.dart index fe4717bd49f..dbc72f26237 100644 --- a/packages/flame/lib/src/sprite_batch.dart +++ b/packages/flame/lib/src/sprite_batch.dart @@ -164,8 +164,11 @@ class SpriteBatch { this._imageKey, }); - /// Takes a path of an image, and optional arguments for the SpriteBatch. + /// Takes the full path of an image, and optional arguments for the + /// SpriteBatch. /// + /// The [path] is the full path of the asset, as declared in the + /// `pubspec.yaml`, for example `assets/images/tiles.png`. /// When the [images] is omitted, the global [Flame.images] is used. static Future load( String path, { diff --git a/packages/flame/lib/src/widgets/animation_widget.dart b/packages/flame/lib/src/widgets/animation_widget.dart index d0455c25a8e..9b899a45533 100644 --- a/packages/flame/lib/src/widgets/animation_widget.dart +++ b/packages/flame/lib/src/widgets/animation_widget.dart @@ -56,6 +56,9 @@ class SpriteAnimationWidget extends StatefulWidget { /// To render without loading, or when you want to have a gapless playback /// when the [path] value changes, consider loading the [SpriteAnimation] /// beforehand and direct pass it to the default constructor. + /// + /// The [path] is the full path of the asset, as declared in the + /// `pubspec.yaml`, for example `assets/images/player.png`. SpriteAnimationWidget.asset({ required String path, required SpriteAnimationData data, diff --git a/packages/flame/lib/src/widgets/nine_tile_box.dart b/packages/flame/lib/src/widgets/nine_tile_box.dart index 66a00d98ad0..cb5af07ff25 100644 --- a/packages/flame/lib/src/widgets/nine_tile_box.dart +++ b/packages/flame/lib/src/widgets/nine_tile_box.dart @@ -77,6 +77,9 @@ class NineTileBoxWidget extends StatefulWidget { /// To render without loading, or when you want to have a gapless playback /// when the [path] value changes, consider loading the image beforehand /// and direct pass it to the default constructor. + /// + /// The [path] is the full path of the asset, as declared in the + /// `pubspec.yaml`, for example `assets/images/player.png`. NineTileBoxWidget.asset({ required String path, required this.tileSize, diff --git a/packages/flame/lib/src/widgets/sprite_button.dart b/packages/flame/lib/src/widgets/sprite_button.dart index c5919a3baee..7143591912d 100644 --- a/packages/flame/lib/src/widgets/sprite_button.dart +++ b/packages/flame/lib/src/widgets/sprite_button.dart @@ -110,6 +110,9 @@ class SpriteButton extends StatelessWidget { /// To render without loading, or when you want to have a gapless playback /// when the [path] value changes, consider loading the image beforehand /// and direct pass it to the default constructor. + /// + /// The [path] is the full path of the asset, as declared in the + /// `pubspec.yaml`, for example `assets/images/player.png`. SpriteButton.asset({ required String path, required String pressedPath, diff --git a/packages/flame/lib/src/widgets/sprite_widget.dart b/packages/flame/lib/src/widgets/sprite_widget.dart index a017c009e29..18685d6b8c0 100644 --- a/packages/flame/lib/src/widgets/sprite_widget.dart +++ b/packages/flame/lib/src/widgets/sprite_widget.dart @@ -58,6 +58,9 @@ class SpriteWidget extends StatefulWidget { /// To render without loading, or when you want to have a gapless playback /// when the [path] value changes, consider loading the image beforehand /// and direct pass it to the default constructor. + /// + /// The [path] is the full path of the asset, as declared in the + /// `pubspec.yaml`, for example `assets/images/player.png`. SpriteWidget.asset({ required String path, Images? images, diff --git a/packages/flame/test/cache/assets_cache_test.dart b/packages/flame/test/cache/assets_cache_test.dart index 82886cf3d41..b1677884374 100644 --- a/packages/flame/test/cache/assets_cache_test.dart +++ b/packages/flame/test/cache/assets_cache_test.dart @@ -14,7 +14,7 @@ void main() { group('AssetsCache', () { test('readFile', () async { - final assetsCache = AssetsCache(prefix: ''); + final assetsCache = AssetsCache(); final fileName = fixture('test_text_file.txt').path; final file = await assetsCache.readFile(fileName); expect(file, isA()); @@ -26,13 +26,13 @@ void main() { }); test('readJson', () async { - final assetsCache = AssetsCache(prefix: ''); + final assetsCache = AssetsCache(); final file = await assetsCache.readJson(fixture('chopper.json').path); expect(file, isA>()); }); test('readBinaryFile', () async { - final assetsCache = AssetsCache(prefix: ''); + final assetsCache = AssetsCache(); final fileName = fixture('cave_ace.fa').path; final file = await assetsCache.readBinaryFile(fileName); expect(file, isA()); @@ -44,7 +44,7 @@ void main() { }); test('clear', () async { - final assetsCache = AssetsCache(prefix: ''); + final assetsCache = AssetsCache(); final fileName = fixture('test_text_file.txt').path; final file = await assetsCache.readFile(fileName); @@ -55,7 +55,7 @@ void main() { }); test('clearCache', () async { - final assetsCache = AssetsCache(prefix: ''); + final assetsCache = AssetsCache(); final fileName = fixture('test_text_file.txt').path; final file = await assetsCache.readFile(fileName); @@ -65,14 +65,6 @@ void main() { expect(assetsCache.cacheCount, equals(0)); }); - testWithFlameGame( - 'prefix on assets can not be changed', - (game) async { - game.assets = AssetsCache(); - expect(game.assets.prefix, 'assets/'); - }, - ); - testWithFlameGame( 'Game.assets is same as Flame.assets', (game) async { @@ -86,7 +78,7 @@ void main() { final cache = AssetsCache(bundle: bundle); - final result = await cache.readFile('duck_count'); + final result = await cache.readFile('assets/duck_count'); expect(result, equals('Two ducks')); verify(() => bundle.loadString('assets/duck_count')).called(1); }); @@ -99,7 +91,10 @@ void main() { final cache = AssetsCache(bundle: bundle); - final result = await cache.readFile('duck_count', package: 'my_pkg'); + final result = await cache.readFile( + 'assets/duck_count', + package: 'my_pkg', + ); expect(result, equals('Three ducks')); verify( () => bundle.loadString('packages/my_pkg/assets/duck_count'), @@ -108,7 +103,7 @@ void main() { group('fromCache', () { test('returns cached string asset', () async { - final assetsCache = AssetsCache(prefix: ''); + final assetsCache = AssetsCache(); final fileName = fixture('test_text_file.txt').path; await assetsCache.readFile(fileName); @@ -123,7 +118,7 @@ void main() { }); test('returns cached binary asset', () async { - final assetsCache = AssetsCache(prefix: ''); + final assetsCache = AssetsCache(); final fileName = fixture('cave_ace.fa').path; await assetsCache.readBinaryFile(fileName); @@ -132,7 +127,7 @@ void main() { }); test('returns cached json asset', () async { - final assetsCache = AssetsCache(prefix: ''); + final assetsCache = AssetsCache(); final fileName = fixture('chopper.json').path; final file = await assetsCache.readJson(fileName); expect(file, isA>()); @@ -143,7 +138,7 @@ void main() { }); test('throws assertion when asset not in cache', () { - final assetsCache = AssetsCache(prefix: ''); + final assetsCache = AssetsCache(); expect( () => assetsCache.fromCache('nonexistent.txt'), diff --git a/packages/flame/test/cache/images_test.dart b/packages/flame/test/cache/images_test.dart index d49809abb1f..412accad7c6 100644 --- a/packages/flame/test/cache/images_test.dart +++ b/packages/flame/test/cache/images_test.dart @@ -103,18 +103,6 @@ void main() { ); }); - testWithFlameGame( - 'prefix on game.images can be changed', - (game) async { - game.images = Images(); - expect(game.images.prefix, 'assets/images/'); - game.images.prefix = 'assets/pictures/'; - expect(game.images.prefix, 'assets/pictures/'); - game.images.prefix = ''; - expect(game.images.prefix, ''); - }, - ); - testWithFlameGame( 'Game.images is same as Flame.images', (game) async { @@ -131,14 +119,6 @@ void main() { }, ); - test('throws when setting an invalid prefix', () { - final images = Images(); - expect( - () => images.prefix = 'foo', - failsAssert('Prefix must be empty or end with a "/"'), - ); - }); - test('.ready()', () async { final images = Images(); images.fromBase64('image1', pixel); @@ -160,7 +140,7 @@ void main() { ); final images = Images(bundle: bundle); - await images.load('pixel.png', package: 'my_pkg'); + await images.load('assets/images/pixel.png', package: 'my_pkg'); verify( () => bundle.load('packages/my_pkg/assets/images/pixel.png'), @@ -177,16 +157,121 @@ void main() { ); final images = Images(bundle: bundle); - final image = await images.load('pixel.png'); + final image = await images.load('assets/images/pixel.png'); expect(image.width, equals(1)); expect(image.height, equals(1)); verify(() => bundle.load('assets/images/pixel.png')).called(1); }); + + group('loadAllFromPattern', () { + _ManifestAssetBundle bundleWith(List paths) { + return _ManifestAssetBundle( + paths, + base64Decode(pixel.split(',').last), + ); + } + + test('only loads assets under the given directory', () async { + final bundle = bundleWith([ + 'assets/images/player.png', + 'assets/images/enemy.jpg', + 'assets/images/notes.txt', + 'assets/tiles/map.png', + 'packages/other/assets/images/logo.png', + ]); + final images = Images(bundle: bundle); + + await images.loadAllImages(directory: 'assets/images/'); + + expect( + images.keys.toSet(), + {'assets/images/player.png', 'assets/images/enemy.jpg'}, + ); + }); + + test('caches entries under their full manifest path', () async { + final bundle = bundleWith(['assets/images/nested/player.png']); + final images = Images(bundle: bundle); + + await images.loadAllImages(directory: 'assets/images/'); + + expect(images.keys, equals(['assets/images/nested/player.png'])); + expect(bundle.loadedKeys, equals(['assets/images/nested/player.png'])); + }); + + test('an empty directory matches the whole bundle', () async { + final bundle = bundleWith([ + 'assets/images/player.png', + 'assets/tiles/map.png', + ]); + final images = Images(bundle: bundle); + + await images.loadAllImages(directory: ''); + + expect( + images.keys.toSet(), + {'assets/images/player.png', 'assets/tiles/map.png'}, + ); + }); + + test('throws when the directory does not end with a slash', () { + final images = Images(bundle: bundleWith([])); + expect( + () => images.loadAllImages(directory: 'assets/images'), + failsAssert('directory must be empty or end with a "/"'), + ); + }); + }); + + test('the same file in two packages does not collide', () async { + final bundle = _MockAssetBundle(); + when(() => bundle.load(any())).thenAnswer( + (_) async { + final list = base64Decode(pixel.split(',').last); + return ByteData.view(list.buffer); + }, + ); + + final images = Images(bundle: bundle); + await images.load('assets/images/pixel.png', package: 'pkg_a'); + await images.load('assets/images/pixel.png', package: 'pkg_b'); + + expect(images.keys.toSet(), { + 'packages/pkg_a/assets/images/pixel.png', + 'packages/pkg_b/assets/images/pixel.png', + }); + verify( + () => bundle.load('packages/pkg_a/assets/images/pixel.png'), + ).called(1); + verify( + () => bundle.load('packages/pkg_b/assets/images/pixel.png'), + ).called(1); + }); }); } +class _ManifestAssetBundle extends CachingAssetBundle { + _ManifestAssetBundle(this.assetPaths, this.pixelBytes); + + final List assetPaths; + final Uint8List pixelBytes; + + final List loadedKeys = []; + + @override + Future load(String key) async { + if (key == 'AssetManifest.bin') { + return const StandardMessageCodec().encodeMessage({ + for (final path in assetPaths) path: [], + })!; + } + loadedKeys.add(key); + return ByteData.view(pixelBytes.buffer); + } +} + class _MockImage extends Mock implements Image { int disposedCount = 0; diff --git a/packages/flame_audio/example/lib/main.dart b/packages/flame_audio/example/lib/main.dart index 5a86a38dca8..e7944040ce8 100644 --- a/packages/flame_audio/example/lib/main.dart +++ b/packages/flame_audio/example/lib/main.dart @@ -29,7 +29,7 @@ class AudioGame extends FlameGame with TapCallbacks { @override Future onLoad() async { pool = await FlameAudio.createPool( - 'sfx/fire_2.mp3', + 'assets/audio/sfx/fire_2.mp3', minPlayers: 3, maxPlayers: 4, ); @@ -40,11 +40,11 @@ class AudioGame extends FlameGame with TapCallbacks { Future startBgmMusic() async { await FlameAudio.bgm.initialize(); - await FlameAudio.bgm.play('music/bg_music.ogg'); + await FlameAudio.bgm.play('assets/audio/music/bg_music.ogg'); } void fireOne() { - FlameAudio.play('sfx/fire_1.mp3'); + FlameAudio.play('assets/audio/sfx/fire_1.mp3'); } void fireTwo() { diff --git a/packages/flame_audio/lib/bgm.dart b/packages/flame_audio/lib/bgm.dart index be68e03f23c..efb78f5ff59 100644 --- a/packages/flame_audio/lib/bgm.dart +++ b/packages/flame_audio/lib/bgm.dart @@ -54,6 +54,9 @@ class Bgm extends WidgetsBindingObserver { /// Plays and loops a background music file specified by [fileName]. /// + /// The [fileName] is the full path of the asset, as declared in the + /// `pubspec.yaml`, for example `assets/audio/song.mp3`. + /// /// The volume can be specified in the optional named parameter [volume] /// where `0` means off and `1` means max. /// @@ -67,17 +70,8 @@ class Bgm extends WidgetsBindingObserver { await audioPlayer.release(); await audioPlayer.setReleaseMode(ReleaseMode.loop); await audioPlayer.setVolume(volume); - final path = package == null - ? fileName - : 'packages/$package/${audioPlayer.audioCache.prefix}$fileName'; - if (package != null) { - final originalPrefix = audioPlayer.audioCache.prefix; - audioPlayer.audioCache.prefix = ''; - await audioPlayer.setSource(AssetSource(path)); - audioPlayer.audioCache.prefix = originalPrefix; - } else { - await audioPlayer.setSource(AssetSource(path)); - } + final path = package == null ? fileName : 'packages/$package/$fileName'; + await audioPlayer.setSource(AssetSource(path)); await audioPlayer.resume(); isPlaying = true; } diff --git a/packages/flame_audio/lib/flame_audio.dart b/packages/flame_audio/lib/flame_audio.dart index 38eb1669a1c..c2d7cee7873 100644 --- a/packages/flame_audio/lib/flame_audio.dart +++ b/packages/flame_audio/lib/flame_audio.dart @@ -29,21 +29,16 @@ class FlameAudio { static BgmFactory bgmFactory = Bgm.new; /// Access a shared instance of the [AudioCache] class. - static AudioCache audioCache = audioCacheFactory( - prefix: 'assets/audio/', - ); + /// + /// Assets are addressed by their full path, as declared in the + /// `pubspec.yaml`, for example `assets/audio/boom.mp3`. + static AudioCache audioCache = audioCacheFactory(prefix: ''); /// Access a shared instance of the [Bgm] class. /// /// This will use the same global audio cache from [FlameAudio]. static final Bgm bgm = bgmFactory(audioCache: audioCache); - /// Updates the prefix in the global [AudioCache] and [bgm] instances. - static void updatePrefix(String prefix) { - audioCache.prefix = prefix; - bgm.audioPlayer.audioCache.prefix = prefix; - } - static Future _preparePlayer( String file, double volume, @@ -53,16 +48,10 @@ class FlameAudio { String? package, }) async { final player = AudioPlayer(); - if (package != null) { - player.audioCache = audioCacheFactory(prefix: ''); - } else { - player.audioCache = audioCache; - } + player.audioCache = audioCache; await player.setAudioContext(audioContext ?? _defaultAudioContext); await player.setReleaseMode(releaseMode); - final path = package == null - ? file - : 'packages/$package/${audioCache.prefix}$file'; + final path = package == null ? file : 'packages/$package/$file'; await player.play( AssetSource(path), volume: volume, @@ -72,6 +61,9 @@ class FlameAudio { } /// Plays a single run of the given [file], with a given [volume]. + /// + /// The [file] is the full path of the asset, as declared in the + /// `pubspec.yaml`, for example `assets/audio/boom.mp3`. static Future play( String file, { double volume = 1.0, @@ -89,6 +81,9 @@ class FlameAudio { } /// Plays, and keeps looping the given [file]. + /// + /// The [file] is the full path of the asset, as declared in the + /// `pubspec.yaml`, for example `assets/audio/song.mp3`. static Future loop( String file, { double volume = 1.0, @@ -154,12 +149,10 @@ class FlameAudio { String? package, }) async { audioContext ??= _defaultAudioContext; - final path = package == null - ? sound - : 'packages/$package/${audioCache.prefix}$sound'; + final path = package == null ? sound : 'packages/$package/$sound'; return AudioPool.create( source: AssetSource(path), - audioCache: package == null ? audioCache : audioCacheFactory(prefix: ''), + audioCache: audioCache, minPlayers: minPlayers, maxPlayers: maxPlayers, audioContext: audioContext, diff --git a/packages/flame_audio/test/flame_audio_test.dart b/packages/flame_audio/test/flame_audio_test.dart index e447eea5174..d83bece6441 100644 --- a/packages/flame_audio/test/flame_audio_test.dart +++ b/packages/flame_audio/test/flame_audio_test.dart @@ -1,43 +1,10 @@ -import 'package:flame_audio/bgm.dart'; import 'package:flame_audio/flame_audio.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:mocktail/mocktail.dart'; - -class _MockAudioCache extends Mock implements AudioCache {} - -class _MockAudioPlayer extends Mock implements AudioPlayer {} - -class _MockBgmCache extends Mock implements Bgm {} void main() { group('FlameAudio', () { - test('starts the audioCache with the default prefix', () { - expect( - FlameAudio.audioCache.prefix, - equals('assets/audio/'), - ); - }); - - group('updatePrefix', () { - test('updates the prefix on both bgm and audioCache', () { - final audioCache = _MockAudioCache(); - - FlameAudio.audioCache = audioCache; - - final bgm = _MockBgmCache(); - final bgmAudioPlayer = _MockAudioPlayer(); - when(() => bgm.audioPlayer).thenReturn(bgmAudioPlayer); - final bgmAudioCache = _MockAudioCache(); - when(() => bgmAudioPlayer.audioCache).thenReturn(bgmAudioCache); - - FlameAudio.bgmFactory = ({required AudioCache audioCache}) => bgm; - - const newPrefix = 'newPrefix/'; - FlameAudio.updatePrefix(newPrefix); - - verify(() => audioCache.prefix = newPrefix).called(1); - verify(() => bgmAudioCache.prefix = newPrefix).called(1); - }); + test('starts the audioCache with an empty prefix', () { + expect(FlameAudio.audioCache.prefix, isEmpty); }); }); } diff --git a/packages/flame_bloc/example/lib/src/game/components/enemy.dart b/packages/flame_bloc/example/lib/src/game/components/enemy.dart index 2a9c64f2a58..4a3a748c0a2 100644 --- a/packages/flame_bloc/example/lib/src/game/components/enemy.dart +++ b/packages/flame_bloc/example/lib/src/game/components/enemy.dart @@ -19,7 +19,7 @@ class EnemyComponent extends SpriteAnimationComponent Future onLoad() async { await super.onLoad(); animation = await game.loadSpriteAnimation( - 'enemy.png', + 'assets/images/enemy.png', SpriteAnimationData.sequenced( stepTime: 0.2, amount: 4, diff --git a/packages/flame_bloc/example/lib/src/game/components/explosion.dart b/packages/flame_bloc/example/lib/src/game/components/explosion.dart index a92430ede73..ec0a24455f5 100644 --- a/packages/flame_bloc/example/lib/src/game/components/explosion.dart +++ b/packages/flame_bloc/example/lib/src/game/components/explosion.dart @@ -15,7 +15,7 @@ class ExplosionComponent extends SpriteAnimationComponent Future onLoad() async { await super.onLoad(); animation = await game.loadSpriteAnimation( - 'explosion.png', + 'assets/images/explosion.png', SpriteAnimationData.sequenced( stepTime: 0.1, amount: 6, diff --git a/packages/flame_bloc/example/lib/src/game/components/player.dart b/packages/flame_bloc/example/lib/src/game/components/player.dart index 45c5a6ce6e8..2b2f93cde32 100644 --- a/packages/flame_bloc/example/lib/src/game/components/player.dart +++ b/packages/flame_bloc/example/lib/src/game/components/player.dart @@ -48,7 +48,7 @@ class PlayerComponent extends SpriteAnimationComponent Future onLoad() async { await super.onLoad(); animation = await game.loadSpriteAnimation( - 'player.png', + 'assets/images/player.png', SpriteAnimationData.sequenced( stepTime: 0.2, amount: 4, diff --git a/packages/flame_fire_atlas/example/lib/main.dart b/packages/flame_fire_atlas/example/lib/main.dart index 595e52803fc..3b2967b885c 100644 --- a/packages/flame_fire_atlas/example/lib/main.dart +++ b/packages/flame_fire_atlas/example/lib/main.dart @@ -16,7 +16,7 @@ class ExampleGame extends FlameGame with TapCallbacks { @override Future onLoad() async { - _atlas = await loadFireAtlas('cave_ace.fa'); + _atlas = await loadFireAtlas('assets/cave_ace.fa'); add( SpriteAnimationComponent( size: Vector2(150, 100), diff --git a/packages/flame_isolate/example/lib/colonists_game.dart b/packages/flame_isolate/example/lib/colonists_game.dart index 760dc2bff4a..b90bd087e0a 100755 --- a/packages/flame_isolate/example/lib/colonists_game.dart +++ b/packages/flame_isolate/example/lib/colonists_game.dart @@ -31,9 +31,9 @@ class ColonistsGame extends FlameGame with KeyboardEvents { camera.follow(_cameraPosition); camera.viewfinder.zoom = 0.4; - await Flame.images.load('bread.png'); - await Flame.images.load('ant_walk.png'); - await Flame.images.load('cheese.png'); + await Flame.images.load('assets/images/bread.png'); + await Flame.images.load('assets/images/ant_walk.png'); + await Flame.images.load('assets/images/cheese.png'); world.add(_currentMap = GameMap()); diff --git a/packages/flame_isolate/example/lib/objects/bread.dart b/packages/flame_isolate/example/lib/objects/bread.dart index c3027da5327..247d6e5f40c 100755 --- a/packages/flame_isolate/example/lib/objects/bread.dart +++ b/packages/flame_isolate/example/lib/objects/bread.dart @@ -6,7 +6,9 @@ import 'package:flame_isolate_example/standard/int_vector2.dart'; class Bread extends StaticColonistsObject { @override - Sprite objectSprite = Sprite(Flame.images.fromCache('bread.png')); + Sprite objectSprite = Sprite( + Flame.images.fromCache('assets/images/bread.png'), + ); @override IntVector2 tileSize = const IntVector2(1, 1); diff --git a/packages/flame_isolate/example/lib/objects/cheese.dart b/packages/flame_isolate/example/lib/objects/cheese.dart index 8c4379934c7..e3d9b81bc6a 100755 --- a/packages/flame_isolate/example/lib/objects/cheese.dart +++ b/packages/flame_isolate/example/lib/objects/cheese.dart @@ -5,7 +5,9 @@ import 'package:flame_isolate_example/standard/int_vector2.dart'; class Cheese extends StaticColonistsObject { @override - final Sprite objectSprite = Sprite(Flame.images.fromCache('cheese.png')); + final Sprite objectSprite = Sprite( + Flame.images.fromCache('assets/images/cheese.png'), + ); @override final IntVector2 tileSize = const IntVector2(1, 1); diff --git a/packages/flame_isolate/example/lib/units/worker.dart b/packages/flame_isolate/example/lib/units/worker.dart index 13af5ca09c0..0a5ad4dfe44 100755 --- a/packages/flame_isolate/example/lib/units/worker.dart +++ b/packages/flame_isolate/example/lib/units/worker.dart @@ -40,7 +40,7 @@ class Worker extends SpriteAnimationGroupComponent SpriteAnimation getSpriteAnimation(int row) { return SpriteAnimation.fromFrameData( - Flame.images.fromCache('ant_walk.png'), + Flame.images.fromCache('assets/images/ant_walk.png'), SpriteAnimationData.sequenced( amount: 4, stepTime: 0.1, diff --git a/packages/flame_kenney_xml/example/lib/main.dart b/packages/flame_kenney_xml/example/lib/main.dart index debc6d18833..b2a4388eedf 100644 --- a/packages/flame_kenney_xml/example/lib/main.dart +++ b/packages/flame_kenney_xml/example/lib/main.dart @@ -23,8 +23,8 @@ class KenneyWorld extends World with TapCallbacks { @override Future onLoad() async { spritesheet = await XmlSpriteSheet.load( - imagePath: 'spritesheet_stone.png', - xmlPath: 'spritesheet_stone.xml', + imagePath: 'assets/images/spritesheet_stone.png', + xmlPath: 'assets/spritesheet_stone.xml', ); add(randomSpriteComponent()); } diff --git a/packages/flame_markdown/example/lib/main.dart b/packages/flame_markdown/example/lib/main.dart index 94db4ba1221..cf4ca158351 100644 --- a/packages/flame_markdown/example/lib/main.dart +++ b/packages/flame_markdown/example/lib/main.dart @@ -18,7 +18,7 @@ void main() { class MarkdownGame extends FlameGame { @override Future onLoad() async { - final markdown = await Flame.assets.readFile('fire_and_ice.md'); + final markdown = await Flame.assets.readFile('assets/fire_and_ice.md'); add( TextElementComponent.fromDocument( document: FlameMarkdown.toDocument( diff --git a/packages/flame_sprite_fusion/example/lib/main.dart b/packages/flame_sprite_fusion/example/lib/main.dart index 567b79c67c8..3019a7fb713 100644 --- a/packages/flame_sprite_fusion/example/lib/main.dart +++ b/packages/flame_sprite_fusion/example/lib/main.dart @@ -33,8 +33,8 @@ class PlatformerGame extends FlameGame { @override Future onLoad() async { final map = await SpriteFusionTilemapComponent.load( - mapJsonFile: 'map.json', - spriteSheetFile: 'spritesheet.png', + mapJsonFile: 'assets/tiles/map.json', + spriteSheetFile: 'assets/images/spritesheet.png', ); world.add(map); diff --git a/packages/flame_sprite_fusion/lib/src/sprite_fusion_tilemap_component.dart b/packages/flame_sprite_fusion/lib/src/sprite_fusion_tilemap_component.dart index b3b6e63bb51..68dfe6bc8bc 100644 --- a/packages/flame_sprite_fusion/lib/src/sprite_fusion_tilemap_component.dart +++ b/packages/flame_sprite_fusion/lib/src/sprite_fusion_tilemap_component.dart @@ -68,11 +68,14 @@ class SpriteFusionTilemapComponent extends PositionComponent { /// Loads a [SpriteFusionTilemapComponent] from the given json file and /// spritesheet file. + /// + /// Both [mapJsonFile] and [spriteSheetFile] are full paths, as declared in + /// the `pubspec.yaml`, for example `assets/tiles/map.json` and + /// `assets/images/spritesheet.png`. static Future load({ required String mapJsonFile, required String spriteSheetFile, bool useAtlas = true, - String tilemapPrefix = 'assets/tiles/', AssetBundle? assetBundle, Images? images, Vector2? position, @@ -85,12 +88,10 @@ class SpriteFusionTilemapComponent extends PositionComponent { ComponentKey? key, String? package, }) async { - final prefix = package == null - ? tilemapPrefix - : 'packages/$package/$tilemapPrefix'; - final content = await (assetBundle ?? Flame.bundle).loadString( - '$prefix$mapJsonFile', - ); + final mapPath = package == null + ? mapJsonFile + : 'packages/$package/$mapJsonFile'; + final content = await (assetBundle ?? Flame.bundle).loadString(mapPath); final json = jsonDecode(content) as Map; diff --git a/packages/flame_sprite_fusion/test/sprite_fusion_tilemap_component_test.dart b/packages/flame_sprite_fusion/test/sprite_fusion_tilemap_component_test.dart index 76758664e4e..d9a244f55d1 100644 --- a/packages/flame_sprite_fusion/test/sprite_fusion_tilemap_component_test.dart +++ b/packages/flame_sprite_fusion/test/sprite_fusion_tilemap_component_test.dart @@ -34,7 +34,7 @@ void main() { ); final spriteSheet = SpriteSheet( - image: await images.load('spritesheet.png'), + image: await images.load('assets/spritesheet.png'), srcSize: Vector2.all(tilemapData.tileSize), ); @@ -50,11 +50,10 @@ void main() { test('loads map from file', () { expect( SpriteFusionTilemapComponent.load( - mapJsonFile: 'map.json', - spriteSheetFile: 'spritesheet.png', + mapJsonFile: 'assets/map.json', + spriteSheetFile: 'assets/spritesheet.png', assetBundle: bundle, images: images, - tilemapPrefix: '', ), completes, ); @@ -69,7 +68,7 @@ void main() { ); final spriteSheet = SpriteSheet( - image: await images.load('spritesheet.png'), + image: await images.load('assets/spritesheet.png'), srcSize: Vector2.all(tilemapData.tileSize), ); @@ -91,11 +90,10 @@ void main() { 'renders the map correctly', (game, tester) async { final map = await SpriteFusionTilemapComponent.load( - mapJsonFile: 'map.json', - spriteSheetFile: 'spritesheet.png', + mapJsonFile: 'assets/map.json', + spriteSheetFile: 'assets/spritesheet.png', assetBundle: bundle, images: images, - tilemapPrefix: '', ); game.add(map); await game.ready(); @@ -108,11 +106,10 @@ void main() { 'position is respected when rendering', (game, tester) async { final map = await SpriteFusionTilemapComponent.load( - mapJsonFile: 'map.json', - spriteSheetFile: 'spritesheet.png', + mapJsonFile: 'assets/map.json', + spriteSheetFile: 'assets/spritesheet.png', assetBundle: bundle, images: images, - tilemapPrefix: '', position: Vector2(100, 100), ); game.add(map); @@ -126,11 +123,10 @@ void main() { 'anchor is respected when rendering', (game, tester) async { final map = await SpriteFusionTilemapComponent.load( - mapJsonFile: 'map.json', - spriteSheetFile: 'spritesheet.png', + mapJsonFile: 'assets/map.json', + spriteSheetFile: 'assets/spritesheet.png', assetBundle: bundle, images: images, - tilemapPrefix: '', anchor: Anchor.center, ); game.add(map); @@ -144,11 +140,10 @@ void main() { 'scale is respected when rendering', (game, tester) async { final map = await SpriteFusionTilemapComponent.load( - mapJsonFile: 'map.json', - spriteSheetFile: 'spritesheet.png', + mapJsonFile: 'assets/map.json', + spriteSheetFile: 'assets/spritesheet.png', assetBundle: bundle, images: images, - tilemapPrefix: '', scale: Vector2.all(0.5), ); game.add(map); @@ -162,11 +157,10 @@ void main() { 'angle is respected when rendering', (game, tester) async { final map = await SpriteFusionTilemapComponent.load( - mapJsonFile: 'map.json', - spriteSheetFile: 'spritesheet.png', + mapJsonFile: 'assets/map.json', + spriteSheetFile: 'assets/spritesheet.png', assetBundle: bundle, images: images, - tilemapPrefix: '', angle: pi * 0.125, ); game.add(map); diff --git a/packages/flame_sprite_fusion/test/test_asset_bundle.dart b/packages/flame_sprite_fusion/test/test_asset_bundle.dart index fe7ff0e072b..f84cd5d9650 100644 --- a/packages/flame_sprite_fusion/test/test_asset_bundle.dart +++ b/packages/flame_sprite_fusion/test/test_asset_bundle.dart @@ -3,6 +3,11 @@ import 'dart:typed_data'; import 'package:flutter/services.dart' show CachingAssetBundle; +/// An asset bundle that serves the fixtures under `test/assets/`. +/// +/// Keys are full asset paths, exactly as they would be declared in a +/// `pubspec.yaml`, and are mapped onto the fixture directory. For example, +/// `assets/map.json` resolves to `test/assets/map.json`. class TestAssetBundle extends CachingAssetBundle { TestAssetBundle({ required this.imageNames, @@ -12,52 +17,26 @@ class TestAssetBundle extends CachingAssetBundle { final List imageNames; final List stringNames; - @override - Future load(String key) async { - late String imgName; - late String fileName; - if (key.contains('..')) { - final parts = key.split('/'); - - final index = parts.indexOf('..'); - - imgName = parts.sublist(index + 1).join('/'); - - fileName = key.replaceFirst('assets/images/', 'test/assets/'); - } else { - final pattern = RegExp(r'assets/images/(\.\./)*'); - final split = key.split('/'); - imgName = split.isNotEmpty ? key.replaceFirst(pattern, '') : key; - - final toLoadName = key.replaceFirst(pattern, ''); - fileName = 'test/assets/$toLoadName'; - } - - if (!imageNames.contains(imgName)) { + String _resolve(String key, List known) { + final name = key.startsWith('assets/') + ? key.substring('assets/'.length) + : key; + if (!known.contains(name)) { throw StateError( - 'No $fileName found in the TestAssetBundle. Did you forget to add it?', + 'No $key found in the TestAssetBundle. Did you forget to add it?', ); } - return File(fileName).readAsBytes().then( - (bytes) => ByteData.view(Uint8List.fromList(bytes).buffer), - ); + return 'test/assets/$name'; } @override - Future loadString(String key, {bool cache = true}) { - final pattern = RegExp(r'assets/tiles/(\.\./)*'); - final split = key.split('/'); - final mapName = split.isNotEmpty ? key.replaceFirst(pattern, '') : key; - - final toLoadName = key.replaceFirst(pattern, ''); - final fileName = 'test/assets/$toLoadName'; - - if (!stringNames.contains(mapName)) { - throw StateError( - 'No $fileName found in the TestAssetBundle. Did you forget to add it?', - ); - } + Future load(String key) async { + final bytes = await File(_resolve(key, imageNames)).readAsBytes(); + return ByteData.view(Uint8List.fromList(bytes).buffer); + } - return File(fileName).readAsString(); + @override + Future loadString(String key, {bool cache = true}) { + return File(_resolve(key, stringNames)).readAsString(); } } diff --git a/packages/flame_svg/example/lib/main.dart b/packages/flame_svg/example/lib/main.dart index e9f938b6b16..5411151ccc2 100644 --- a/packages/flame_svg/example/lib/main.dart +++ b/packages/flame_svg/example/lib/main.dart @@ -18,7 +18,7 @@ class MyGame extends FlameGame { @override Future onLoad() async { await super.onLoad(); - svgInstance = await loadSvg('android.svg'); + svgInstance = await loadSvg('assets/android.svg'); final android = SvgComponent( svg: svgInstance, position: Vector2.all(100), diff --git a/packages/flame_test/example/lib/game.dart b/packages/flame_test/example/lib/game.dart index 17345008cff..fad6373fb72 100644 --- a/packages/flame_test/example/lib/game.dart +++ b/packages/flame_test/example/lib/game.dart @@ -14,7 +14,7 @@ class MyGameWidget extends StatelessWidget { class Background extends SpriteComponent with HasGameReference { @override Future onLoad() async { - sprite = await game.loadSprite('city.png'); + sprite = await game.loadSprite('assets/images/city.png'); size = Vector2.all(200); position = Vector2.all(100); } diff --git a/packages/flame_texturepacker/example/lib/main.dart b/packages/flame_texturepacker/example/lib/main.dart index 24dce3f9c69..3b493ff2d49 100644 --- a/packages/flame_texturepacker/example/lib/main.dart +++ b/packages/flame_texturepacker/example/lib/main.dart @@ -18,7 +18,7 @@ class MyGame extends FlameGame { super.onLoad(); // Load the atlasMap. - final atlas = await atlasFromAssets('atlas_map.atlas'); + final atlas = await atlasFromAssets('assets/images/atlas_map.atlas'); // Get a list of sprites ordered by their index final walkingSprites = atlas.findSpritesByName('robot_walk'); diff --git a/packages/flame_texturepacker/lib/src/extension_on_game.dart b/packages/flame_texturepacker/lib/src/extension_on_game.dart index 0355e409525..1aa002f42e3 100644 --- a/packages/flame_texturepacker/lib/src/extension_on_game.dart +++ b/packages/flame_texturepacker/lib/src/extension_on_game.dart @@ -3,15 +3,17 @@ import 'package:flame/game.dart'; import 'package:flame_texturepacker/flame_texturepacker.dart'; extension TexturepackerLoader on Game { - /// Loads the specified pack file from assets - /// Uses the parent directory of the pack file to find the page images. + /// Loads the specified pack file from assets. + /// + /// The [assetsPath] is the full path of the atlas, as declared in the + /// `pubspec.yaml`, for example `assets/images/sprites.atlas`. The parent + /// directory of the pack file is used to find the page images. Future atlasFromAssets( String assetsPath, { Images? images, AssetsCache? assets, bool useOriginalSize = true, List whiteList = const [], - String assetsPrefix = 'images', String? package, }) => TexturePackerAtlas.load( assetsPath, @@ -19,7 +21,6 @@ extension TexturepackerLoader on Game { assets: assets ?? this.assets, useOriginalSize: useOriginalSize, whiteList: whiteList, - assetsPrefix: assetsPrefix, package: package, ); diff --git a/packages/flame_texturepacker/lib/src/texture_packer_atlas.dart b/packages/flame_texturepacker/lib/src/texture_packer_atlas.dart index 05e9ee105b1..2eb678de3dd 100644 --- a/packages/flame_texturepacker/lib/src/texture_packer_atlas.dart +++ b/packages/flame_texturepacker/lib/src/texture_packer_atlas.dart @@ -49,11 +49,12 @@ class TexturePackerAtlas { /// Loads a texture atlas from a file path. /// - /// [path] - The path to the atlas file + /// [path] - The full path to the atlas file, as declared in the + /// `pubspec.yaml`, for example `assets/images/sprites.atlas`. + /// Page textures are resolved relative to that path. /// [fromStorage] - Load from device storage (true) or assets (false) /// [useOriginalSize] - Use original sprite dimensions before packing or not. /// [images] - Optional Images cache to use for loading textures - /// [assetsPrefix] - Prefix for asset paths (default: 'images') /// [assets] - Optional AssetsCache to use for loading assets /// [whiteList] - Optional list of sprite names to include. /// If empty, all sprites are included @@ -64,7 +65,6 @@ class TexturePackerAtlas { bool fromStorage = false, bool useOriginalSize = true, Images? images, - String assetsPrefix = 'images', AssetsCache? assets, List whiteList = const [], String? package, @@ -74,7 +74,6 @@ class TexturePackerAtlas { fromStorage: fromStorage, images: images, assets: assets, - assetsPrefix: assetsPrefix, package: package, ); @@ -90,7 +89,6 @@ class TexturePackerAtlas { /// [path] - The path to the atlas file /// [fromStorage] - Load from device storage (true) or assets (false) /// [images] - Optional Images cache to use for loading textures - /// [assetsPrefix] - Prefix for asset paths (default: 'images') /// [assets] - Optional AssetsCache to use for loading assets /// [loadImages] - Whether to load images (default: true) /// @@ -100,7 +98,6 @@ class TexturePackerAtlas { bool fromStorage = false, Images? images, AssetsCache? assets, - String assetsPrefix = 'images', String? package, bool loadImages = true, }) async { @@ -109,7 +106,6 @@ class TexturePackerAtlas { path, fromStorage: fromStorage, assets: assets, - assetsPrefix: assetsPrefix, package: package, ); @@ -120,8 +116,6 @@ class TexturePackerAtlas { fromStorage: fromStorage, images: images, package: package, - assetsPrefix: assetsPrefix, - assets: assets, ); } return atlasData; diff --git a/packages/flame_texturepacker/lib/src/texture_packer_parser.dart b/packages/flame_texturepacker/lib/src/texture_packer_parser.dart index c9fc42aab31..e0eaa34d5c2 100644 --- a/packages/flame_texturepacker/lib/src/texture_packer_parser.dart +++ b/packages/flame_texturepacker/lib/src/texture_packer_parser.dart @@ -14,11 +14,13 @@ typedef TextureAtlasData = ({List pages, List regions}); /// Internal parser for TexturePacker atlas files. abstract class TexturePackerParser { /// Parses structural data of a texture atlas file. + /// + /// The [path] is the full path of the atlas, as declared in the + /// `pubspec.yaml`, for example `assets/images/sprites.atlas`. static Future parseAtlasMetadata( String path, { required bool fromStorage, AssetsCache? assets, - String? assetsPrefix, String? package, }) async { final pages = []; @@ -28,28 +30,9 @@ abstract class TexturePackerParser { if (fromStorage) { fileContent = await XFile(path).readAsString(); } else { - final assetsCache = assets ?? Flame.assets; - final prefix = (assetsPrefix ?? '').trim(); - final cleanPath = path.trim().replaceFirst(RegExp('^/'), ''); - - var fullPath = cleanPath; - if (prefix.isNotEmpty && - !cleanPath.contains('packages/') && - !cleanPath.startsWith('assets/')) { - final effectivePrefix = prefix.endsWith('/') ? prefix : '$prefix/'; - if (!cleanPath.startsWith(effectivePrefix)) { - fullPath = '$effectivePrefix$cleanPath'; - } - } - - final resolved = resolvePath(fullPath, package); - final finalPath = resolved.path.startsWith(assetsCache.prefix) - ? resolved.path.substring(assetsCache.prefix.length) - : resolved.path; - - fileContent = await assetsCache.readFile( - finalPath, - package: resolved.package, + fileContent = await (assets ?? Flame.assets).readFile( + path, + package: package, ); } @@ -106,19 +89,19 @@ abstract class TexturePackerParser { } /// Loads images for all pages in the given atlas data. + /// + /// Page textures are resolved relative to the directory of [path]. static Future loadAtlasDataImages( TextureAtlasData atlasData, String path, { required bool fromStorage, Images? images, String? package, - String? assetsPrefix, - AssetsCache? assets, }) async { final img = images ?? Flame.images; for (final page in atlasData.pages) { final parentPath = (path.split('/')..removeLast()).join('/'); - var texturePath = parentPath.isEmpty + final texturePath = parentPath.isEmpty ? page.textureFile : '$parentPath/${page.textureFile}'; @@ -128,36 +111,7 @@ abstract class TexturePackerParser { img.add(texturePath, image); page.texture = img.fromCache(texturePath); } else { - final prefix = (assetsPrefix ?? '').trim(); - if (prefix.isNotEmpty && - !texturePath.contains('packages/') && - !texturePath.startsWith('assets/')) { - final effectivePrefix = prefix.endsWith('/') ? prefix : '$prefix/'; - if (!texturePath.startsWith(effectivePrefix)) { - texturePath = '$effectivePrefix$texturePath'; - } - } - - final resolved = resolvePath(texturePath, package); - final assetsCachePrefix = (assets ?? Flame.assets).prefix; - - String toRelative(String p) => p.startsWith(assetsCachePrefix) - ? p.substring(assetsCachePrefix.length) - : p; - - final relativePath = toRelative(resolved.path); - final relativePrefix = toRelative(img.prefix); - - final finalTexturePath = - (relativePrefix.isNotEmpty && - relativePath.startsWith(relativePrefix)) - ? relativePath.substring(relativePrefix.length) - : relativePath; - - page.texture = await img.load( - finalTexturePath, - package: resolved.package, - ); + page.texture = await img.load(texturePath, package: package); } } } @@ -305,25 +259,6 @@ abstract class TexturePackerParser { return imageExtensions.any(trimmed.endsWith); } - static ({String path, String? package}) resolvePath( - String path, - String? package, - ) { - const pkg = 'packages/'; - final index = path.indexOf(pkg); - if (index != -1) { - final subPath = path.substring(index + pkg.length); - final segments = subPath.split('/'); - if (segments.length > 1) { - return ( - path: segments.sublist(1).join('/'), - package: package ?? segments[0], - ); - } - } - return (path: path, package: package); - } - static int _parseDegrees(String? value) { if (value == null) { return 0; diff --git a/packages/flame_texturepacker/test/atlas_path_resolution_test.dart b/packages/flame_texturepacker/test/atlas_path_resolution_test.dart index bbab123140e..ef818330a23 100644 --- a/packages/flame_texturepacker/test/atlas_path_resolution_test.dart +++ b/packages/flame_texturepacker/test/atlas_path_resolution_test.dart @@ -44,76 +44,95 @@ sprite1 when( () => images.load(any(), package: any(named: 'package')), ).thenAnswer((_) async => FakeImage()); - - when(() => images.prefix).thenReturn('assets/images/'); }); - test('should resolve paths correctly with leading slashes', () async { + test('loads the atlas from the path exactly as given', () async { final assets = AssetsCache(bundle: bundle); await TexturePackerAtlas.load( - '/path/to/atlas_name.atlas', + 'assets/images/atlas_name.atlas', assets: assets, images: images, ); - // Verify it tried to load 'images/path/to/atlas.atlas' - // The leading slash in /path/to/atlas.atlas should be removed. verify( () => bundle.loadString( - 'assets/images/path/to/atlas_name.atlas', + 'assets/images/atlas_name.atlas', cache: any(named: 'cache'), ), ).called(1); }); - test('should handle assetsPrefix WITH trailing slash', () async { + test('resolves page textures relative to the atlas directory', () async { final assets = AssetsCache(bundle: bundle); await TexturePackerAtlas.load( - 'atlas_name.atlas', - assetsPrefix: 'custom/', + 'assets/atlases/atlas_name.atlas', assets: assets, images: images, ); verify( - () => bundle.loadString( - 'assets/custom/atlas_name.atlas', - cache: any(named: 'cache'), + () => images.load( + 'assets/atlases/test.png', + package: any(named: 'package'), ), ).called(1); }); - test('should handle assetsPrefix WITHOUT trailing slash', () async { + test('resolves a page texture with no atlas directory', () async { final assets = AssetsCache(bundle: bundle); await TexturePackerAtlas.load( 'atlas_name.atlas', - assetsPrefix: 'custom', assets: assets, images: images, ); verify( - () => bundle.loadString( - 'assets/custom/atlas_name.atlas', - cache: any(named: 'cache'), + () => images.load('test.png', package: any(named: 'package')), + ).called(1); + }); + + test('honours a relative page texture path literally', () async { + final assets = AssetsCache(bundle: bundle); + const nestedAtlasContent = ''' +pages/test.png +size: 64, 64 +filter: Nearest, Nearest +repeat: none +sprite1 + bounds: 0, 0, 32, 32 +'''; + + when( + () => bundle.loadString(any(), cache: any(named: 'cache')), + ).thenAnswer((_) async => nestedAtlasContent); + + await TexturePackerAtlas.load( + 'assets/images/atlas_name.atlas', + assets: assets, + images: images, + ); + + verify( + () => images.load( + 'assets/images/pages/test.png', + package: any(named: 'package'), ), ).called(1); }); - test('should pass package parameter to AssetsCache and Images', () async { + test('passes the package through to both caches', () async { final assets = AssetsCache(bundle: bundle); await TexturePackerAtlas.load( - 'atlas_name.atlas', + 'assets/images/atlas_name.atlas', assets: assets, images: images, package: 'my_package', ); - // Verify bundle call includes the package-prefixed path verify( () => bundle.loadString( 'packages/my_package/assets/images/atlas_name.atlas', @@ -121,88 +140,37 @@ sprite1 ), ).called(1); - // Verify images.load call also includes the package verify( - () => images.load('test.png', package: 'my_package'), + () => images.load( + 'assets/images/test.png', + package: 'my_package', + ), ).called(1); }); - test( - 'should auto-detect package from path if package parameter is null', - () async { - final assets = AssetsCache(bundle: bundle); - - await TexturePackerAtlas.load( - 'packages/custom_package/assets/images/atlas_name.atlas', - assets: assets, - images: images, - ); - - // Verify bundle call extracted 'custom_package' and cleaned the path - verify( - () => bundle.loadString( - 'packages/custom_package/assets/images/atlas_name.atlas', - cache: any(named: 'cache'), - ), - ).called(1); - - // Verify images.load also uses the extracted package - verify( - () => images.load('test.png', package: 'custom_package'), - ).called(1); - }, - ); - - test( - 'should load correctly when full assets/ path is provided with empty prefix', - () async { - final assets = AssetsCache(bundle: bundle); - - await TexturePackerAtlas.load( - 'assets/images/atlas_name.atlas', - assetsPrefix: '', - assets: assets, - images: images, - ); - - verify( - () => bundle.loadString( - 'assets/images/atlas_name.atlas', - cache: any(named: 'cache'), - ), - ).called(1); - }, - ); - - test( - 'should handle redundant images/ prefix in atlas file for page images', - () async { - final assets = AssetsCache(bundle: bundle); - const redundantAtlasContent = ''' -images/test.png -size: 64, 64 -filter: Nearest, Nearest -repeat: none -sprite1 - bounds: 0, 0, 32, 32 -'''; + test('loads a path that already points inside a package', () async { + final assets = AssetsCache(bundle: bundle); - when( - () => bundle.loadString(any(), cache: any(named: 'cache')), - ).thenAnswer((_) async => redundantAtlasContent); + await TexturePackerAtlas.load( + 'packages/custom_package/assets/images/atlas_name.atlas', + assets: assets, + images: images, + ); - await TexturePackerAtlas.load( - 'atlas_name.atlas', - assets: assets, - images: images, - ); + verify( + () => bundle.loadString( + 'packages/custom_package/assets/images/atlas_name.atlas', + cache: any(named: 'cache'), + ), + ).called(1); - // Verify images.load call strips the redundant 'images/' from inside the atlas - verify( - () => images.load('test.png', package: any(named: 'package')), - ).called(1); - }, - ); + verify( + () => images.load( + 'packages/custom_package/assets/images/test.png', + package: any(named: 'package'), + ), + ).called(1); + }); test( 'should correctly parse region names with .png and extracted indexes', @@ -224,7 +192,7 @@ knight_walk_02.png ).thenAnswer((_) async => complexAtlasContent); final atlas = await TexturePackerAtlas.load( - 'knight.atlas', + 'assets/images/knight.atlas', assets: assets, images: images, ); diff --git a/packages/flame_texturepacker/test/flame_texturepacker_test.dart b/packages/flame_texturepacker/test/flame_texturepacker_test.dart index fb3c06e5a9f..83c3ccc34b8 100644 --- a/packages/flame_texturepacker/test/flame_texturepacker_test.dart +++ b/packages/flame_texturepacker/test/flame_texturepacker_test.dart @@ -44,8 +44,8 @@ void main() { ); final flameGame = FlameGame() - ..assets = AssetsCache(bundle: bundle, prefix: '') - ..images = Images(bundle: bundle, prefix: ''); + ..assets = AssetsCache(bundle: bundle) + ..images = Images(bundle: bundle); final atlas = await flameGame.atlasFromAssets(atlasPath); diff --git a/packages/flame_tiled/example/lib/main.dart b/packages/flame_tiled/example/lib/main.dart index 5474d03d025..c0f11456a65 100644 --- a/packages/flame_tiled/example/lib/main.dart +++ b/packages/flame_tiled/example/lib/main.dart @@ -36,13 +36,16 @@ class TiledGame extends FlameGame { ), ); - mapComponent = await TiledComponent.load('map.tmx', Vector2.all(16)); + mapComponent = await TiledComponent.load( + 'assets/tiles/map.tmx', + Vector2.all(16), + ); world.add(mapComponent); final objectGroup = mapComponent.tileMap.getLayer( 'AnimatedCoins', ); - final coins = await Flame.images.load('coins.png'); + final coins = await Flame.images.load('assets/images/coins.png'); // We are 100% sure that an object layer named `AnimatedCoins` // exists in the example `map.tmx`. diff --git a/packages/flame_tiled/lib/src/flame_tsx_provider.dart b/packages/flame_tiled/lib/src/flame_tsx_provider.dart index d9d4f710b6a..a84571ec255 100644 --- a/packages/flame_tiled/lib/src/flame_tsx_provider.dart +++ b/packages/flame_tiled/lib/src/flame_tsx_provider.dart @@ -35,13 +35,14 @@ class FlameTsxProvider implements TsxProvider { /// Parses a file returning a [FlameTsxProvider]. /// - /// {@macro renderable_tile_prefix_path} + /// The [key] is resolved against [tsxDirectory], which is the directory of + /// the map that references this tileset. static Future parse( String key, [ AssetBundle? bundle, - String prefix = 'assets/tiles/', + String tsxDirectory = '', ]) async { - final data = await (bundle ?? Flame.bundle).loadString('$prefix$key'); + final data = await (bundle ?? Flame.bundle).loadString('$tsxDirectory$key'); return FlameTsxProvider._(data, key); } } diff --git a/packages/flame_tiled/lib/src/renderable_layers/image_layer.dart b/packages/flame_tiled/lib/src/renderable_layers/image_layer.dart index 93db866cf98..26b4d35d172 100644 --- a/packages/flame_tiled/lib/src/renderable_layers/image_layer.dart +++ b/packages/flame_tiled/lib/src/renderable_layers/image_layer.dart @@ -121,6 +121,7 @@ class FlameImageLayer extends RenderableLayer { FilterQuality? filterQuality, Images? images, String? package, + String imagesDirectory = 'assets/images/', }) async { return FlameImageLayer( layer: layer, @@ -129,7 +130,7 @@ class FlameImageLayer extends RenderableLayer { destTileSize: destTileSize, filterQuality: filterQuality, image: await (images ?? Flame.images).load( - layer.image.source!, + '$imagesDirectory${layer.image.source!}', package: package, ), ); diff --git a/packages/flame_tiled/lib/src/renderable_layers/renderable_layer.dart b/packages/flame_tiled/lib/src/renderable_layers/renderable_layer.dart index dfeaea2a1ae..7ac69a5be02 100644 --- a/packages/flame_tiled/lib/src/renderable_layers/renderable_layer.dart +++ b/packages/flame_tiled/lib/src/renderable_layers/renderable_layer.dart @@ -46,6 +46,7 @@ abstract class RenderableLayer { bool? ignoreFlip, Images? images, String? package, + String imagesDirectory = 'assets/images/', }) async { if (layer is TileLayer) { return FlameTileLayer.load( @@ -69,6 +70,7 @@ abstract class RenderableLayer { filterQuality: filterQuality, images: images, package: package, + imagesDirectory: imagesDirectory, ); } else if (layer is ObjectGroup) { return ObjectLayer.load( diff --git a/packages/flame_tiled/lib/src/renderable_tile_map.dart b/packages/flame_tiled/lib/src/renderable_tile_map.dart index 9205be78a49..d0a21e77e93 100644 --- a/packages/flame_tiled/lib/src/renderable_tile_map.dart +++ b/packages/flame_tiled/lib/src/renderable_tile_map.dart @@ -250,9 +250,15 @@ class RenderableTiledMap { /// Parses a file returning a [RenderableTiledMap]. /// - /// {@template renderable_tile_prefix_path} - /// This method looks for files under the path "assets/tiles/" by default. - /// This can be changed by providing a different path to [prefix]. + /// {@template renderable_tile_map_path} + /// The [fileName] is the full path of the map, as declared in the + /// `pubspec.yaml`, for example `assets/tiles/map.tmx`. Any external `.tsx` + /// tileset the map references is resolved relative to that path. + /// {@endtemplate} + /// + /// {@template tiled_images_directory} + /// Tileset and image-layer sources are resolved against [imagesDirectory], + /// which defaults to `assets/images/`. /// {@endtemplate} /// /// {@template renderable_tile_map_factory} @@ -264,7 +270,6 @@ class RenderableTiledMap { Vector2 destTileSize, { double? atlasMaxX, double? atlasMaxY, - String prefix = 'assets/tiles/', CameraComponent? camera, bool? ignoreFlip, Images? images, @@ -275,22 +280,17 @@ class RenderableTiledMap { double atlasPackingSpacingX = 0, double atlasPackingSpacingY = 0, String? package, + String imagesDirectory = 'assets/images/', }) async { - assert( - !fileName.contains(RegExp(r'[/\\]')), - 'fileName should not contain path separators, use prefix to specify a ' - 'path.', - ); - final fullPrefix = package == null ? prefix : 'packages/$package/$prefix'; - final contents = await (bundle ?? Flame.bundle).loadString( - '$fullPrefix$fileName', - ); + final mapPath = package == null ? fileName : 'packages/$package/$fileName'; + final contents = await (bundle ?? Flame.bundle).loadString(mapPath); return fromString( contents, destTileSize, atlasMaxX: atlasMaxX, atlasMaxY: atlasMaxY, - prefix: fullPrefix, + tsxDirectory: mapPath.substring(0, mapPath.lastIndexOf('/') + 1), + imagesDirectory: imagesDirectory, camera: camera, ignoreFlip: ignoreFlip, images: images, @@ -306,7 +306,10 @@ class RenderableTiledMap { /// Parses a string returning a [RenderableTiledMap]. /// - /// {@macro renderable_tile_prefix_path} + /// External `.tsx` tilesets the map references are resolved against + /// [tsxDirectory]. + /// + /// {@macro tiled_images_directory} /// /// {@macro renderable_tile_map_factory} static Future fromString( @@ -314,7 +317,8 @@ class RenderableTiledMap { Vector2 destTileSize, { double? atlasMaxX, double? atlasMaxY, - String prefix = 'assets/tiles/', + String tsxDirectory = '', + String imagesDirectory = 'assets/images/', CameraComponent? camera, bool? ignoreFlip, Images? images, @@ -328,13 +332,14 @@ class RenderableTiledMap { }) async { final map = await TiledMap.fromString( contents, - (key) => FlameTsxProvider.parse(key, bundle, prefix), + (key) => FlameTsxProvider.parse(key, bundle, tsxDirectory), ); return fromTiledMap( map, destTileSize, atlasMaxX: atlasMaxX, atlasMaxY: atlasMaxY, + imagesDirectory: imagesDirectory, camera: camera, ignoreFlip: ignoreFlip, images: images, @@ -350,12 +355,15 @@ class RenderableTiledMap { /// Parses a [TiledMap] returning a [RenderableTiledMap]. /// + /// {@macro tiled_images_directory} + /// /// {@macro renderable_tile_map_factory} static Future fromTiledMap( TiledMap map, Vector2 destTileSize, { double? atlasMaxX, double? atlasMaxY, + String imagesDirectory = 'assets/images/', CameraComponent? camera, bool? ignoreFlip, Images? images, @@ -393,11 +401,13 @@ class RenderableTiledMap { spacingX: atlasPackingSpacingX, spacingY: atlasPackingSpacingY, package: package, + imagesDirectory: imagesDirectory, ), ignoreFlip: ignoreFlip, images: images, layerPaintFactory: layerPaintFactory ?? _defaultLayerPaintFactory, package: package, + imagesDirectory: imagesDirectory, ); return RenderableTiledMap( @@ -421,6 +431,7 @@ class RenderableTiledMap { bool? ignoreFlip, Images? images, String? package, + String imagesDirectory = 'assets/images/', }) { final visibleLayers = layers.where((layer) => layer.visible); @@ -437,6 +448,7 @@ class RenderableTiledMap { images: images, layerPaintFactory: layerPaintFactory, package: package, + imagesDirectory: imagesDirectory, ); if (layer is Group && renderableLayer is GroupLayer) { @@ -452,6 +464,7 @@ class RenderableTiledMap { images: images, layerPaintFactory: layerPaintFactory, package: package, + imagesDirectory: imagesDirectory, ); } diff --git a/packages/flame_tiled/lib/src/tile_atlas.dart b/packages/flame_tiled/lib/src/tile_atlas.dart index 3ee78920a6d..5c445f03aa4 100644 --- a/packages/flame_tiled/lib/src/tile_atlas.dart +++ b/packages/flame_tiled/lib/src/tile_atlas.dart @@ -104,6 +104,8 @@ class TiledAtlas { } /// Loads all the tileset images for the [map] into one [TiledAtlas]. + /// + /// {@macro tiled_images_directory} static Future fromTiledMap( TiledMap map, { double? maxX, @@ -114,6 +116,7 @@ class TiledAtlas { double spacingX = 0, double spacingY = 0, String? package, + String imagesDirectory = 'assets/images/', }) async { final tilesetImageList = _onlyTileImages( map, @@ -125,21 +128,19 @@ class TiledAtlas { var tileImageSource = tiledImage.source!; final tilesetSource = entry.$1; - if (tilesetSource == null) { - return (tileImageSource, tiledImage); - } - - final tilesetParts = tilesetSource.split('/'); - final imageParts = tileImageSource.split('/'); + if (tilesetSource != null) { + final tilesetParts = tilesetSource.split('/'); + final imageParts = tileImageSource.split('/'); - if (tilesetParts.length != imageParts.length) { - tileImageSource = [ - ...tilesetParts.sublist(0, tilesetParts.length - 1), - ...imageParts, - ].join('/'); + if (tilesetParts.length != imageParts.length) { + tileImageSource = [ + ...tilesetParts.sublist(0, tilesetParts.length - 1), + ...imageParts, + ].join('/'); + } } - return (tileImageSource, tiledImage); + return ('$imagesDirectory$tileImageSource', tiledImage); }); if (mappedImageList.isEmpty) { @@ -156,7 +157,7 @@ class TiledAtlas { final imageList = mappedImageList.map((e) => e.$2).toList(); - final key = atlasKey(imageList); + final key = '$imagesDirectory${atlasKey(imageList)}'; if (atlasMap.containsKey(key)) { return atlasMap[key]!.clone(); } diff --git a/packages/flame_tiled/lib/src/tiled_component.dart b/packages/flame_tiled/lib/src/tiled_component.dart index f284c1611ae..d923d22cb68 100644 --- a/packages/flame_tiled/lib/src/tiled_component.dart +++ b/packages/flame_tiled/lib/src/tiled_component.dart @@ -91,7 +91,9 @@ class TiledComponent extends PositionComponent /// Loads a [TiledComponent] from a file. /// - /// {@macro renderable_tile_prefix_path} + /// {@macro renderable_tile_map_path} + /// + /// {@macro tiled_images_directory} /// /// By default, [RenderableTiledMap] renders flipped tiles if they exist. /// You can disable it by passing [ignoreFlip] as `true`. @@ -109,7 +111,6 @@ class TiledComponent extends PositionComponent Vector2 destTileSize, { double? atlasMaxX, double? atlasMaxY, - String prefix = 'assets/tiles/', int? priority, bool? ignoreFlip, AssetBundle? bundle, @@ -121,6 +122,7 @@ class TiledComponent extends PositionComponent double atlasPackingSpacingY = 0, ComponentKey? key, String? package, + String imagesDirectory = 'assets/images/', }) async { return TiledComponent( await RenderableTiledMap.fromFile( @@ -129,7 +131,6 @@ class TiledComponent extends PositionComponent atlasMaxX: atlasMaxX, atlasMaxY: atlasMaxY, ignoreFlip: ignoreFlip, - prefix: prefix, bundle: bundle, images: images, tsxPackingFilter: tsxPackingFilter, @@ -138,6 +139,7 @@ class TiledComponent extends PositionComponent atlasPackingSpacingX: atlasPackingSpacingX, atlasPackingSpacingY: atlasPackingSpacingY, package: package, + imagesDirectory: imagesDirectory, ), priority: priority, key: key, diff --git a/packages/flame_tiled/test/image_layer_test.dart b/packages/flame_tiled/test/image_layer_test.dart index 47ff28d78ab..8eb902b041f 100644 --- a/packages/flame_tiled/test/image_layer_test.dart +++ b/packages/flame_tiled/test/image_layer_test.dart @@ -26,7 +26,7 @@ void main() { ); final component = await TiledComponent.load( - 'image_layer_full_screen.tmx', + 'assets/tiles/image_layer_full_screen.tmx', Vector2.all(16), bundle: bundle, images: Images(bundle: bundle), diff --git a/packages/flame_tiled/test/test_asset_bundle.dart b/packages/flame_tiled/test/test_asset_bundle.dart index fe7ff0e072b..0ef82f48389 100644 --- a/packages/flame_tiled/test/test_asset_bundle.dart +++ b/packages/flame_tiled/test/test_asset_bundle.dart @@ -3,6 +3,13 @@ import 'dart:typed_data'; import 'package:flutter/services.dart' show CachingAssetBundle; +/// An asset bundle that serves the fixtures under `test/assets/`. +/// +/// Keys are full asset paths, exactly as they would be declared in a +/// `pubspec.yaml`, and are mapped onto the fixture directory. Both +/// `assets/images/map.png` and `assets/tiles/map.tmx` resolve to +/// `test/assets/...`, so fixtures can be laid out flat regardless of the +/// directory a test addresses them through. class TestAssetBundle extends CachingAssetBundle { TestAssetBundle({ required this.imageNames, @@ -12,52 +19,48 @@ class TestAssetBundle extends CachingAssetBundle { final List imageNames; final List stringNames; - @override - Future load(String key) async { - late String imgName; - late String fileName; - if (key.contains('..')) { - final parts = key.split('/'); - - final index = parts.indexOf('..'); - - imgName = parts.sublist(index + 1).join('/'); - - fileName = key.replaceFirst('assets/images/', 'test/assets/'); - } else { - final pattern = RegExp(r'assets/images/(\.\./)*'); - final split = key.split('/'); - imgName = split.isNotEmpty ? key.replaceFirst(pattern, '') : key; + static const _roots = ['assets/images/', 'assets/tiles/', 'assets/']; - final toLoadName = key.replaceFirst(pattern, ''); - fileName = 'test/assets/$toLoadName'; + /// Collapses `..` segments, the way a real asset layout would already have + /// them resolved. Tiled writes tileset image sources relative to the `.tsx` + /// file, so `tiles/../images/green.png` is normal and must land on + /// `images/green.png`. + static String _normalize(String path) { + final segments = []; + for (final segment in path.split('/')) { + if (segment == '..' && segments.isNotEmpty && segments.last != '..') { + segments.removeLast(); + } else if (segment != '.') { + segments.add(segment); + } } + return segments.join('/'); + } - if (!imageNames.contains(imgName)) { + String _resolve(String key, List known) { + var name = _normalize(key); + for (final root in _roots) { + if (name.startsWith(root)) { + name = name.substring(root.length); + break; + } + } + if (!known.contains(name)) { throw StateError( - 'No $fileName found in the TestAssetBundle. Did you forget to add it?', + 'No $key found in the TestAssetBundle. Did you forget to add it?', ); } - return File(fileName).readAsBytes().then( - (bytes) => ByteData.view(Uint8List.fromList(bytes).buffer), - ); + return 'test/assets/$name'; } @override - Future loadString(String key, {bool cache = true}) { - final pattern = RegExp(r'assets/tiles/(\.\./)*'); - final split = key.split('/'); - final mapName = split.isNotEmpty ? key.replaceFirst(pattern, '') : key; - - final toLoadName = key.replaceFirst(pattern, ''); - final fileName = 'test/assets/$toLoadName'; - - if (!stringNames.contains(mapName)) { - throw StateError( - 'No $fileName found in the TestAssetBundle. Did you forget to add it?', - ); - } + Future load(String key) async { + final bytes = await File(_resolve(key, imageNames)).readAsBytes(); + return ByteData.view(Uint8List.fromList(bytes).buffer); + } - return File(fileName).readAsString(); + @override + Future loadString(String key, {bool cache = true}) { + return File(_resolve(key, stringNames)).readAsString(); } } diff --git a/packages/flame_tiled/test/tile_atlas_test.dart b/packages/flame_tiled/test/tile_atlas_test.dart index 9d623324cb8..934fbdb993b 100644 --- a/packages/flame_tiled/test/tile_atlas_test.dart +++ b/packages/flame_tiled/test/tile_atlas_test.dart @@ -111,9 +111,12 @@ void main() { expect(atlas.atlas, isNotNull); expect(atlas.atlas!.width, 128); expect(atlas.atlas!.height, 74); - expect(atlas.key, 'images/green.png'); + expect(atlas.key, 'assets/images/images/green.png'); - expect(images.containsKey('images/green.png'), isTrue); + expect( + images.containsKey('assets/images/images/green.png'), + isTrue, + ); expect(images.keys, hasLength(1)); expect( @@ -133,7 +136,7 @@ void main() { expect(atlas.offsets, hasLength(1)); expect(atlas.atlas, isNotNull); - expect(atlas.key, '../images/green.png'); + expect(atlas.key, 'assets/images/../images/green.png'); }, ); @@ -154,7 +157,7 @@ void main() { test('packs complex maps with multiple images', () async { final component = await TiledComponent.load( - 'isometric_plain.tmx', + 'assets/tiles/isometric_plain.tmx', Vector2(128, 74), bundle: bundle, images: Images(bundle: bundle), @@ -175,7 +178,7 @@ void main() { 'packs complex maps with multiple images using a custom spacing', () async { final component = await TiledComponent.load( - 'isometric_plain.tmx', + 'assets/tiles/isometric_plain.tmx', Vector2(128, 74), bundle: bundle, images: Images(bundle: bundle), @@ -199,7 +202,7 @@ void main() { test('can ignore tilesets in the packing', () async { await TiledComponent.load( - 'isometric_plain.tmx', + 'assets/tiles/isometric_plain.tmx', Vector2(128, 74), bundle: bundle, images: Images(bundle: bundle), @@ -248,13 +251,13 @@ void main() { () async { final components = await Future.wait([ TiledComponent.load( - 'single_tile_map_1.tmx', + 'assets/tiles/single_tile_map_1.tmx', Vector2(16, 16), bundle: bundle, images: Images(bundle: bundle), ), TiledComponent.load( - 'single_tile_map_2.tmx', + 'assets/tiles/single_tile_map_2.tmx', Vector2(16, 16), bundle: bundle, images: Images(bundle: bundle), diff --git a/packages/flame_tiled/test/tiled_test.dart b/packages/flame_tiled/test/tiled_test.dart index dae06c636d9..1cd47514ea2 100644 --- a/packages/flame_tiled/test/tiled_test.dart +++ b/packages/flame_tiled/test/tiled_test.dart @@ -35,7 +35,7 @@ void main() { stringNames: ['map.tmx', 'tiles_custom_path/map_custom_path.tmx'], ); tiled = await TiledComponent.load( - 'map.tmx', + 'assets/tiles/map.tmx', Vector2.all(16), key: ComponentKey.named('test'), ); @@ -48,29 +48,18 @@ void main() { test('component atlases returns the loaded atlases', () { final atlases = tiled.atlases(); expect(atlases, hasLength(1)); - expect(atlases.first.$1, equals('map-level1.png')); + expect(atlases.first.$1, equals('assets/images/map-level1.png')); }); - test('correct loads the file, with different prefix', () async { + test('correct loads the file, from a nested directory', () async { tiled = await TiledComponent.load( - 'map_custom_path.tmx', + 'assets/tiles/tiles_custom_path/map_custom_path.tmx', Vector2.all(16), - prefix: 'assets/tiles/tiles_custom_path/', ); expect(tiled.tileMap.renderableLayers.length, equals(3)); }); - test('throws assertion error if fileName contains a path', () async { - expectLater( - TiledComponent.load( - 'path/to/map.tmx', - Vector2.all(16), - ), - throwsAssertionError, - ); - }); - test('assigns key', () async { expect(tiled.key, equals(ComponentKey.named('test'))); }); @@ -149,7 +138,6 @@ void main() { ], ); - // TestAssetBundle strips assets/tiles/ from the prefix. final tsxProvider = await FlameTsxProvider.parse( 'external_tileset_custom_path.tsx', Flame.bundle, @@ -183,7 +171,7 @@ void main() { stringNames: ['2_tiles-green_on_red.tmx'], ); overlapMap = await RenderableTiledMap.fromFile( - '2_tiles-green_on_red.tmx', + 'assets/tiles/2_tiles-green_on_red.tmx', Vector2.all(16), bundle: bundle, images: Images(bundle: bundle), @@ -285,7 +273,7 @@ void main() { stringNames: ['8_tiles-flips.tmx'], ); overlapMap = await RenderableTiledMap.fromFile( - '8_tiles-flips.tmx', + 'assets/tiles/8_tiles-flips.tmx', Vector2.all(16), bundle: bundle, images: Images(bundle: bundle), @@ -397,7 +385,7 @@ void main() { ); final tiledComponent = TiledComponent( await RenderableTiledMap.fromFile( - '8_tiles-flips.tmx', + 'assets/tiles/8_tiles-flips.tmx', Vector2.all(16), ignoreFlip: ignoreFlip, bundle: bundle, @@ -442,7 +430,7 @@ void main() { stringNames: ['layers_test.tmx'], ); renderableTiledMap = await RenderableTiledMap.fromFile( - 'layers_test.tmx', + 'assets/tiles/layers_test.tmx', Vector2.all(32), bundle: Flame.bundle, ); @@ -497,7 +485,7 @@ void main() { stringNames: ['map.tmx'], ); component = await TiledComponent.load( - 'map.tmx', + 'assets/tiles/map.tmx', Vector2(16, 16), bundle: Flame.bundle, ); @@ -542,7 +530,7 @@ void main() { stringNames: ['test_isometric.tmx'], ); component = await TiledComponent.load( - 'test_isometric.tmx', + 'assets/tiles/test_isometric.tmx', Vector2(256 / 4, 128 / 4), bundle: bundle, images: Images(bundle: bundle), @@ -840,7 +828,7 @@ void main() { stringNames: ['test_shifted.tmx'], ); component = await TiledComponent.load( - 'test_shifted.tmx', + 'assets/tiles/test_shifted.tmx', destTileSize, bundle: bundle, images: Images(bundle: bundle), @@ -892,7 +880,7 @@ void main() { stringNames: ['test_isometric.tmx'], ); component = await TiledComponent.load( - 'test_isometric.tmx', + 'assets/tiles/test_isometric.tmx', size, bundle: bundle, images: Images(bundle: bundle), @@ -963,7 +951,7 @@ void main() { stringNames: ['dungeon_animation_$mapType.tmx'], ); component = await TiledComponent.load( - 'dungeon_animation_$mapType.tmx', + 'assets/tiles/dungeon_animation_$mapType.tmx', size, bundle: bundle, images: Images(bundle: bundle), @@ -1091,7 +1079,7 @@ void main() { stringNames: ['oversized_tiles_$mapType.tmx'], ); component = await TiledComponent.load( - 'oversized_tiles_$mapType.tmx', + 'assets/tiles/oversized_tiles_$mapType.tmx', size, bundle: bundle, images: Images(bundle: bundle), @@ -1118,7 +1106,7 @@ void main() { stringNames: ['deleted_layer_map.tmx'], ); renderableTiledMap = await RenderableTiledMap.fromFile( - 'deleted_layer_map.tmx', + 'assets/tiles/deleted_layer_map.tmx', Vector2.all(16), bundle: bundle, images: Images(bundle: bundle), @@ -1152,7 +1140,7 @@ void main() { stringNames: ['layers_test.tmx'], ); renderableTiledMap = await RenderableTiledMap.fromFile( - 'layers_test.tmx', + 'assets/tiles/layers_test.tmx', Vector2.all(32), bundle: Flame.bundle, ); @@ -1205,7 +1193,7 @@ void main() { stringNames: ['map.tmx'], ); renderableTiledMap = await RenderableTiledMap.fromFile( - 'map.tmx', + 'assets/tiles/map.tmx', Vector2.all(16), bundle: Flame.bundle, );