Ver código fonte

init(first): first init

zhaoyadi 1 ano atrás
commit
9f6a551c79
51 arquivos alterados com 2382 adições e 0 exclusões
  1. 3 0
      .fvmrc
  2. 46 0
      .gitignore
  3. 30 0
      .metadata
  4. 28 0
      analysis_options.yaml
  5. 13 0
      android/.gitignore
  6. 58 0
      android/app/build.gradle
  7. 7 0
      android/app/src/debug/AndroidManifest.xml
  8. 45 0
      android/app/src/main/AndroidManifest.xml
  9. 5 0
      android/app/src/main/kotlin/com/zaojiao/battle/MainActivity.kt
  10. 12 0
      android/app/src/main/res/drawable-v21/launch_background.xml
  11. 12 0
      android/app/src/main/res/drawable/launch_background.xml
  12. BIN
      android/app/src/main/res/mipmap-hdpi/ic_launcher.png
  13. BIN
      android/app/src/main/res/mipmap-mdpi/ic_launcher.png
  14. BIN
      android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
  15. BIN
      android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
  16. BIN
      android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
  17. 22 0
      android/app/src/main/res/values-night/styles.xml
  18. 22 0
      android/app/src/main/res/values/styles.xml
  19. 7 0
      android/app/src/profile/AndroidManifest.xml
  20. 18 0
      android/build.gradle
  21. 3 0
      android/gradle.properties
  22. 5 0
      android/gradle/wrapper/gradle-wrapper.properties
  23. 25 0
      android/settings.gradle
  24. BIN
      assets/images/background.png
  25. 19 0
      lib/app/battle_app.dart
  26. 10 0
      lib/button/button_color.dart
  27. 113 0
      lib/button/button_controller.dart
  28. 32 0
      lib/button/button_painter.dart
  29. 9 0
      lib/data/data.dart
  30. 12 0
      lib/main.dart
  31. 0 0
      lib/page/about_page.dart
  32. 82 0
      lib/page/game_page.dart
  33. 50 0
      lib/page/home_page.dart
  34. 0 0
      lib/page/setting_page.dart
  35. 10 0
      packages/repository/.metadata
  36. 4 0
      packages/repository/analysis_options.yaml
  37. 7 0
      packages/repository/lib/repository.dart
  38. 205 0
      packages/repository/pubspec.lock
  39. 54 0
      packages/repository/pubspec.yaml
  40. 10 0
      packages/widget/.metadata
  41. 4 0
      packages/widget/analysis_options.yaml
  42. 33 0
      packages/widget/lib/src/battle_background.dart
  43. 114 0
      packages/widget/lib/src/battle_foreground.dart
  44. 88 0
      packages/widget/lib/src/battle_layout.dart
  45. 54 0
      packages/widget/lib/src/battle_path.dart
  46. 65 0
      packages/widget/lib/src/constant.dart
  47. 5 0
      packages/widget/lib/widget.dart
  48. 205 0
      packages/widget/pubspec.lock
  49. 54 0
      packages/widget/pubspec.yaml
  50. 736 0
      pubspec.lock
  51. 46 0
      pubspec.yaml

+ 3 - 0
.fvmrc

@@ -0,0 +1,3 @@
+{
+  "flutter": "stable"
+}

+ 46 - 0
.gitignore

@@ -0,0 +1,46 @@
+# Miscellaneous
+*.class
+*.log
+*.pyc
+*.swp
+.DS_Store
+.atom/
+.buildlog/
+.history
+.svn/
+migrate_working_dir/
+
+# IntelliJ related
+*.iml
+*.ipr
+*.iws
+.idea/
+
+# The .vscode folder contains launch configuration and tasks you configure in
+# VS Code which you may wish to be included in version control, so this line
+# is commented out by default.
+#.vscode/
+
+# Flutter/Dart/Pub related
+**/doc/api/
+**/ios/Flutter/.last_build_id
+.dart_tool/
+.flutter-plugins
+.flutter-plugins-dependencies
+.pub-cache/
+.pub/
+/build/
+
+# Symbolication related
+app.*.symbols
+
+# Obfuscation related
+app.*.map.json
+
+# Android Studio will place build artifacts here
+/android/app/debug
+/android/app/profile
+/android/app/release
+
+# FVM Version Cache
+.fvm/

+ 30 - 0
.metadata

@@ -0,0 +1,30 @@
+# This file tracks properties of this Flutter project.
+# Used by Flutter tool to assess capabilities and perform upgrades etc.
+#
+# This file should be version controlled and should not be manually edited.
+
+version:
+  revision: "5dcb86f68f239346676ceb1ed1ea385bd215fba1"
+  channel: "stable"
+
+project_type: app
+
+# Tracks metadata for the flutter migrate command
+migration:
+  platforms:
+    - platform: root
+      create_revision: 5dcb86f68f239346676ceb1ed1ea385bd215fba1
+      base_revision: 5dcb86f68f239346676ceb1ed1ea385bd215fba1
+    - platform: android
+      create_revision: 5dcb86f68f239346676ceb1ed1ea385bd215fba1
+      base_revision: 5dcb86f68f239346676ceb1ed1ea385bd215fba1
+
+  # User provided section
+
+  # List of Local paths (relative to this file) that should be
+  # ignored by the migrate tool.
+  #
+  # Files that are not part of the templates will be ignored by default.
+  unmanaged_files:
+    - 'lib/main.dart'
+    - 'ios/Runner.xcodeproj/project.pbxproj'

+ 28 - 0
analysis_options.yaml

@@ -0,0 +1,28 @@
+# This file configures the analyzer, which statically analyzes Dart code to
+# check for errors, warnings, and lints.
+#
+# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
+# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
+# invoked from the command line by running `flutter analyze`.
+
+# The following line activates a set of recommended lints for Flutter apps,
+# packages, and plugins designed to encourage good coding practices.
+include: package:flutter_lints/flutter.yaml
+
+linter:
+  # The lint rules applied to this project can be customized in the
+  # section below to disable rules from the `package:flutter_lints/flutter.yaml`
+  # included above or to enable additional rules. A list of all available lints
+  # and their documentation is published at https://dart.dev/lints.
+  #
+  # Instead of disabling a lint rule for the entire project in the
+  # section below, it can also be suppressed for a single line of code
+  # or a specific dart file by using the `// ignore: name_of_lint` and
+  # `// ignore_for_file: name_of_lint` syntax on the line or in the file
+  # producing the lint.
+  rules:
+    # avoid_print: false  # Uncomment to disable the `avoid_print` rule
+    # prefer_single_quotes: true  # Uncomment to enable the `prefer_single_quotes` rule
+
+# Additional information about this file can be found at
+# https://dart.dev/guides/language/analysis-options

+ 13 - 0
android/.gitignore

@@ -0,0 +1,13 @@
+gradle-wrapper.jar
+/.gradle
+/captures/
+/gradlew
+/gradlew.bat
+/local.properties
+GeneratedPluginRegistrant.java
+
+# Remember to never publicly share your keystore.
+# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
+key.properties
+**/*.keystore
+**/*.jks

+ 58 - 0
android/app/build.gradle

@@ -0,0 +1,58 @@
+plugins {
+    id "com.android.application"
+    id "kotlin-android"
+    // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
+    id "dev.flutter.flutter-gradle-plugin"
+}
+
+def localProperties = new Properties()
+def localPropertiesFile = rootProject.file("local.properties")
+if (localPropertiesFile.exists()) {
+    localPropertiesFile.withReader("UTF-8") { reader ->
+        localProperties.load(reader)
+    }
+}
+
+def flutterVersionCode = localProperties.getProperty("flutter.versionCode")
+if (flutterVersionCode == null) {
+    flutterVersionCode = "1"
+}
+
+def flutterVersionName = localProperties.getProperty("flutter.versionName")
+if (flutterVersionName == null) {
+    flutterVersionName = "1.0"
+}
+
+android {
+    namespace = "com.zaojiao.battle"
+    compileSdk = flutter.compileSdkVersion
+    ndkVersion = flutter.ndkVersion
+
+    compileOptions {
+        sourceCompatibility = JavaVersion.VERSION_1_8
+        targetCompatibility = JavaVersion.VERSION_1_8
+    }
+
+    defaultConfig {
+        // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
+        applicationId = "com.zaojiao.battle"
+        // You can update the following values to match your application needs.
+        // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
+        minSdk = flutter.minSdkVersion
+        targetSdk = flutter.targetSdkVersion
+        versionCode = flutterVersionCode.toInteger()
+        versionName = flutterVersionName
+    }
+
+    buildTypes {
+        release {
+            // TODO: Add your own signing config for the release build.
+            // Signing with the debug keys for now, so `flutter run --release` works.
+            signingConfig = signingConfigs.debug
+        }
+    }
+}
+
+flutter {
+    source = "../.."
+}

+ 7 - 0
android/app/src/debug/AndroidManifest.xml

