import 'dart:io'; import 'package:audioplayers/audioplayers.dart'; import 'package:flame/cache.dart'; import 'package:flame/flame.dart'; import 'package:flame/game.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:funny_letters/app_binder.dart'; import 'package:funny_letters/funny_letters.dart'; import 'package:funny_letters/gen/assets.gen.dart'; import 'package:funny_letters/runner/ui/button.dart'; import 'package:mnemo_cards_game_api/mnemo_cards_game_api.dart'; import 'runner/bonuses/letter_bonus.dart'; import 'runner/game_manager.dart'; var _game = GameManager()..pauseEngine(); var menuKey = GlobalKey(); var effectPlayer = AudioPlayer(); var audioPlayer = AudioPlayer()..setVolume(0.25); late AppBinder assetLoader; late FunnyLettersSettings gameSettings; // Run web app Future main(List args) async { WidgetsFlutterBinding.ensureInitialized(); Flame.images.prefix = ''; await Flame.images.loadAll([ Assets.images.gameOver.path, Assets.images.icons.play.path, Assets.images.icons.restart.path, ]); await Flame.device.fullScreen(); runApp( ScreenUtilInit( designSize: const Size(360, 690), minTextAdapt: true, splitScreenMode: true, child: MaterialApp( home: FutureBuilder( future: Future.value(),//MyApp.initialize(), builder: (context, snapshot) { if (snapshot.hasError) { return Center( child: Text('Error: ${snapshot.error}'), ); } if (!snapshot.hasData) { return const Center( child: CircularProgressIndicator(), ); } return snapshot.data!; }, ), ), ), ); } class MyApp extends StatelessWidget { final AppBinder assetLoader; final FunnyLettersSettings gameSettings; MyApp._({ required this.assetLoader, required this.gameSettings, }); static Future initialize() async { // final loader = AppBinderImpl(); // Initialize JavaScript environment for web communication // loader.initializeJavaScript(); // final settings = await loader.loadSettings(); // return MyApp._( // assetLoader: loader, // gameSettings: settings, // ); } @override Widget build(BuildContext context) { return MaterialApp( theme: gameSettings.themeData.toMaterialTheme(), home: GameView( assetLoader, gameSettings, ), ); } } class GameView extends StatelessWidget { GameView( AppBinder loader, FunnyLettersSettings settings, { super.key, }) { assetLoader = loader; gameSettings = settings; } @override Widget build(BuildContext context) { WidgetsBinding.instance.addObserver(_Handler()); Flame.images = Images(prefix: ''); Flame.assets = AssetsCache(prefix: ''); _game = GameManager()..pauseEngine(); menuKey = GlobalKey(); effectPlayer = AudioPlayer(); audioPlayer = AudioPlayer()..setVolume(0.25); return PopScope( onPopInvokedWithResult: (didPop, result) { if (didPop) { _game.pauseEngine(); audioPlayer.stop(); effectPlayer.stop(); _game.dispose(); } }, child: Menu(key: menuKey), ); } } class Menu extends StatefulWidget { @override State createState() => MenuState(); const Menu({super.key}); } class MenuState extends State { int index = 2; void openGameOver() { setState(() { index = 0; }); } void restartGame() => _startGame(); @override void initState() { super.initState(); // audioPlayer.setReleaseMode(ReleaseMode.loop); // if (gameSettings.musicEnabled) { // audioPlayer.play( // BytesSource( // assetLoader.loadFile('assets/go.mp3').readAsBytesSync(), // ), // ); // } } @override Widget build(BuildContext context) { return MaterialApp( theme: gameSettings.themeData.toMaterialTheme(), home: Scaffold( body: Container( decoration: background != null ? null // Background will be handled by GameManager : null, child: IndexedStack( index: index, children: [ gameOver(), game(), startPage(), ], ), ), ), ); } Widget gameOver() { return Column( mainAxisAlignment: MainAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.center, children: [ const SizedBox( height: 80, ), Image( image: Assets.images.gameOver.provider(), width: MediaQuery.of(context).size.width, ), const SizedBox( height: 64, ), Padding( padding: const EdgeInsets.symmetric(vertical: 50.0), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ ...goText.characters.map( (e) => e == ' ' ? const SizedBox(width: 20) : LetterBonus.image(letter: e, width: 42), ) ], ), ), Button( Assets.images.icons.restart.path, () => restartGame(), ), const SizedBox( height: 64, ), ], ); } Widget startPage() { return Column( mainAxisAlignment: MainAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.center, children: [ const SizedBox( height: 80, ), Padding( padding: const EdgeInsets.symmetric(vertical: 50.0), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ ...goText.characters.map( (e) => e == ' ' ? const SizedBox(width: 20) : LetterBonus.image(letter: e, width: 42), ) ], ), ), Button( Assets.images.icons.play.path, () => setState(() { _startGame(); }), ), const SizedBox( height: 64, ), ], ); } Widget game() => GameWidget( game: _game, backgroundBuilder: (context) => Scaffold(), ); Widget levelButton( VoidCallback onTap, String title, ) { return InkWell( onTap: onTap, child: Padding( padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 12.0), child: Container( padding: const EdgeInsets.symmetric(vertical: 16.0, horizontal: 12.0), decoration: BoxDecoration( borderRadius: BorderRadius.circular(32), gradient: const LinearGradient( colors: [ Color(0xff2F61D1), Color(0xff53AFED), ], begin: Alignment.bottomLeft, end: Alignment.topRight, )), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ ...title.toLowerCase().characters.map( (e) => e == ' ' ? const SizedBox( width: 32, ) : LetterBonus.image(letter: e, width: 32), ) ], ), ), ), ); } void _startGame() { setState(() { index = 1; // level = nextLevel; _game.resumeEngine(); }); } Widget button(VoidCallback onTap, String asset) { return Container( padding: const EdgeInsets.symmetric(vertical: 12.0, horizontal: 24), width: 240, child: InkWell( onTap: onTap, child: Image(image: AssetImage('assets/images/$asset')), ), ); } } class _Handler extends WidgetsBindingObserver { @override void didChangeAppLifecycleState(AppLifecycleState state) { if (state == AppLifecycleState.resumed) { if (gameSettings.musicEnabled) { audioPlayer.resume(); } if (gameSettings.soundEnabled) { effectPlayer.resume(); } } else { audioPlayer.pause(); effectPlayer.pause(); } } }