Skip to main content

dragonbones_flutter 0.4.1 copy "dragonbones_flutter: ^0.4.1" to clipboard
dragonbones_flutter: ^0.4.1 copied to clipboard

Draw DragonBones skeletal animations on a Flutter Canvas: update(dt) + render(Canvas), plus a ready-made widget and no game engine dependency.

example/example.dart

// A runnable example of the renderer: one armature drawn on a Flutter Canvas,
// with no asset files at all.
//
// The skeleton and atlas are embedded as strings and the atlas image is
// generated in memory, so this file is self-contained — no `assets:` section, no
// PNG to ship, nothing to fetch. A real app loads them from its bundle instead
// (`DragonBonesAssets.loadAsset(bundle: rootBundle, ...)`); everything after that
// call is identical.
//
// Run it with:
//   flutter run -t example/example.dart
//
// Note the imports: this package re-exports the whole runtime, and the runtime
// has its own `Transform` and `Animation` classes, so those two names would be
// ambiguous next to `package:flutter/widgets.dart`. The example simply does not
// use them.
import 'dart:convert';
import 'dart:ui' as ui;

import 'package:dragonbones_flutter/dragonbones_flutter.dart';
import 'package:flutter/widgets.dart';

/// A minimal DragonBones 5.5 skeleton: two bones (`root` -> `arm`), one image
/// slot, and a looping animation that swings the arm from 0 to 60 degrees.
///
/// The display sits 10px out along the `arm` bone, so the rotation is visible:
/// the sprite orbits the bone origin.
const String _skeletonJson = '''
{
  "frameRate": 24,
  "name": "Example",
  "version": "5.5",
  "compatibleVersion": "5.5",
  "armature": [
    {
      "type": "Armature",
      "frameRate": 24,
      "name": "Armature",
      "aabb": { "x": -20, "y": -20, "width": 40, "height": 40 },
      "bone": [
        { "name": "root" },
        { "name": "arm", "parent": "root", "transform": { "x": 0, "y": 0 } }
      ],
      "slot": [
        { "name": "box", "parent": "arm" }
      ],
      "skin": [
        {
          "name": "",
          "slot": [
            {
              "name": "box",
              "display": [
                { "type": "image", "name": "box", "transform": { "x": 10, "y": 0 } }
              ]
            }
          ]
        }
      ],
      "animation": [
        {
          "duration": 24,
          "playTimes": 0,
          "name": "wave",
          "bone": [
            {
              "name": "arm",
              "rotateFrame": [
                { "duration": 12, "tweenEasing": 0, "rotate": 0, "transform": { "x": 0, "y": 0 } },
                { "duration": 12, "tweenEasing": 0, "rotate": 60, "transform": { "x": 0, "y": 0 } }
              ]
            }
          ]
        }
      ]
    }
  ]
}
''';

/// The matching texture atlas: a single 10x10 region called `box`. The renderer
/// only needs to know *which* region to sample and where it lands; the pixels
/// come from the `ui.Image` below.
const String _atlasJson = '''
{
  "name": "Example",
  "imagePath": "example.png",
  "width": 16,
  "height": 16,
  "SubTexture": [
    { "name": "box", "x": 0, "y": 0, "width": 10, "height": 10 }
  ]
}
''';

/// The raster the atlas points at, drawn in memory: a 16x16 checker, so the
/// rotation is visible on screen.
///
/// A real app would use `DragonBonesAssets.decodeImageBytes` on the exported
/// PNG instead.
Future<ui.Image> _atlasImage() async {
  final recorder = ui.PictureRecorder();
  final canvas = ui.Canvas(recorder);

  canvas.drawRect(
    const ui.Rect.fromLTWH(0, 0, 16, 16),
    ui.Paint()..color = const ui.Color(0xFF3A7BD5),
  );

  final light = ui.Paint()..color = const ui.Color(0xFFCFE0F7);
  const cell = 4.0;
  for (var y = 0; y < 4; y++) {
    for (var x = 0; x < 4; x++) {
      if ((x + y).isEven) {
        canvas.drawRect(
          ui.Rect.fromLTWH(x * cell, y * cell, cell, cell),
          light,
        );
      }
    }
  }

  final picture = recorder.endRecording();
  final image = await picture.toImage(16, 16);
  picture.dispose();
  return image;
}

Future<void> main() async {
  // `Picture.toImage` above needs the engine, so the binding comes up first.
  WidgetsFlutterBinding.ensureInitialized();

  final assets = DragonBonesAssets.fromDecoded(
    skeletonJson: jsonDecode(_skeletonJson),
    textureJson: jsonDecode(_atlasJson),
    image: await _atlasImage(),
  );

  final armature = assets.buildArmature('Armature');
  if (armature == null) {
    throw StateError('the armature could not be built');
  }

  // `scale` and `offset` are only used by `DragonBonesFit.none`; with `contain`
  // the widget fits the armature to its box instead.
  final player = DragonBonesPlayer(
    armature,
    resolveImage: assets.imageFor,
    scale: 12,
    offset: const Offset(160, 160),
  );

  runApp(
    ColoredBox(
      color: const Color(0xFF101418),
      child: DragonBonesWidget(
        player: player,
        animation: 'wave',
        fit: DragonBonesFit.none,
      ),
    ),
  );
}
1
likes
160
points
496
downloads

Documentation

Documentation
API reference

Publisher

verified publisherrafaelbarbosatec.com

Weekly Downloads

Draw DragonBones skeletal animations on a Flutter Canvas: update(dt) + render(Canvas), plus a ready-made widget and no game engine dependency.

Repository (GitHub)
View/report issues

Topics

#dragonbones #skeletal-animation #gamedev #canvas

License

MIT (license)

Dependencies

dragonbones, flutter

More

Packages that depend on dragonbones_flutter