@@ -0,0 +1,7 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android">
+    <!-- The INTERNET permission is required for development. Specifically,
+         the Flutter tool needs it to communicate with the running application
+         to allow setting breakpoints, to provide hot reload, etc.
+    -->
+    <uses-permission android:name="android.permission.INTERNET"/>
+</manifest>

+ 45 - 0
android/app/src/main/AndroidManifest.xml

@@ -0,0 +1,45 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android">
+    <application
+        android:label="battle"
+        android:name="${applicationName}"
+        android:icon="@mipmap/ic_launcher">
+        <activity
+            android:name=".MainActivity"
+            android:exported="true"
+            android:launchMode="singleTop"
+            android:taskAffinity=""
+            android:theme="@style/LaunchTheme"
+            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
+            android:hardwareAccelerated="true"
+            android:windowSoftInputMode="adjustResize">
+            <!-- Specifies an Android theme to apply to this Activity as soon as
+                 the Android process has started. This theme is visible to the user
+                 while the Flutter UI initializes. After that, this theme continues
+                 to determine the Window background behind the Flutter UI. -->
+            <meta-data
+              android:name="io.flutter.embedding.android.NormalTheme"
+              android:resource="@style/NormalTheme"
+              />
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
+        <!-- Don't delete the meta-data below.
+             This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
+        <meta-data
+            android:name="flutterEmbedding"
+            android:value="2" />
+    </application>
+    <!-- Required to query activities that can process text, see:
+         https://developer.android.com/training/package-visibility and
+         https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.
+
+         In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
+    <queries>
+        <intent>
+            <action android:name="android.intent.action.PROCESS_TEXT"/>
+            <data android:mimeType="text/plain"/>
+        </intent>
+    </queries>
+</manifest>

+ 5 - 0
android/app/src/main/kotlin/com/zaojiao/battle/MainActivity.kt

@@ -0,0 +1,5 @@
+package com.zaojiao.battle
+
+import io.flutter.embedding.android.FlutterActivity
+
+class MainActivity: FlutterActivity()

+ 12 - 0
android/app/src/main/res/drawable-v21/launch_background.xml

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Modify this file to customize your launch splash screen -->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:drawable="?android:colorBackground" />
+
+    <!-- You can insert your own image assets here -->
+    <!-- <item>
+        <bitmap
+            android:gravity="center"
+            android:src="@mipmap/launch_image" />
+    </item> -->
+</layer-list>

+ 12 - 0
android/app/src/main/res/drawable/launch_background.xml

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Modify this file to customize your launch splash screen -->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:drawable="@android:color/white" />
+
+    <!-- You can insert your own image assets here -->
+    <!-- <item>
+        <bitmap
+            android:gravity="center"
+            android:src="@mipmap/launch_image" />
+    </item> -->
+</layer-list>

BIN
android/app/src/main/res/mipmap-hdpi/ic_launcher.png


BIN
android/app/src/main/res/mipmap-mdpi/ic_launcher.png


BIN
android/app/src/main/res/mipmap-xhdpi/ic_launcher.png


BIN
android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png


BIN
android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png


+ 22 - 0
android/app/src/main/res/values-night/styles.xml

@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
+    <style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
+        <!-- Show a splash screen on the activity. Automatically removed when
+             the Flutter engine draws its first frame -->
+        <item name="android:windowBackground">@drawable/launch_background</item>
+    </style>
+    <!-- Theme applied to the Android Window as soon as the process has started.
+         This theme determines the color of the Android Window while your
+         Flutter UI initializes, as well as behind your Flutter UI while its
+         running.
+
+         This Theme is only used starting with V2 of Flutter's Android embedding. -->
+    <style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
+        <item name="android:windowBackground">?android:colorBackground</item>
+        <item name="android:windowDrawsSystemBarBackgrounds">true</item>
+        <item name="android:statusBarColor">@android:color/transparent</item>
+        <item name="android:navigationBarColor">@android:color/transparent</item>
+        <item name="android:windowLayoutInDisplayCutoutMode">always</item>
+    </style>
+</resources>

+ 22 - 0
android/app/src/main/res/values/styles.xml

@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
+    <style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
+        <!-- Show a splash screen on the activity. Automatically removed when
+             the Flutter engine draws its first frame -->
+        <item name="android:windowBackground">@drawable/launch_background</item>
+    </style>
+    <!-- Theme applied to the Android Window as soon as the process has started.
+         This theme determines the color of the Android Window while your
+         Flutter UI initializes, as well as behind your Flutter UI while its
+         running.
+
+         This Theme is only used starting with V2 of Flutter's Android embedding. -->
+    <style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
+        <item name="android:windowBackground">?android:colorBackground</item>
+        <item name="android:windowDrawsSystemBarBackgrounds">true</item>
+        <item name="android:statusBarColor">@android:color/transparent</item>
+        <item name="android:navigationBarColor">@android:color/transparent</item>
+        <item name="android:windowLayoutInDisplayCutoutMode">always</item>
+    </style>
+</resources>

+ 7 - 0
android/app/src/profile/AndroidManifest.xml

@@ -0,0 +1,7 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android">
+    <!-- The INTERNET permission is required for development. Specifically,
+         the Flutter tool needs it to communicate with the running application
+         to allow setting breakpoints, to provide hot reload, etc.
+    -->
+    <uses-permission android:name="android.permission.INTERNET"/>
+</manifest>

+ 18 - 0
android/build.gradle

@@ -0,0 +1,18 @@
+allprojects {
+    repositories {
+        google()
+        mavenCentral()
+    }
+}
+
+rootProject.buildDir = "../build"
+subprojects {
+    project.buildDir = "${rootProject.buildDir}/${project.name}"
+}
+subprojects {
+    project.evaluationDependsOn(":app")
+}
+
+tasks.register("clean", Delete) {
+    delete rootProject.buildDir
+}

+ 3 - 0
android/gradle.properties

@@ -0,0 +1,3 @@
+org.gradle.jvmargs=-Xmx4G -XX:+HeapDumpOnOutOfMemoryError
+android.useAndroidX=true
+android.enableJetifier=true

+ 5 - 0
android/gradle/wrapper/gradle-wrapper.properties

@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip

+ 25 - 0
android/settings.gradle

@@ -0,0 +1,25 @@
+pluginManagement {
+    def flutterSdkPath = {
+        def properties = new Properties()
+        file("local.properties").withInputStream { properties.load(it) }
+        def flutterSdkPath = properties.getProperty("flutter.sdk")
+        assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
+        return flutterSdkPath
+    }()
+
+    includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
+
+    repositories {
+        google()
+        mavenCentral()
+        gradlePluginPortal()
+    }
+}
+
+plugins {
+    id "dev.flutter.flutter-plugin-loader" version "1.0.0"
+    id "com.android.application" version "7.3.0" apply false
+    id "org.jetbrains.kotlin.android" version "1.7.10" apply false
+}
+
+include ":app"

BIN
assets/images/background.png


+ 19 - 0
lib/app/battle_app.dart

