Support TexturePacker image atlases
This commit is contained in:
@@ -10,6 +10,9 @@ void main() {
|
||||
'type': 'button',
|
||||
'parent': 'top_bar',
|
||||
'asset': 'dice_normal',
|
||||
'frame': 'dice_idle.png',
|
||||
'pressedFrame': 'dice_pressed.png',
|
||||
'disabledFrame': 'dice_disabled.png',
|
||||
'sourceX': 4,
|
||||
'sourceY': 5,
|
||||
'sourceWidth': 64,
|
||||
@@ -80,6 +83,9 @@ void main() {
|
||||
expect(node.type, 'button');
|
||||
expect(node.parent, 'top_bar');
|
||||
expect(node.asset, 'dice_normal');
|
||||
expect(node.frame, 'dice_idle.png');
|
||||
expect(node.pressedFrame, 'dice_pressed.png');
|
||||
expect(node.disabledFrame, 'dice_disabled.png');
|
||||
expect(node.sourceX, 4);
|
||||
expect(node.sourceY, 5);
|
||||
expect(node.sourceWidth, 64);
|
||||
@@ -163,6 +169,9 @@ void main() {
|
||||
expect(node.textShadowOffsetX, isNull);
|
||||
expect(node.textShadowOffsetY, isNull);
|
||||
expect(node.textShadowBlur, isNull);
|
||||
expect(node.frame, isNull);
|
||||
expect(node.pressedFrame, isNull);
|
||||
expect(node.disabledFrame, isNull);
|
||||
expect(node.sourceX, isNull);
|
||||
expect(node.sourceY, isNull);
|
||||
expect(node.sourceWidth, isNull);
|
||||
@@ -210,6 +219,9 @@ void main() {
|
||||
'sourceY': 4,
|
||||
'sourceWidth': 40,
|
||||
'sourceHeight': 41,
|
||||
'frame': 'piece.png',
|
||||
'pressedFrame': 'piece_down.png',
|
||||
'disabledFrame': 'piece_disabled.png',
|
||||
'sliceLeft': 5,
|
||||
'sliceTop': 6,
|
||||
'sliceRight': 7,
|
||||
@@ -249,6 +261,9 @@ void main() {
|
||||
expect(updated.sourceY, 4);
|
||||
expect(updated.sourceWidth, 40);
|
||||
expect(updated.sourceHeight, 41);
|
||||
expect(updated.frame, 'piece.png');
|
||||
expect(updated.pressedFrame, 'piece_down.png');
|
||||
expect(updated.disabledFrame, 'piece_disabled.png');
|
||||
expect(updated.sliceLeft, 5);
|
||||
expect(updated.sliceTop, 6);
|
||||
expect(updated.sliceRight, 7);
|
||||
@@ -296,19 +311,13 @@ void main() {
|
||||
throwsFormatException,
|
||||
);
|
||||
expect(
|
||||
() => RuntimeNode.fromMap({
|
||||
'id': 'a',
|
||||
'type': 'image',
|
||||
'sourceWidth': 0,
|
||||
}),
|
||||
() =>
|
||||
RuntimeNode.fromMap({'id': 'a', 'type': 'image', 'sourceWidth': 0}),
|
||||
throwsFormatException,
|
||||
);
|
||||
expect(
|
||||
() => RuntimeNode.fromMap({
|
||||
'id': 'a',
|
||||
'type': 'image',
|
||||
'sliceLeft': -1,
|
||||
}),
|
||||
() =>
|
||||
RuntimeNode.fromMap({'id': 'a', 'type': 'image', 'sliceLeft': -1}),
|
||||
throwsFormatException,
|
||||
);
|
||||
expect(
|
||||
|
||||
@@ -26,6 +26,7 @@ void main() {
|
||||
'board': {
|
||||
'type': 'image',
|
||||
'path': 'assets/board.png',
|
||||
'atlas': 'assets/board.json',
|
||||
'preload': 'lazy',
|
||||
'group': 'board',
|
||||
},
|
||||
@@ -53,6 +54,7 @@ void main() {
|
||||
expect(manifest.display.scaleMode, 'fit');
|
||||
expect(manifest.resources['board']?.type, 'image');
|
||||
expect(manifest.resources['board']?.path, 'assets/board.png');
|
||||
expect(manifest.resources['board']?.atlas, 'assets/board.json');
|
||||
expect(manifest.resources['board']?.preload, GameResourcePreload.lazy);
|
||||
expect(manifest.resources['board']?.group, 'board');
|
||||
expect(manifest.resources['roll']?.type, GameResourceType.audio);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'dart:async' as async;
|
||||
import 'dart:io';
|
||||
import 'dart:typed_data';
|
||||
import 'dart:ui' show Rect;
|
||||
|
||||
import 'package:flame_lua_runtime/runtime/diagnostics/runtime_diagnostics.dart';
|
||||
import 'package:flame_lua_runtime/runtime/packages/game_package.dart';
|
||||
@@ -61,6 +62,19 @@ void main() {
|
||||
},
|
||||
);
|
||||
|
||||
test('loads TexturePacker atlas frames for image resources', () async {
|
||||
final resources = GameResourceManager();
|
||||
final package = await _createTextureAtlasPackage('texture_atlas');
|
||||
|
||||
await resources.mount(package);
|
||||
|
||||
final idle = resources.textureFrame('ui', 'button_idle.png');
|
||||
final pressed = resources.textureFrame('ui', 'button_pressed.png');
|
||||
expect(idle?.rect, Rect.fromLTWH(2, 3, 40, 20));
|
||||
expect(pressed?.rect, Rect.fromLTWH(44, 3, 40, 20));
|
||||
expect(resources.textureFrame('ui', 'missing.png'), isNull);
|
||||
});
|
||||
|
||||
test('exports image debug json and evicts failed records', () async {
|
||||
final resources = GameResourceManager();
|
||||
final package = await _createPackage('debug_json');
|
||||
@@ -332,6 +346,83 @@ Future<GamePackage> _createPackage(
|
||||
);
|
||||
}
|
||||
|
||||
Future<GamePackage> _createTextureAtlasPackage(String name) async {
|
||||
final root = await Directory.systemTemp.createTemp('resource_${name}_');
|
||||
Directory('${root.path}/assets').createSync(recursive: true);
|
||||
File('${root.path}/assets/ui.png').writeAsBytesSync(_pngBytes);
|
||||
File('${root.path}/assets/ui.json').writeAsStringSync('''
|
||||
{
|
||||
"frames": {
|
||||
"button_idle.png": {
|
||||
"frame": { "x": 2, "y": 3, "w": 40, "h": 20 },
|
||||
"rotated": false,
|
||||
"trimmed": false
|
||||
}
|
||||
}
|
||||
}
|
||||
''');
|
||||
|
||||
addTearDown(() {
|
||||
if (root.existsSync()) {
|
||||
root.deleteSync(recursive: true);
|
||||
}
|
||||
});
|
||||
|
||||
final hashAtlas = RuntimeTextureAtlas.fromJsonString(
|
||||
File('${root.path}/assets/ui.json').readAsStringSync(),
|
||||
);
|
||||
expect(hashAtlas.frames['button_idle.png']?.rect, Rect.fromLTWH(2, 3, 40, 20));
|
||||
final arrayAtlas = RuntimeTextureAtlas.fromJsonString('''
|
||||
{
|
||||
"frames": [
|
||||
{
|
||||
"filename": "button_pressed.png",
|
||||
"frame": { "x": 44, "y": 3, "w": 40, "h": 20 },
|
||||
"rotated": false,
|
||||
"trimmed": false
|
||||
}
|
||||
]
|
||||
}
|
||||
''');
|
||||
final mergedAtlas = '''
|
||||
{
|
||||
"frames": {
|
||||
"button_idle.png": {
|
||||
"frame": { "x": 2, "y": 3, "w": 40, "h": 20 },
|
||||
"rotated": false,
|
||||
"trimmed": false
|
||||
},
|
||||
"button_pressed.png": {
|
||||
"frame": { "x": ${arrayAtlas.frames['button_pressed.png']!.x}, "y": 3, "w": 40, "h": 20 },
|
||||
"rotated": false,
|
||||
"trimmed": false
|
||||
}
|
||||
}
|
||||
}
|
||||
''';
|
||||
File('${root.path}/assets/ui.json').writeAsStringSync(mergedAtlas);
|
||||
|
||||
return GamePackage.file(
|
||||
rootPath: root.path,
|
||||
manifest: GamePackageManifest(
|
||||
gameId: 'test',
|
||||
name: 'Test',
|
||||
version: '0.1.0',
|
||||
runtimeApiVersion: 1,
|
||||
entry: 'scripts/main.lua',
|
||||
assetsBase: 'assets',
|
||||
resources: const {
|
||||
'ui': GameResource(
|
||||
type: GameResourceType.image,
|
||||
path: 'assets/ui.png',
|
||||
atlas: 'assets/ui.json',
|
||||
preload: GameResourcePreload.lazy,
|
||||
),
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<GamePackage> _createMultiImagePackage(String name) async {
|
||||
final root = await Directory.systemTemp.createTemp('resource_${name}_');
|
||||
Directory('${root.path}/assets').createSync(recursive: true);
|
||||
|
||||
Reference in New Issue
Block a user