Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
March 14, 2021 05:29 am GMT

How I built a math game using Flutter & Firebase

You might know that I am currently learning Flutter. I watched few YouTube tutorials, wrote few posts about my learnings, and signed up for the #30DaysOfFlutter. I decided to take my learning journey to the next level by actually implementing something

BrainTrainer is a math game where you have 30 seconds to solve as many questions as possible. Your highest score will be displayed on the app bar and saved in Firebase.

BrainTrainer

The game has two screens in total. On main.dart we watch the firebase user to determine which screen to display.

class MyHomePage extends StatelessWidget {  @override  Widget build(BuildContext context) {    final firebaseUser = context.watch<User>();    return Scaffold(        appBar: AppBar(          title: Text('BrainTrainer'),        ),        body: firebaseUser != null ? loadGameScreen(context) : LoginPage());  }  Future<Object> loadGameScreen(BuildContext context) {    Future.delayed(Duration.zero, () {      return Navigator.of(context).pushNamedAndRemoveUntil(          GameScreen.routeName, (Route<dynamic> route) => false);    });  }}

We are using a provider to enable (Apple Sign In) using Firebase. check my previous post on that

We are using few widgets in the game:

ActionButtons Widget: This is where we show the play button to start the game. we also use to indicate to the player if their selected answer is correct or now

import 'package:brain_trainer_app/models/game.dart';import 'package:flutter/material.dart';import 'package:provider/provider.dart';class ActionButtons extends StatefulWidget {  const ActionButtons({    Key key,  }) : super(key: key);  @override  _ActionButtonsState createState() => _ActionButtonsState();}class _ActionButtonsState extends State<ActionButtons> {  @override  Widget build(BuildContext context) {    final _game = Provider.of<Game>(context);    return SizedBox(      height: 100,      child: GestureDetector(        onTap: () {          _game.playTheGame();        },        child: Card(          margin: EdgeInsets.all(10),          elevation: 8,          child: Container(            decoration: BoxDecoration(              borderRadius: BorderRadius.circular(10),              boxShadow: [                BoxShadow(color: Colors.white, spreadRadius: 3),              ],            ),            padding: EdgeInsets.all(10),            child: Consumer<Game>(              builder: (context, game, child) {                return Image.asset(                  _game.actionButtonImage,                  fit: BoxFit.cover,                );              },            ),          ),        ),      ),    );  }}

AnswerItem Widget: This represents an item on a grid to display a number for the player to select. One of those items will be the correct answer.

import 'package:brain_trainer_app/models/game.dart';import 'package:flutter/material.dart';import 'package:provider/provider.dart';class AnswerItem extends StatelessWidget {  final Answer answer;  final int index;  static const _answercolot = [    Color.fromRGBO(224, 81, 98, 1),    Color.fromRGBO(84, 160, 86, 1),    Color.fromRGBO(68, 150, 224, 1),    Color.fromRGBO(111, 64, 222, 1),  ];  const AnswerItem({Key key, this.answer, this.index}) : super(key: key);  @override  Widget build(BuildContext context) {    final _game = Provider.of<Game>(context);    return ClipRRect(      borderRadius: BorderRadius.circular(10),      child: GridTile(        child: GestureDetector(          onTap: () {            _game.answerSelected(this.answer);          },          child: Container(            decoration: BoxDecoration(              borderRadius: BorderRadius.circular(10),              color: _answercolot[this.index],              boxShadow: [                BoxShadow(color: Colors.white, spreadRadius: 3),              ],            ),            padding: EdgeInsets.all(10),            child: Center(                child: Text(              answer.value.toString(),              style: TextStyle(                  fontSize: 24,                  fontStyle: FontStyle.italic,                  fontWeight: FontWeight.bold),            )),          ),        ),      ),    );  }}

AnswersGrid Widget: A grid of 4 AnswerItem widgets.