@@ -0,0 +1,19 @@
+import 'package:flutter/material.dart';
+
+import '../page/game_page.dart';
+
+class BattleApp extends StatelessWidget {
+  const BattleApp({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return MaterialApp(
+      title: '逻辑狗AI对抗',
+      theme: ThemeData(
+        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
+        useMaterial3: true,
+      ),
+      home: const GamePage(),
+    );
+  }
+}

+ 10 - 0
lib/button/button_color.dart

@@ -0,0 +1,10 @@
+import 'dart:ui';
+
+List<Color> colors = <Color>[
+  const Color(0xFFFF0000),
+  const Color(0xFF00FF00),
+  const Color(0xFF0000FF),
+  const Color(0xFFFFFF00),
+  const Color(0xFF00FFFF),
+  const Color(0xFFFF00FF),
+];

+ 113 - 0
lib/button/button_controller.dart

@@ -0,0 +1,113 @@
+import 'dart:math';
+
+import 'package:battle/button/button_color.dart';
+import 'package:flutter/animation.dart';
+import 'package:flutter/foundation.dart';
+
+import '../data/data.dart';
+
+enum ButtonState { start, stop }
+
+class ButtonInfo {
+  Color color;
+  int startIndex;
+  int endIndex;
+  double process;
+
+  ButtonInfo({
+    required this.color,
+    required this.startIndex,
+    required this.endIndex,
+    this.process = 0,
+  });
+}
+
+class ButtonController with ChangeNotifier {
+  final TickerProvider vsync;
+
+  ButtonController({required this.vsync}) {
+    _animationController = AnimationController(
+      upperBound: 6.0,
+      vsync: vsync,
+      duration: Duration(seconds: 10),
+    );
+
+    List<Color> colorList = _generateColorList();
+    List<int> startIndex = _generateIntList();
+    List<int> endIndex = _generateIntList();
+
+    startButton = List.generate(6, (index) {
+      return ButtonInfo(
+        color: colorList[index],
+        startIndex: startIndex[index],
+        endIndex: endIndex[index],
+      );
+    });
+
+    _animationController.addListener(() {
+      int index = _animationController.value ~/ 1;
+      double process = _animationController.value % 1.0;
+
+      startButton[index].process = process;
+
+      notifyListeners();
+    });
+  }
+
+  void start() {
+    _animationController.forward();
+  }
+
+  void reset() {
+    List<Color> colorList = _generateColorList();
+    List<int> startIndex = _generateIntList();
+    List<int> endIndex = _generateIntList();
+
+    startButton = List.generate(6, (index) {
+      return ButtonInfo(
+        color: colorList[index],
+        startIndex: startIndex[index],
+        endIndex: endIndex[index],
+      );
+    });
+
+    _animationController.forward(from: 0);
+  }
+
+  void stop() {
+    _animationController.stop();
+  }
+
+  late AnimationController _animationController;
+  late List<ButtonInfo> startButton = [];
+
+  List<Color> _generateColorList() {
+    List<Color> list = List.of(colors);
+    var random = Random.secure();
+    for (int i = 0; i < 10; i++) {
+      int i = random.nextInt(list.length);
+      int j = random.nextInt(list.length);
+
+      Color temp = list[i];
+      list[i] = list[j];
+      list[j] = temp;
+    }
+
+    return list;
+  }
+
+  List<int> _generateIntList() {
+    List<int> list = answers[0].toList();
+    var random = Random.secure();
+    for (int i = 0; i < 3; i++) {
+      int i = random.nextInt(list.length);
+      int j = random.nextInt(list.length);
+
+      int temp = list[i];
+      list[i] = list[j];
+      list[j] = temp;
+    }
+
+    return list;
+  }
+}

+ 32 - 0
lib/button/button_painter.dart

@@ -0,0 +1,32 @@
+import 'dart:ui';
+
+import 'package:battle/button/button_controller.dart';
+import 'package:flutter/material.dart';
+import 'package:widget/widget.dart';
+
+class ButtonPainter extends CustomPainter {
+  final ButtonController controller;
+
+  ButtonPainter({required this.controller}) : super(repaint: controller);
+
+  @override
+  void paint(Canvas canvas, Size size) {
+    final paint = Paint()
+      ..style = PaintingStyle.fill
+      ..strokeWidth = 4;
+
+    for (var button in controller.startButton) {
+      var path = fromBottomToCenter(size, button.startIndex, button.endIndex);
+      var pms = path.computeMetrics();
+      for (var pm in pms) {
+        Tangent? tangent = pm.getTangentForOffset(pm.length * button.process);
+        if (tangent == null) continue;
+        paint.color = button.color;
+        canvas.drawCircle(tangent.position, getButtonSize(size) / 2, paint);
+      }
+    }
+  }
+
+  @override
+  bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
+}

+ 9 - 0
lib/data/data.dart

@@ -0,0 +1,9 @@
+final List<(int, int, int, int, int, int)> answers = [
+  (4, 3, 2, 5, 1, 0),
+];
+
+extension AnswerToList on (int, int, int, int, int, int) {
+  List<int> toList() {
+    return [$1, $2, $3, $4, $5, $6];
+  }
+}

+ 12 - 0
lib/main.dart

@@ -0,0 +1,12 @@
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+
+import 'app/battle_app.dart';
+
+void main() {
+  WidgetsFlutterBinding.ensureInitialized();
+
+  SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky);
+
+  runApp(const BattleApp());
+}

+ 0 - 0
lib/page/about_page.dart


+ 82 - 0
lib/page/game_page.dart

@@ -0,0 +1,82 @@
+import 'package:battle/button/button_controller.dart';
+import 'package:flutter/material.dart';
+import 'package:widget/widget.dart';
+
+import '../button/button_painter.dart';
+
+class GamePage extends StatefulWidget {
+  const GamePage({super.key});
+
+  @override
+  State<GamePage> createState() => _GamePageState();
+}
+
+class _GamePageState extends State<GamePage> with SingleTickerProviderStateMixin {
+  late ButtonController _controller;
+
+  @override
+  void initState() {
+    super.initState();
+    _controller = ButtonController(vsync: this);
+    _controller.start();
+  }
+
+  void _reset() {
+    _controller.reset();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return Scaffold(
+      body: Stack(
+        children: [
+          Positioned.fill(
+            child: ColorFiltered(
+              colorFilter: const ColorFilter.matrix(<double>[
+                1, 0, 0, 0, 0, //r
+                0, 1, 0, 0, 0, //r
+                0, 0, 1, 0, 0, //r
+                0, 0, 0, 0.25, 0, //r
+              ]),
+              child: Image.asset(
+                'assets/images/background.png',
+                repeat: ImageRepeat.repeat,
+                cacheWidth: 30,
+                cacheHeight: 30,
+              ),
+            ),
+          ),
+          Positioned.fill(
+            child: Column(
+              children: [
+                Expanded(
+                  child: Padding(
+                    padding: const EdgeInsets.symmetric(horizontal: 16),
+                    child: BattleBoard(
+                      card: ClipRRect(
+                        borderRadius: BorderRadius.circular(8),
+                        child: Container(
+                          color: Colors.grey,
+                        ),
+                      ),
+                      button: CustomPaint(
+                        painter: ButtonPainter(controller: _controller),
+                        child: const SizedBox.expand(),
+                      ),
+                    ),
+                  ),
+                ),
+                TextButton(
+                  onPressed: () {
+                    _reset();
+                  },
+                  child: const Text('重新开始'),
+                ),
+              ],
+            ),
+          ),
+        ],
+      ),
+    );
+  }
+}

+ 50 - 0
lib/page/home_page.dart

@@ -0,0 +1,50 @@
+
+import 'package:flutter/material.dart';
+
+class MyHomePage extends StatefulWidget {
+  const MyHomePage({super.key, required this.title});
+
+  final String title;
+
+  @override
+  State<MyHomePage> createState() => _MyHomePageState();
+}
+
+class _MyHomePageState extends State<MyHomePage> {
+  int _counter = 0;
+
+  void _incrementCounter() {
+    setState(() {
+      _counter++;
+    });
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return Scaffold(
+      appBar: AppBar(
+        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
+        title: Text(widget.title),
+      ),
+      body: Center(
+        child: Column(
+          mainAxisAlignment: MainAxisAlignment.center,
+          children: <Widget>[
+            const Text(
+              'You have pushed the button this many times:',
+            ),
+            Text(
+              '$_counter',
+              style: Theme.of(context).textTheme.headlineMedium,
+            ),
+          ],
+        ),
+      ),
+      floatingActionButton: FloatingActionButton(
+        onPressed: _incrementCounter,
+        tooltip: 'Increment',
+        child: const Icon(Icons.add),
+      ),
+    );
+  }
+}

+ 0 - 0
lib/page/setting_page.dart


+ 10 - 0
packages/repository/.metadata

@@ -0,0 +1,10 @@
+# This file tracks properties of this Flutter project.
+# Used by Flutter tool to assess capabilities and perform upgrades etc.
+#
+# This file should be version controlled and should not be manually edited.
+
+version:
+  revision: "5dcb86f68f239346676ceb1ed1ea385bd215fba1"
+  channel: "stable"
+
+project_type: package

+ 4 - 0
packages/repository/analysis_options.yaml

@@ -0,0 +1,4 @@
+include: package:flutter_lints/flutter.yaml
+
+# Additional information about this file can be found at
+# https://dart.dev/guides/language/analysis-options

+ 7 - 0
packages/repository/lib/repository.dart

@@ -0,0 +1,7 @@
+library repository;
+
+/// A Calculator.
+class Calculator {
+  /// Returns [value] plus 1.
+  int addOne(int value) => value + 1;
+}

+ 205 - 0
packages/repository/pubspec.lock

