mirror of
https://github.com/flame-engine/flame.git
synced 2025-11-01 10:38:17 +08:00
Move flame_audio & update to work with current rc11 (#807)
This commit is contained in:
@ -15,4 +15,5 @@ Bridge packages are packages which:
|
|||||||
|
|
||||||
## Index
|
## Index
|
||||||
- [Flame](./flame)
|
- [Flame](./flame)
|
||||||
|
- [Flame Audio](./flame_audio)
|
||||||
- [Fire Atlas](./flame_fire_atlas)
|
- [Fire Atlas](./flame_fire_atlas)
|
||||||
|
|||||||
75
packages/flame_audio/.gitignore
vendored
Normal file
75
packages/flame_audio/.gitignore
vendored
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
# Miscellaneous
|
||||||
|
*.class
|
||||||
|
*.log
|
||||||
|
*.pyc
|
||||||
|
*.swp
|
||||||
|
.DS_Store
|
||||||
|
.atom/
|
||||||
|
.buildlog/
|
||||||
|
.history
|
||||||
|
.svn/
|
||||||
|
|
||||||
|
# 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/
|
||||||
|
.dart_tool/
|
||||||
|
.flutter-plugins
|
||||||
|
.flutter-plugins-dependencies
|
||||||
|
.packages
|
||||||
|
.pub-cache/
|
||||||
|
.pub/
|
||||||
|
build/
|
||||||
|
|
||||||
|
# Android related
|
||||||
|
**/android/**/gradle-wrapper.jar
|
||||||
|
**/android/.gradle
|
||||||
|
**/android/captures/
|
||||||
|
**/android/gradlew
|
||||||
|
**/android/gradlew.bat
|
||||||
|
**/android/local.properties
|
||||||
|
**/android/**/GeneratedPluginRegistrant.java
|
||||||
|
|
||||||
|
# iOS/XCode related
|
||||||
|
**/ios/**/*.mode1v3
|
||||||
|
**/ios/**/*.mode2v3
|
||||||
|
**/ios/**/*.moved-aside
|
||||||
|
**/ios/**/*.pbxuser
|
||||||
|
**/ios/**/*.perspectivev3
|
||||||
|
**/ios/**/*sync/
|
||||||
|
**/ios/**/.sconsign.dblite
|
||||||
|
**/ios/**/.tags*
|
||||||
|
**/ios/**/.vagrant/
|
||||||
|
**/ios/**/DerivedData/
|
||||||
|
**/ios/**/Icon?
|
||||||
|
**/ios/**/Pods/
|
||||||
|
**/ios/**/.symlinks/
|
||||||
|
**/ios/**/profile
|
||||||
|
**/ios/**/xcuserdata
|
||||||
|
**/ios/.generated/
|
||||||
|
**/ios/Flutter/App.framework
|
||||||
|
**/ios/Flutter/Flutter.framework
|
||||||
|
**/ios/Flutter/Flutter.podspec
|
||||||
|
**/ios/Flutter/Generated.xcconfig
|
||||||
|
**/ios/Flutter/app.flx
|
||||||
|
**/ios/Flutter/app.zip
|
||||||
|
**/ios/Flutter/flutter_assets/
|
||||||
|
**/ios/Flutter/flutter_export_environment.sh
|
||||||
|
**/ios/ServiceDefinitions.json
|
||||||
|
**/ios/Runner/GeneratedPluginRegistrant.*
|
||||||
|
|
||||||
|
# Exceptions to above rules.
|
||||||
|
!**/ios/**/default.mode1v3
|
||||||
|
!**/ios/**/default.mode2v3
|
||||||
|
!**/ios/**/default.pbxuser
|
||||||
|
!**/ios/**/default.perspectivev3
|
||||||
|
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
|
||||||
24
packages/flame_audio/CHANGELOG.md
Normal file
24
packages/flame_audio/CHANGELOG.md
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
## [next]
|
||||||
|
* Moved project to the mono-repo
|
||||||
|
* Updated flame, audioplayers
|
||||||
|
|
||||||
|
## [0.1.0-rc5]
|
||||||
|
* Updated `audioplayers` version
|
||||||
|
* Updated Flame version
|
||||||
|
* Add support to null safety
|
||||||
|
|
||||||
|
## [0.1.0-rc4]
|
||||||
|
* Update audioplayers version
|
||||||
|
|
||||||
|
## [0.1.0-rc3]
|
||||||
|
* Bump flame version to rc5, upgrade code to match, update other dependencies
|
||||||
|
* Add linter and fix code to comply
|
||||||
|
|
||||||
|
## [0.1.0-rc2]
|
||||||
|
* Bump flame version to rc2 and audioplayers version to 0.17
|
||||||
|
|
||||||
|
## [0.1.0-rc1]
|
||||||
|
* First real version, including all necessary files for 1.0.0
|
||||||
|
|
||||||
|
## [0.0.1]
|
||||||
|
* Empty release; in the future all flame audio related code will live here.
|
||||||
1
packages/flame_audio/LICENSE
Symbolic link
1
packages/flame_audio/LICENSE
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../../LICENSE
|
||||||
28
packages/flame_audio/README.md
Normal file
28
packages/flame_audio/README.md
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# flame_audio
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://flame-engine.org">
|
||||||
|
<img alt="flame" width="200px" src="https://user-images.githubusercontent.com/6718144/101553774-3bc7b000-39ad-11eb-8a6a-de2daa31bd64.png">
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
Adds audio support for <a href="https://github.com/flame-engine/flame">Flame</a> using the <a href="https://github.com/luanpotter/audioplayers">audioplayers</a> package.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a title="Pub" href="https://pub.dartlang.org/packages/flame_audio" ><img src="https://img.shields.io/pub/v/flame_audio.svg?style=popout&include_prereleases" /></a>
|
||||||
|
<img src="https://github.com/flame-engine/flame_audio/workflows/Lint/badge.svg?branch=master&event=push" alt="Test" />
|
||||||
|
<a title="Discord" href="https://discord.gg/pxrBmy4" ><img src="https://img.shields.io/discord/509714518008528896.svg" /></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
This package makes it easy to add audio capabilities to your games, integrating [Audioplayers](https://github.com/luanpotter/audioplayers) features seamless into your Flame game code.
|
||||||
|
|
||||||
|
Add this as a dependency alongside Flame v1 to your game if you want to play background music, ambient sounds, sound effects, etc.
|
||||||
|
|
||||||
|
# Credits
|
||||||
|
|
||||||
|
* The [Flame Engine team](https://github.com/orgs/flame-engine/people), who is continuously working on maintaining and improving Flame.
|
||||||
|
* [luanpotter's audioplayers](https://github.com/luanpotter/audioplayer) lib, which was originally a fork from [rxlabz's audioplayer](https://github.com/rxlabz/audioplayer).
|
||||||
149
packages/flame_audio/analysis_options.yaml
Normal file
149
packages/flame_audio/analysis_options.yaml
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
# Source of linter options:
|
||||||
|
# http://dart-lang.github.io/linter/lints/options/options.html
|
||||||
|
|
||||||
|
analyzer:
|
||||||
|
strong-mode:
|
||||||
|
implicit-casts: false
|
||||||
|
implicit-dynamic: false
|
||||||
|
|
||||||
|
plugins:
|
||||||
|
- dart_code_metrics
|
||||||
|
|
||||||
|
linter:
|
||||||
|
rules:
|
||||||
|
- always_declare_return_types
|
||||||
|
- always_put_control_body_on_new_line
|
||||||
|
- always_require_non_null_named_parameters
|
||||||
|
- annotate_overrides
|
||||||
|
- avoid_double_and_int_checks
|
||||||
|
- avoid_dynamic_calls
|
||||||
|
- avoid_empty_else
|
||||||
|
- avoid_equals_and_hash_code_on_mutable_classes
|
||||||
|
- avoid_escaping_inner_quotes
|
||||||
|
- avoid_field_initializers_in_const_classes
|
||||||
|
- avoid_init_to_null
|
||||||
|
- avoid_js_rounded_ints
|
||||||
|
- avoid_null_checks_in_equality_operators
|
||||||
|
- avoid_private_typedef_functions
|
||||||
|
- avoid_redundant_argument_values
|
||||||
|
- avoid_relative_lib_imports
|
||||||
|
- avoid_return_types_on_setters
|
||||||
|
- avoid_shadowing_type_parameters
|
||||||
|
- avoid_slow_async_io
|
||||||
|
- avoid_type_to_string
|
||||||
|
- avoid_types_as_parameter_names
|
||||||
|
- avoid_unused_constructor_parameters
|
||||||
|
- await_only_futures
|
||||||
|
- camel_case_extensions
|
||||||
|
- camel_case_types
|
||||||
|
- cancel_subscriptions
|
||||||
|
- cast_nullable_to_non_nullable
|
||||||
|
- close_sinks
|
||||||
|
- comment_references
|
||||||
|
- constant_identifier_names
|
||||||
|
- control_flow_in_finally
|
||||||
|
- curly_braces_in_flow_control_structures
|
||||||
|
- directives_ordering
|
||||||
|
- do_not_use_environment
|
||||||
|
- empty_catches
|
||||||
|
- empty_constructor_bodies
|
||||||
|
- empty_statements
|
||||||
|
- exhaustive_cases
|
||||||
|
- file_names
|
||||||
|
- hash_and_equals
|
||||||
|
- implementation_imports
|
||||||
|
- invariant_booleans
|
||||||
|
- iterable_contains_unrelated_type
|
||||||
|
- join_return_with_assignment
|
||||||
|
- library_names
|
||||||
|
- library_prefixes
|
||||||
|
- list_remove_unrelated_type
|
||||||
|
- literal_only_boolean_expressions
|
||||||
|
- missing_whitespace_between_adjacent_strings
|
||||||
|
- no_adjacent_strings_in_list
|
||||||
|
- no_duplicate_case_values
|
||||||
|
- no_runtimeType_toString
|
||||||
|
- omit_local_variable_types
|
||||||
|
- package_api_docs
|
||||||
|
- package_names
|
||||||
|
- package_prefixed_library_names
|
||||||
|
- parameter_assignments
|
||||||
|
- prefer_adjacent_string_concatenation
|
||||||
|
- prefer_asserts_in_initializer_lists
|
||||||
|
- prefer_collection_literals
|
||||||
|
- prefer_conditional_assignment
|
||||||
|
- prefer_const_constructors
|
||||||
|
- prefer_const_constructors_in_immutables
|
||||||
|
- prefer_const_declarations
|
||||||
|
- prefer_const_literals_to_create_immutables
|
||||||
|
- prefer_contains
|
||||||
|
- prefer_equal_for_default_values
|
||||||
|
- prefer_final_fields
|
||||||
|
- prefer_final_in_for_each
|
||||||
|
- prefer_final_locals
|
||||||
|
- prefer_for_elements_to_map_fromIterable
|
||||||
|
- prefer_foreach
|
||||||
|
- prefer_function_declarations_over_variables
|
||||||
|
- prefer_generic_function_type_aliases
|
||||||
|
- prefer_if_elements_to_conditional_expressions
|
||||||
|
- prefer_if_null_operators
|
||||||
|
- prefer_initializing_formals
|
||||||
|
- prefer_inlined_adds
|
||||||
|
- prefer_interpolation_to_compose_strings
|
||||||
|
- prefer_is_empty
|
||||||
|
- prefer_is_not_empty
|
||||||
|
- prefer_is_not_operator
|
||||||
|
- prefer_iterable_whereType
|
||||||
|
- prefer_mixin
|
||||||
|
- prefer_null_aware_operators
|
||||||
|
- prefer_single_quotes
|
||||||
|
- prefer_spread_collections
|
||||||
|
- prefer_relative_imports
|
||||||
|
- prefer_typing_uninitialized_variables
|
||||||
|
- prefer_void_to_null
|
||||||
|
- provide_deprecation_message
|
||||||
|
- recursive_getters
|
||||||
|
- slash_for_doc_comments
|
||||||
|
- sort_unnamed_constructors_first
|
||||||
|
- test_types_in_equals
|
||||||
|
- throw_in_finally
|
||||||
|
- type_annotate_public_apis
|
||||||
|
- type_init_formals
|
||||||
|
- unnecessary_await_in_return
|
||||||
|
- unnecessary_brace_in_string_interps
|
||||||
|
- unnecessary_const
|
||||||
|
- unnecessary_getters_setters
|
||||||
|
- unnecessary_lambdas
|
||||||
|
- unnecessary_new
|
||||||
|
- unnecessary_null_aware_assignments
|
||||||
|
- unnecessary_null_in_if_null_operators
|
||||||
|
- unnecessary_overrides
|
||||||
|
- unnecessary_parenthesis
|
||||||
|
- unnecessary_raw_strings
|
||||||
|
- unnecessary_statements
|
||||||
|
- unnecessary_string_escapes
|
||||||
|
- unnecessary_string_interpolations
|
||||||
|
- unnecessary_this
|
||||||
|
- use_full_hex_values_for_flutter_colors
|
||||||
|
- use_function_type_syntax_for_parameters
|
||||||
|
- use_is_even_rather_than_modulo
|
||||||
|
- use_rethrow_when_possible
|
||||||
|
- unrelated_type_equality_checks
|
||||||
|
- unsafe_html
|
||||||
|
- void_checks
|
||||||
|
|
||||||
|
dart_code_metrics:
|
||||||
|
rules:
|
||||||
|
- prefer-trailing-comma
|
||||||
|
- prefer-trailing-comma-for-collection
|
||||||
|
- no-equal-then-else
|
||||||
|
- no-object-declaration
|
||||||
|
- potential-null-dereference
|
||||||
|
metrics-exclude:
|
||||||
|
- test/**
|
||||||
|
metrics:
|
||||||
|
number-of-parameters: 8
|
||||||
|
number-of-methods: 32
|
||||||
|
source-lines-of-code: 200
|
||||||
|
cyclomatic-complexity: 36
|
||||||
|
maximum-nesting-level: 8
|
||||||
51
packages/flame_audio/example/.gitignore
vendored
Normal file
51
packages/flame_audio/example/.gitignore
vendored
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
# Miscellaneous
|
||||||
|
*.class
|
||||||
|
*.log
|
||||||
|
*.pyc
|
||||||
|
*.swp
|
||||||
|
.DS_Store
|
||||||
|
.atom/
|
||||||
|
.buildlog/
|
||||||
|
.history
|
||||||
|
.svn/
|
||||||
|
|
||||||
|
# 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
|
||||||
|
.packages
|
||||||
|
.pub-cache/
|
||||||
|
.pub/
|
||||||
|
/build/
|
||||||
|
|
||||||
|
# Web related
|
||||||
|
lib/generated_plugin_registrant.dart
|
||||||
|
|
||||||
|
# Symbolication related
|
||||||
|
app.*.symbols
|
||||||
|
|
||||||
|
# Obfuscation related
|
||||||
|
app.*.map.json
|
||||||
|
|
||||||
|
# Exceptions to above rules.
|
||||||
|
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
|
||||||
|
|
||||||
|
android
|
||||||
|
ios
|
||||||
|
web
|
||||||
|
integration_test
|
||||||
|
macos
|
||||||
|
test
|
||||||
10
packages/flame_audio/example/.metadata
Normal file
10
packages/flame_audio/example/.metadata
Normal file
@ -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: a2bde82fbd52e09057a4146f46889f4e10342d32
|
||||||
|
channel: beta
|
||||||
|
|
||||||
|
project_type: app
|
||||||
6
packages/flame_audio/example/CREDITS.md
Normal file
6
packages/flame_audio/example/CREDITS.md
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# Credits
|
||||||
|
|
||||||
|
CC-0 audio files for this examples obtained here:
|
||||||
|
|
||||||
|
* sfx: https://opengameart.org/content/63-digital-sound-effects-lasers-phasers-space-etc
|
||||||
|
* bg music: https://opengameart.org/content/another-space-background-track
|
||||||
3
packages/flame_audio/example/README.md
Normal file
3
packages/flame_audio/example/README.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# flame audio example
|
||||||
|
|
||||||
|
Simple project to showcase the usage of flame_audio
|
||||||
BIN
packages/flame_audio/example/assets/audio/music/bg_music.ogg
Normal file
BIN
packages/flame_audio/example/assets/audio/music/bg_music.ogg
Normal file
Binary file not shown.
BIN
packages/flame_audio/example/assets/audio/sfx/fire_1.mp3
Normal file
BIN
packages/flame_audio/example/assets/audio/sfx/fire_1.mp3
Normal file
Binary file not shown.
BIN
packages/flame_audio/example/assets/audio/sfx/fire_2.mp3
Normal file
BIN
packages/flame_audio/example/assets/audio/sfx/fire_2.mp3
Normal file
Binary file not shown.
81
packages/flame_audio/example/lib/main.dart
Normal file
81
packages/flame_audio/example/lib/main.dart
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
import 'package:flame/components.dart';
|
||||||
|
import 'package:flame/extensions.dart';
|
||||||
|
import 'package:flame/game.dart';
|
||||||
|
import 'package:flame/gestures.dart';
|
||||||
|
import 'package:flame/palette.dart';
|
||||||
|
import 'package:flame_audio/audio_pool.dart';
|
||||||
|
import 'package:flame_audio/flame_audio.dart';
|
||||||
|
import 'package:flutter/widgets.dart' hide Animation;
|
||||||
|
|
||||||
|
void main() async {
|
||||||
|
runApp(GameWidget(game: AudioGame()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This example game showcases three possible use cases:
|
||||||
|
///
|
||||||
|
/// 1. Use the static FlameAudio class to easily fire a sfx using the default
|
||||||
|
/// configs for the button tap.
|
||||||
|
/// 2. Uses a custom AudioPool for extremely efficient audio loading and pooling
|
||||||
|
/// for tapping elsewhere.
|
||||||
|
/// 3. Uses the Bgm utility for background music.
|
||||||
|
class AudioGame extends BaseGame with TapDetector {
|
||||||
|
static Paint black = BasicPalette.black.paint();
|
||||||
|
static Paint gray = const PaletteEntry(Color(0xFFCCCCCC)).paint();
|
||||||
|
static TextPaint text = TextPaint(
|
||||||
|
config: TextPaintConfig(color: BasicPalette.white.color),
|
||||||
|
);
|
||||||
|
|
||||||
|
late AudioPool pool;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> onLoad() async {
|
||||||
|
pool = await AudioPool.create('fire_2.mp3', minPlayers: 3, maxPlayers: 4);
|
||||||
|
startBgmMusic();
|
||||||
|
}
|
||||||
|
|
||||||
|
Rect get button => Rect.fromLTWH(20, size.y - 300, size.x - 40, 200);
|
||||||
|
|
||||||
|
void startBgmMusic() {
|
||||||
|
FlameAudio.bgm.initialize();
|
||||||
|
FlameAudio.bgm.play('music/bg_music.ogg');
|
||||||
|
}
|
||||||
|
|
||||||
|
void fireOne() {
|
||||||
|
FlameAudio.audioCache.play('sfx/fire_1.mp3');
|
||||||
|
}
|
||||||
|
|
||||||
|
void fireTwo() {
|
||||||
|
pool.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void render(Canvas canvas) {
|
||||||
|
super.render(canvas);
|
||||||
|
canvas.drawRect(size.toRect(), black);
|
||||||
|
|
||||||
|
text.render(
|
||||||
|
canvas,
|
||||||
|
'(click anywhere for 1)',
|
||||||
|
Vector2(size.x / 2, 200),
|
||||||
|
anchor: Anchor.topCenter,
|
||||||
|
);
|
||||||
|
|
||||||
|
canvas.drawRect(button, gray);
|
||||||
|
|
||||||
|
text.render(
|
||||||
|
canvas,
|
||||||
|
'click here for 2',
|
||||||
|
Vector2(size.x / 2, size.y - 200),
|
||||||
|
anchor: Anchor.bottomCenter,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onTapDown(TapDownInfo details) {
|
||||||
|
if (button.containsPoint(details.eventPosition.game)) {
|
||||||
|
fireTwo();
|
||||||
|
} else {
|
||||||
|
fireOne();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
26
packages/flame_audio/example/pubspec.yaml
Normal file
26
packages/flame_audio/example/pubspec.yaml
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
name: example
|
||||||
|
description: Simple project to showcase the usage of flame_audio
|
||||||
|
|
||||||
|
publish_to: 'none'
|
||||||
|
|
||||||
|
version: 1.0.0+1
|
||||||
|
|
||||||
|
environment:
|
||||||
|
sdk: ">=2.12.0 <3.0.0"
|
||||||
|
|
||||||
|
dependencies:
|
||||||
|
flame: 1.0.0-releasecandidate.11
|
||||||
|
flame_audio:
|
||||||
|
path: ../
|
||||||
|
flutter:
|
||||||
|
sdk: flutter
|
||||||
|
|
||||||
|
dev_dependencies:
|
||||||
|
dart_code_metrics: ^3.2.2
|
||||||
|
|
||||||
|
flutter:
|
||||||
|
uses-material-design: false
|
||||||
|
assets:
|
||||||
|
- assets/audio/music/bg_music.ogg
|
||||||
|
- assets/audio/sfx/fire_1.mp3
|
||||||
|
- assets/audio/sfx/fire_2.mp3
|
||||||
101
packages/flame_audio/lib/audio_pool.dart
Normal file
101
packages/flame_audio/lib/audio_pool.dart
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:audioplayers/audioplayers.dart';
|
||||||
|
import 'package:synchronized/synchronized.dart';
|
||||||
|
|
||||||
|
typedef Stoppable = void Function();
|
||||||
|
|
||||||
|
/// An AudioPool is a provider of AudioPlayers that leaves them pre-loaded to minimize delays.
|
||||||
|
///
|
||||||
|
/// All AudioPlayers loaded are for the same [sound]. If you want multiple sounds use multiple [AudioPool].
|
||||||
|
/// Use this class if you'd like have extremely quick firing, repetitive and simultaneous sounds, like shooting a laser in a fast-paced spaceship game.
|
||||||
|
class AudioPool {
|
||||||
|
final AudioCache _cache;
|
||||||
|
final Map<String, AudioPlayer> _currentPlayers = {};
|
||||||
|
final List<AudioPlayer> _availablePlayers = [];
|
||||||
|
|
||||||
|
final String sound;
|
||||||
|
final bool repeating;
|
||||||
|
final int minPlayers, maxPlayers;
|
||||||
|
|
||||||
|
final Lock _lock = Lock();
|
||||||
|
|
||||||
|
AudioPool._(
|
||||||
|
this.sound, {
|
||||||
|
bool? repeating,
|
||||||
|
int? maxPlayers,
|
||||||
|
int? minPlayers = 1,
|
||||||
|
String? prefix,
|
||||||
|
}) : _cache = AudioCache(prefix: prefix ?? 'assets/audio/sfx/'),
|
||||||
|
repeating = repeating ?? false,
|
||||||
|
maxPlayers = maxPlayers ?? 1,
|
||||||
|
minPlayers = minPlayers ?? 1;
|
||||||
|
|
||||||
|
static Future<AudioPool> create(
|
||||||
|
String sound, {
|
||||||
|
bool? repeating,
|
||||||
|
int? maxPlayers,
|
||||||
|
int? minPlayers = 1,
|
||||||
|
String? prefix,
|
||||||
|
}) async {
|
||||||
|
final instance = AudioPool._(
|
||||||
|
sound,
|
||||||
|
repeating: repeating,
|
||||||
|
maxPlayers: maxPlayers,
|
||||||
|
minPlayers: minPlayers,
|
||||||
|
prefix: prefix,
|
||||||
|
);
|
||||||
|
for (var i = 0; i < instance.minPlayers; i++) {
|
||||||
|
instance._availablePlayers.add(await instance._createNewAudioPlayer());
|
||||||
|
}
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Stoppable> start({double volume = 1.0}) async {
|
||||||
|
return _lock.synchronized(() async {
|
||||||
|
if (_availablePlayers.isEmpty) {
|
||||||
|
_availablePlayers.add(await _createNewAudioPlayer());
|
||||||
|
}
|
||||||
|
final player = _availablePlayers.removeAt(0);
|
||||||
|
_currentPlayers[player.playerId] = player;
|
||||||
|
await player.setVolume(volume);
|
||||||
|
await player.resume();
|
||||||
|
|
||||||
|
late StreamSubscription<void> subscription;
|
||||||
|
|
||||||
|
void stop() {
|
||||||
|
_lock.synchronized(() async {
|
||||||
|
final p = _currentPlayers.remove(player.playerId);
|
||||||
|
if (p != null) {
|
||||||
|
subscription.cancel();
|
||||||
|
await p.stop();
|
||||||
|
if (_availablePlayers.length >= maxPlayers) {
|
||||||
|
await p.release();
|
||||||
|
} else {
|
||||||
|
_availablePlayers.add(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
subscription = player.onPlayerCompletion.listen((_) {
|
||||||
|
if (repeating) {
|
||||||
|
player.resume();
|
||||||
|
} else {
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return stop;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<AudioPlayer> _createNewAudioPlayer() async {
|
||||||
|
final player = AudioPlayer();
|
||||||
|
final url = (await _cache.load(sound)).path;
|
||||||
|
await player.setUrl(url);
|
||||||
|
await player.setReleaseMode(ReleaseMode.STOP);
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
}
|
||||||
123
packages/flame_audio/lib/bgm.dart
Normal file
123
packages/flame_audio/lib/bgm.dart
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:audioplayers/audioplayers.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
|
/// The looping background music class.
|
||||||
|
///
|
||||||
|
/// This class helps with looping background music management that reacts to
|
||||||
|
/// application lifecycle state changes. On construction, the instance is added
|
||||||
|
/// as an observer to the [WidgetsBinding] instance. A [dispose] function is
|
||||||
|
/// provided in case this functionality needs to be unloaded but the app needs
|
||||||
|
/// to keep running.
|
||||||
|
class Bgm extends WidgetsBindingObserver {
|
||||||
|
bool _isRegistered = false;
|
||||||
|
late AudioCache audioCache;
|
||||||
|
AudioPlayer? audioPlayer;
|
||||||
|
bool isPlaying = false;
|
||||||
|
|
||||||
|
Bgm({AudioCache? audioCache}) : audioCache = audioCache ?? AudioCache();
|
||||||
|
|
||||||
|
/// Registers a [WidgetsBinding] observer.
|
||||||
|
///
|
||||||
|
/// This must be called for auto-pause and resume to work properly.
|
||||||
|
void initialize() {
|
||||||
|
if (_isRegistered) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_isRegistered = true;
|
||||||
|
WidgetsBinding.instance?.addObserver(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Dispose the [WidgetsBinding] observer.
|
||||||
|
void dispose() {
|
||||||
|
if (!_isRegistered) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
WidgetsBinding.instance?.removeObserver(this);
|
||||||
|
_isRegistered = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Plays and loops a background music file specified by [filename].
|
||||||
|
///
|
||||||
|
/// The volume can be specified in the optional named parameter [volume]
|
||||||
|
/// where `0` means off and `1` means max.
|
||||||
|
///
|
||||||
|
/// It is safe to call this function even when a current BGM track is
|
||||||
|
/// playing.
|
||||||
|
Future<void> play(String filename, {double volume = 1}) async {
|
||||||
|
final currentPlayer = audioPlayer;
|
||||||
|
if (currentPlayer != null && currentPlayer.state != PlayerState.STOPPED) {
|
||||||
|
currentPlayer.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
isPlaying = true;
|
||||||
|
audioPlayer = await audioCache.loop(filename, volume: volume);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Stops the currently playing background music track (if any).
|
||||||
|
Future<void> stop() async {
|
||||||
|
isPlaying = false;
|
||||||
|
if (audioPlayer != null) {
|
||||||
|
await audioPlayer!.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Resumes the currently played (but resumed) background music.
|
||||||
|
Future<void> resume() async {
|
||||||
|
if (audioPlayer != null) {
|
||||||
|
isPlaying = true;
|
||||||
|
await audioPlayer!.resume();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Pauses the background music without unloading or resetting the audio
|
||||||
|
/// player.
|
||||||
|
Future<void> pause() async {
|
||||||
|
if (audioPlayer != null) {
|
||||||
|
isPlaying = false;
|
||||||
|
await audioPlayer!.pause();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Pre-fetch an audio and store it in the cache.
|
||||||
|
///
|
||||||
|
/// Alias of `audioCache.load();`.
|
||||||
|
Future<Uri> load(String file) => audioCache.load(file);
|
||||||
|
|
||||||
|
/// Pre-fetch an audio and store it in the cache.
|
||||||
|
///
|
||||||
|
/// Alias of `audioCache.loadAsFile();`.
|
||||||
|
Future<File> loadAsFile(String file) => audioCache.loadAsFile(file);
|
||||||
|
|
||||||
|
/// Pre-fetch a list of audios and store them in the cache.
|
||||||
|
///
|
||||||
|
/// Alias of `audioCache.loadAll();`.
|
||||||
|
Future<List<Uri>> loadAll(List<String> files) => audioCache.loadAll(files);
|
||||||
|
|
||||||
|
/// Clears the file in the cache.
|
||||||
|
///
|
||||||
|
/// Alias of `audioCache.clear();`.
|
||||||
|
void clear(Uri file) => audioCache.clear(file);
|
||||||
|
|
||||||
|
/// Clears all the audios in the cache.
|
||||||
|
///
|
||||||
|
/// Alias of `audioCache.clearAll();`.
|
||||||
|
void clearAll() => audioCache.clearAll();
|
||||||
|
|
||||||
|
/// Handler for AppLifecycleState changes.
|
||||||
|
///
|
||||||
|
/// This function handles the automatic pause and resume when the app
|
||||||
|
/// lifecycle state changes. There is NO NEED to call this function directly
|
||||||
|
/// directly.
|
||||||
|
@override
|
||||||
|
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||||||
|
if (state == AppLifecycleState.resumed) {
|
||||||
|
if (isPlaying && audioPlayer?.state == PlayerState.PAUSED) {
|
||||||
|
audioPlayer?.resume();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
audioPlayer?.pause();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
43
packages/flame_audio/lib/flame_audio.dart
Normal file
43
packages/flame_audio/lib/flame_audio.dart
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import 'package:audioplayers/audioplayers.dart';
|
||||||
|
|
||||||
|
import 'bgm.dart';
|
||||||
|
|
||||||
|
/// This utility class holds static references to some global audio objects.
|
||||||
|
///
|
||||||
|
/// You can use as a helper to very simply play a sound or a background music.
|
||||||
|
/// Alternatively you can create your own instances and control them yourself.
|
||||||
|
class FlameAudio {
|
||||||
|
/// Access a shared instance of the [AudioCache] class.
|
||||||
|
static AudioCache audioCache = AudioCache(prefix: 'assets/audio/');
|
||||||
|
|
||||||
|
/// Plays a single run of the given [file], with a given [volume].
|
||||||
|
static Future<AudioPlayer> play(String file, {double volume = 1.0}) {
|
||||||
|
return audioCache.play(file, volume: volume, mode: PlayerMode.LOW_LATENCY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Plays, and keep looping the given [file]
|
||||||
|
static Future<AudioPlayer> loop(String file, {double volume = 1.0}) {
|
||||||
|
return audioCache.loop(file, volume: volume, mode: PlayerMode.LOW_LATENCY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Plays a single run of the given file [file]
|
||||||
|
/// This method supports long audio files
|
||||||
|
static Future<AudioPlayer> playLongAudio(String file, {double volume = 1.0}) {
|
||||||
|
return audioCache.play(file, volume: volume);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Plays, and keep looping the given [file]
|
||||||
|
/// This method supports long audio files
|
||||||
|
///
|
||||||
|
/// NOTE: Length audio files on Android have an audio gap between loop
|
||||||
|
/// iterations, this happens due to limitations on Android's native media
|
||||||
|
/// player features, if you need a gapless loop, prefer the loop method
|
||||||
|
static Future<AudioPlayer> loopLongAudio(String file, {double volume = 1.0}) {
|
||||||
|
return audioCache.loop(file, volume: volume);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Access a shared instance of the [Bgm] class.
|
||||||
|
///
|
||||||
|
/// This will use the same global audio cache from [FlameAudio].
|
||||||
|
static late final Bgm bgm = Bgm(audioCache: audioCache);
|
||||||
|
}
|
||||||
22
packages/flame_audio/pubspec.yaml
Normal file
22
packages/flame_audio/pubspec.yaml
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
name: flame_audio
|
||||||
|
description: Audio support for the Flame game engine. This containst all audio related code will live in the future, using the audioplayers package.
|
||||||
|
version: 0.1.0-rc5
|
||||||
|
homepage: https://github.com/flame-engine/flame_audio
|
||||||
|
|
||||||
|
environment:
|
||||||
|
sdk: ">=2.12.0 <3.0.0"
|
||||||
|
flutter: ">=1.17.0"
|
||||||
|
|
||||||
|
dependencies:
|
||||||
|
flame: '>=1.0.0-releasecandidate.11'
|
||||||
|
audioplayers: ^0.19.0
|
||||||
|
synchronized: ^3.0.0
|
||||||
|
flutter:
|
||||||
|
sdk: flutter
|
||||||
|
|
||||||
|
dev_dependencies:
|
||||||
|
dart_code_metrics: ^3.2.2
|
||||||
|
dartdoc: ^0.42.0
|
||||||
|
flutter_test:
|
||||||
|
sdk: flutter
|
||||||
|
test: ^1.9.4
|
||||||
Reference in New Issue
Block a user