import 'package:brain_trainer_app/models/game.dart';import 'package:brain_trainer_app/widgets/answer_item.dart';import 'package:flutter/material.dart';import 'package:provider/provider.dart';class AnswersGrid extends StatelessWidget {  @override  @override  Widget build(BuildContext context) {    final gameData = Provider.of<Game>(context);    final answers = gameData.answers;    return GridView.builder(        padding: const EdgeInsets.all(10.0),        itemCount: answers.length,        gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(            crossAxisCount: 2,            childAspectRatio: 3 / 2,            crossAxisSpacing: 10,            mainAxisSpacing: 10),        itemBuilder: (BuildContext context, int index) {          return AnswerItem(            answer: answers[index],            index: index,          );        });  }}

GameAds Widget: This is where we display Google AdMob Ads

import 'package:flutter/material.dart';import 'package:google_mobile_ads/google_mobile_ads.dart';class GameAds extends StatefulWidget {  @override  _GameAdsState createState() => _GameAdsState();}class _GameAdsState extends State<GameAds> {  BannerAd _bannerAd;  @override  void initState() {    super.initState();    MobileAds.instance.initialize();    _bannerAd = BannerAd(      size: AdSize.banner,      adUnitId: BannerAd.testAdUnitId,      listener: AdListener(),      request: AdRequest(),    );    _bannerAd..load();  }  @override  void dispose() {    super.dispose();    _bannerAd.dispose();  }  @override  Widget build(BuildContext context) {    return SizedBox(height: 50, child: AdWidget(ad: _bannerAd));  }}

GameConfetti Widget: We use this fun widget to display a celebration animation when the play finish the game