@@ -0,0 +1,205 @@
+# Generated by pub
+# See https://dart.dev/tools/pub/glossary#lockfile
+packages:
+  async:
+    dependency: transitive
+    description:
+      name: async
+      sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.11.0"
+  boolean_selector:
+    dependency: transitive
+    description:
+      name: boolean_selector
+      sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.1.1"
+  characters:
+    dependency: transitive
+    description:
+      name: characters
+      sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.3.0"
+  clock:
+    dependency: transitive
+    description:
+      name: clock
+      sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.1.1"
+  collection:
+    dependency: transitive
+    description:
+      name: collection
+      sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.18.0"
+  fake_async:
+    dependency: transitive
+    description:
+      name: fake_async
+      sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.3.1"
+  flutter:
+    dependency: "direct main"
+    description: flutter
+    source: sdk
+    version: "0.0.0"
+  flutter_lints:
+    dependency: "direct dev"
+    description:
+      name: flutter_lints
+      sha256: "9e8c3858111da373efc5aa341de011d9bd23e2c5c5e0c62bccf32438e192d7b1"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "3.0.2"
+  flutter_test:
+    dependency: "direct dev"
+    description: flutter
+    source: sdk
+    version: "0.0.0"
+  leak_tracker:
+    dependency: transitive
+    description:
+      name: leak_tracker
+      sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "10.0.4"
+  leak_tracker_flutter_testing:
+    dependency: transitive
+    description:
+      name: leak_tracker_flutter_testing
+      sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "3.0.3"
+  leak_tracker_testing:
+    dependency: transitive
+    description:
+      name: leak_tracker_testing
+      sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "3.0.1"
+  lints:
+    dependency: transitive
+    description:
+      name: lints
+      sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "3.0.0"
+  matcher:
+    dependency: transitive
+    description:
+      name: matcher
+      sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "0.12.16+1"
+  material_color_utilities:
+    dependency: transitive
+    description:
+      name: material_color_utilities
+      sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "0.8.0"
+  meta:
+    dependency: transitive
+    description:
+      name: meta
+      sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.12.0"
+  path:
+    dependency: transitive
+    description:
+      name: path
+      sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.9.0"
+  sky_engine:
+    dependency: transitive
+    description: flutter
+    source: sdk
+    version: "0.0.99"
+  source_span:
+    dependency: transitive
+    description:
+      name: source_span
+      sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.10.0"
+  stack_trace:
+    dependency: transitive
+    description:
+      name: stack_trace
+      sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.11.1"
+  stream_channel:
+    dependency: transitive
+    description:
+      name: stream_channel
+      sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.1.2"
+  string_scanner:
+    dependency: transitive
+    description:
+      name: string_scanner
+      sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.2.0"
+  term_glyph:
+    dependency: transitive
+    description:
+      name: term_glyph
+      sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.2.1"
+  test_api:
+    dependency: transitive
+    description:
+      name: test_api
+      sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "0.7.0"
+  vector_math:
+    dependency: transitive
+    description:
+      name: vector_math
+      sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.1.4"
+  vm_service:
+    dependency: transitive
+    description:
+      name: vm_service
+      sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "14.2.1"
+sdks:
+  dart: ">=3.4.0 <4.0.0"
+  flutter: ">=3.18.0-18.0.pre.54"

+ 54 - 0
packages/repository/pubspec.yaml

@@ -0,0 +1,54 @@
+name: repository
+description: "A new Flutter package project."
+version: 0.0.1
+homepage:
+
+environment:
+  sdk: '>=3.4.0 <4.0.0'
+  flutter: ^3.22.0
+
+dependencies:
+  flutter:
+    sdk: flutter
+
+dev_dependencies:
+  flutter_test:
+    sdk: flutter
+  flutter_lints: ^3.0.0
+
+# For information on the generic Dart part of this file, see the
+# following page: https://dart.dev/tools/pub/pubspec
+
+# The following section is specific to Flutter packages.
+flutter:
+
+  # To add assets to your package, add an assets section, like this:
+  # assets:
+  #   - images/a_dot_burr.jpeg
+  #   - images/a_dot_ham.jpeg
+  #
+  # For details regarding assets in packages, see
+  # https://flutter.dev/assets-and-images/#from-packages
+  #
+  # An image asset can refer to one or more resolution-specific "variants", see
+  # https://flutter.dev/assets-and-images/#resolution-aware
+
+  # To add custom fonts to your package, add a fonts section here,
+  # in this "flutter" section. Each entry in this list should have a
+  # "family" key with the font family name, and a "fonts" key with a
+  # list giving the asset and other descriptors for the font. For
+  # example:
+  # fonts:
+  #   - family: Schyler
+  #     fonts:
+  #       - asset: fonts/Schyler-Regular.ttf
+  #       - asset: fonts/Schyler-Italic.ttf
+  #         style: italic
+  #   - family: Trajan Pro
+  #     fonts:
+  #       - asset: fonts/TrajanPro.ttf
+  #       - asset: fonts/TrajanPro_Bold.ttf
+  #         weight: 700
+  #
+  # For details regarding fonts in packages, see
+  # https://flutter.dev/custom-fonts/#from-packages

+ 10 - 0
packages/widget/.metadata

@@ -0,0 +1,10 @@
+# This file tracks properties of this Flutter project.
+# Used by Flutter tool to assess capabilities and perform upgrades etc.
+#
+# This file should be version controlled and should not be manually edited.
+
+version:
+  revision: "5dcb86f68f239346676ceb1ed1ea385bd215fba1"
+  channel: "stable"
+
+project_type: package

+ 4 - 0
packages/widget/analysis_options.yaml

@@ -0,0 +1,4 @@
+include: package:flutter_lints/flutter.yaml
+
+# Additional information about this file can be found at
+# https://dart.dev/guides/language/analysis-options

+ 33 - 0
packages/widget/lib/src/battle_background.dart

