flame_riverpod 2.0.0 flame_riverpod: ^2.0.0 copied to clipboard
Widgets, providers, and an example project for using Riverpod in conjunction with Flame.
import 'dart:async';
import 'package:flame/components.dart' hide Timer;
import 'package:flame/game.dart';
import 'package:flame_riverpod/flame_riverpod.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
final countingStreamProvider = StreamProvider<int>((ref) {
return Stream.periodic(const Duration(seconds: 1), (inc) => inc);
});
void main() {
runApp(const ProviderScope(child: MyApp()));
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: Row(crossAxisAlignment: CrossAxisAlignment.start, children: [
const Expanded(child: FlutterCountingComponent()),
Expanded(
child: RiverpodGameWidget.initialiseWithGame(
uninitialisedGame: (ref) => RefExampleGame(ref)))
]),
);
}
}
class FlutterCountingComponent extends ConsumerWidget {
const FlutterCountingComponent({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final textStyle =
Theme.of(context).textTheme.headline5?.copyWith(color: Colors.white);
final stream = ref.watch(countingStreamProvider);
return Material(
color: Colors.transparent,
child: Column(
children: [
Text('Flutter', style: textStyle),
stream.when(
data: (value) => Text('$value', style: textStyle),
error: (error, stackTrace) => Text('$error', style: textStyle),
loading: () => Text('Loading...', style: textStyle))
],
),
);
}
}
class RefExampleGame extends FlameGame with HasComponentRef {
RefExampleGame(WidgetRef ref) {
this.ref = ComponentRef(ref);
}
@override
onLoad() async {
await super.onLoad();
add(TextComponent(text: 'Flame'));
add(RiverpodAwareTextComponent(ref));
}
}
class RiverpodGameWidget extends ConsumerStatefulWidget {
const RiverpodGameWidget.readFromProvider({super.key})
: uninitialisedGame = null;
const RiverpodGameWidget.initialiseWithGame(
{super.key, required this.uninitialisedGame});
final HasComponentRef Function(WidgetRef ref)? uninitialisedGame;
@override
ConsumerState<RiverpodGameWidget> createState() => _RiverpodGameWidgetState();
}
class _RiverpodGameWidgetState extends ConsumerState<RiverpodGameWidget> {
@override
void initState() {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
if (widget.uninitialisedGame is HasComponentRef Function(
WidgetRef ref)) {
ref
.read(riverpodAwareGameProvider.notifier)
.set(widget.uninitialisedGame!(ref));
}
});
super.initState();
}
@override
Widget build(BuildContext context) {
final game = ref.watch(riverpodAwareGameProvider);
if (game is! Game) {
return Container();
}
return GameWidget(game: game!);
}
}
class RiverpodAwareTextComponent extends PositionComponent
with RiverpodComponentMixin {
// ComponentRef is a wrapper around WidgetRef and exposes
// a subset of its API.
RiverpodAwareTextComponent(ComponentRef ref) {
this.ref = ref;
}
late TextComponent textComponent;
int currentValue = 0;
/// [onMount] should be used over [onLoad], as subscriptions are cancelled
/// inside [onRemove], which is only called if the [Component] was mounted.
@override
void onMount() {
super.onMount();
add(textComponent = TextComponent(position: position + Vector2(0, 27)));
listen(countingStreamProvider, (p0, p1) {
if (p1.hasValue) {
currentValue = p1.value!;
textComponent.text = '$currentValue';
}
});
}
}