import 'package:brain_trainer_app/models/game.dart';import 'package:confetti/confetti.dart';import 'package:flutter/material.dart';import 'package:provider/provider.dart';import 'package:rflutter_alert/rflutter_alert.dart';class GameConfetti extends StatefulWidget {  @override  _GameConfettiState createState() => _GameConfettiState();}class _GameConfettiState extends State<GameConfetti> {  ConfettiController _controllerCenter;  @override  void initState() {    _controllerCenter =        ConfettiController(duration: const Duration(seconds: 10));    _controllerCenter.play();    super.initState();  }  @override  void dispose() {    _controllerCenter.dispose();    super.dispose();  }  _showAlert(context) {    Future.delayed(Duration.zero, () async {      final String _gameMsg =          Provider.of<Game>(context, listen: false).completionMsg;      var alertStyle = AlertStyle(        animationType: AnimationType.fromTop,        isCloseButton: false,        isOverlayTapDismiss: false,        descStyle: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),        descTextAlign: TextAlign.start,        animationDuration: Duration(milliseconds: 400),        overlayColor: Colors.transparent,        alertBorder: RoundedRectangleBorder(          borderRadius: BorderRadius.circular(0.0),          side: BorderSide(            color: Colors.grey,          ),        ),        titleStyle: TextStyle(          color: Colors.green,        ),        alertAlignment: Alignment.center,      );      Alert(        style: alertStyle,        context: context,        type: AlertType.success,        title: "Well done",        desc: _gameMsg,        buttons: [          DialogButton(            child: Text(              "Brilliant!!!",              style: TextStyle(color: Colors.white, fontSize: 16),            ),            onPressed: () => Navigator.pop(context),            width: 120,          )        ],      ).show();    });  }  @override  Widget build(BuildContext context) {    return Align(      alignment: Alignment.topCenter,      child: ConfettiWidget(          confettiController: _controllerCenter,          blastDirectionality: BlastDirectionality              .explosive, // don't specify a direction, blast randomly          shouldLoop: false,          gravity: 0.5,          emissionFrequency: 0.05,          numberOfParticles:              20, // start again as soon as the animation is finished          colors: const [            Colors.green,            Colors.blue,            Colors.pink,            Colors.orange,            Colors.purple          ], // manually specify the colors to be used          child: _showAlert(context)          ),    );  }}

TimerQuestionScoreRow Widget: Here, we show the 30s timer, The math question, and we keep track of the player score/

import 'package:brain_trainer_app/models/game.dart';import 'package:flutter/material.dart';import 'package:provider/provider.dart';class TimerQuestionScoreRow extends StatefulWidget {  const TimerQuestionScoreRow({    Key key,  }) : super(key: key);  @override  _TimerQuestionScoreRowState createState() => _TimerQuestionScoreRowState();}class _TimerQuestionScoreRowState extends State<TimerQuestionScoreRow> {  @override  Widget build(BuildContext context) {    final _game = Provider.of<Game>(context);    return Row(      mainAxisAlignment: MainAxisAlignment.spaceEvenly,      children: [        Expanded(          flex: 3,          child: SizedBox(            height: 100,            child: Card(              margin: EdgeInsets.all(10),              elevation: 8,              child: Container(                decoration: BoxDecoration(                  borderRadius: BorderRadius.circular(10),                  color: Color.fromRGBO(255, 152, 0, 1),                  boxShadow: [                    BoxShadow(color: Colors.white, spreadRadius: 3),                  ],                ),                padding: EdgeInsets.all(10),                child: Consumer<Game>(                  builder: (context, game, child) {                    return Center(                        child: Text(                      '${game.timer}s',                      style:                          TextStyle(fontSize: 16, fontWeight: FontWeight.bold),                    ));                  },                ),              ),            ),          ),        ),        Expanded(          flex: 4,          child: SizedBox(            height: 100,            child: Card(              margin: EdgeInsets.all(10),              elevation: 8,              child: Container(                decoration: BoxDecoration(                  borderRadius: BorderRadius.circular(10),                  boxShadow: [                    BoxShadow(color: Colors.white, spreadRadius: 3),                  ],                ),                padding: EdgeInsets.all(10),                child: Consumer<Game>(                  builder: (context, game, child) {                    return Center(                        child: Text(                      '${game.question}',                      style:                          TextStyle(fontSize: 16, fontWeight: FontWeight.bold),                    ));                  },                ),              ),            ),          ),        ),        Expanded(          flex: 3,          child: SizedBox(            height: 100,            child: Card(              margin: EdgeInsets.all(10),              elevation: 8,              child: Container(                decoration: BoxDecoration(                  borderRadius: BorderRadius.circular(10),                  color: Color.fromRGBO(3, 169, 244, 1),                  boxShadow: [                    BoxShadow(color: Colors.white, spreadRadius: 3),                  ],                ),                padding: EdgeInsets.all(10),                child: Consumer<Game>(                  builder: (context, game, child) {                    return Center(                        child: Text(                      '${game.score}',                      style:                          TextStyle(fontSize: 16, fontWeight: FontWeight.bold),                    ));                  },                ),              ),            ),          ),        ),      ],    );  }}

The game use three models:

Game: This is the primary model where we set up the game. Here we also verify the selected answer and keep track of the timer.

Answer: This is a simple model to represent the answer value

Player: This is where we have the player information we get from Firebase, and we also use it to track the high score.

We are using DataRepository class to retrieves and saves the data.

import 'package:brain_trainer_app/models/player.dart';import 'package:cloud_firestore/cloud_firestore.dart';class DataRepository {  final CollectionReference collection =      FirebaseFirestore.instance.collection('players');  Future<void> addPlayer(Player player) {    return collection.doc(player.uid).set(player.toJson());  }  updatePlayer(Player player) async {    await collection.doc(player.uid).update(player.toJson());  }  Future<Player> getPlayer(String uid) async {    var doc = await collection.doc(uid).get();    if (doc.data() == null) {      return null;    }    return Player.fromJson(doc.data());  }}

The game is on Apple Store here and Google Play here

Check the code here

brain_trainer_app

Do you enjoy math? Do you enjoy games? Want to relax and train your brain? Try this amazing app for some fun Brain Trainer.

Brain Trainer consists of simple math-based games designed to exercise memory, speed, and attention. Take a break from your busy schedule and use Brain Trainer to relax and practice some math.

Follow me on Twitter for more tips about #coding, #learning, #technology, #Java, #JavaScript...etc.

Check my Apps on Google Play

Cover image Amol Tyagi on Unsplash


Original Link: https://dev.to/offlineprogrammer/how-i-built-a-math-game-using-flutter-firebase-i4o

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To