@@ -0,0 +1,33 @@
+import 'package:flutter/widgets.dart';
+
+import 'constant.dart';
+
+class BattleBackground extends StatelessWidget {
+  const BattleBackground({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return CustomPaint(
+      painter: _BattleBackgroundPainter(),
+      child: const SizedBox.expand(),
+    );
+  }
+}
+
+class _BattleBackgroundPainter extends CustomPainter {
+  @override
+  void paint(Canvas canvas, Size size) {
+    final paint = Paint()
+      ..color = kBoardBackgroundColor
+      ..style = PaintingStyle.fill;
+
+    canvas.drawRRect(_getBoardRRect(size), paint);
+  }
+
+  RRect _getBoardRRect(Size size) {
+    return RRect.fromRectAndRadius(Offset.zero & size, const Radius.circular(8));
+  }
+
+  @override
+  bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
+}

+ 114 - 0
packages/widget/lib/src/battle_foreground.dart

@@ -0,0 +1,114 @@
+import 'package:flutter/widgets.dart';
+import 'package:widget/src/constant.dart';
+
+class BattleForeground extends StatelessWidget {
+  const BattleForeground({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return CustomPaint(
+      painter: _BattleForegroundPainter(),
+      child: const SizedBox.expand(),
+    );
+  }
+}
+
+class _BattleForegroundPainter extends CustomPainter {
+  @override
+  void paint(Canvas canvas, Size size) {
+    final paint = Paint()
+      ..color = kBoardForegroundColor
+      ..style = PaintingStyle.fill;
+
+    paint.color = kBoardForegroundColor;
+    canvas.drawPath(_getBoardPath(size), paint);
+  }
+
+  Path _getBoardPath(Size size) {
+    Path resultPath = Path();
+    final boardRRect = RRect.fromRectAndRadius(Offset.zero & size, const Radius.circular(kBoardRadius));
+
+    resultPath.addRRect(boardRRect);
+    resultPath = Path.combine(PathOperation.difference, resultPath, _getCardPath(size));
+    resultPath = Path.combine(PathOperation.difference, resultPath, _getBottomButtonPath(size));
+    resultPath = Path.combine(PathOperation.difference, resultPath, _getRightButtonPath(size));
+    return resultPath;
+  }
+
+  // 除去卡片的部分
+  Path _getCardPath(Size size) {
+    Path path = Path();
+    final cardRect = Rect.fromLTWH(
+      size.width * (kLeftBorderAspectRatio),
+      0,
+      size.width * (kCardWidthAspectRatio - 2 * kCardCoverAspectRatio),
+      size.height * (kCardHeightAspectRatio - kCardOverflowAspectRatio),
+    );
+
+    path.addRRect(RRect.fromRectAndCorners(
+      cardRect,
+      bottomLeft: const Radius.circular(kCardRadius),
+      bottomRight: const Radius.circular(kCardRadius),
+    ));
+
+    return path;
+  }
+
+  // 除去底部按钮部分的部分
+  Path _getBottomButtonPath(Size size) {
+    final double left = size.width * kBottomButtonLeftAspectRatio;
+    final double right = size.width * kBottomButtonRightAspectRatio;
+    final double top = size.height * kBottomButtonTopAspectRatio;
+    final double bottom = size.height * kBottomButtonBottomAspectRatio;
+    final double line = size.width * kButtonLineAspectRatio;
+
+    final double rightSide = size.width * kRightButtonRightAspectRatio;
+
+    final double spacing = ((right - left) - line * 6) / 5 + line;
+    final path = Path();
+    final offset = Offset(left, top);
+
+    // 底部按钮的横线部分
+    path.addRRect(RRect.fromLTRBR(left, top, rightSide, top + line, const Radius.circular(100)));
+
+    final double lineHeight = bottom - top - line;
+    final Size lineSize = Size(line, lineHeight);
+    path.addRRect(RRect.fromRectAndRadius((offset + const Offset(0, 0)) & lineSize, const Radius.circular(100)));
+    path.addRRect(RRect.fromRectAndRadius((offset + Offset(spacing, 0)) & lineSize, const Radius.circular(100)));
+    path.addRRect(RRect.fromRectAndRadius((offset + Offset(spacing * 2, 0)) & lineSize, const Radius.circular(100)));
+    path.addRRect(RRect.fromRectAndRadius((offset + Offset(spacing * 3, 0)) & lineSize, const Radius.circular(100)));
+    path.addRRect(RRect.fromRectAndRadius((offset + Offset(spacing * 4, 0)) & lineSize, const Radius.circular(100)));
+    path.addRRect(RRect.fromRectAndRadius((offset + Offset(spacing * 5, 0)) & lineSize, const Radius.circular(100)));
+    return path;
+  }
+
+  Path _getRightButtonPath(Size size) {
+    final double left = size.width * kRightButtonLeftAspectRatio;
+    final double right = size.width * kRightButtonRightAspectRatio;
+    final double top = size.height * kRightButtonTopAspectRatio;
+    final double bottom = size.height * kRightButtonBottomAspectRatio;
+    final double line = size.width * kButtonLineAspectRatio;
+
+    final double bottomSide = size.height * kBottomButtonTopAspectRatio + line;
+
+    final double spacing = ((bottom - top) - line * 6) / 5 + line;
+    final path = Path();
+    final offset = Offset(left, top);
+
+    // 右侧按钮的横线部分
+    path.addRRect(RRect.fromLTRBR(right - line, top, right, bottomSide, const Radius.circular(100)));
+
+    final double lineWidth = right - left;
+    final Size lineSize = Size(lineWidth, line);
+    path.addRRect(RRect.fromRectAndRadius((offset + const Offset(0, 0)) & lineSize, const Radius.circular(100)));
+    path.addRRect(RRect.fromRectAndRadius((offset + Offset(0, spacing)) & lineSize, const Radius.circular(100)));
+    path.addRRect(RRect.fromRectAndRadius((offset + Offset(0, spacing * 2)) & lineSize, const Radius.circular(100)));
+    path.addRRect(RRect.fromRectAndRadius((offset + Offset(0, spacing * 3)) & lineSize, const Radius.circular(100)));
+    path.addRRect(RRect.fromRectAndRadius((offset + Offset(0, spacing * 4)) & lineSize, const Radius.circular(100)));
+    path.addRRect(RRect.fromRectAndRadius((offset + Offset(0, spacing * 5)) & lineSize, const Radius.circular(100)));
+    return path;
+  }
+
+  @override
+  bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
+}

+ 88 - 0
packages/widget/lib/src/battle_layout.dart

@@ -0,0 +1,88 @@
+import 'package:flutter/widgets.dart';
+import 'package:widget/src/constant.dart';
+
+import 'battle_background.dart';
+import 'battle_foreground.dart';
+
+enum _BattleSlot {
+  background,
+  card,
+  foreground,
+  topRightLogo,
+  bottomLeftLogo,
+  bottomRightLogo,
+  button,
+}
+
+class _BattleLayoutDelegate extends MultiChildLayoutDelegate {
+  @override
+  void performLayout(Size size) {
+    final constraints = BoxConstraints.loose(size);
+
+    double boardWidth = size.width * kBoardWidthAspectRatio;
+    double boardHeight = size.height * kBoardHeightAspectRatio;
+    final boardConstraints = BoxConstraints.loose(Size(boardWidth, boardHeight));
+    layoutChild(_BattleSlot.background, boardConstraints);
+    positionChild(_BattleSlot.background, Offset(size.width - boardWidth, size.height - boardHeight));
+    layoutChild(_BattleSlot.foreground, boardConstraints);
+    positionChild(_BattleSlot.foreground, Offset(size.width - boardWidth, size.height - boardHeight));
+
+    double cardWidth = size.width * kCardWidthAspectRatio;
+    double cardHeight = size.height * kCardHeightAspectRatio;
+    double leftPadding = size.width * kLeftBorderAspectRatio;
+    double coverPadding = size.width * kCardCoverAspectRatio;
+    final cardConstraints = BoxConstraints.loose(Size(cardWidth, cardHeight));
+    layoutChild(_BattleSlot.card, cardConstraints);
+    positionChild(_BattleSlot.card, Offset(leftPadding - coverPadding, 0));
+
+    layoutChild(_BattleSlot.button, boardConstraints);
+    positionChild(_BattleSlot.button, Offset(size.width - boardWidth, size.height - boardHeight));
+
+  }
+
+  @override
+  bool shouldRelayout(_BattleLayoutDelegate oldDelegate) => false;
+}
+
+class BattleBoard extends StatefulWidget {
+  final Widget card;
+  final Widget button;
+
+  const BattleBoard({
+    super.key,
+    required this.card,
+    required this.button,
+  });
+
+  @override
+  State<BattleBoard> createState() => _BattleBoardState();
+}
+
+class _BattleBoardState extends State<BattleBoard> {
+  void _addWithSlot(List<LayoutId> children, _BattleSlot slot, Widget child) {
+    children.add(LayoutId(id: slot, child: child));
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    List<LayoutId> children = <LayoutId>[];
+
+    const Widget foreground = BattleForeground();
+    const Widget background = BattleBackground();
+
+    children.add(LayoutId(id: _BattleSlot.background, child: background));
+    children.add(LayoutId(id: _BattleSlot.card, child: widget.card));
+    children.add(LayoutId(id: _BattleSlot.foreground, child: foreground));
+    children.add(LayoutId(id: _BattleSlot.button, child: widget.button));
+
+    return Center(
+      child: AspectRatio(
+        aspectRatio: kTextureAspectRatio,
+        child: CustomMultiChildLayout(
+          delegate: _BattleLayoutDelegate(),
+          children: children,
+        ),
+      ),
+    );
+  }
+}

+ 54 - 0
packages/widget/lib/src/battle_path.dart

@@ -0,0 +1,54 @@
+import 'dart:ui';
+
+import 'constant.dart';
+
+///本质是求五个点的位置,依次lineTo起来形成一条路径
+
+Path fromBottomToCenter(Size size, int start, int end) {
+  final path = Path();
+
+  final double line = size.width * kButtonLineAspectRatio;
+
+  final double l1 = size.width * kBottomButtonLeftAspectRatio;
+  final double r1 = size.width * kBottomButtonRightAspectRatio;
+  final double t1 = size.height * kBottomButtonTopAspectRatio;
+  final double b1 = size.height * kBottomButtonBottomAspectRatio;
+
+  final double l2 = size.width * kRightButtonLeftAspectRatio;
+  final double r2 = size.width * kRightButtonRightAspectRatio;
+  final double t2 = size.height * kRightButtonTopAspectRatio;
+  final double b2 = size.height * kRightButtonBottomAspectRatio;
+
+  final double cr = size.width * kRightButtonRightAspectRatio;
+  final double cb = size.height * kBottomButtonTopAspectRatio;
+
+  final double spacing1 = ((r1 - l1) - line * 6) / 5 + line;
+  final double spacing2 = ((b2 - t2) - line * 6) / 5 + line;
+
+  final double p1x = l1 + spacing1 * start + line / 2;
+  final double p1y = b1 - line * 3 / 2;
+
+  final double p2x = p1x;
+  final double p2y = t1 + line / 2;
+
+  final double p3x = r2 - line / 2;
+  final double p3y = t2 + spacing2 * end + line / 2;
+
+  final double p4x = l2 + line / 2;
+  final double p4y = p3y;
+
+  path.moveTo(p1x, p1y);
+  path.lineTo(p2x, p2y);
+  assert(cr - line / 2 == p3x);
+  assert(p2y == cb + line / 2);
+  path.lineTo(cr - line / 2, p2y);
+  path.lineTo(p3x, cb + line / 2);
+  path.lineTo(p3x, p3y);
+  path.lineTo(p4x, p4y);
+
+  return path;
+}
+
+double getButtonSize(Size size) {
+  return kButtonAspectRatio * size.width;
+}

+ 65 - 0
packages/widget/lib/src/constant.dart

@@ -0,0 +1,65 @@
+library constant;
+
+import 'dart:ui';
+
+/// * [_kTextureWidth]画布宽度
+/// * [_kTextureHeight]画布高度
+/// * [_kBoardWidth]画布高度
+/// * [_kBoardHeight]画布高度
+/// * [_kCardWidth]画布高度
+/// * [_kCardHeight]画布高度
+const int _kTextureWidth = 1846;
+const int _kTextureHeight = 2305;
+const int _kBoardWidth = _kTextureWidth;
+const int _kBoardHeight = 2253;
+const int _kCardWidth = 1280;
+const int _kCardHeight = 1826;
+const int _kCardPadding = 35;
+
+const double kTextureAspectRatio = _kTextureWidth / _kTextureHeight;
+const double kBoardWidthAspectRatio = _kBoardWidth / _kTextureWidth;
+const double kBoardHeightAspectRatio = _kBoardHeight / _kTextureHeight;
+
+const int _kLeftBorderWidth = 120;
+const double kLeftBorderAspectRatio = _kLeftBorderWidth / _kBoardWidth;
+
+const int _kCardOverflowHeight = _kTextureHeight - _kBoardHeight;
+const double kCardAspectRatio = _kCardWidth / _kCardHeight;
+const double kCardWidthAspectRatio = _kCardWidth / _kBoardWidth;
+const double kCardHeightAspectRatio = _kCardHeight / _kBoardHeight;
+const double kCardOverflowAspectRatio = _kCardOverflowHeight / _kTextureHeight;
+const double kCardCoverAspectRatio = _kCardPadding / _kBoardWidth;
+
+/// 推钮的直径大小
+const int _kButtonSize = 200;
+const double kButtonAspectRatio = _kButtonSize / _kBoardWidth;
+
+/// 推钮滑轨线的宽度
+const int _kButtonLineSize = 50;
+const double kButtonLineAspectRatio = _kButtonLineSize / _kBoardWidth;
+
+/// 底部推钮的区域定位
+const int _kBottomButtonLeft = 147;
+const int _kBottomButtonTop = 1910;
+const int _kBottomButtonRight = 1320;
+const int _kBottomButtonBottom = 2200;
+const double kBottomButtonLeftAspectRatio = _kBottomButtonLeft / _kTextureWidth;
+const double kBottomButtonTopAspectRatio = _kBottomButtonTop / _kTextureHeight;
+const double kBottomButtonRightAspectRatio = _kBottomButtonRight / _kTextureWidth;
+const double kBottomButtonBottomAspectRatio = _kBottomButtonBottom / _kTextureHeight;
+
+const int _kRightButtonLeft = 1480;
+const int _kRightButtonTop = 300;
+const int _kRightButtonRight = 1720;
+const int _kRightButtonBottom = 1695;
+const double kRightButtonLeftAspectRatio = _kRightButtonLeft / _kTextureWidth;
+const double kRightButtonTopAspectRatio = _kRightButtonTop / _kTextureHeight;
+const double kRightButtonRightAspectRatio = _kRightButtonRight / _kTextureWidth;
+const double kRightButtonBottomAspectRatio = _kRightButtonBottom / _kTextureHeight;
+
+const double kTopLogoAspectRatio = 10 / 95;
+const Color kBoardBackgroundColor = Color(0xFFDDD8BA);
+const Color kBoardForegroundColor = Color(0xFF252C74);
+
+const double kBoardRadius = 8;
+const double kCardRadius = 4;

+ 5 - 0
packages/widget/lib/widget.dart

@@ -0,0 +1,5 @@
+library widget;
+
+export 'src/battle_layout.dart';
+export 'src/battle_path.dart';
+

+ 205 - 0
packages/widget/pubspec.lock

@@ -0,0 +1,205 @@
+# Generated by pub
+# See https://dart.dev/tools/pub/glossary#lockfile
+packages:
+  async:
+    dependency: transitive
+    description:
+      name: async
+      sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.11.0"
+  boolean_selector:
+    dependency: transitive
+    description:
+      name: boolean_selector
+      sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.1.1"
+  characters:
+    dependency: transitive
+    description:
+      name: characters
+      sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.3.0"
+  clock:
+    dependency: transitive
+    description:
+      name: clock
+      sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.1.1"
+  collection:
+    dependency: transitive
+    description:
+      name: collection
+      sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.18.0"
+  fake_async:
+    dependency: transitive
+    description:
+      name: fake_async
+      sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.3.1"
+  flutter:
+    dependency: "direct main"
+    description: flutter
+    source: sdk
+    version: "0.0.0"
+  flutter_lints:
+    dependency: "direct dev"
+    description:
+      name: flutter_lints
+      sha256: "9e8c3858111da373efc5aa341de011d9bd23e2c5c5e0c62bccf32438e192d7b1"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "3.0.2"
+  flutter_test:
+    dependency: "direct dev"
+    description: flutter
+    source: sdk
+    version: "0.0.0"
+  leak_tracker:
+    dependency: transitive
+    description:
+      name: leak_tracker
+      sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "10.0.4"
+  leak_tracker_flutter_testing:
+    dependency: transitive
+    description:
+      name: leak_tracker_flutter_testing
+      sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "3.0.3"
+  leak_tracker_testing:
+    dependency: transitive
+    description:
+      name: leak_tracker_testing
+      sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "3.0.1"
+  lints:
+    dependency: transitive
+    description:
+      name: lints
+      sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "3.0.0"
+  matcher:
+    dependency: transitive
+    description:
+      name: matcher
+      sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "0.12.16+1"
+  material_color_utilities:
+    dependency: transitive
+    description:
+      name: material_color_utilities
+      sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "0.8.0"
+  meta:
+    dependency: transitive
+    description:
+      name: meta
+      sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.12.0"
+  path:
+    dependency: transitive
+    description:
+      name: path
+      sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.9.0"
+  sky_engine:
+    dependency: transitive
+    description: flutter
+    source: sdk
+    version: "0.0.99"
+  source_span:
+    dependency: transitive
+    description:
+      name: source_span
+      sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.10.0"
+  stack_trace:
+    dependency: transitive
+    description:
+      name: stack_trace
+      sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.11.1"
+  stream_channel:
+    dependency: transitive
+    description:
+      name: stream_channel
+      sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.1.2"
+  string_scanner:
+    dependency: transitive
+    description:
+      name: string_scanner
+      sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.2.0"
+  term_glyph:
+    dependency: transitive
+    description:
+      name: term_glyph
+      sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.2.1"
+  test_api:
+    dependency: transitive
+    description:
+      name: test_api
+      sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "0.7.0"
+  vector_math:
+    dependency: transitive
+    description:
+      name: vector_math
+      sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.1.4"
+  vm_service:
+    dependency: transitive
+    description:
+      name: vm_service
+      sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "14.2.1"
+sdks:
+  dart: ">=3.4.0 <4.0.0"
+  flutter: ">=3.22.0"

+ 54 - 0
packages/widget/pubspec.yaml

@@ -0,0 +1,54 @@
+name: widget
+description: "A new Flutter package project."
+version: 0.0.1
+homepage:
+
+environment:
+  sdk: '>=3.4.0 <4.0.0'
+  flutter: ^3.22.0
+
+dependencies:
+  flutter:
+    sdk: flutter
+
+dev_dependencies:
+  flutter_test:
+    sdk: flutter
+  flutter_lints: ^3.0.0
+
+# For information on the generic Dart part of this file, see the
+# following page: https://dart.dev/tools/pub/pubspec
+
+# The following section is specific to Flutter packages.
+flutter:
+
+  # To add assets to your package, add an assets section, like this:
+  # assets:
+  #   - images/a_dot_burr.jpeg
+  #   - images/a_dot_ham.jpeg
+  #
+  # For details regarding assets in packages, see
+  # https://flutter.dev/assets-and-images/#from-packages
+  #
+  # An image asset can refer to one or more resolution-specific "variants", see
+  # https://flutter.dev/assets-and-images/#resolution-aware
+
+  # To add custom fonts to your package, add a fonts section here,
+  # in this "flutter" section. Each entry in this list should have a
+  # "family" key with the font family name, and a "fonts" key with a
+  # list giving the asset and other descriptors for the font. For
+  # example:
+  # fonts:
+  #   - family: Schyler
+  #     fonts:
+  #       - asset: fonts/Schyler-Regular.ttf
+  #       - asset: fonts/Schyler-Italic.ttf
+  #         style: italic
+  #   - family: Trajan Pro
+  #     fonts:
+  #       - asset: fonts/TrajanPro.ttf
+  #       - asset: fonts/TrajanPro_Bold.ttf
+  #         weight: 700
+  #
+  # For details regarding fonts in packages, see
+  # https://flutter.dev/custom-fonts/#from-packages

+ 736 - 0
pubspec.lock

@@ -0,0 +1,736 @@
+# Generated by pub
+# See https://dart.dev/tools/pub/glossary#lockfile
+packages:
+  archive:
+    dependency: transitive
+    description:
+      name: archive
+      sha256: "6bd38d335f0954f5fad9c79e614604fbf03a0e5b975923dd001b6ea965ef5b4b"
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.6.0"
+  args:
+    dependency: transitive
+    description:
+      name: args
+      sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.5.0"
+  async:
+    dependency: transitive
+    description:
+      name: async
+      sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.11.0"
+  audioplayers:
+    dependency: transitive
+    description:
+      name: audioplayers
+      sha256: "752039d6aa752597c98ec212e9759519061759e402e7da59a511f39d43aa07d2"
+      url: "https://pub.dev"
+    source: hosted
+    version: "6.0.0"
+  audioplayers_android:
+    dependency: transitive
+    description:
+      name: audioplayers_android
+      sha256: de576b890befe27175c2f511ba8b742bec83765fa97c3ce4282bba46212f58e4
+      url: "https://pub.dev"
+    source: hosted
+    version: "5.0.0"
+  audioplayers_darwin:
+    dependency: transitive
+    description:
+      name: audioplayers_darwin
+      sha256: e507887f3ff18d8e5a10a668d7bedc28206b12e10b98347797257c6ae1019c3b
+      url: "https://pub.dev"
+    source: hosted
+    version: "6.0.0"
+  audioplayers_linux:
+    dependency: transitive
+    description:
+      name: audioplayers_linux
+      sha256: "3d3d244c90436115417f170426ce768856d8fe4dfc5ed66a049d2890acfa82f9"
+      url: "https://pub.dev"
+    source: hosted
+    version: "4.0.0"
+  audioplayers_platform_interface:
+    dependency: transitive
+    description:
+      name: audioplayers_platform_interface
+      sha256: "6834dd48dfb7bc6c2404998ebdd161f79cd3774a7e6779e1348d54a3bfdcfaa5"
+      url: "https://pub.dev"
+    source: hosted
+    version: "7.0.0"
+  audioplayers_web:
+    dependency: transitive
+    description:
+      name: audioplayers_web
+      sha256: db8fc420dadf80da18e2286c18e746fb4c3b2c5adbf0c963299dde046828886d
+      url: "https://pub.dev"
+    source: hosted
+    version: "5.0.0"
+  audioplayers_windows:
+    dependency: transitive
+    description:
+      name: audioplayers_windows
+      sha256: "8605762dddba992138d476f6a0c3afd9df30ac5b96039929063eceed416795c2"
+      url: "https://pub.dev"
+    source: hosted
+    version: "4.0.0"
+  bloc:
+    dependency: transitive
+    description:
+      name: bloc
+      sha256: "106842ad6569f0b60297619e9e0b1885c2fb9bf84812935490e6c5275777804e"
+      url: "https://pub.dev"
+    source: hosted
+    version: "8.1.4"
+  boolean_selector:
+    dependency: transitive
+    description:
+      name: boolean_selector
+      sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.1.1"
+  characters:
+    dependency: transitive
+    description:
+      name: characters
+      sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.3.0"
+  clock:
+    dependency: transitive
+    description:
+      name: clock
+      sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.1.1"
+  collection:
+    dependency: transitive
+    description:
+      name: collection
+      sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.18.0"
+  crypto:
+    dependency: transitive
+    description:
+      name: crypto
+      sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.0.3"
+  cupertino_icons:
+    dependency: "direct main"
+    description:
+      name: cupertino_icons
+      sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.0.8"
+  dev:
+    dependency: transitive
+    description:
+      name: dev
+      sha256: e7e806af20d53e293a7878212d2246d3e9fccd2b49d597600f9898ed83501cb4
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.0.0"
+  fake_async:
+    dependency: transitive
+    description:
+      name: fake_async
+      sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.3.1"
+  ffi:
+    dependency: transitive
+    description:
+      name: ffi
+      sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.1.2"
+  file:
+    dependency: transitive
+    description:
+      name: file
+      sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c"
+      url: "https://pub.dev"
+    source: hosted
+    version: "7.0.0"
+  fixnum:
+    dependency: transitive
+    description:
+      name: fixnum
+      sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1"
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.1.0"
+  flame:
+    dependency: "direct main"
+    description:
+      name: flame
+      sha256: "79133dc46a3ff870950f41d0dc1598414e7bd7ae2c29bd9f0a9de208d9a70cb7"
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.18.0"
+  flame_audio:
+    dependency: "direct main"
+    description:
+      name: flame_audio
+      sha256: "32e5788945469cebb807e741027e645a737e2618afc9b682e7f48607e0637f48"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.10.2"
+  flame_bloc:
+    dependency: "direct main"
+    description:
+      name: flame_bloc
+      sha256: "19d907204b65f81b08adf71da02e632e68757b1a6738378d8dd4bc024c1660b8"
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.12.0"
+  flame_forge2d:
+    dependency: "direct main"
+    description:
+      name: flame_forge2d
+      sha256: "1ec1c5b4978b64d2d16ca90f86de469959991ef996970866c3f9de580b3dbe40"
+      url: "https://pub.dev"
+    source: hosted
+    version: "0.18.1"
+  flame_isolate:
+    dependency: "direct main"
+    description:
+      name: flame_isolate
+      sha256: "2c7848226b355fd631bec114a19bcc5b9b8f1c3538798a0e9c0fae6ec8f48f8b"
+      url: "https://pub.dev"
+    source: hosted
+    version: "0.6.1"
+  flame_lottie:
+    dependency: "direct main"
+    description:
+      name: flame_lottie
+      sha256: e3a6a3326a53a6d1ebfc5483220cb0979cfccbb58e5e8d68c9f0847782659be6
+      url: "https://pub.dev"
+    source: hosted
+    version: "0.4.1"
+  flame_markdown:
+    dependency: "direct main"
+    description:
+      name: flame_markdown
+      sha256: "6a4bb403ed66161c59061d54c8910179b213673f16fe1215108f0d419cec9c83"
+      url: "https://pub.dev"
+    source: hosted
+    version: "0.2.1"
+  flame_network_assets:
+    dependency: "direct main"
+    description:
+      name: flame_network_assets
+      sha256: "8fa0981620ecc86a17a6efdafaea1d1e3ccde4e42bbe50558161c53c38f52f94"
+      url: "https://pub.dev"
+    source: hosted
+    version: "0.3.2"
+  flame_riverpod:
+    dependency: "direct main"
+    description:
+      name: flame_riverpod
+      sha256: e04d47cf43c9e2bfb4a70cc8f5dbcbe7e7b2b1e1f2b8ff8ad1ef7b90e2aec09d
+      url: "https://pub.dev"
+    source: hosted
+    version: "5.4.2"
+  flame_svg:
+    dependency: "direct main"
+    description:
+      name: flame_svg
+      sha256: b8da1bd3780cc1f45b72f451800c9d5392db5eb6fe1efb820cc47d5a8d3c4b1f
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.10.2"
+  flame_tiled:
+    dependency: "direct main"
+    description:
+      name: flame_tiled
+      sha256: "519dc91412dc617203ed182712c2d44343ce2ab103ab81921cd4032b10b0cc2b"
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.20.2"
+  flutter:
+    dependency: "direct main"
+    description: flutter
+    source: sdk
+    version: "0.0.0"
+  flutter_bloc:
+    dependency: transitive
+    description:
+      name: flutter_bloc
+      sha256: f0ecf6e6eb955193ca60af2d5ca39565a86b8a142452c5b24d96fb477428f4d2
+      url: "https://pub.dev"
+    source: hosted
+    version: "8.1.5"
+  flutter_lints:
+    dependency: "direct dev"
+    description:
+      name: flutter_lints
+      sha256: "9e8c3858111da373efc5aa341de011d9bd23e2c5c5e0c62bccf32438e192d7b1"
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.0.2"
+  flutter_riverpod:
+    dependency: "direct main"
+    description:
+      name: flutter_riverpod
+      sha256: "0f1974eff5bbe774bf1d870e406fc6f29e3d6f1c46bd9c58e7172ff68a785d7d"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.5.1"
+  flutter_svg:
+    dependency: transitive
+    description:
+      name: flutter_svg
+      sha256: "7b4ca6cf3304575fe9c8ec64813c8d02ee41d2afe60bcfe0678bcb5375d596a2"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.0.10+1"
+  flutter_test:
+    dependency: "direct dev"
+    description: flutter
+    source: sdk
+    version: "0.0.0"
+  flutter_web_plugins:
+    dependency: transitive
+    description: flutter
+    source: sdk
+    version: "0.0.0"
+  forge2d:
+    dependency: transitive
+    description:
+      name: forge2d
+      sha256: "40915333b688ddaaa616d9c8ab9ff205faea0adf83dddc1a6e617694ffa9e16e"
+      url: "https://pub.dev"
+    source: hosted
+    version: "0.13.0"
+  gestures:
+    dependency: transitive
+    description:
+      name: gestures
+      sha256: "6e75e4ba1ad033a8be9a682974dfe6a2be96ab07b4aa8335ed37bbecb75b7770"
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.0.0"
+  http:
+    dependency: transitive
+    description:
+      name: http
+      sha256: "761a297c042deedc1ffbb156d6e2af13886bb305c2a343a4d972504cd67dd938"
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.2.1"
+  http_parser:
+    dependency: transitive
+    description:
+      name: http_parser
+      sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
+      url: "https://pub.dev"
+    source: hosted
+    version: "4.0.2"
+  integral_isolates:
+    dependency: transitive
+    description:
+      name: integral_isolates
+      sha256: "62b1b45ea6350edc92d555aa1a98cbda09836b42e51e19e39d49bc39a686e601"
+      url: "https://pub.dev"
+    source: hosted
+    version: "0.5.1"
+  leak_tracker:
+    dependency: transitive
+    description:
+      name: leak_tracker
+      sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a"
+      url: "https://pub.dev"
+    source: hosted
+    version: "10.0.4"
+  leak_tracker_flutter_testing:
+    dependency: transitive
+    description:
+      name: leak_tracker_flutter_testing
+      sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8"
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.0.3"
+  leak_tracker_testing:
+    dependency: transitive
+    description:
+      name: leak_tracker_testing
+      sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.0.1"
+  lints:
+    dependency: transitive
+    description:
+      name: lints
+      sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.0.0"
+  lottie:
+    dependency: transitive
+    description:
+      name: lottie
+      sha256: "6a24ade5d3d918c306bb1c21a6b9a04aab0489d51a2582522eea820b4093b62b"
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.1.2"
+  markdown:
+    dependency: transitive
+    description:
+      name: markdown
+      sha256: ef2a1298144e3f985cc736b22e0ccdaf188b5b3970648f2d9dc13efd1d9df051
+      url: "https://pub.dev"
+    source: hosted
+    version: "7.2.2"
+  matcher:
+    dependency: transitive
+    description:
+      name: matcher
+      sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
+      url: "https://pub.dev"
+    source: hosted
+    version: "0.12.16+1"
+  material_color_utilities:
+    dependency: transitive
+    description:
+      name: material_color_utilities
+      sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a"
+      url: "https://pub.dev"
+    source: hosted
+    version: "0.8.0"
+  meta:
+    dependency: transitive
+    description:
+      name: meta
+      sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.12.0"
+  nested:
+    dependency: transitive
+    description:
+      name: nested
+      sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.0.0"
+  ordered_set:
+    dependency: transitive
+    description:
+      name: ordered_set
+      sha256: "1bfaaaee0419e43ecc9eaebd410eb4bd5039657b72011de75ff3e2915c9aac60"
+      url: "https://pub.dev"
+    source: hosted
+    version: "5.0.3"
+  path:
+    dependency: transitive
+    description:
+      name: path
+      sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.9.0"
+  path_parsing:
+    dependency: transitive
+    description:
+      name: path_parsing
+      sha256: e3e67b1629e6f7e8100b367d3db6ba6af4b1f0bb80f64db18ef1fbabd2fa9ccf
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.0.1"
+  path_provider:
+    dependency: transitive
+    description:
+      name: path_provider
+      sha256: c9e7d3a4cd1410877472158bee69963a4579f78b68c65a2b7d40d1a7a88bb161
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.1.3"
+  path_provider_android:
+    dependency: transitive
+    description:
+      name: path_provider_android
+      sha256: "9c96da072b421e98183f9ea7464898428e764bc0ce5567f27ec8693442e72514"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.2.5"
+  path_provider_foundation:
+    dependency: transitive
+    description:
+      name: path_provider_foundation
+      sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.4.0"
+  path_provider_linux:
+    dependency: transitive
+    description:
+      name: path_provider_linux
+      sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.2.1"
+  path_provider_platform_interface:
+    dependency: transitive
+    description:
+      name: path_provider_platform_interface
+      sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.1.2"
+  path_provider_windows:
+    dependency: transitive
+    description:
+      name: path_provider_windows
+      sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.2.1"
+  petitparser:
+    dependency: transitive
+    description:
+      name: petitparser
+      sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27
+      url: "https://pub.dev"
+    source: hosted
+    version: "6.0.2"
+  platform:
+    dependency: transitive
+    description:
+      name: platform
+      sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec"
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.1.4"
+  plugin_platform_interface:
+    dependency: transitive
+    description:
+      name: plugin_platform_interface
+      sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.1.8"
+  provider:
+    dependency: transitive
+    description:
+      name: provider
+      sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c
+      url: "https://pub.dev"
+    source: hosted
+    version: "6.1.2"
+  repository:
+    dependency: "direct main"
+    description:
+      path: "packages/repository"
+      relative: true
+    source: path
+    version: "0.0.1"
+  riverpod:
+    dependency: "direct main"
+    description:
+      name: riverpod
+      sha256: f21b32ffd26a36555e501b04f4a5dca43ed59e16343f1a30c13632b2351dfa4d
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.5.1"
+  sky_engine:
+    dependency: transitive
+    description: flutter
+    source: sdk
+    version: "0.0.99"
+  source_span:
+    dependency: transitive
+    description:
+      name: source_span
+      sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.10.0"
+  sprintf:
+    dependency: transitive
+    description:
+      name: sprintf
+      sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23"
+      url: "https://pub.dev"
+    source: hosted
+    version: "7.0.0"
+  stack_trace:
+    dependency: transitive
+    description:
+      name: stack_trace
+      sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.11.1"
+  state_notifier:
+    dependency: transitive
+    description:
+      name: state_notifier
+      sha256: b8677376aa54f2d7c58280d5a007f9e8774f1968d1fb1c096adcb4792fba29bb
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.0.0"
+  stream_channel:
+    dependency: transitive
+    description:
+      name: stream_channel
+      sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.1.2"
+  string_scanner:
+    dependency: transitive
+    description:
+      name: string_scanner
+      sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.2.0"
+  synchronized:
+    dependency: transitive
+    description:
+      name: synchronized
+      sha256: "539ef412b170d65ecdafd780f924e5be3f60032a1128df156adad6c5b373d558"
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.1.0+1"
+  term_glyph:
+    dependency: transitive
+    description:
+      name: term_glyph
+      sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.2.1"
+  test_api:
+    dependency: transitive
+    description:
+      name: test_api
+      sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f"
+      url: "https://pub.dev"
+    source: hosted
+    version: "0.7.0"
+  tiled:
+    dependency: transitive
+    description:
+      name: tiled
+      sha256: "988a57a07df280bb4a5d722c9e400b282d8d9a652b5a2afc8b68e1308bbf8222"
+      url: "https://pub.dev"
+    source: hosted
+    version: "0.10.2"
+  typed_data:
+    dependency: transitive
+    description:
+      name: typed_data
+      sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.3.2"
+  uuid:
+    dependency: transitive
+    description:
+      name: uuid
+      sha256: "814e9e88f21a176ae1359149021870e87f7cddaf633ab678a5d2b0bff7fd1ba8"
+      url: "https://pub.dev"
+    source: hosted
+    version: "4.4.0"
+  vector_graphics:
+    dependency: transitive
+    description:
+      name: vector_graphics
+      sha256: "32c3c684e02f9bc0afb0ae0aa653337a2fe022e8ab064bcd7ffda27a74e288e3"
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.1.11+1"
+  vector_graphics_codec:
+    dependency: transitive
+    description:
+      name: vector_graphics_codec
+      sha256: c86987475f162fadff579e7320c7ddda04cd2fdeffbe1129227a85d9ac9e03da
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.1.11+1"
+  vector_graphics_compiler:
+    dependency: transitive
+    description:
+      name: vector_graphics_compiler
+      sha256: "12faff3f73b1741a36ca7e31b292ddeb629af819ca9efe9953b70bd63fc8cd81"
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.1.11+1"
+  vector_math:
+    dependency: transitive
+    description:
+      name: vector_math
+      sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.1.4"
+  vm_service:
+    dependency: transitive
+    description:
+      name: vm_service
+      sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec"
+      url: "https://pub.dev"
+    source: hosted
+    version: "14.2.1"
+  web:
+    dependency: transitive
+    description:
+      name: web
+      sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27"
+      url: "https://pub.dev"
+    source: hosted
+    version: "0.5.1"
+  widget:
+    dependency: "direct main"
+    description:
+      path: "packages/widget"
+      relative: true
+    source: path
+    version: "0.0.1"
+  win32:
+    dependency: transitive
+    description:
+      name: win32
+      sha256: a79dbe579cb51ecd6d30b17e0cae4e0ea15e2c0e66f69ad4198f22a6789e94f4
+      url: "https://pub.dev"
+    source: hosted
+    version: "5.5.1"
+  xdg_directories:
+    dependency: transitive
+    description:
+      name: xdg_directories
+      sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.0.4"
+  xml:
+    dependency: transitive
+    description:
+      name: xml
+      sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226
+      url: "https://pub.dev"
+    source: hosted
+    version: "6.5.0"
+sdks:
+  dart: ">=3.4.0 <4.0.0"
+  flutter: ">=3.22.0"

+ 46 - 0
pubspec.yaml

@@ -0,0 +1,46 @@
+name: battle
+description: "A new Flutter project."
+publish_to: 'none'
+version: 1.0.0+1
+
+environment:
+  sdk: '>=3.4.0 <4.0.0'
+  flutter: ^3.22.0
+
+dependencies:
+  flutter:
+    sdk: flutter
+
+  cupertino_icons: ^1.0.6
+
+  riverpod: ^2.5.1
+  flutter_riverpod: ^2.5.1
+
+  flame: ^1.17.0
+  flame_tiled: ^1.20.0
+  flame_bloc: ^1.11.0
+  flame_forge2d: ^0.18.0
+  flame_svg: ^1.10.0
+  flame_audio: ^2.10.0
+  flame_riverpod: ^5.0.0
+  flame_isolate: ^0.6.0
+  flame_lottie: ^0.4.0
+  flame_markdown: ^0.2.0
+  flame_network_assets: ^0.3.0
+
+  repository:
+    path: packages/repository
+  widget:
+    path: packages/widget
+
+dev_dependencies:
+  flutter_test:
+    sdk: flutter
+
+  flutter_lints: ^3.0.0
+
+flutter:
+  uses-material-design: true
+
+  assets:
+    - assets/images/background.png