衝突判定

2023-05-03

HasCollisionDetection

HasCollisionDetectionミックスインを使うことで物理演算を使わない当たり判定をすることができます。

各コンポーネントに Hitbox を設定すると、衝突時にonCollisionが呼ばれるようになります。

公式ドキュメント https://docs.flame-engine.org/latest/flame/collision_detection.html#hascollisiondetection
APIリファレンス https://pub.dev/documentation/flame/latest/game/HasCollisionDetection-mixin.html

動かしてみる

地面を作り、タップした場所にボールを生成するサンプルを作ってみます。 ボールは落下しますが、地面か他のボールに触れると停止します。

まずは地面を作ります。 RectangleHitboxを使って、四角形の Hitbox を作ります。

class Ground extends RectangleComponent {
  Ground({super.position, super.size})
      : super(
          paint: BasicPalette.gray.paint(),
        );

  @override
  Future<void> onLoad() async {
    super.onLoad();
    await add(RectangleHitbox());
  }
}

次にボールクラスを用意します。 CircleHitboxを使って、円形の Hitbox を作ります。 またupdateでは落下させるためにyを増やしています。 onCollisionで落下を止めます。

class Ball extends CircleComponent with CollisionCallbacks {
  Ball({super.position})
      : super(
          radius: 10,
        );

  var vy = 2.0;

  @override
  Future<void> onLoad() async {
    super.onLoad();
    await add(CircleHitbox());
  }

  @override
  void onCollision(Set<Vector2> intersectionPoints, PositionComponent other) {
    super.onCollision(intersectionPoints, other);

    if (other is Ground || other is Ball) {
      vy = 0;
    }
  }

  @override
  void update(double dt) {
    super.update(dt);

    y += vy;
  }
}

あとはゲームクラスで、地面やボールを生成します。

class CollisionGame extends FlameGame with TapCallbacks, HasCollisionDetection {
  @override
  Future<void> onLoad() async {
    super.onLoad();

    await add(
      Ground(
        position: Vector2(0, size.y * 0.9),
        size: Vector2(size.x, size.y * 0.1),
      ),
    );
  }

  @override
  void onTapDown(TapDownEvent event) {
    super.onTapDown(event);

    add(
      Ball(position: event.localPosition),
    );
  }
}

これで当たり判定が動くようになりました。

© 2023 tnantoka