Added music and perfom bug fixes

This commit is contained in:
Vladislav Khorev 2026-07-18 20:21:31 +03:00
parent e5e3d7bb28
commit 825a56a4a4
29 changed files with 185 additions and 68 deletions

5
.gitignore vendored
View File

@ -409,3 +409,8 @@ web_resources/
pc_resources/
resources_hd/
web_resources_x2/
.artifacts/
*.zip

View File

@ -39,7 +39,8 @@ add_subdirectory("${TP_ROOT}/libpng-1.6.51" libpng-build)
# --- SDL2 ---
# Android-версия SDL требует специфичных настроек, но add_subdirectory обычно подхватывает их сама
add_subdirectory("${TP_ROOT}/SDL-release-2.32.10" sdl-build)
#add_subdirectory("${TP_ROOT}/SDL_mixer-release-2.8.0" sdl-mixer-build)
add_subdirectory("${TP_ROOT}/SDL_mixer-release-2.8.0" sdl-mixer-build)
add_subdirectory("${TP_ROOT}/SDL_ttf-release-2.24.0" sdl-ttf-build)

View File

@ -150,6 +150,7 @@ target_link_libraries(main
z
SDL2
SDL2_ttf
SDL2_mixer
log
android
OpenSLES
@ -163,6 +164,7 @@ target_link_libraries(main
target_include_directories(main PRIVATE
#${CMAKE_CURRENT_SOURCE_DIR}/../SDL/include
${CMAKE_CURRENT_SOURCE_DIR}/../../../../thirdparty/SDL_ttf-release-2.24.0/external/freetype/include
#${CMAKE_CURRENT_SOURCE_DIR}/../zlib
#${CMAKE_CURRENT_SOURCE_DIR}/../libpng
${CMAKE_CURRENT_SOURCE_DIR}/../../../../thirdparty/eigen-5.0.0

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
proj-android/app/src/main/assets/audio/bishkek fight.ogg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
proj-android/app/src/main/assets/audio/bishkek night.ogg (Stored with Git LFS) Normal file

Binary file not shown.

Binary file not shown.

BIN
proj-android/app/src/main/assets/audio/main menu final.ogg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
proj-android/app/src/main/assets/audio/obshaga.ogg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
proj-android/app/src/main/assets/audio/sound_bag001.ogg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
proj-android/app/src/main/assets/audio/sound_bag_close.ogg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
proj-android/app/src/main/assets/audio/sound_bag_open.ogg (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -2,6 +2,11 @@
#include <iostream>
#include "utils/Utils.h"
#ifdef __ANDROID__
#include <android/log.h>
#endif
#ifdef __EMSCRIPTEN__
AudioPlayerAsync::AudioPlayerAsync() {}
#else
@ -22,33 +27,34 @@ AudioPlayerAsync::~AudioPlayerAsync() {
}
bool AudioPlayerAsync::init() {
/*if (initialized) return true;
if (initialized) return true;
if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) {
std::cerr << "SDL_InitSubSystem(SDL_INIT_AUDIO) failed: " << SDL_GetError() << std::endl;
FRG::logger() << "SDL_InitSubSystem(SDL_INIT_AUDIO) failed: " << SDL_GetError() << std::endl;
return false;
}
if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 2048) < 0) {
std::cerr << "Mix_OpenAudio failed: " << Mix_GetError() << std::endl;
FRG::logger() << "Mix_OpenAudio failed: " << Mix_GetError() << std::endl;
return false;
}
Mix_AllocateChannels(16);
initialized = true;
FRG::logger() << "AudioPlayerAsync initialized with SDL2_mixer" << std::endl;*/
FRG::logger() << "AudioPlayerAsync initialized with SDL2_mixer" << std::endl;
return true;
}
void AudioPlayerAsync::shutdown() {
if (!initialized) return;
/*
if (currentMusic_) {
Mix_HaltMusic();
Mix_FreeMusic(currentMusic_);
currentMusic_ = nullptr;
}
currentMusicData_.clear();
{
std::lock_guard<std::mutex> lock(soundCacheMutex);
@ -61,16 +67,20 @@ void AudioPlayerAsync::shutdown() {
Mix_CloseAudio();
SDL_QuitSubSystem(SDL_INIT_AUDIO);
initialized = false;
FRG::logger() << "AudioPlayerAsync shutdown" << std::endl;*/
FRG::logger() << "AudioPlayerAsync shutdown" << std::endl;
}
void AudioPlayerAsync::playSoundAsync(const std::string& filePath, int loops, int channel) {
/*if (!initialized) {
std::cerr << "AudioPlayerAsync not initialized" << std::endl;
if (!initialized) {
FRG::logger() << "AudioPlayerAsync not initialized" << std::endl;
return;
}
if (!soundEnabled_) return;
auto task = [this, filePath, loops, channel]() {
Mix_Chunk* sound = nullptr;
{
@ -82,9 +92,32 @@ void AudioPlayerAsync::playSoundAsync(const std::string& filePath, int loops, in
}
if (!sound) {
#ifdef __ANDROID__
__android_log_print(ANDROID_LOG_ERROR, "Game",
"AudioPlayerAsync::playSoundAsync step x2");
std::vector<char> buffer = FRG::readFile(filePath);
if (buffer.empty()) {
__android_log_print(ANDROID_LOG_ERROR, "Game",
"AudioPlayerAsync::playSoundAsync step x3");
FRG::logger() << "Failed to read sound file into buffer: " << filePath << std::endl;
return;
}
__android_log_print(ANDROID_LOG_ERROR, "Game",
"AudioPlayerAsync::playSoundAsync step x4");
SDL_RWops* rw = SDL_RWFromMem(buffer.data(), buffer.size());
if (!rw) {
FRG::logger() << "Failed to create RWops from buffer for " << filePath << ": " << SDL_GetError() << std::endl;
return;
}
sound = Mix_LoadWAV_RW(rw, 1); // 1 means it will free rw automatically
FRG::logger() << "sound = Mix_LoadWAV_RW(rw, 1); just fired " << std::endl;
#else
sound = Mix_LoadWAV(filePath.c_str());
#endif
if (!sound) {
std::cerr << "Failed to load sound " << filePath << ": " << Mix_GetError() << std::endl;
FRG::logger() << "Failed to load sound " << filePath << ": " << Mix_GetError() << std::endl;
return;
}
std::lock_guard<std::mutex> cacheLock(soundCacheMutex);
@ -93,7 +126,7 @@ void AudioPlayerAsync::playSoundAsync(const std::string& filePath, int loops, in
int result = Mix_PlayChannel(channel, sound, loops);
if (result == -1) {
std::cerr << "Mix_PlayChannel failed: " << Mix_GetError() << std::endl;
FRG::logger() << "Mix_PlayChannel failed: " << Mix_GetError() << std::endl;
}
};
@ -104,11 +137,11 @@ void AudioPlayerAsync::playSoundAsync(const std::string& filePath, int loops, in
taskQueue.push(std::move(task));
cv.notify_one();
#endif
*/
}
void AudioPlayerAsync::playMusicAsync(const std::string& filePath, int loops) {
/*if (!initialized) return;
if (!initialized) return;
if (filePath == currentTrack)
return;
@ -122,14 +155,29 @@ void AudioPlayerAsync::playMusicAsync(const std::string& filePath, int loops) {
Mix_FreeMusic(currentMusic_);
currentMusic_ = nullptr;
}
Mix_Music* music = Mix_LoadMUS(filePath.c_str());
currentMusicData_.clear();
Mix_Music* music = nullptr;
#ifdef __ANDROID__
currentMusicData_ = FRG::readFile(filePath);
if (!currentMusicData_.empty()) {
SDL_RWops* rw = SDL_RWFromMem(currentMusicData_.data(), currentMusicData_.size());
if (rw) {
music = Mix_LoadMUS_RW(rw, 1);
}
}
#else
music = Mix_LoadMUS(filePath.c_str());
#endif
if (!music) {
std::cerr << "Failed to load music " << filePath << ": " << Mix_GetError() << std::endl;
FRG::logger() << "Failed to load music " << filePath << ": " << Mix_GetError() << std::endl;
return;
}
if (Mix_PlayMusic(music, loops) == -1) {
std::cerr << "Mix_PlayMusic failed: " << Mix_GetError() << std::endl;
FRG::logger() << "Mix_PlayMusic failed: " << Mix_GetError() << std::endl;
Mix_FreeMusic(music);
currentMusicData_.clear();
return;
}
currentMusic_ = music;
@ -142,11 +190,11 @@ void AudioPlayerAsync::playMusicAsync(const std::string& filePath, int loops) {
taskQueue.push(std::move(task));
cv.notify_one();
#endif
*/
}
void AudioPlayerAsync::stopMusicAsync() {
/*if (!initialized) return;
if (!initialized) return;
currentTrack = "";
@ -159,11 +207,11 @@ void AudioPlayerAsync::stopMusicAsync() {
});
cv.notify_one();
#endif
*/
}
void AudioPlayerAsync::pauseMusicAsync() {
/*if (!initialized) return;
if (!initialized) return;
#ifdef __EMSCRIPTEN__
Mix_PauseMusic();
#else
@ -173,11 +221,11 @@ void AudioPlayerAsync::pauseMusicAsync() {
});
cv.notify_one();
#endif
*/
}
void AudioPlayerAsync::resumeMusicAsync() {
/*if (!initialized) return;
if (!initialized) return;
#ifdef __EMSCRIPTEN__
Mix_ResumeMusic();
#else
@ -187,11 +235,11 @@ void AudioPlayerAsync::resumeMusicAsync() {
});
cv.notify_one();
#endif
*/
}
void AudioPlayerAsync::setMusicVolume(int volume) {
/*
if (!initialized) return;
volume = std::max(0, std::min(128, volume));
musicVolume_ = volume;
@ -204,11 +252,11 @@ void AudioPlayerAsync::setMusicVolume(int volume) {
});
cv.notify_one();
#endif
*/
}
void AudioPlayerAsync::setSoundVolume(int volume) {
/*
if (!initialized) return;
volume = std::max(0, std::min(128, volume));
soundVolume_ = volume;
@ -221,11 +269,11 @@ void AudioPlayerAsync::setSoundVolume(int volume) {
});
cv.notify_one();
#endif
*/
}
void AudioPlayerAsync::crossFadeMusicAsync(const std::string& filePath, int fadeDurationMs, int loops) {
/*if (!initialized) return;
if (!initialized) return;
if (filePath == currentTrack) return;
currentTrack = filePath;
if (!musicEnabled_) return;
@ -241,14 +289,26 @@ void AudioPlayerAsync::crossFadeMusicAsync(const std::string& filePath, int fade
}
Mix_HaltMusic();
if (currentMusic_) { Mix_FreeMusic(currentMusic_); currentMusic_ = nullptr; }
currentMusicData_.clear();
#endif
Mix_Music* music = nullptr;
#ifdef __ANDROID__
currentMusicData_ = FRG::readFile(filePath);
if (!currentMusicData_.empty()) {
SDL_RWops* rw = SDL_RWFromMem(currentMusicData_.data(), currentMusicData_.size());
if (rw) {
music = Mix_LoadMUS_RW(rw, 1);
}
}
#else
music = Mix_LoadMUS(filePath.c_str());
#endif
Mix_Music* music = Mix_LoadMUS(filePath.c_str());
if (!music) {
std::cerr << "Failed to load music " << filePath << ": " << Mix_GetError() << std::endl;
FRG::logger() << "Failed to load music " << filePath << ": " << Mix_GetError() << std::endl;
return;
}
if (Mix_FadeInMusic(music, loops, fadeDurationMs / 2) == -1) {
std::cerr << "Mix_FadeInMusic failed: " << Mix_GetError() << std::endl;
FRG::logger() << "Mix_FadeInMusic failed: " << Mix_GetError() << std::endl;
Mix_FreeMusic(music);
return;
}
@ -262,11 +322,11 @@ void AudioPlayerAsync::crossFadeMusicAsync(const std::string& filePath, int fade
taskQueue.push(std::move(task));
cv.notify_one();
#endif
*/
}
void AudioPlayerAsync::crossFadeMusicFromPositionAsync(const std::string& filePath, int fadeDurationMs, int loops) {
/*if (!initialized) return;
if (!initialized) return;
if (filePath == currentTrack) return;
currentTrack = filePath;
if (!musicEnabled_) return;
@ -288,11 +348,11 @@ void AudioPlayerAsync::crossFadeMusicFromPositionAsync(const std::string& filePa
Mix_Music* music = Mix_LoadMUS(filePath.c_str());
if (!music) {
std::cerr << "Failed to load music " << filePath << ": " << Mix_GetError() << std::endl;
FRG::logger() << "Failed to load music " << filePath << ": " << Mix_GetError() << std::endl;
return;
}
if (Mix_FadeInMusicPos(music, loops, fadeDurationMs / 2, position) == -1) {
std::cerr << "Mix_FadeInMusicPos failed: " << Mix_GetError() << std::endl;
FRG::logger() << "Mix_FadeInMusicPos failed: " << Mix_GetError() << std::endl;
Mix_FreeMusic(music);
return;
}
@ -306,11 +366,11 @@ void AudioPlayerAsync::crossFadeMusicFromPositionAsync(const std::string& filePa
taskQueue.push(std::move(task));
cv.notify_one();
#endif
*/
}
void AudioPlayerAsync::setMusicEnabled(bool enabled) {
/*if (musicEnabled_ == enabled) return;
if (musicEnabled_ == enabled) return;
musicEnabled_ = enabled;
if (!initialized) return;
@ -330,7 +390,7 @@ void AudioPlayerAsync::setMusicEnabled(bool enabled) {
currentTrack = ""; // clear so crossFadeMusicAsync doesn't bail early
crossFadeMusicAsync(track);
}
}*/
}
}
void AudioPlayerAsync::setSoundEnabled(bool enabled) {

View File

@ -1,13 +1,16 @@
#pragma once
#if 0
#ifdef __ANDROID__
#include <SDL_mixer.h>
#include <SDL.h>
#else
#include <SDL2/SDL_mixer.h>
#include <SDL2/SDL.h>
#endif
#include <string>
#include <unordered_map>
#include <memory>
#include <mutex>
#include <SDL2/SDL.h>
#include <vector>
#ifndef __EMSCRIPTEN__
#include <queue>
@ -53,14 +56,15 @@ private:
std::queue<std::function<void()>> taskQueue;
#endif
bool stop = false;
#if 0
std::unordered_map<std::string, Mix_Chunk*> soundCache;
std::mutex soundCacheMutex;
std::string currentTrack;
Mix_Music* currentMusic_ = nullptr;
#endif
std::vector<char> currentMusicData_;
int musicVolume_ = 128;
int soundVolume_ = 128;
bool musicEnabled_ = true;

View File

@ -1518,40 +1518,22 @@ namespace FRG
const int uiX = mx;
const int uiY = Environment::projectionHeight - my;
#ifdef __ANDROID__
__android_log_print(ANDROID_LOG_ERROR, "Game",
"Game::onPointerDown step 1");
#endif
menuManager.topUiManager.onTouchDown(fingerId, uiX, uiY);
const bool capturedByTopUi = menuManager.topUiManager.isUiInteractionForFinger(fingerId);
const bool dialogueActive = currentLocation() && currentLocation()->dialogueSystem.isActive();
if (!dialogueActive && !capturedByTopUi) {
#ifdef __ANDROID__
__android_log_print(ANDROID_LOG_ERROR, "Game",
"Game::onPointerDown step 2");
#endif
menuManager.uiManager.onTouchDown(fingerId, uiX, uiY);
}
st.capturedByUi = capturedByTopUi || (!dialogueActive && menuManager.uiManager.isUiInteractionForFinger(fingerId));
activePointers[fingerId] = st;
#ifdef __ANDROID__
__android_log_print(ANDROID_LOG_ERROR, "Game",
"Game::onPointerDown step 3");
#endif
if (st.capturedByUi) {
// UI button / slider / text-field grabbed this press; don't drive
// gameplay or pinch from it.
#ifdef __ANDROID__
__android_log_print(ANDROID_LOG_ERROR, "Game",
"Game::onPointerDown step 4");
#endif
return;
}
#ifdef __ANDROID__
__android_log_print(ANDROID_LOG_ERROR, "Game",
"Game::onPointerDown step 5");
#endif
if (countNonUiPointers() >= 2) {
// Second finger landed on the gameplay area: switch to pinch-zoom

View File

@ -378,7 +378,7 @@ namespace FRG {
#ifndef EMSCRIPTEN
#if !defined(EMSCRIPTEN) && !defined(__ANDROID__)
uiManager.setTextButtonCallback("menuExitButton", [this](const std::string&) {
audioPlayer_.playSoundAsync("audio/751089__smallconfusion__mechanical-plastic-click-11.ogg");
Environment::exitGameLoop = true;

View File

@ -206,7 +206,7 @@ int main(int argc, char* argv[]) {
"Shadow Over Bishkek",
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
0, 0,
SDL_WINDOW_FULLSCREEN | SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN
SDL_WINDOW_FULLSCREEN | SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE
);
if (!FRG::Environment::window) {