diff --git a/spine-flutter/example/lib/animation_state_events.dart b/spine-flutter/example/lib/animation_state_events.dart index 9f78007ea..8186b023c 100644 --- a/spine-flutter/example/lib/animation_state_events.dart +++ b/spine-flutter/example/lib/animation_state_events.dart @@ -1,6 +1,6 @@ // ignore_for_file: avoid_print -import 'package:flutter/material.dart'; import 'package:esotericsoftware_spine_flutter/spine_flutter.dart'; +import 'package:flutter/material.dart'; class AnimationStateEvents extends StatelessWidget { const AnimationStateEvents({Key? key}) : super(key: key); @@ -22,22 +22,18 @@ class AnimationStateEvents extends StatelessWidget { }); controller.animationState.setListener((type, trackEntry, event) { if (type == EventType.event) { - print("User event: { name: ${event?.getData().getName()}, intValue: ${event?.getIntValue()}, floatValue: intValue: ${event?.getFloatValue()}, stringValue: ${event?.getStringValue()} }"); + print( + "User event: { name: ${event?.getData().getName()}, intValue: ${event?.getIntValue()}, floatValue: intValue: ${event?.getFloatValue()}, stringValue: ${event?.getStringValue()} }"); } }); print("Current: ${controller.animationState.getCurrent(0)?.getAnimation().getName()}"); }); return Scaffold( - appBar: AppBar(title: const Text('Spineboy')), - body: Column( - children: [ + appBar: AppBar(title: const Text('Spineboy')), + body: Column(children: [ const Text("See output in console!"), - Expanded( - child: SpineWidget.asset("assets/spineboy.atlas", "assets/spineboy-pro.skel", controller) - ) - ] - ) - ); + Expanded(child: SpineWidget.asset("assets/spineboy.atlas", "assets/spineboy-pro.skel", controller)) + ])); } -} \ No newline at end of file +} diff --git a/spine-flutter/example/lib/debug_rendering.dart b/spine-flutter/example/lib/debug_rendering.dart index 2f2458089..eb2faa3dc 100644 --- a/spine-flutter/example/lib/debug_rendering.dart +++ b/spine-flutter/example/lib/debug_rendering.dart @@ -1,5 +1,5 @@ -import 'package:flutter/material.dart'; import 'package:esotericsoftware_spine_flutter/spine_flutter.dart'; +import 'package:flutter/material.dart'; class DebugRendering extends StatelessWidget { const DebugRendering({Key? key}) : super(key: key); @@ -9,18 +9,15 @@ class DebugRendering extends StatelessWidget { reportLeaks(); const debugRenderer = DebugRenderer(); - final controller = SpineWidgetController( - onInitialized: (controller) { - controller.animationState.setAnimationByName(0, "walk", true); - }, - onAfterPaint: (controller, canvas, commands) { - debugRenderer.render(controller.drawable, canvas, commands); - } - ); + final controller = SpineWidgetController(onInitialized: (controller) { + controller.animationState.setAnimationByName(0, "walk", true); + }, onAfterPaint: (controller, canvas, commands) { + debugRenderer.render(controller.drawable, canvas, commands); + }); return Scaffold( appBar: AppBar(title: const Text('Debug Renderer')), body: SpineWidget.asset("assets/spineboy.atlas", "assets/spineboy-pro.skel", controller), ); } -} \ No newline at end of file +} diff --git a/spine-flutter/example/lib/dress_up.dart b/spine-flutter/example/lib/dress_up.dart index b4b1090c7..9331c99a1 100644 --- a/spine-flutter/example/lib/dress_up.dart +++ b/spine-flutter/example/lib/dress_up.dart @@ -1,6 +1,6 @@ +import 'package:esotericsoftware_spine_flutter/spine_flutter.dart'; import 'package:flutter/material.dart'; import 'package:flutter/painting.dart' as painting; -import 'package:esotericsoftware_spine_flutter/spine_flutter.dart'; import 'package:raw_image_provider/raw_image_provider.dart'; class DressUp extends StatefulWidget { @@ -61,40 +61,38 @@ class DressUpState extends State { appBar: AppBar(title: const Text('Dress Up')), body: _skinImages.isEmpty ? const SizedBox() - : Row( - children: [ - SizedBox(width: thumbnailSize, child: - ListView( - children: _skinImages.keys.map((skinName) { - var rawImageData = _skinImages[skinName]!; - var image = Image(image: RawImageProvider(rawImageData)); - var box = SizedBox(width: 200, height: 200, child: image); - return GestureDetector( - onTap: () { - _toggleSkin(skinName); - setState(() {}); - }, - child: _selectedSkins[skinName] == true - ? box - // Does not work on web. - //: ColorFiltered(colorFilter: const ColorFilter.mode(Colors.grey, painting.BlendMode.saturation,), child: box) - : Container( - foregroundDecoration: const BoxDecoration( - color: Colors.grey, - backgroundBlendMode: painting.BlendMode.saturation, - ), - child: box - ) - ); - }).toList() - ), - ), - Expanded( - child: SpineWidget.drawable(_drawable, controller, boundsProvider: SkinAndAnimationBounds(skins: ["full-skins/girl"]),) - ) - ] - ) - ); + : Row(children: [ + SizedBox( + width: thumbnailSize, + child: ListView( + children: _skinImages.keys.map((skinName) { + var rawImageData = _skinImages[skinName]!; + var image = Image(image: RawImageProvider(rawImageData)); + var box = SizedBox(width: 200, height: 200, child: image); + return GestureDetector( + onTap: () { + _toggleSkin(skinName); + setState(() {}); + }, + child: _selectedSkins[skinName] == true + ? box + // Does not work on web. + //: ColorFiltered(colorFilter: const ColorFilter.mode(Colors.grey, painting.BlendMode.saturation,), child: box) + : Container( + foregroundDecoration: const BoxDecoration( + color: Colors.grey, + backgroundBlendMode: painting.BlendMode.saturation, + ), + child: box)); + }).toList()), + ), + Expanded( + child: SpineWidget.drawable( + _drawable, + controller, + boundsProvider: SkinAndAnimationBounds(skins: ["full-skins/girl"]), + )) + ])); } @override @@ -103,4 +101,4 @@ class DressUpState extends State { _drawable.dispose(); _customSkin?.dispose(); } -} \ No newline at end of file +} diff --git a/spine-flutter/example/lib/flame_example.dart b/spine-flutter/example/lib/flame_example.dart index c383d5a37..efed83ca7 100644 --- a/spine-flutter/example/lib/flame_example.dart +++ b/spine-flutter/example/lib/flame_example.dart @@ -1,9 +1,9 @@ import 'dart:math'; +import 'package:esotericsoftware_spine_flutter/spine_flutter.dart'; import 'package:flame/components.dart'; import 'package:flame/game.dart'; import 'package:flutter/material.dart'; -import 'package:esotericsoftware_spine_flutter/spine_flutter.dart'; class SpineComponent extends PositionComponent { final BoundsProvider _boundsProvider; @@ -11,34 +11,36 @@ class SpineComponent extends PositionComponent { late final Bounds _bounds; final bool _ownsDrawable; - SpineComponent(this._drawable, { - bool ownsDrawable = true, - BoundsProvider boundsProvider = const SetupPoseBounds(), - super.position, - super.scale, - double super.angle = 0.0, - Anchor super.anchor = Anchor.topLeft, - super.children, - super.priority, - }) : - _ownsDrawable = ownsDrawable, + SpineComponent( + this._drawable, { + bool ownsDrawable = true, + BoundsProvider boundsProvider = const SetupPoseBounds(), + super.position, + super.scale, + double super.angle = 0.0, + Anchor super.anchor = Anchor.topLeft, + super.children, + super.priority, + }) : _ownsDrawable = ownsDrawable, _boundsProvider = boundsProvider { _drawable.update(0); _bounds = _boundsProvider.computeBounds(_drawable); size = Vector2(_bounds.width, _bounds.height); } - static Future fromAssets(String atlasFile, String skeletonFile, { - AssetBundle? bundle, BoundsProvider boundsProvider = const SetupPoseBounds(), - Vector2? position, - Vector2? scale, - double angle = 0.0, - Anchor anchor = Anchor.topLeft, - Iterable? children, - int? priority, - }) async { - return SpineComponent( - await SkeletonDrawable.fromAsset(atlasFile, skeletonFile, bundle: bundle), + static Future fromAssets( + String atlasFile, + String skeletonFile, { + AssetBundle? bundle, + BoundsProvider boundsProvider = const SetupPoseBounds(), + Vector2? position, + Vector2? scale, + double angle = 0.0, + Anchor anchor = Anchor.topLeft, + Iterable? children, + int? priority, + }) async { + return SpineComponent(await SkeletonDrawable.fromAsset(atlasFile, skeletonFile, bundle: bundle), ownsDrawable: true, boundsProvider: boundsProvider, position: position, @@ -54,12 +56,12 @@ class SpineComponent extends PositionComponent { _drawable.dispose(); } } - + @override void update(double dt) { _drawable.update(dt); } - + @override void render(Canvas canvas) { canvas.save(); @@ -69,7 +71,9 @@ class SpineComponent extends PositionComponent { } get animationState => _drawable.animationState; + get animationStateData => _drawable.animationStateData; + get skeleton => _drawable.skeleton; } @@ -81,12 +85,8 @@ class SimpleFlameExample extends FlameGame { // Load the Spineboy atlas and skeleton data from asset files // and create a SpineComponent from them, scaled down and // centered on the screen - spineboy = await SpineComponent.fromAssets( - "assets/spineboy.atlas", "assets/spineboy-pro.skel", - scale: Vector2(0.4, 0.4), - anchor: Anchor.center, - position: Vector2(size.x / 2, size.y / 2) - ); + spineboy = await SpineComponent.fromAssets("assets/spineboy.atlas", "assets/spineboy-pro.skel", + scale: Vector2(0.4, 0.4), anchor: Anchor.center, position: Vector2(size.x / 2, size.y / 2)); // Set the "walk" animation on track 0 in looping mode spineboy.animationState.setAnimationByName(0, "walk", true); @@ -119,11 +119,7 @@ class PreloadAndShareSpineDataExample extends FlameGame { final drawable = SkeletonDrawable(cachedAtlas, cachedSkeletonData, false); final scale = 0.1 + rng.nextDouble() * 0.2; final position = Vector2(rng.nextDouble() * size.x, rng.nextDouble() * size.y); - final spineboy = SpineComponent( - drawable, - scale: Vector2(scale, scale), - position: position - ); + final spineboy = SpineComponent(drawable, scale: Vector2(scale, scale), position: position); spineboy.animationState.setAnimationByName(0, "walk", true); spineboys.add(spineboy); await add(spineboy); @@ -145,13 +141,11 @@ class PreloadAndShareSpineDataExample extends FlameGame { class SpineFlameGameWidget extends StatelessWidget { final FlameGame game; + const SpineFlameGameWidget(this.game, {super.key}); @override Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar(title: const Text('Flame Integration')), - body: GameWidget(game: game) - ); + return Scaffold(appBar: AppBar(title: const Text('Flame Integration')), body: GameWidget(game: game)); } -} \ No newline at end of file +} diff --git a/spine-flutter/example/lib/ik_following.dart b/spine-flutter/example/lib/ik_following.dart index 52e5d7f7d..045f3512e 100644 --- a/spine-flutter/example/lib/ik_following.dart +++ b/spine-flutter/example/lib/ik_following.dart @@ -1,5 +1,5 @@ -import 'package:flutter/material.dart'; import 'package:esotericsoftware_spine_flutter/spine_flutter.dart'; +import 'package:flutter/material.dart'; class IkFollowing extends StatefulWidget { const IkFollowing({Key? key}) : super(key: key); diff --git a/spine-flutter/example/lib/main.dart b/spine-flutter/example/lib/main.dart index 688d38366..d4364047b 100644 --- a/spine-flutter/example/lib/main.dart +++ b/spine-flutter/example/lib/main.dart @@ -1,13 +1,13 @@ -import 'package:flutter/material.dart'; import 'package:esotericsoftware_spine_flutter/spine_flutter.dart'; +import 'package:flutter/material.dart'; import 'package:spine_flutter_example/debug_rendering.dart'; -import 'flame_example.dart'; -import 'simple_animation.dart'; import 'animation_state_events.dart'; -import 'pause_play_animation.dart'; import 'dress_up.dart'; +import 'flame_example.dart'; import 'ik_following.dart'; +import 'pause_play_animation.dart'; +import 'simple_animation.dart'; class ExampleSelector extends StatelessWidget { const ExampleSelector({super.key}); @@ -18,117 +18,109 @@ class ExampleSelector extends StatelessWidget { return Scaffold( appBar: AppBar(title: const Text('Spine Examples')), body: Center( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - ElevatedButton( - child: const Text('Simple Animation'), - onPressed: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => const SimpleAnimation(), - ), - ); - }, - ), - spacer, - ElevatedButton( - child: const Text('Pause/Play animation'), - onPressed: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => const PlayPauseAnimation(), - ), - ); - }, - ), - spacer, - ElevatedButton( - child: const Text('Animation State Listener'), - onPressed: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => const AnimationStateEvents(), - ), - ); - }, - ), - spacer, - ElevatedButton( - child: const Text('Debug Rendering'), - onPressed: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => const DebugRendering(), - ), - ); - }, - ), - spacer, - ElevatedButton( - child: const Text('Dress Up'), - onPressed: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => const DressUp(), - ), - ); - }, - ), - spacer, - ElevatedButton( - child: const Text('IK Following'), - onPressed: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => const IkFollowing(), - ), - ); - }, - ), - spacer, - ElevatedButton( - child: const Text('Flame: Simple Example'), - onPressed: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => SpineFlameGameWidget(SimpleFlameExample()), - ), - ); - }, - ), - spacer, - ElevatedButton( - child: const Text('Flame: Pre-load and share Spine data'), - onPressed: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => SpineFlameGameWidget(PreloadAndShareSpineDataExample()), - ), - ); - }, - ), - spacer - ] - ) - ) - ); + child: Column(mainAxisSize: MainAxisSize.min, children: [ + ElevatedButton( + child: const Text('Simple Animation'), + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const SimpleAnimation(), + ), + ); + }, + ), + spacer, + ElevatedButton( + child: const Text('Pause/Play animation'), + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const PlayPauseAnimation(), + ), + ); + }, + ), + spacer, + ElevatedButton( + child: const Text('Animation State Listener'), + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const AnimationStateEvents(), + ), + ); + }, + ), + spacer, + ElevatedButton( + child: const Text('Debug Rendering'), + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const DebugRendering(), + ), + ); + }, + ), + spacer, + ElevatedButton( + child: const Text('Dress Up'), + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const DressUp(), + ), + ); + }, + ), + spacer, + ElevatedButton( + child: const Text('IK Following'), + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const IkFollowing(), + ), + ); + }, + ), + spacer, + ElevatedButton( + child: const Text('Flame: Simple Example'), + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => SpineFlameGameWidget(SimpleFlameExample()), + ), + ); + }, + ), + spacer, + ElevatedButton( + child: const Text('Flame: Pre-load and share Spine data'), + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => SpineFlameGameWidget(PreloadAndShareSpineDataExample()), + ), + ); + }, + ), + spacer + ]))); } } void main() async { WidgetsFlutterBinding.ensureInitialized(); await initSpineFlutter(enableMemoryDebugging: false); - runApp(const MaterialApp( - title: "Spine Examples", - home: ExampleSelector() - )); + runApp(const MaterialApp(title: "Spine Examples", home: ExampleSelector())); } diff --git a/spine-flutter/example/lib/pause_play_animation.dart b/spine-flutter/example/lib/pause_play_animation.dart index 38c158d82..eb570a5f4 100644 --- a/spine-flutter/example/lib/pause_play_animation.dart +++ b/spine-flutter/example/lib/pause_play_animation.dart @@ -1,5 +1,5 @@ -import 'package:flutter/material.dart'; import 'package:esotericsoftware_spine_flutter/spine_flutter.dart'; +import 'package:flutter/material.dart'; class PlayPauseAnimation extends StatefulWidget { const PlayPauseAnimation({Key? key}) : super(key: key); @@ -33,11 +33,16 @@ class PlayPauseAnimationState extends State { return Scaffold( appBar: AppBar(title: const Text('Play/Pause')), - body: SpineWidget.asset("assets/dragon.atlas", "assets/dragon-ess.skel", controller, boundsProvider: SkinAndAnimationBounds(animation: "flying"),), + body: SpineWidget.asset( + "assets/dragon.atlas", + "assets/dragon-ess.skel", + controller, + boundsProvider: SkinAndAnimationBounds(animation: "flying"), + ), floatingActionButton: FloatingActionButton( onPressed: _togglePlay, child: Icon(isPlaying ? Icons.pause : Icons.play_arrow), ), ); } -} \ No newline at end of file +} diff --git a/spine-flutter/example/lib/simple_animation.dart b/spine-flutter/example/lib/simple_animation.dart index 5e14bcb7c..fb81c8480 100644 --- a/spine-flutter/example/lib/simple_animation.dart +++ b/spine-flutter/example/lib/simple_animation.dart @@ -1,5 +1,5 @@ -import 'package:flutter/material.dart'; import 'package:esotericsoftware_spine_flutter/spine_flutter.dart'; +import 'package:flutter/material.dart'; class SimpleAnimation extends StatelessWidget { const SimpleAnimation({Key? key}) : super(key: key); @@ -19,4 +19,4 @@ class SimpleAnimation extends StatelessWidget { // body: const SpineWidget.http("https://marioslab.io/dump/spineboy/spineboy.atlas", "https://marioslab.io/dump/spineboy/spineboy-pro.json"), ); } -} \ No newline at end of file +} diff --git a/spine-flutter/lib/ffi_utf8.dart b/spine-flutter/lib/ffi_utf8.dart index 2af6b78dd..8c00297c6 100644 --- a/spine-flutter/lib/ffi_utf8.dart +++ b/spine-flutter/lib/ffi_utf8.dart @@ -3,9 +3,10 @@ // BSD-style license that can be found in the LICENSE file. import 'dart:convert'; -import 'ffi_proxy.dart'; import 'dart:typed_data'; +import 'ffi_proxy.dart'; + /// The contents of a native zero-terminated array of UTF-8 code units. /// /// The Utf8 type itself has no functionality, it's only intended to be used @@ -57,8 +58,7 @@ extension Utf8Pointer on Pointer { void _ensureNotNullptr(String operation) { if (this == nullptr) { - throw UnsupportedError( - "Operation '$operation' not allowed on a 'nullptr'."); + throw UnsupportedError("Operation '$operation' not allowed on a 'nullptr'."); } } } @@ -84,4 +84,4 @@ extension StringUtf8Pointer on String { nativeString[units.length] = 0; return result.cast(); } -} \ No newline at end of file +} diff --git a/spine-flutter/lib/init_web.dart b/spine-flutter/lib/init_web.dart index 920bd5510..8c73b5510 100644 --- a/spine-flutter/lib/init_web.dart +++ b/spine-flutter/lib/init_web.dart @@ -3,6 +3,7 @@ import 'package:flutter/services.dart'; import 'package:inject_js/inject_js.dart' as js; import 'package:web_ffi_fork/web_ffi.dart'; import 'package:web_ffi_fork/web_ffi_modules.dart'; + import 'spine_flutter_bindings_generated.dart'; Module? _module; @@ -61,7 +62,8 @@ Future initSpineFlutterFFI() async { registerOpaqueType(); await js.importLibrary('assets/packages/esotericsoftware_spine_flutter/lib/assets/libspine_flutter.js'); - Uint8List wasmBinaries = (await rootBundle.load('packages/esotericsoftware_spine_flutter/lib/assets/libspine_flutter.wasm')).buffer.asUint8List(); + Uint8List wasmBinaries = + (await rootBundle.load('packages/esotericsoftware_spine_flutter/lib/assets/libspine_flutter.wasm')).buffer.asUint8List(); _module = await EmscriptenModule.compile(wasmBinaries, 'libspine_flutter'); } Module? m = _module; @@ -71,4 +73,4 @@ Future initSpineFlutterFFI() async { } else { throw Exception("Couldn't load libspine-flutter.js/.wasm"); } -} \ No newline at end of file +}