Detect tap on PositionComponent with FixedResolutionViewport

Viewed 44

When using a FixedResolutionViewport the tap event on a PositionComponent is relative to the screen size and not to the resized viewport as expected. If I remove FixedResolutionViewport the tap is registered correctly. Am I missing something? What can I do to tap correctly on my Component (Circle)?

This is my code. I'm using flame 1.1.0.

Vector2 calculateVector(
    double x, double y, double fieldW, double fieldH, Vector2 size) {
  var calcY = (y / fieldH) * size.y;
  var calcX = (y / fieldW) * size.x;

  return Vector2(calcX, calcY);
}

class TestGame extends FlameGame with HasTappableComponents, ScaleDetector {
  TestGame();

  @override
  bool debugMode = true;

  late double startZoom;
  static double fieldW = 1080;
  static double fieldH = 1717;

  @override
  backgroundColor() => const Color.fromARGB(255, 65, 129, 77);

  @override
  Future<void> onLoad() async {
    double maxSide = max(size.x, size.y);

    var side = maxSide * (fieldW / fieldH);

    camera.viewport =
        FixedResolutionViewport(Vector2(side, maxSide), clip: false);

    final fieldSprite = await loadSprite('field_checkered.png');
    final field = SpriteComponent(
      sprite: fieldSprite,
      size: Vector2(side, maxSide),
    );

    var ply = Circle(
        position: calculateVector(500, 500, fieldH, fieldH, size),
        size: Vector2(50, 50));

    await add(field);
    await add(ply);
  }
}

class Circle extends PositionComponent with TapCallbacks, HasGameRef<TestGame> {
  var isSelected = false;

  var radius = 0.0;
  var paint = Paint()..color = const Color(0xFF80C080);

  Circle({required position, required size}) {
    super.position = Vector2(
      position.x,
      position.y,
    );
    super.size = size;
    super.positionType = PositionType.viewport;
    radius = size.x / 2;
  }

  @override
  void render(Canvas canvas) {
    gameRef.camera.viewport.apply(canvas);
    canvas.drawCircle(Offset(radius, radius), radius, paint);
    super.render(canvas);
  }

  @override
  void onTapDown(TapDownEvent event) {
    isSelected = !isSelected;

    if (isSelected) {
      paint = Paint()..color = Color.fromARGB(255, 75, 0, 76);
      priority = 2;
    } else {
      paint = Paint()..color = Color.fromARGB(255, 253, 147, 255);
      priority = 1;
    }
  }
}

1 Answers

You should be able to use the Tappable and HasTappables mixins instead. The HasTappableComponents mixin is still in the experimental package and is to be used with the new CameraComponent and not the viewport+camera on the FlameGame.

Related