Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ dependencies:
```

## Usage


### Asset Storage

Drop generated atlas file and sprite sheet images into the `assets/` and link the files in your `pubspec.yaml` file:

```yaml
Expand All @@ -31,6 +33,16 @@ Load the TextureAtlas passing the path of the sprite sheet atlas file:
final atlas = await fromAtlas('FlameAtlasMap.atlas');
```

### File Storage

If you are using file storage, grab your atlas file like this:

```Dart
final atlas = await fromAtlas("${(await getApplicationDocumentsDirectory()).path}/FlamAtlasMap.atlas", fromStorage: true);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
final atlas = await fromAtlas("${(await getApplicationDocumentsDirectory()).path}/FlamAtlasMap.atlas", fromStorage: true);
final atlas = await fromAtlas("${(await getApplicationDocumentsDirectory()).path}/FlameAtlasMap.atlas", fromStorage: true);

```

### Getting Sprites

Get a list of sprites ordered by their index, you can use the list to generate an animation:

```Dart
Expand All @@ -51,6 +63,13 @@ final fallSprite = atlas.findSpriteByName('robot_fall')!;
final idleSprite = atlas.findSpriteByName('robot_idle')!;
```

Get a single sprite or list of sprites by keyword:

```Dart
final jumpSprites = atlas.findSpritesByKeyword('robot_jump')!;
final fallSprite = atlas.findSpriteByKeyword('robot_fall')!;
```

Full working example can be found in [example folder][3].

Note: Sprites used in this example can be found OpenGameArt [here][4].
Expand Down
68 changes: 64 additions & 4 deletions lib/atlas/texture_atlas.dart
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
library flame_texturepacker;

import 'dart:convert';
import 'dart:io';

import 'package:flame/cache.dart';
import 'package:flame/flame.dart';
import 'package:flame_texturepacker/atlas/model/page.dart';
import 'package:flame_texturepacker/atlas/model/region.dart';
import 'package:flame_texturepacker/atlas/model/atlas_sprite.dart';
import 'package:collection/collection.dart';
import 'package:flutter/painting.dart';

final _images = Images(prefix: 'assets/');

Expand All @@ -19,6 +21,11 @@ class TextureAtlas {
AtlasSprite? findSpriteByName(String name) =>
sprites.firstWhereOrNull((e) => e.name == name);

/// Returns first region found where name matches keyword. This method uses string comparison to find
/// the region, so the result should be cached rather than calling this method multiple times.
AtlasSprite? findSpriteByKeyword(String keyword) =>
sprites.firstWhereOrNull((e) => e.name.contains(keyword));

/// Returns the first region found with the specified name and index. This method uses string
/// comparison to find the region, so the result should be cached rather than calling this
/// method multiple times.
Expand All @@ -40,8 +47,28 @@ class TextureAtlas {
return matched;
}

/// Returns all regions that match a keyword, ordered by smallest to largest index. This method uses
/// string comparison to find the regions, so the result should be cached rather than calling
/// this method multiple times.
List<AtlasSprite> findSpritesByKeyword(String name) {
final matched = <AtlasSprite>[];
for (final sprite in sprites) {
if (sprite.name.contains(name)) matched.add(sprite);
}
return matched;
}

Future<TextureAtlas> load(String path) async {
final atlasData = await _TextureAtlasData()._load(path);
final atlasData = await _TextureAtlasData()._fromAssets(path);

for (final region in atlasData.regions) {
sprites.add(AtlasSprite(region));
}
return this;
}

Future<TextureAtlas> loadFromStorage(String path) async {
final atlasData = await _TextureAtlasData()._fromStorage(path);

for (final region in atlasData.regions) {
sprites.add(AtlasSprite(region));
Expand All @@ -54,9 +81,28 @@ class _TextureAtlasData {
final pages = <Page>[];
final regions = <Region>[];

Future<_TextureAtlasData> _load(String path) async {
Future<_TextureAtlasData> _fromAssets(String path) async {
final fileAsString = await Flame.assets.readFile(path);

await _parse(fileAsString, path, fromStorage: false);
return this;
}

Future<_TextureAtlasData> _fromStorage(String path) async {
File file = File(path);

try {
final fileAsString = await file.readAsString();
await _parse(fileAsString, path, fromStorage: true);
} catch (e) {
throw Exception("Error loading from storage: ${e.toString()}");
}

return this;
}

Future<void> _parse(String fileAsString, String path,
{required bool fromStorage}) async {
final iterator = LineSplitter.split(fileAsString).iterator;
var line = iterator.moveNextAndGet();
var hasIndexes = false;
Expand All @@ -75,7 +121,22 @@ class _TextureAtlasData {
page.textureFile = line;
final parentPath = (path.split('/')..removeLast()).join('/');
final texturePath = '$parentPath/$line';
page.texture = await _images.load(texturePath);

if (fromStorage) {
try {
File textureFile = File(texturePath);
final bytes = await textureFile.readAsBytes();
final decodedBytes = await decodeImageFromList(bytes);
Flame.images.add(texturePath, decodedBytes);
page.texture = Flame.images.fromCache(texturePath);
} catch (e) {
throw Exception(
"Could not add storage file to Flame cache. ${e.toString()}");
}
} else {
page.texture = await _images.load(texturePath);
}

while (true) {
line = iterator.moveNextAndGet();
if (line == null) break;
Expand Down Expand Up @@ -159,7 +220,6 @@ class _TextureAtlasData {
return i1 - i2;
});
}
return this;
}

({int count, List<String> entry}) _readEntry(String line) {
Expand Down
7 changes: 5 additions & 2 deletions lib/flame_texturepacker.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,11 @@ export 'package:flame_texturepacker/atlas/model/atlas_sprite.dart';

extension TexturepackerLoader on Game {
/// Loads the specified pack file, using the parent directory of the pack file to find the page images.
Future<TextureAtlas> fromAtlas(String assetsPath) async =>
TextureAtlas().load(assetsPath);
Future<TextureAtlas> fromAtlas(String assetsPath,
{bool fromStorage = false}) async =>
fromStorage
? await TextureAtlas().loadFromStorage(assetsPath)
: await TextureAtlas().load(assetsPath);

@Deprecated('Please use fromAtlas() and files with extension .atlas')
Future<List<Sprite>> fromJSONAtlas(String imagePath, String dataPath) async {
Expand Down