Initial engine repository

This commit is contained in:
2026-06-08 19:58:35 +08:00
commit 7a925c3736
137 changed files with 162421 additions and 0 deletions
@@ -0,0 +1,353 @@
#pragma once
#include <frostbite2D/types/type_alias.h>
#include <optional>
#include <random>
#include <string>
#include <unordered_map>
#include <vector>
namespace frostbite2D {
/**
* @brief 音频项类型枚举
*/
enum class AudioEntryType {
None, ///< invalid
Effect, ///< one-shot sound effect
Ambient, ///< looping ambient track
Music, ///< background music
Random ///< random sound group
};
/**
* @brief 音效配置
*/
struct AudioEffect {
std::string id; ///< 音效 ID
std::string file; ///< 文件路径
std::string subgroup; ///< 子组(可选)
int32 loopDelay = -1; ///< 循环延迟(-1 表示未设置)
int32 loopDelayRange = -1;///< 循环延迟范围(-1 表示未设置)
};
/**
* @brief 音乐配置
*/
struct AudioMusic {
std::string id; ///< 音乐 ID
std::string file; ///< 文件路径
int32 loopDelay = -1; ///< 循环延迟(-1 表示未设置)
};
/**
* @brief ?????????
*/
struct AudioAmbient {
std::string id; ///< ?????ID
std::string file; ///< ??????
int32 loopDelay = -1; ///< ????????1 ?????????
int32 loopDelayRange = -1;///< ???????????1 ?????????
};
/**
* @brief 随机音效项
*/
struct RandomItem {
std::string tag; ///< 音效标签(ID
int32 probability = 0; ///< 概率权重
};
/**
* @brief 随机音效组
*/
struct AudioRandom {
std::string id; ///< 随机组 ID
std::vector<RandomItem> items; ///< 随机项列表
};
/**
* @brief 统一的音频条目(包含类型和数据)
*/
struct AudioEntry {
AudioEntryType type = AudioEntryType::None; ///< 条目类型
const AudioEffect* effect = nullptr; ///< 音效指针(type == Effect 时有效)
const AudioAmbient* ambient = nullptr;///< ???????????ype == Ambient ??????
const AudioMusic* music = nullptr; ///< 音乐指针(type == Music 时有效)
const AudioRandom* random = nullptr; ///< 随机组指针(type == Random 时有效)
/// @brief 判断是否有效
bool isValid() const { return type != AudioEntryType::None; }
/// @brief 判断是否为音效
bool isEffect() const { return type == AudioEntryType::Effect; }
/// @brief ????????????
bool isAmbient() const { return type == AudioEntryType::Ambient; }
/// @brief 判断是否为音乐
bool isMusic() const { return type == AudioEntryType::Music; }
/// @brief 判断是否为随机组
bool isRandom() const { return type == AudioEntryType::Random; }
/// @brief 安全获取文件路径
std::string getFilePath() const {
if (type == AudioEntryType::Effect && effect)
return effect->file;
if (type == AudioEntryType::Ambient && ambient)
return ambient->file;
if (type == AudioEntryType::Music && music)
return music->file;
return "";
}
/// @brief 安全获取子组
std::string getSubgroup() const {
if (type == AudioEntryType::Effect && effect)
return effect->subgroup;
return "";
}
};
/**
* @brief 音频数据库(单例)
*
* 用于解析和访问 audio.xml 文件中的音频配置。
* 提供统一的查询接口,自动判断音频类型。
*
* @example
* auto& audioDB = AudioDatabase::get();
* if (audioDB.loadFromFile("audio.xml")) {
* // 统一查询
* if (auto entry = audioDB.get("GN_FINAL_SHOT_01")) {
* // 使用 entry
* }
*
* // 获取文件路径
* if (auto filePath = audioDB.getFilePath("GN_FINAL_SHOT_01")) {
* // 使用 *filePath
* }
*
* // 获取音效(自动处理随机组)
* if (auto soundId = audioDB.getSound("R_GN_FINAL_SHOT")) {
* // 使用 *soundId
* }
* }
*/
class AudioDatabase {
public:
/**
* @brief 获取单例实例
* @return 音频数据库实例引用
*/
static AudioDatabase& get();
AudioDatabase(const AudioDatabase&) = delete;
AudioDatabase& operator=(const AudioDatabase&) = delete;
// ---------------------------------------------------------------------------
// 加载和解析
// ---------------------------------------------------------------------------
/**
* @brief 从文件加载音频数据库
* @param path XML 文件路径
* @return 加载成功返回 true
*/
bool loadFromFile(const std::string& path);
/**
* @brief 从字符串加载音频数据库
* @param xmlContent XML 内容字符串
* @return 加载成功返回 true
*/
bool loadFromString(const std::string& xmlContent);
/**
* @brief 清空数据库
*/
void clear();
/**
* @brief 检查数据库是否已加载
* @return 已加载返回 true
*/
bool isLoaded() const;
// ---------------------------------------------------------------------------
// 统一查询接口
// ---------------------------------------------------------------------------
/**
* @brief 统一查询:输入任意 ID,自动判断类型
* @param id 音频 ID(可以是 EFFECT、MUSIC 或 RANDOM 的 ID
* @return 音频条目,未找到返回 std::nullopt
*/
std::optional<AudioEntry> get(const std::string& id);
/**
* @brief 获取音效 ID(自动处理 RANDOM 类型)
*
* 如果 id 是 RANDOM 类型,会按概率随机选择一个音效;
* 如果 id 是 EFFECT 类型,直接返回该 ID。
*
* @param id 音效 ID 或随机组 ID
* @return 音效 ID,未找到返回 std::nullopt
*/
std::optional<std::string> getSound(const std::string& id);
/**
* @brief 获取文件路径
*
* 对于 EFFECT 和 MUSIC 类型,返回对应的文件路径;
* 对于 RANDOM 类型,先随机选择一个音效再返回其文件路径。
*
* @param id 音频 ID
* @return 文件路径,未找到返回 std::nullopt
*/
std::optional<std::string> getFilePath(const std::string& id);
// ---------------------------------------------------------------------------
// 类型特定查询(高级用法)
// ---------------------------------------------------------------------------
/**
* @brief 获取音效配置
* @param id 音效 ID
* @return 音效配置指针,未找到返回 std::nullopt
*/
std::optional<const AudioEffect*> getEffect(const std::string& id);
/**
* @brief ????????????
* @param id ?????ID
* @return ????????????????????? std::nullopt
*/
std::optional<const AudioAmbient*> getAmbient(const std::string& id);
/**
* @brief 获取音乐配置
* @param id 音乐 ID
* @return 音乐配置指针,未找到返回 std::nullopt
*/
std::optional<const AudioMusic*> getMusic(const std::string& id);
/**
* @brief 获取随机音效组配置
* @param id 随机组 ID
* @return 随机组配置指针,未找到返回 std::nullopt
*/
std::optional<const AudioRandom*> getRandom(const std::string& id);
// ---------------------------------------------------------------------------
// 统计信息
// ---------------------------------------------------------------------------
/**
* @brief 获取音效数量
*/
size_t effectCount() const;
/**
* @brief ???????????
*/
size_t ambientCount() const;
/**
* @brief 获取音乐数量
*/
size_t musicCount() const;
/**
* @brief 获取随机组数量
*/
size_t randomCount() const;
// ---------------------------------------------------------------------------
// 便捷访问方法(推荐使用)
// ---------------------------------------------------------------------------
/**
* @brief 检查 ID 是否存在
* @param id 音频 ID
* @return 存在返回 true
*/
bool has(const std::string& id);
/**
* @brief 获取文件路径(不存在返回空字符串)
* @param id 音频 ID
* @return 文件路径,未找到返回空字符串
*/
std::string filePath(const std::string& id);
/**
* @brief 获取音效 ID(自动处理随机组,不存在返回空字符串)
* @param idOrRandomId 音效 ID 或随机组 ID
* @return 音效 ID,未找到返回空字符串
*/
std::string soundId(const std::string& idOrRandomId);
/**
* @brief 获取子组(EFFECT 的 SUBGROUP 属性)
* @param id 音频 ID
* @return 子组名,未找到或不存在返回空字符串
*/
std::string subgroup(const std::string& id);
/**
* @brief 获取条目类型
* @param id 音频 ID
* @return 条目类型,未找到返回 AudioEntryType::None
*/
AudioEntryType typeOf(const std::string& id);
// ---------------------------------------------------------------------------
// 带检查的访问方法
// ---------------------------------------------------------------------------
/**
* @brief 尝试获取文件路径,带成功标志
* @param id 音频 ID
* @param outPath 输出文件路径
* @return 成功返回 true
*/
bool tryGetFilePath(const std::string& id, std::string& outPath);
/**
* @brief 尝试获取音效 ID,带成功标志
* @param id 音效 ID 或随机组 ID
* @param outSoundId 输出音效 ID
* @return 成功返回 true
*/
bool tryGetSoundId(const std::string& id, std::string& outSoundId);
private:
AudioDatabase() = default;
~AudioDatabase() = default;
/**
* @brief 初始化随机数生成器
*/
void initializeRNG();
/**
* @brief 从随机组中按概率选择一个音效
* @param randomGroup 随机组配置
* @return 选中的音效 ID
*/
std::string selectFromRandom(const AudioRandom& randomGroup);
std::unordered_map<std::string, AudioEffect> effectMap_; ///< 音效映射
std::unordered_map<std::string, AudioAmbient> ambientMap_; ///< ????????
std::unordered_map<std::string, AudioMusic> musicMap_; ///< 音乐映射
std::unordered_map<std::string, AudioRandom> randomMap_; ///< 随机组映射
std::mt19937 rng_; ///< 随机数生成器
bool rngInitialized_ = false; ///< 随机数生成器是否已初始化
bool loaded_ = false;
};
} // namespace frostbite2D