How to play Background Music on loop in a game with Flutter?
Coding a game on Flutter, Want to play music on loop in Background when the app starts with audioplayers: ^0.20.1 package and WidgetsBindingObserver, doesn't work! The audio doesn't play.
The other ".wav" format works fine with "AudioCache". But "AudioCache" doesn't have pause and resume properties. So tired of "AudioPlayer" and the ".mp3" extension audio doesn't play. But the same ".mp3" extension audio plays with "AudioCache".
Check the Code Below
import 'dart:async';
import 'package:bugbee2/barrier.dart';
import 'package:bugbee2/bee.dart';
import 'package:bugbee2/coverScreen.dart';
import 'package:flutter/material.dart';
import 'package:audioplayers/audioplayers.dart';
import 'package:shared_preferences/shared_preferences.dart';
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> with WidgetsBindingObserver {
// bee variables
static double beeY = 0;
double initialPos = beeY;
double height = 0;
double time = 0;
double gravity = -4.9; // how strong the gravity is
double velocity = 3.5; // how strong the jump is
double beeWidth = 0.1; // out of 2, 2 being the entire width of the screen
double beeHeight = 0.1; // out of 2, 2 being the entire height of the screen
// inciment score
int score = 0;
int bestScore = 0;
// game settings
bool gameHasStarted = false;
// Best Score Value Update
@override
void initState() {
super.initState();
checkBestScore();
WidgetsBinding.instance?.addObserver(this);
}
// Remove Observer
@override
void dispose() {
WidgetsBinding.instance?.removeObserver(this);
super.dispose();
}
// Background Music
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
AudioPlayer player = AudioPlayer();
super.didChangeAppLifecycleState(state);
if (state == AppLifecycleState.resumed) {
player.play("sounds/tea-ceremony.mp3");
} else if (state == AppLifecycleState.paused) {
player.pause();
} else if (state == AppLifecycleState.inactive) {
player.pause();
} else if (state == AppLifecycleState.detached) {
player.stop();
}
}
// Saving Best Score
getBestScore() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
int bestScore = prefs.getInt('bestScore') ?? 0;
return bestScore;
}
setBestScore() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setInt('bestScore', bestScore);
}
// barrier variables
static List<double> barrierX = [2, 2 + 1.5];
static double barrierWidth = 0.5; // out of 2
List<List<double>> barrierHeight = [
// out of 2, where 2 is the entire height of the screen
// [topHeight, bottomHeight]
[0.6, 0.4],
[0.4, 0.6],
];
void startGame() {
final player = AudioCache();
player.play(
"sounds/jump.wav",
);
gameHasStarted = true;
Timer.periodic(Duration(milliseconds: 10), (timer) {
// a real physical jump is the same as an upside down parabola
// so this is a simple quadratic equation
height = gravity * time * time + velocity * time;
setState(() {
beeY = initialPos - height;
});
// check if bird is dead
if (beeIsDead()) {
timer.cancel();
_showDialog();
final player = AudioCache();
player.play(
"sounds/slide-hit.wav",
);
}
// keep the map moving (move barriers)
moveMap();
// keep the time going!
time += 0.01;
});
}
void moveMap() {
for (int i = 0; i < barrierX.length; i++) {
// keep barriers moving
setState(() {
barrierX[i] -= 0.005;
});
// if barrier exits the left part of the screen, keep it looping
if (barrierX[i] < -1.5) {
barrierX[i] += 3;
score++;
final player = AudioCache();
player.play(
"sounds/coin-touch.wav",
);
setBestScore();
if (score > bestScore) {
bestScore = score;
}
}
}
}
checkBestScore() async {
int tempBestScore = await getBestScore() ?? 0;
setState(() {
bestScore = tempBestScore;
});
}
void resetGame() {
Navigator.pop(context); // dismisses the alert dialog
setState(() {
beeY = 0;
gameHasStarted = false;
time = 0;
initialPos = beeY;
barrierX = [2, 2 + 1.5];
score = 0;
});
}
void _showDialog() {
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
backgroundColor: Colors.brown,
title: Center(
child: Text(
"G A M E O V E R",
style: TextStyle(color: Colors.white),
),
),
actions: [
GestureDetector(
onTap: resetGame,
child: ClipRRect(
borderRadius: BorderRadius.circular(5),
child: Container(
padding: EdgeInsets.all(7),
color: Colors.white,
child: Text(
'PLAY AGAIN',
style: TextStyle(color: Colors.brown),
),
),
),
),
],
);
});
}
void jump() {
final player = AudioCache();
player.play(
"sounds/jump.wav",
);
setState(() {
time = 0;
initialPos = beeY;
});
}
bool beeIsDead() {
// check if the bird is hitting the top or the bottom of the screen
if (beeY < -1 || beeY > 1) {
return true;
}
// hits barriers
// checks if bird is within x coordinates and y coordinates of barriers
for (int i = 0; i < barrierX.length; i++) {
if (barrierX[i] <= beeWidth &&
barrierX[i] + barrierWidth >= -beeWidth &&
(beeY <= -1 + barrierHeight[i][0] ||
beeY + beeHeight >= 1 - barrierHeight[i][1])) {
return true;
}
}
return false;
}
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: gameHasStarted ? jump : startGame,
child: Scaffold(
body: Column(
children: [
Expanded(
flex: 3,
child: Container(
color: Colors.blue.shade500,
child: Center(
child: Stack(
children: [
// bird
MyBee(
beeY: beeY,
beeWidth: beeWidth,
beeHeight: beeHeight,
),
// tap to play
MyCoverScreen(gameHasStarted: gameHasStarted),
MyBarrier(
barrierX: barrierX[0],
barrierWidth: barrierWidth,
barrierHeight: barrierHeight[0][0],
isThisBottomBarrier: false,
),
// Bottom barrier 0
MyBarrier(
barrierX: barrierX[0],
barrierWidth: barrierWidth,
barrierHeight: barrierHeight[0][1],
isThisBottomBarrier: true,
),
// Top barrier 1
MyBarrier(
barrierX: barrierX[1],
barrierWidth: barrierWidth,
barrierHeight: barrierHeight[1][0],
isThisBottomBarrier: false,
),
// Bottom barrier 1
MyBarrier(
barrierX: barrierX[1],
barrierWidth: barrierWidth,
barrierHeight: barrierHeight[1][1],
isThisBottomBarrier: true,
),
],
),
),
),
),
SizedBox(
height: 10,
child: Container(
color: Colors.green,
),
),
Expanded(
child: Container(
color: Colors.brown,
child: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
score.toString(),
style: TextStyle(color: Colors.white, fontSize: 35),
),
SizedBox(
height: 15,
),
Text(
'S C O R E',
style: TextStyle(color: Colors.white, fontSize: 20),
),
],
),
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
bestScore.toString(),
style: TextStyle(color: Colors.white, fontSize: 35),
),
SizedBox(
height: 15,
),
Text(
'B E S T',
style: TextStyle(color: Colors.white, fontSize: 20),
),
],
),
],
),
),
),
),
],
),
),
);
}
}
I am using audioplayers: ^ 0.19.1
AudioPlayer advancedPlayer;
AudioCache audioCache;
String audioCorrect = "audio/access_granted.mp3";
I have this method that call in initState()
void initPlayer() {
advancedPlayer = new AudioPlayer();
audioCache = new AudioCache(fixedPlayer: advancedPlayer);
}
I play the audio this way
audioCache.play(audioCorrect);