Louis
Louis

Reputation: 59

Show/Hide a SpriteComponent using Flame in Flutter

I am a beginner with the use of Flame, and I have a small problem.

My game has 3 states:

During each state, there should be different buttons displayed. I use SpriteComponent to display my buttons, but I can't make elements "disappear" and reappear in the following functions:

// For example, I use this button 
// need to be displayed only during the pause state
PauseMenuButton pauseMenuButton = PauseMenuButton();

@override
Future<void>? onLoad() async {
  pauseMenuButton
      ..sprite = await loadSprite("btnFastForward.png")
      ..size = pauseButtonSize
      ..position = Vector2(size[0] * 0.3, size[1]*0.3);
  
  add(pauseMenuButton);

  if(gamePaused) {
      renderGamePause(canvas);
    } else if(gameOver) {
      renderGameOver(canvas);
    } else {
      renderGamePlay(canvas);
    }
}

renderGamePlay(Canvas canvas) {
    
 // hide pauseMenuButton
    
}

renderGamePause(Canvas canvas) {

  // show pauseMenuButton

}

Here is my SpriteComponent class :

class PauseMenuButton extends SpriteComponent with Tappable {
  @override
  bool onTapDown(TapDownInfo event) {
    try {

      print("back to menu");

      return true;
    } catch(error) {
      print(error);
      return false;
    }
  }
}

Thank you !

Upvotes: 0

Views: 1707

Answers (2)

shingo.nakanishi
shingo.nakanishi

Reputation: 2817

This is not a direct answer, but since this question appears at the top of Google search results for "hide flutter flame," I will document this here. With the introduction of the HasVisibility mixin, you can now achieve simple hiding functionality by using it.

Here is a simple sample code for hiding (the object moves to the right edge of the screen, hides for a while, and then reappears from the left edge):

import 'package:flame/components.dart';
import 'package:flame/game.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(const FooApp());
}

class FooApp extends StatelessWidget {
  const FooApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: GameWidget.controlled(gameFactory: FooFlameGame.new),
    );
  }
}

class BallCircleComponent extends CircleComponent with HasGameReference<FooFlameGame>, HasVisibility {
  BallCircleComponent({
    super.position,
    super.radius,
    super.anchor,
  }) : super();

  var _speed = 200.0;

  @override
  void update(double dt) {
    super.update(dt);
    final x = position.x + _speed * dt;
    if (x < radius || x > game.size.x - radius) {
      _speed *= -1;
    }
    position.x = x.clamp(radius, game.size.x - radius);
    if(_speed < 0) {
      isVisible = false;
    } else {
      isVisible = true;
    }
  }
}

class FooFlameGame extends FlameGame {
  late final BallCircleComponent ballCircleComponent;

  @override
  Future<void> onLoad() async {
    super.onLoad();

    ballCircleComponent = BallCircleComponent(
      position: Vector2(size.x * 0.5, size.y * 0.5),
      radius: size.x * 0.1,
      anchor: Anchor.center,
    );

    await add(ballCircleComponent);
  }
}

References:

Upvotes: 0

spydon
spydon

Reputation: 11562

onLoad will only be called once when the game is loaded, so you don't want to have logic like this in there. Usually you want to have logic when an event happens or in the update method. In this case you probably want to do it when the buttons are pressed.

For hiding the Components the easiest way is to simply remove them from the game.

You could create a world component that you add everything that is related to the actual gameplay in and then you can add the other screens, or buttons in this case directly in your game class.

So your game could look something like this:

class World extends Component with HasGameRef<MyGame> {
  @override
  void updateTree(double dt) {
    if(gameRef.isPaused) return;
    super.updateTree(dt);
  }
}

class MyGame extends FlameGame {
  PauseMenuButton pauseMenuButton = PauseMenuButton();
  late final World world;

  bool isPaused = false;
  bool gameOver = false;

  @override
  Future<void>? onLoad() async {
    pauseMenuButton
      ..sprite = await loadSprite("btnFastForward.png")
      ..size = pauseButtonSize
      ..position = Vector2(size[0] * 0.3, size[1]*0.3);
    add(world = World());
    world.add(Your game components);
  }
}

And then add HasGameRef<MyGame> to your PauseMenuButton, and when the button is clicked you just set gameRef.isPaused = true and remove any unwanted components from the game with gameRef.remove(...).

There is a SpriteButtonComponent that you might want to extend for your button instead of SpriteComponent.

Upvotes: 2

Related Questions