Search code examples
flutterdartflame

Flutter flame drawRect tappable


I am drawing a lot of rectangles on the screen for a demo and would love to show which you clicked/tapped on. I have the option to move over the screen with and zoom in and out, but I can't get it working that you can show which rectangle is tapped (the tapped function in the positionComponent are not firing). Does someone know if I am forgetting something or are using the wrong technique to achieve this?

class GameEngine extends FlameGame
    with ScaleDetector, ScrollDetector, HasTappables {
  final List<Paint> colors;
  late double startZoom;

  GameEngine(this.colors);

  @override
  Future<void>? onLoad() {
    camera.speed = 250;
    for (int i = 0; i < 250; i++) {
      for (int j = 0; j < 300; j++) {
        Paint color = colors[(i * (j + 1)) + j];

        add(Rectangle(color, j * 50, i * 30));
      }
    }

    return super.onLoad();
  }

  @override
  void onScaleStart(info) {
    startZoom = camera.zoom;
  }

  @override
  void onScaleUpdate(ScaleUpdateInfo info) {
    final currentScale = info.scale.global;
    if (!currentScale.isIdentity()) {
      camera.zoom = startZoom * currentScale.y;
    } else {
      camera.translateBy(-info.delta.game);
      camera.snap();
    }
  }

  @override
  void onScroll(PointerScrollInfo info) {
    double zoomValue = info.raw.scrollDelta.dy;

    if (zoomValue > 0) {
      camera.zoom = camera.zoom * 0.75;
    } else {
      camera.zoom = camera.zoom * 1.25;
    }

    return super.onScroll(info);
  }
}

class Rectangle extends PositionComponent with Tappable {
  final Paint color;
  final double left;
  final double top;

  Rectangle(this.color, this.left, this.top);

  @override
  void render(Canvas canvas) {
    canvas.drawRect(Rect.fromLTWH(left, top, 50, 30), color);
  }

  @override
  bool onTapUp(TapUpInfo info) {
    print("tap up");
    return true;
  }

  @override
  bool onTapDown(TapDownInfo info) {
    print("tap down");
    return true;
  }

  @override
  bool onTapCancel() {
    print("tap cancel");
    return true;
  }
}

Solution

  • Your rectangle doesn't set the size and position, so Flame can not determine whether a tap is within the component or not.

    I recommend that you extend the RectangleComponent instead of extending PositionComponent, since it's harder to miss something when using the RectangleComponent.

    You can see the docs for RectangleComponent here.