Make loading for BGMs loopless.
This commit is contained in:
parent
42d4e794c7
commit
76c1487871
@ -1823,6 +1823,7 @@ void AiL::InitializeLevel(std::string mapFile,MapName map){
|
|||||||
|
|
||||||
void AiL::LoadLevel(MapName map){
|
void AiL::LoadLevel(MapName map){
|
||||||
LoadingScreen::loading=true;
|
LoadingScreen::loading=true;
|
||||||
|
#pragma region Reset all data (Loading phase 1)
|
||||||
if(game->MAP_DATA.count(map)==0)ERR(std::format("WARNING! Could not load map {}! Does not exist! Refer to levels.txt for valid maps.",map));
|
if(game->MAP_DATA.count(map)==0)ERR(std::format("WARNING! Could not load map {}! Does not exist! Refer to levels.txt for valid maps.",map));
|
||||||
if(game->MAP_DATA[map].GetMapType()=="Hub"&&GameState::STATE!=GameState::states[States::GAME_HUB])ERR("WARNING! A hub level should only be initiated in the GAME_HUB game state!");
|
if(game->MAP_DATA[map].GetMapType()=="Hub"&&GameState::STATE!=GameState::states[States::GAME_HUB])ERR("WARNING! A hub level should only be initiated in the GAME_HUB game state!");
|
||||||
|
|
||||||
@ -1857,9 +1858,11 @@ void AiL::LoadLevel(MapName map){
|
|||||||
GetPlayer()->GetCastInfo()={};
|
GetPlayer()->GetCastInfo()={};
|
||||||
GetPlayer()->ResetAccumulatedXP();
|
GetPlayer()->ResetAccumulatedXP();
|
||||||
|
|
||||||
|
#pragma endregion
|
||||||
|
|
||||||
ZONE_LIST=game->MAP_DATA[game->GetCurrentLevel()].ZoneData;
|
ZONE_LIST=game->MAP_DATA[game->GetCurrentLevel()].ZoneData;
|
||||||
|
|
||||||
#pragma region Monster Spawn Data Setup
|
#pragma region Monster Spawn Data Setup (Loading phase 2)
|
||||||
for(auto&[key,value]:MAP_DATA[map].SpawnerData){
|
for(auto&[key,value]:MAP_DATA[map].SpawnerData){
|
||||||
SpawnerTag&spawnData=MAP_DATA[map].SpawnerData[key];
|
SpawnerTag&spawnData=MAP_DATA[map].SpawnerData[key];
|
||||||
std::vector<std::pair<std::string,vf2d>>monster_list;
|
std::vector<std::pair<std::string,vf2d>>monster_list;
|
||||||
@ -1873,7 +1876,7 @@ void AiL::LoadLevel(MapName map){
|
|||||||
}
|
}
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
||||||
#pragma region Identify Upper Foreground Tiles
|
#pragma region Identify Upper Foreground Tiles (Loading phase 3)
|
||||||
auto GetUpperZones=[&](){
|
auto GetUpperZones=[&](){
|
||||||
for(auto&zoneSet:MAP_DATA[map].ZoneData){
|
for(auto&zoneSet:MAP_DATA[map].ZoneData){
|
||||||
if(zoneSet.first=="UpperZone"){ //We are interested in all upper zones.
|
if(zoneSet.first=="UpperZone"){ //We are interested in all upper zones.
|
||||||
@ -1902,7 +1905,7 @@ void AiL::LoadLevel(MapName map){
|
|||||||
}
|
}
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
||||||
#pragma region Foreground and Upper Foreground Tile Fade Group Setup
|
#pragma region Foreground and Upper Foreground Tile Fade Group Setup (Loading phase 4)
|
||||||
std::set<vi2d>foregroundTilesAdded,upperForegroundTilesAdded;
|
std::set<vi2d>foregroundTilesAdded,upperForegroundTilesAdded;
|
||||||
for(int x=0;x<GetCurrentMapData().width;x++){
|
for(int x=0;x<GetCurrentMapData().width;x++){
|
||||||
for(int y=0;y<GetCurrentMapData().height;y++){
|
for(int y=0;y<GetCurrentMapData().height;y++){
|
||||||
@ -1992,7 +1995,7 @@ void AiL::LoadLevel(MapName map){
|
|||||||
}
|
}
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
||||||
#pragma region Foreground and Upper Foreground Tile Fade Group Individual Object Grouping Splitting
|
#pragma region Foreground and Upper Foreground Tile Fade Group Individual Object Grouping Splitting (Loading phase 5)
|
||||||
auto SplitUp=[&](std::vector<TileGroup>&group){
|
auto SplitUp=[&](std::vector<TileGroup>&group){
|
||||||
std::multimap<vi2d,TileRenderData>data;
|
std::multimap<vi2d,TileRenderData>data;
|
||||||
using TileDataGroup=std::multimap<vi2d,TileRenderData>; //See below.
|
using TileDataGroup=std::multimap<vi2d,TileRenderData>; //See below.
|
||||||
@ -2059,7 +2062,7 @@ void AiL::LoadLevel(MapName map){
|
|||||||
SplitUp(upperForegroundTileGroups);
|
SplitUp(upperForegroundTileGroups);
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
||||||
#pragma region Bridge Layer Setup
|
#pragma region Bridge Layer Setup (Loading Phase 6)
|
||||||
bridgeLayerIndex=-1;
|
bridgeLayerIndex=-1;
|
||||||
for(int counter=0;LayerTag&layer:MAP_DATA[map].LayerData){
|
for(int counter=0;LayerTag&layer:MAP_DATA[map].LayerData){
|
||||||
if(IsBridgeLayer(layer)){
|
if(IsBridgeLayer(layer)){
|
||||||
@ -2069,6 +2072,7 @@ void AiL::LoadLevel(MapName map){
|
|||||||
}
|
}
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
||||||
|
#pragma region Setup NPCs (Loading Phase 7)
|
||||||
for(NPCData data:game->MAP_DATA[game->GetCurrentLevel()].npcs){
|
for(NPCData data:game->MAP_DATA[game->GetCurrentLevel()].npcs){
|
||||||
if(Unlock::IsUnlocked(data.unlockCondition)){
|
if(Unlock::IsUnlocked(data.unlockCondition)){
|
||||||
MONSTER_LIST.push_back(Monster{data.spawnPos,MONSTER_DATA[data.name]});
|
MONSTER_LIST.push_back(Monster{data.spawnPos,MONSTER_DATA[data.name]});
|
||||||
@ -2076,7 +2080,9 @@ void AiL::LoadLevel(MapName map){
|
|||||||
MONSTER_LIST.back().npcData=data;
|
MONSTER_LIST.back().npcData=data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#pragma endregion
|
||||||
|
|
||||||
|
#pragma region Setup Player and Camera (Loading Phase 8)
|
||||||
player->GetAbility1().cooldown=0.f;
|
player->GetAbility1().cooldown=0.f;
|
||||||
player->GetAbility2().cooldown=0.f;
|
player->GetAbility2().cooldown=0.f;
|
||||||
player->GetAbility3().cooldown=0.f;
|
player->GetAbility3().cooldown=0.f;
|
||||||
@ -2091,8 +2097,12 @@ void AiL::LoadLevel(MapName map){
|
|||||||
|
|
||||||
vf2d cameraStartPos=player->GetPos()+vf2d(-24*6,0);
|
vf2d cameraStartPos=player->GetPos()+vf2d(-24*6,0);
|
||||||
camera.MoveCamera(cameraStartPos);
|
camera.MoveCamera(cameraStartPos);
|
||||||
|
#pragma endregion
|
||||||
|
|
||||||
|
#pragma region Setup Pathfinding (Loading Phase 9)
|
||||||
pathfinder.Initialize();
|
pathfinder.Initialize();
|
||||||
|
#pragma endregion
|
||||||
|
|
||||||
Audio::SetAudioEvent("Default Volume");
|
Audio::SetAudioEvent("Default Volume");
|
||||||
game->audioEngine.fullyLoaded=true; //We assume there's no audio to load, so we just set the audio as fully loaded by default.
|
game->audioEngine.fullyLoaded=true; //We assume there's no audio to load, so we just set the audio as fully loaded by default.
|
||||||
if(MAP_DATA[map].bgmSongName.length()>0){
|
if(MAP_DATA[map].bgmSongName.length()>0){
|
||||||
|
@ -39,6 +39,7 @@ All rights reserved.
|
|||||||
#include "AdventuresInLestoria.h"
|
#include "AdventuresInLestoria.h"
|
||||||
#include "DEFINES.h"
|
#include "DEFINES.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "LoadingScreen.h"
|
||||||
|
|
||||||
INCLUDE_game
|
INCLUDE_game
|
||||||
INCLUDE_DATA
|
INCLUDE_DATA
|
||||||
@ -121,12 +122,21 @@ const size_t Audio::LoadAndPlay(const std::string_view sound,const bool loop){
|
|||||||
Engine().Play(soundID,loop);
|
Engine().Play(soundID,loop);
|
||||||
return soundID;
|
return soundID;
|
||||||
};
|
};
|
||||||
void Audio::PlayBGM(const std::string_view sound,const bool loop){
|
void Audio::PrepareBGM(const std::string_view sound,const bool loop){
|
||||||
BGM&track=Self().bgm[std::string(sound)];
|
BGM&track=Self().bgm[std::string(sound)];
|
||||||
Self().fullyLoaded=false;
|
Self().fullyLoaded=false;
|
||||||
StopBGM(); //Stop any currently playing track.
|
StopBGM(); //Stop any currently playing track.
|
||||||
Self().playParams={std::string(sound),loop};
|
Self().playParams={std::string(sound),loop};
|
||||||
Self().playBGMWaitTime=0.7f;
|
Self().playBGMWaitTime=0.7f;
|
||||||
|
|
||||||
|
#pragma region Internal Loading Loop Setup
|
||||||
|
Self().trackLoadStarted=false;
|
||||||
|
Self().trackLoadComplete=false;
|
||||||
|
Self().channelPlayingStarted=false;
|
||||||
|
Self().channelPlayingComplete=false;
|
||||||
|
int currentLoopIndex=0;
|
||||||
|
#pragma endregion
|
||||||
|
Self().immediatelyLoadAudio=false;
|
||||||
};
|
};
|
||||||
|
|
||||||
void Audio::StopBGM(){
|
void Audio::StopBGM(){
|
||||||
@ -142,11 +152,13 @@ const bool Audio::BGMIsPlaying(){
|
|||||||
return Self().currentBGM.length()>0;
|
return Self().currentBGM.length()>0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Volume&Audio::BGM::GetVolume(const Event&eventName,const ChannelID&id)const{
|
const Volume&Audio::BGM::GetVolume(const Event&eventName,const int&index)const{
|
||||||
return eventVolumes.GetVolumes(eventName).at(id);
|
return eventVolumes.GetVolumes(eventName).at(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Audio::BGM::Load(){
|
void Audio::BGM::Load(){
|
||||||
|
if(!Self().trackLoadStarted){
|
||||||
|
Self().trackLoadStarted=true;
|
||||||
if(Self().BGMIsPlaying()){
|
if(Self().BGMIsPlaying()){
|
||||||
if(Self().GetTrackName()==songFileName)return; //We are already playing the current track.
|
if(Self().GetTrackName()==songFileName)return; //We are already playing the current track.
|
||||||
BGM&bgm=Self().bgm[Self().GetTrackName()];
|
BGM&bgm=Self().bgm[Self().GetTrackName()];
|
||||||
@ -155,11 +167,20 @@ void Audio::BGM::Load(){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Self().currentBGM=songFileName;
|
Self().currentBGM=songFileName;
|
||||||
|
Self().currentLoopIndex=0;
|
||||||
BGM&newBgm=Self().bgm[songFileName];
|
BGM&newBgm=Self().bgm[songFileName];
|
||||||
if(newBgm.channels.size()>0)ERR(std::format("WARNING! The size of the channels list is greater than zero! Size: {}",newBgm.channels.size()));
|
if(newBgm.channels.size()>0)ERR(std::format("WARNING! The size of the channels list is greater than zero! Size: {}",newBgm.channels.size()));
|
||||||
for(const ChannelName&channel:newBgm.GetChannels()){
|
}else{
|
||||||
|
BGM&newBgm=Self().bgm[songFileName];
|
||||||
|
const ChannelName&channel=newBgm.GetChannels()[Self().currentLoopIndex];
|
||||||
ChannelID soundID=Engine().LoadSound("bgm_directory"_S+channel);
|
ChannelID soundID=Engine().LoadSound("bgm_directory"_S+channel);
|
||||||
newBgm.channels.push_back(soundID);
|
newBgm.channels.push_back(soundID);
|
||||||
|
#pragma region Handle threaded loop indexing
|
||||||
|
Self().currentLoopIndex++;
|
||||||
|
if(Self().currentLoopIndex>=newBgm.GetChannels().size()){
|
||||||
|
Self().trackLoadComplete=true;
|
||||||
|
}
|
||||||
|
#pragma endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -255,27 +276,54 @@ const SongName&Audio::GetTrackName(){
|
|||||||
return Self().currentBGM;
|
return Self().currentBGM;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Audio::Update(){
|
void Audio::UpdateLoop(){
|
||||||
if(Self().playBGMWaitTime>0.f){
|
|
||||||
Self().playBGMWaitTime=std::max(Self().playBGMWaitTime-game->GetElapsedTime(),0.f);
|
|
||||||
if(Self().playBGMWaitTime==0.f){
|
if(Self().playBGMWaitTime==0.f){
|
||||||
BGM&track=Self().bgm[Self().playParams.sound];
|
BGM&track=Self().bgm[Self().playParams.sound];
|
||||||
|
if(!Self().trackLoadComplete){
|
||||||
track.Load();
|
track.Load();
|
||||||
|
}else
|
||||||
|
if(!Self().channelPlayingComplete){
|
||||||
|
if(!Self().channelPlayingStarted){
|
||||||
Self().prevVolumes.clear();
|
Self().prevVolumes.clear();
|
||||||
Self().targetVolumes.clear();
|
Self().targetVolumes.clear();
|
||||||
Self().fadeToTargetVolumeTime=0.f;
|
Self().fadeToTargetVolumeTime=0.f;
|
||||||
for(int channelListIndex=0;int trackID:track.GetChannelIDs()){
|
Self().currentLoopIndex=0;
|
||||||
float channelVol=track.GetVolume(Self().currentAudioEvent,channelListIndex);
|
Self().channelPlayingStarted=true;
|
||||||
|
}else{
|
||||||
|
|
||||||
|
int trackID=track.GetChannelIDs()[Self().currentLoopIndex];
|
||||||
|
float channelVol=track.GetVolume(Self().currentAudioEvent,Self().currentLoopIndex);
|
||||||
Self().prevVolumes.push_back(channelVol);
|
Self().prevVolumes.push_back(channelVol);
|
||||||
Self().targetVolumes.push_back(channelVol);
|
Self().targetVolumes.push_back(channelVol);
|
||||||
Engine().SetVolume(trackID,channelVol*GetBGMVolume());
|
Engine().SetVolume(trackID,channelVol*GetBGMVolume());
|
||||||
Engine().Play(trackID,Self().playParams.loop);
|
Engine().Play(trackID,Self().playParams.loop);
|
||||||
channelListIndex++;
|
#pragma region Handle threaded loop indexing
|
||||||
|
Self().currentLoopIndex++;
|
||||||
|
if(Self().currentLoopIndex>=track.GetChannelIDs().size()){
|
||||||
|
Self().channelPlayingComplete=true;
|
||||||
}
|
}
|
||||||
|
#pragma endregion
|
||||||
|
}
|
||||||
|
}else{
|
||||||
Self().fullyLoaded=true;
|
Self().fullyLoaded=true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Audio::PlayBGM(const std::string_view sound,const bool loop){
|
||||||
|
PrepareBGM(sound,loop);
|
||||||
|
Self().immediatelyLoadAudio=true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Audio::Update(){
|
||||||
|
if(Self().playBGMWaitTime>0.f){
|
||||||
|
Self().playBGMWaitTime=std::max(Self().playBGMWaitTime-game->GetElapsedTime(),0.f);
|
||||||
|
if(Self().playBGMWaitTime==0.f&&Self().immediatelyLoadAudio){
|
||||||
|
while(!Self().BGMFullyLoaded()){
|
||||||
|
UpdateLoop(); //We immediately load the file. In a loading screen setting we would defer UpdateLoop() such that we have extra time to update the screen, UpdateLoop() is divided into many parts of the music loading process.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if(Self().fadeToTargetVolumeTime>0.f){
|
if(Self().fadeToTargetVolumeTime>0.f){
|
||||||
Self().fadeToTargetVolumeTime=std::max(0.f,Self().fadeToTargetVolumeTime-game->GetElapsedTime());
|
Self().fadeToTargetVolumeTime=std::max(0.f,Self().fadeToTargetVolumeTime-game->GetElapsedTime());
|
||||||
for(int counter=0;float&vol:Self().prevVolumes){
|
for(int counter=0;float&vol:Self().prevVolumes){
|
||||||
|
@ -56,10 +56,13 @@ public:
|
|||||||
static MiniAudio&Engine();
|
static MiniAudio&Engine();
|
||||||
static void Initialize();
|
static void Initialize();
|
||||||
static void Update();
|
static void Update();
|
||||||
|
static void UpdateLoop();
|
||||||
static void Play(const std::string_view sound);
|
static void Play(const std::string_view sound);
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
static const size_t LoadAndPlay(const std::string_view sound,const bool loop=true);
|
static const size_t LoadAndPlay(const std::string_view sound,const bool loop=true);
|
||||||
//Play a BGM given a name found in bgm.txt configuration file.
|
//Prepares a BGM for loading. This means we call UpdateLoop() repeatedly until the loading of the music is complete. Names are found in bgm.txt configuration file.
|
||||||
|
static void PrepareBGM(const std::string_view sound,const bool loop=true);
|
||||||
|
//Play immediately a BGM given a name found in bgm.txt configuration file.
|
||||||
static void PlayBGM(const std::string_view sound,const bool loop=true);
|
static void PlayBGM(const std::string_view sound,const bool loop=true);
|
||||||
static void StopBGM();
|
static void StopBGM();
|
||||||
static const Event&GetAudioEvent();
|
static const Event&GetAudioEvent();
|
||||||
@ -73,6 +76,14 @@ public:
|
|||||||
static float&GetSFXVolume();
|
static float&GetSFXVolume();
|
||||||
static float GetMuteMult();
|
static float GetMuteMult();
|
||||||
private:
|
private:
|
||||||
|
bool trackLoadStarted=false;
|
||||||
|
bool trackLoadComplete=false;
|
||||||
|
bool channelPlayingStarted=false;
|
||||||
|
bool channelPlayingComplete=false;
|
||||||
|
int currentLoopIndex=0;
|
||||||
|
//Set to false by PrepareBGM(). If PlayBGM() is called instead, it will set the state of this variable to true, such that the loading is performed in Audio::Update()!
|
||||||
|
bool immediatelyLoadAudio=false;
|
||||||
|
|
||||||
struct BGMPlayParams{
|
struct BGMPlayParams{
|
||||||
std::string sound;
|
std::string sound;
|
||||||
bool loop;
|
bool loop;
|
||||||
@ -92,7 +103,7 @@ private:
|
|||||||
const size_t GetChannelCount()const;
|
const size_t GetChannelCount()const;
|
||||||
const std::vector<ChannelName>&GetChannels()const;
|
const std::vector<ChannelName>&GetChannels()const;
|
||||||
const SongName&GetName()const;
|
const SongName&GetName()const;
|
||||||
const Volume&GetVolume(const Event&eventName,const ChannelID&id)const;
|
const Volume&GetVolume(const Event&eventName,const int&index)const;
|
||||||
void SetName(std::string_view name);
|
void SetName(std::string_view name);
|
||||||
void SetFileName(std::string_view name);
|
void SetFileName(std::string_view name);
|
||||||
void AddChannel(const ChannelName&name);
|
void AddChannel(const ChannelName&name);
|
||||||
|
@ -45,10 +45,14 @@ INCLUDE_WINDOW_SIZE
|
|||||||
bool LoadingScreen::loading=false;
|
bool LoadingScreen::loading=false;
|
||||||
int LoadingScreen::totalProgress=0;
|
int LoadingScreen::totalProgress=0;
|
||||||
int LoadingScreen::currentProgress=0;
|
int LoadingScreen::currentProgress=0;
|
||||||
|
float LoadingScreen::waitTime=0.01f;
|
||||||
|
|
||||||
|
void LoadingScreen::DeferLoad(float waitTime){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void LoadingScreen::Update(){
|
void LoadingScreen::Update(){
|
||||||
if(loading){
|
if(loading){
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void LoadingScreen::Draw(){
|
void LoadingScreen::Draw(){
|
||||||
|
@ -42,6 +42,8 @@ public:
|
|||||||
static bool loading;
|
static bool loading;
|
||||||
static int totalProgress;
|
static int totalProgress;
|
||||||
static int currentProgress;
|
static int currentProgress;
|
||||||
|
static float waitTime;
|
||||||
static void Update();
|
static void Update();
|
||||||
static void Draw();
|
static void Draw();
|
||||||
|
static void DeferLoad(float waitTime);
|
||||||
};
|
};
|
@ -39,7 +39,7 @@ All rights reserved.
|
|||||||
#define VERSION_MAJOR 0
|
#define VERSION_MAJOR 0
|
||||||
#define VERSION_MINOR 3
|
#define VERSION_MINOR 3
|
||||||
#define VERSION_PATCH 0
|
#define VERSION_PATCH 0
|
||||||
#define VERSION_BUILD 7521
|
#define VERSION_BUILD 7526
|
||||||
|
|
||||||
#define stringify(a) stringify_(a)
|
#define stringify(a) stringify_(a)
|
||||||
#define stringify_(a) #a
|
#define stringify_(a) #a
|
||||||
|
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user