Patola
Patola

Reputation: 673

Multi touch detection In Flutter flame

I want to implement game control for a boxing game.

Four sections in black represent uppercuts and jabs. In order to block, the player should use multi-touch, where one figure should be on the left half of the screen and another figure on the right half. This is clearly overlapping other controls.

What is the best way to handle multi-touch while little conflicts with other controls in Flame engine (flutter).

enter image description here

Upvotes: 0

Views: 301

Answers (1)

spydon
spydon

Reputation: 11512

Since this was replied to in the GitHub issue, I'll write the answer here too if anyone else stumbles upon this.

You can use Tappable or TapCallbacks mixin on a component that covers those areas, like this:

class MultiTapGame extends FlameGame with HasTappables {
  @override
  Future<void> onLoad() async {
    debugMode = true;
    await add(Controls());
  }
}

class Controls extends Component with HasGameRef {
  bool isLeftDown = false;
  bool isRightDown = false;

  @override
  Future<void> onLoad() async {
    await addAll(
      [
        TappableRegion(
          position: Vector2.all(0),
          size: Vector2(gameRef.size.x * 0.5, gameRef.size.y * 0.75),
          onTapDownCallback: () {
            isLeftDown = true;
            if (isRightDown) {
              print("Block");
            } else {
              print("Left Uppercut");
            }
          },
          onTapUpCallback: () {
            isLeftDown = false;
          },
        ),
        TappableRegion(
          position: Vector2(gameRef.size.x * 0.5, 0),
          size: Vector2(gameRef.size.x * 0.5, gameRef.size.y * 0.75),
          onTapDownCallback: () {
            isRightDown = true;
            if (isLeftDown) {
              print("Block");
            } else {
              print("Right Uppercut");
            }
          },
          onTapUpCallback: () {
            isRightDown = false;
          },
        ),
        TappableRegion(
          position: Vector2(0, gameRef.size.y * 0.75),
          size: Vector2(gameRef.size.x * 0.5, gameRef.size.y * 0.25),
          onTapDownCallback: () {
            isLeftDown = true;
            if (isRightDown) {
              print("Block");
            } else {
              print("Left Jab");
            }
          },
          onTapUpCallback: () {
            isLeftDown = false;
          },
        ),
        TappableRegion(
          position: Vector2(gameRef.size.x * 0.5, gameRef.size.y * 0.75),
          size: Vector2(gameRef.size.x * 0.5, gameRef.size.y * 0.25),
          onTapDownCallback: () {
            isRightDown = true;
            if (isLeftDown) {
              print("Block");
            } else {
              print("Right Jab");
            }
          },
          onTapUpCallback: () {
            isRightDown = false;
          },
        ),
      ],
    );
  }
}

class TappableRegion extends PositionComponent with Tappable {
  TappableRegion({
    super.position,
    super.size,
    super.scale,
    super.angle,
    super.nativeAngle,
    super.anchor,
    super.children,
    super.priority,
    this.onTapDownCallback,
    this.onTapUpCallback,
  });

  late RectangleComponent _rectangleComponent;

  @override
  FutureOr<void> onLoad() {
    _rectangleComponent = RectangleComponent(
      size: size,
      paint: Paint()..color = Colors.green,
    );
    return super.onLoad();
  }

  void Function()? onTapDownCallback;
  void Function()? onTapUpCallback;

  @override
  bool onTapDown(TapDownInfo info) {
    onTapDownCallback?.call();
    add(_rectangleComponent);
    return super.onTapDown(info);
  }

  @override
  bool onTapUp(TapUpInfo info) {
    onTapUpCallback?.call();
    _rectangleComponent.removeFromParent();
    return super.onTapUp(info);
  }

  @override
  bool onTapCancel() {
    onTapUpCallback?.call();
    _rectangleComponent.removeFromParent();
    return super.onTapCancel();
  }
}

Upvotes: 1

Related Questions