• Runtimes
  • Skeleton not render in center of viewport when using flame example.

I was tested two cases.

  1. flame examples with two rectangle;
  2. spine flame dragon example.

It's flame examples

rectangle will be center of viewport

import 'dart:async';

import 'package:flame/components.dart';
import 'package:flame/events.dart';
import 'package:flame/game.dart';
import 'package:flame/palette.dart';

class AnchorGame extends FlameGame {
  final _parentAnchorText = TextComponent(position: Vector2.all(5));
  final _childAnchorText = TextComponent(position: Vector2(5, 30));

  late _AnchoredRectangle _redComponent;
  late _AnchoredRectangle _blueComponent;

  @override
  Future<void> onLoad() async {
    _redComponent = _AnchoredRectangle(
      size: size / 4,
      position: size / 2,
      paint: BasicPalette.red.paint(),
    );

    _blueComponent = _AnchoredRectangle(
      size: size / 8,
      paint: BasicPalette.blue.paint(),
    );

    await _redComponent.addAll([
      _blueComponent,
      CircleComponent(radius: 2, anchor: Anchor.center),
    ]);

    await addAll([
      _redComponent,
      _parentAnchorText,
      _childAnchorText,
      CircleComponent(
        radius: 4,
        position: size / 2,
        anchor: Anchor.center,
      ),
    ]);
  }

  @override
  void update(double dt) {
    _parentAnchorText.text = 'Parent: ${_redComponent.anchor}';
    _childAnchorText.text = 'Child: ${_blueComponent.anchor}';
    super.update(dt);
  }
}

class _AnchoredRectangle extends RectangleComponent with TapCallbacks {
  _AnchoredRectangle({
    super.position,
    super.size,
    super.paint,
  });

  @override
  void onTapDown(TapDownEvent event) {
    var index = Anchor.values.indexOf(anchor) + 1;
    if (index == Anchor.values.length) {
      index = 0;
    }
    anchor = Anchor.values.elementAt(index);
    super.onTapDown(event);
  }
}

it's flame dragon example

Dragon not in center of viewport.

class DragonExample extends FlameGame {
  late final Atlas cachedAtlas;
  late final SkeletonData cachedSkeletonData;
  late final SpineComponent dragon;

  @override
  Future<void> onLoad() async {
    cachedAtlas = await Atlas.fromAsset("assets/dragon.atlas");
    cachedSkeletonData =  await SkeletonData.fromAsset(cachedAtlas, "assets/dragon-ess.skel");
    final drawable = SkeletonDrawable(cachedAtlas, cachedSkeletonData, false);
    dragon = SpineComponent(
      drawable,
      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
    dragon.animationState.setAnimationByName(0, "flying", true);
    await add(dragon);
  }

  @override
  void onDetach() {
    // Dispose the native resources that have been loaded for spineboy.
    dragon.dispose();
    cachedSkeletonData.dispose();
    cachedAtlas.dispose();
  }
}

The dragon was rendered on the left side of the screen.

Related Discussions
...

The issue you're experiencing with the dragon not being centered in the viewport when using the Flame example could be due to the way the SpineComponent is being positioned and scaled. Here are a few things to check and adjust:

  1. Anchor and Position: Ensure that the anchor and position properties are correctly set to center the dragon in the viewport. You have already set the anchor to Anchor.center and the position to the center of the viewport, which is correct.

  2. Scale: The scale of the SpineComponent might be affecting its position. You have set the scale to Vector2(0.4, 0.4). Ensure that this scale is appropriate for your viewport size.

  3. Drawable Bounds: The bounds of the SkeletonDrawable might not be centered. You can adjust the position of the SpineComponent based on the bounds of the drawable.

Here is an updated version of your DragonExample class with additional adjustments to ensure the dragon is centered:

class DragonExample extends FlameGame {
  late final Atlas cachedAtlas;
  late final SkeletonData cachedSkeletonData;
  late final SpineComponent dragon;

  @override
  Future<void> onLoad() async {
    cachedAtlas = await Atlas.fromAsset("assets/dragon.atlas");
    cachedSkeletonData = await SkeletonData.fromAsset(cachedAtlas, "assets/dragon-ess.skel");
    final drawable = SkeletonDrawable(cachedAtlas, cachedSkeletonData, false);
    dragon = SpineComponent(
      drawable,
      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
    dragon.animationState.setAnimationByName(0, "flying", true);
    await add(dragon);
  }

  @override
  void onResize(Vector2 canvasSize) {
    super.onResize(canvasSize);
    // Re-center the dragon when the viewport size changes
    dragon.position = Vector2(canvasSize.x / 2, canvasSize.y / 2);
  }

  @override
  void onDetach() {
    // Dispose the native resources that have been loaded for spineboy.
    dragon.dispose();
    cachedSkeletonData.dispose();
    cachedAtlas.dispose();
  }
}

In this updated version, the onResize method is overridden to re-center the dragon whenever the viewport size changes. This ensures that the dragon remains centered even if the viewport is resized.

Additionally, make sure that the SkeletonDrawable is correctly set up and that its bounds are appropriate for your use case. If the drawable's bounds are not centered, you might need to adjust the position further based on the drawable's dimensions.