Reputation: 23
My flame game concept is that a player moves, and when the player collides with a star object, a pop up flutter window contains a question shall appear, and when the user closes it, the game state and player position will be restored.How can I do so?
I tried Navigator.push but it doesn't work, it says that no context available :(
Also I tried a different way, which is the overlay, but the Star class cannot access the overlays property, I wrote a method in the main game class "PlayerWithBG" but calling it throws an exception...
This is the code inside Star class
import 'package:flame/collisions.dart';
import 'package:flame/components.dart';
import 'package:flame/sprite.dart';
import 'package:flutter/material.dart';
import 'package:khalooq/Game/PlayerWithBG.dart';
import '../Questions/firstLevelQuestions.dart';
import 'helpers/directions.dart';
class Star extends SpriteAnimationComponent
with HasGameRef, CollisionCallbacks {
Star(Vector2 position)
: super(size: Vector2.all(50), position: position, anchor: Anchor.center);
final gameObject = PlayerWithBG();
late final SpriteAnimation _rotateAnimation;
final double _animationSpeed = .3;
Direction direction = Direction.right;
@override
Future<void> onLoad() async {
super.onLoad();
await _loadAnimations().then((_) => {animation = _rotateAnimation});
add(CircleHitbox());
}
Future<void> _loadAnimations() async {
final spriteSheet = SpriteSheet.fromColumnsAndRows(
image: await gameRef.images.load('stars1.png'), columns: 10, rows: 1);
_rotateAnimation = spriteSheet.createAnimation(
row: 0, stepTime: _animationSpeed, from: 0, to: 4);
}
@override
void onCollision(Set<Vector2> intersectionPoints, PositionComponent other) {
super.onCollision(intersectionPoints, other);
// gameObject.showQuestion();
// calling the showQuestion() method throws an exception in the method
/*
* Exception has occurred.
_AssertionError ('package:flame/src/game/overlay_manager.dart': Failed assertion: line 51 pos 7: '_builders.containsKey(name)': Trying to add an unknown overlay "Question")
*/
removeFromParent();
//This is what I want to do--------------------------------------------------
// Navigator.push(
// context, MaterialPageRoute(builder: (context) => firstLevelQuestion()));
}
}
And this is the code inside the main game class "PlayerWithBG"
import 'dart:ui';
import 'package:flame/game.dart';
import 'package:flame/input.dart';
import 'package:flutter/services.dart';
import 'Player.dart';
import 'GameBG.dart';
import 'package:flutter/material.dart';
import 'Star.dart';
import 'helpers/directions.dart';
class PlayerWithBG extends FlameGame
with KeyboardEvents, HasCollisionDetection, TapDetector {
Player _player = Player();
GameBG _gameBG = GameBG();
@override
Future<void> onLoad() async {
super.onLoad();
await add(_gameBG);
double bgWidth = _gameBG.size.x;
double bghight = _gameBG.size.y;
await add(_player);
_player.position = Vector2(bgWidth * 0.05, bghight * 0.95);
camera.followComponent(_player,
worldBounds: Rect.fromLTRB(0, 0, _gameBG.size.x, _gameBG.size.y));
//--------------------------------------------------------------------------------------
//Stars are the elements that should open the question when the player collides with them
add(Star(Vector2(bgWidth * 0.10, bghight * 0.95)));
add(Star(Vector2(bgWidth * 0.30, bghight * 0.95)));
}
void showQuestion() {
if (overlays.isActive('Question')) {
overlays.remove('Question');
resumeEngine();
} else {
overlays.add('Question');
pauseEngine();
}
}
onArrowKeyChanged(Direction direction) {
_player.direction = direction;
}
}
And here where I call the game widget with a temp overlay container
GameWidget(
game: game..paused = false,
//here is the overlayer to render the question--------------------
overlayBuilderMap: {
'Question': (BuildContext context, PlayerWithBG game) {
return Center(
child: Container(
width: 100,
height: 100,
color: Colors.orange,
child: Center(child: Text('This is a question')),
),
);
},
},
//-----------------------------------------------------------------
),
Upvotes: 2
Views: 1549
Reputation: 11512
You can do this in a few different ways:
1.Use the overlays system
Just like you tried, but to access the overlays you can use the fact that you have the HasGameRef
mixin on your component, which gives your access to the gameRef
variable and thus gameRef.overlays.add/remove
.
You can read more about that here.
2. Use the RouterComponent
This technique is slightly more advanced, but it is definitely worth exploring if you will have a lot of different screens and scenes.
Example:
final router = RouterComponent(
routes: {
'ok-dialog': OverlayRoute(
(context, game) {
return Center(
child: DecoratedContainer(...),
);
},
), // OverlayRoute
'confirm-dialog': OverlayRoute.existing(),
},
);
router.pushNamed('ok-dialog);
You can read a lot more about that here.
3. Use the normal Flutter navigation
The last, but least ergonomic way, is to use Flutter's built-in navigation (or another navigation package).
You can get the context in the same way as you accessed the overlays
, when you have the HasGameRef
mixin:
gameRef.buildContext;
Depending on how you do the navigation you might have to use the GameWidget.controlled
constructor when you create your GameWidget
.
Upvotes: 2