mnemo_cards/games/apps/funny_letters/lib/main.dart
2025-11-19 21:00:23 +03:00

335 lines
8.3 KiB
Dart

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<void> main(List<String> 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<MyApp?> 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<StatefulWidget> createState() => MenuState();
const Menu({super.key});
}
class MenuState extends State<Menu> {
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();
}
}
}