mirror of
https://github.com/flame-engine/flame.git
synced 2025-11-03 04:18:25 +08:00
Removing audio stuff in favor of flame_audio
This commit is contained in:
70
doc/examples/sound/.gitignore
vendored
70
doc/examples/sound/.gitignore
vendored
@ -1,70 +0,0 @@
|
|||||||
# Miscellaneous
|
|
||||||
*.class
|
|
||||||
*.log
|
|
||||||
*.pyc
|
|
||||||
*.swp
|
|
||||||
.DS_Store
|
|
||||||
.atom/
|
|
||||||
.buildlog/
|
|
||||||
.history
|
|
||||||
.svn/
|
|
||||||
|
|
||||||
# IntelliJ related
|
|
||||||
*.iml
|
|
||||||
*.ipr
|
|
||||||
*.iws
|
|
||||||
.idea/
|
|
||||||
|
|
||||||
# Visual Studio Code related
|
|
||||||
.vscode/
|
|
||||||
|
|
||||||
# Flutter/Dart/Pub related
|
|
||||||
**/doc/api/
|
|
||||||
.dart_tool/
|
|
||||||
.flutter-plugins
|
|
||||||
.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/Generated.xcconfig
|
|
||||||
**/ios/Flutter/app.flx
|
|
||||||
**/ios/Flutter/app.zip
|
|
||||||
**/ios/Flutter/flutter_assets/
|
|
||||||
**/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
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
# 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: 7fc14a55af64462763d28abfb4e610086c6e0f39
|
|
||||||
channel: dev
|
|
||||||
|
|
||||||
project_type: app
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
# sound
|
|
||||||
|
|
||||||
Flame example application showcasing the audio features
|
|
||||||
Binary file not shown.
Binary file not shown.
@ -1,57 +0,0 @@
|
|||||||
import 'package:flame/flame.dart';
|
|
||||||
import 'package:flame/game.dart';
|
|
||||||
import 'package:flame/extensions/vector2.dart';
|
|
||||||
import 'package:flame/components/position_component.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
void main() async {
|
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
|
||||||
final Vector2 size = await Flame.util.initialDimensions();
|
|
||||||
runApp(MyGame(size).widget);
|
|
||||||
}
|
|
||||||
|
|
||||||
class Ball extends PositionComponent {
|
|
||||||
final Vector2 gameSize;
|
|
||||||
final paint = Paint()..color = const Color(0xFFFFFFFF);
|
|
||||||
|
|
||||||
bool forward = true;
|
|
||||||
|
|
||||||
Ball(this.gameSize);
|
|
||||||
|
|
||||||
@override
|
|
||||||
void render(Canvas c) {
|
|
||||||
super.render(c);
|
|
||||||
c.drawOval(size.toRect(), paint);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void update(double dt) {
|
|
||||||
super.update(dt);
|
|
||||||
x += (forward ? 1 : -1) * 100 * dt;
|
|
||||||
|
|
||||||
if (x <= 0 || x + width >= gameSize.x) {
|
|
||||||
if (forward) {
|
|
||||||
x = gameSize.x - width - 1;
|
|
||||||
} else {
|
|
||||||
x = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
forward = !forward;
|
|
||||||
Flame.audio.play('boin.mp3', volume: 1.0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class MyGame extends BaseGame {
|
|
||||||
MyGame(Vector2 screenSize) {
|
|
||||||
size = screenSize;
|
|
||||||
|
|
||||||
Flame.audio.disableLog();
|
|
||||||
Flame.audio.load('boin.mp3');
|
|
||||||
Flame.audio.loop('music.mp3', volume: 0.4);
|
|
||||||
|
|
||||||
add(Ball(size)
|
|
||||||
..y = (size.y / 2) - 50
|
|
||||||
..size = Vector2.all(100));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,21 +0,0 @@
|
|||||||
name: sound
|
|
||||||
description: Flame example application showcasing the audio features
|
|
||||||
version: 0.1.0
|
|
||||||
|
|
||||||
environment:
|
|
||||||
sdk: ">=2.7.0 <3.0.0"
|
|
||||||
|
|
||||||
dependencies:
|
|
||||||
flutter:
|
|
||||||
sdk: flutter
|
|
||||||
flame:
|
|
||||||
path: ../../../
|
|
||||||
|
|
||||||
dev_dependencies:
|
|
||||||
flutter_test:
|
|
||||||
sdk: flutter
|
|
||||||
|
|
||||||
flutter:
|
|
||||||
assets:
|
|
||||||
- assets/audio/music.mp3
|
|
||||||
- assets/audio/boin.mp3
|
|
||||||
@ -23,6 +23,9 @@ The file structure would have to be:
|
|||||||
└── player.png
|
└── player.png
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Optionally you can split your `audio` folder into two subfolders, one for `music` and one for `sfx`.
|
||||||
|
Be mindful of configuring the `prefix` property correctly if you are changing this structure.
|
||||||
|
|
||||||
Don't forget to add these files to your `pubspec.yaml` file:
|
Don't forget to add these files to your `pubspec.yaml` file:
|
||||||
|
|
||||||
```
|
```
|
||||||
@ -31,4 +34,4 @@ flutter:
|
|||||||
- assets/audio/explosion.mp3
|
- assets/audio/explosion.mp3
|
||||||
- assets/images/player.png
|
- assets/images/player.png
|
||||||
- assets/images/enemy.png
|
- assets/images/enemy.png
|
||||||
```
|
```
|
||||||
|
|||||||
@ -1,82 +0,0 @@
|
|||||||
import 'dart:async';
|
|
||||||
|
|
||||||
import 'package:audioplayers/audio_cache.dart';
|
|
||||||
import 'package:audioplayers/audioplayers.dart';
|
|
||||||
import 'package:synchronized/synchronized.dart';
|
|
||||||
|
|
||||||
typedef void Stoppable();
|
|
||||||
|
|
||||||
/// 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 {
|
|
||||||
AudioCache cache;
|
|
||||||
Map<String, AudioPlayer> currentPlayers = {};
|
|
||||||
List<AudioPlayer> availablePlayers = [];
|
|
||||||
|
|
||||||
String sound;
|
|
||||||
bool repeating;
|
|
||||||
int minPlayers, maxPlayers;
|
|
||||||
|
|
||||||
final Lock _lock = Lock();
|
|
||||||
|
|
||||||
AudioPool(this.sound,
|
|
||||||
{this.repeating = false,
|
|
||||||
this.maxPlayers = 1,
|
|
||||||
this.minPlayers = 1,
|
|
||||||
String prefix = 'audio/sfx/'}) {
|
|
||||||
cache = AudioCache(prefix: prefix);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future init() async {
|
|
||||||
for (int i = 0; i < minPlayers; i++) {
|
|
||||||
availablePlayers.add(await _createNewAudioPlayer());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<Stoppable> start({double volume = 1.0}) async {
|
|
||||||
return _lock.synchronized(() async {
|
|
||||||
if (availablePlayers.isEmpty) {
|
|
||||||
availablePlayers.add(await _createNewAudioPlayer());
|
|
||||||
}
|
|
||||||
final AudioPlayer player = availablePlayers.removeAt(0);
|
|
||||||
currentPlayers[player.playerId] = player;
|
|
||||||
await player.setVolume(volume);
|
|
||||||
await player.resume();
|
|
||||||
|
|
||||||
StreamSubscription<void> subscription;
|
|
||||||
|
|
||||||
final Stoppable stop = () {
|
|
||||||
_lock.synchronized(() async {
|
|
||||||
final AudioPlayer p = currentPlayers.remove(player.playerId);
|
|
||||||
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 AudioPlayer player = AudioPlayer();
|
|
||||||
final String url = (await cache.load(sound)).path;
|
|
||||||
await player.setUrl(url);
|
|
||||||
await player.setReleaseMode(ReleaseMode.STOP);
|
|
||||||
return player;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
118
lib/bgm.dart
118
lib/bgm.dart
@ -1,118 +0,0 @@
|
|||||||
import 'dart:io';
|
|
||||||
|
|
||||||
import 'package:audioplayers/audioplayers.dart';
|
|
||||||
import 'package:flutter/widgets.dart';
|
|
||||||
|
|
||||||
import 'flame.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;
|
|
||||||
AudioPlayer audioPlayer;
|
|
||||||
bool isPlaying = false;
|
|
||||||
|
|
||||||
/// 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}) async {
|
|
||||||
volume ??= 1;
|
|
||||||
|
|
||||||
if (audioPlayer != null && audioPlayer.state != AudioPlayerState.STOPPED) {
|
|
||||||
audioPlayer.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
isPlaying = true;
|
|
||||||
audioPlayer = await Flame.audio.loopLongAudio(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 `FlameAudio.load();`.
|
|
||||||
Future<File> load(String file) => Flame.audio.load(file);
|
|
||||||
|
|
||||||
/// Pre-fetch a list of audios and store them in the cache.
|
|
||||||
///
|
|
||||||
/// Alias of `FlameAudio.loadAll();`.
|
|
||||||
Future<List<File>> loadAll(List<String> files) => Flame.audio.loadAll(files);
|
|
||||||
|
|
||||||
/// Clears the file in the cache.
|
|
||||||
///
|
|
||||||
/// Alias of `FlameAudio.clear();`.
|
|
||||||
void clear(String file) => Flame.audio.clear(file);
|
|
||||||
|
|
||||||
/// Clears all the audios in the cache.
|
|
||||||
///
|
|
||||||
/// Alias of `FlameAudio.clearAll();`.
|
|
||||||
void clearAll() => Flame.audio.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 == AudioPlayerState.PAUSED) {
|
|
||||||
audioPlayer.resume();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
audioPlayer?.pause();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -12,19 +12,15 @@ import 'util.dart';
|
|||||||
|
|
||||||
/// This class holds static references to some useful objects to use in your game.
|
/// This class holds static references to some useful objects to use in your game.
|
||||||
///
|
///
|
||||||
/// You can access shared instances of [AudioCache], [Images] and [Util].
|
/// You can access shared instances of [AssetsCache], [Images] and [Util].
|
||||||
/// Most games should need only one instance of each, and should use this class to manage that reference.
|
/// Most games should need only one instance of each, and should use this class to manage that reference.
|
||||||
class Flame {
|
class Flame {
|
||||||
// Flame asset bundle, defaults to root
|
// Flame asset bundle, defaults to root
|
||||||
static AssetBundle _bundle;
|
static AssetBundle _bundle;
|
||||||
static AssetBundle get bundle => _bundle == null ? rootBundle : _bundle;
|
static AssetBundle get bundle => _bundle == null ? rootBundle : _bundle;
|
||||||
|
|
||||||
/// Access a shared instance of the [FlameAudio] class.
|
/// Access a shard instance of [AssetsCache] class.
|
||||||
static FlameAudio audio = FlameAudio();
|
static AssetsCache assets = AssetsCache();
|
||||||
|
|
||||||
/// Access a shared instance of the [Bgm] class.
|
|
||||||
static Bgm _bgm;
|
|
||||||
static Bgm get bgm => _bgm ??= Bgm();
|
|
||||||
|
|
||||||
/// Access a shared instance of the [Images] class.
|
/// Access a shared instance of the [Images] class.
|
||||||
static Images images = Images();
|
static Images images = Images();
|
||||||
@ -32,9 +28,6 @@ class Flame {
|
|||||||
/// Access a shared instance of the [Util] class.
|
/// Access a shared instance of the [Util] class.
|
||||||
static Util util = Util();
|
static Util util = Util();
|
||||||
|
|
||||||
/// Access a shard instance of [AssetsCache] class.
|
|
||||||
static AssetsCache assets = AssetsCache();
|
|
||||||
|
|
||||||
static Future<void> init(
|
static Future<void> init(
|
||||||
{AssetBundle bundle,
|
{AssetBundle bundle,
|
||||||
bool fullScreen = true,
|
bool fullScreen = true,
|
||||||
|
|||||||
@ -6,10 +6,7 @@ homepage: https://github.com/flame-engine/flame
|
|||||||
dependencies:
|
dependencies:
|
||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
audioplayers: ^0.15.1
|
|
||||||
ordered_set: ^2.0.0
|
ordered_set: ^2.0.0
|
||||||
path_provider: ^1.6.0
|
|
||||||
synchronized: ^2.1.0
|
|
||||||
convert: ^2.0.1
|
convert: ^2.0.1
|
||||||
flare_flutter: ^2.0.1
|
flare_flutter: ^2.0.1
|
||||||
meta: ^1.1.8
|
meta: ^1.1.8
|
||||||
|
|||||||
Reference in New Issue
Block a user