游戏支持系统
游戏支持系统是构成游戏引擎的基础设施,为游戏的各个功能模块提供底层服务和资源管理。本章将深入探讨游戏引擎中常见的支持系统,包括子系统的启动和终止流程、内存管理策略、各种数据容器的实现、字符串处理技术以及引擎配置系统。这些支持系统虽然不直接参与游戏逻辑的实现,但对于游戏性能、稳定性和开发效率具有决定性影响。
5.1 子系统的启动和终止
游戏引擎通常由多个相互依赖的子系统组成,这些子系统需要按照特定顺序启动和关闭,以确保资源的正确初始化和释放。
5.1.1 子系统依赖关系
游戏引擎中的子系统通常存在复杂的依赖关系,需要谨慎管理其初始化和关闭顺序:
cpp
// 定义子系统接口
class ISystem {
public:
virtual ~ISystem() = default;
// 初始化系统
virtual bool Initialize() = 0;
// 关闭系统
virtual void Shutdown() = 0;
// 更新系统状态
virtual void Update(float deltaTime) = 0;
// 获取系统名称
virtual const char* GetName() const = 0;
};
// 子系统依赖管理器
class SystemDependencyManager {
private:
struct SystemNode {
ISystem* system;
std::vector<SystemNode*> dependencies;
std::vector<SystemNode*> dependents;
bool initialized;
SystemNode(ISystem* sys) : system(sys), initialized(false) {}
};
std::unordered_map<std::string, SystemNode*> systems;
std::vector<SystemNode*> initializationOrder;
public:
~SystemDependencyManager() {
// 清理所有节点
for (auto& pair : systems) {
delete pair.second;
}
}
// 注册系统
void RegisterSystem(ISystem* system) {
std::string name = system->GetName();
if (systems.find(name) != systems.end()) {
// 系统已存在,可以选择更新或报错
return;
}
systems[name] = new SystemNode(system);
}
// 添加依赖关系
void AddDependency(const char* systemName, const char* dependsOnName) {
auto systemIt = systems.find(systemName);
auto dependsOnIt = systems.find(dependsOnName);
if (systemIt == systems.end() || dependsOnIt == systems.end()) {
// 系统不存在,报错或记录日志
return;
}
SystemNode* systemNode = systemIt->second;
SystemNode* dependsOnNode = dependsOnIt->second;
// 添加依赖关系
systemNode->dependencies.push_back(dependsOnNode);
dependsOnNode->dependents.push_back(systemNode);
}
// 使用拓扑排序计算初始化顺序
bool CalculateInitializationOrder() {
initializationOrder.clear();
// 统计每个节点的入度(依赖数量)
std::unordered_map<SystemNode*, int> inDegree;
std::queue<SystemNode*> zeroInDegree;
for (auto& pair : systems) {
SystemNode* node = pair.second;
inDegree[node] = node->dependencies.size();
if (inDegree[node] == 0) {
zeroInDegree.push(node);
}
}
// 拓扑排序
while (!zeroInDegree.empty()) {
SystemNode* node = zeroInDegree.front();
zeroInDegree.pop();
initializationOrder.push_back(node);
for (SystemNode* dependent : node->dependents) {
inDegree[dependent]--;
if (inDegree[dependent] == 0) {
zeroInDegree.push(dependent);
}
}
}
// 检查是否有循环依赖
return initializationOrder.size() == systems.size();
}
// 按顺序初始化所有系统
bool InitializeAll() {
if (initializationOrder.empty()) {
if (!CalculateInitializationOrder()) {
// 存在循环依赖,无法初始化
return false;
}
}
for (SystemNode* node : initializationOrder) {
if (!node->system->Initialize()) {
// 初始化失败,可以考虑回滚已初始化的系统
return false;
}
node->initialized = true;
}
return true;
}
// 按逆序关闭所有系统
void ShutdownAll() {
// 逆序关闭系统
for (auto it = initializationOrder.rbegin(); it != initializationOrder.rend(); ++it) {
SystemNode* node = *it;
if (node->initialized) {
node->system->Shutdown();
node->initialized = false;
}
}
}
};
5.1.2 系统启动顺序
游戏引擎启动时需要按照依赖关系顺序初始化各个子系统:
cpp
// 引擎类管理所有子系统
class Engine {
private:
SystemDependencyManager dependencyManager;
// 各个子系统
MemorySystem* memorySystem;
FileSystem* fileSystem;
ConfigSystem* configSystem;
LogSystem* logSystem;
RenderSystem* renderSystem;
AudioSystem* audioSystem;
InputSystem* inputSystem;
PhysicsSystem* physicsSystem;
ScriptSystem* scriptSystem;
NetworkSystem* networkSystem;
bool initialized;
public:
Engine()
: memorySystem(nullptr), fileSystem(nullptr), configSystem(nullptr),
logSystem(nullptr), renderSystem(nullptr), audioSystem(nullptr),
inputSystem(nullptr), physicsSystem(nullptr), scriptSystem(nullptr),
networkSystem(nullptr), initialized(false) {
}
~Engine() {
if (initialized) {
Shutdown();
}
// 释放所有子系统
delete networkSystem;
delete scriptSystem;
delete physicsSystem;
delete inputSystem;
delete audioSystem;
delete renderSystem;
delete logSystem;
delete configSystem;
delete fileSystem;
delete memorySystem;
}
// 初始化引擎
bool Initialize() {
if (initialized) {
return true;
}
// 创建所有子系统
memorySystem = new MemorySystem();
fileSystem = new FileSystem();
configSystem = new ConfigSystem();
logSystem = new LogSystem();
renderSystem = new RenderSystem();
audioSystem = new AudioSystem();
inputSystem = new InputSystem();
physicsSystem = new PhysicsSystem();
scriptSystem = new ScriptSystem();
networkSystem = new NetworkSystem();
// 注册所有子系统
dependencyManager.RegisterSystem(memorySystem);
dependencyManager.RegisterSystem(fileSystem);
dependencyManager.RegisterSystem(configSystem);
dependencyManager.RegisterSystem(logSystem);
dependencyManager.RegisterSystem(renderSystem);
dependencyManager.RegisterSystem(audioSystem);
dependencyManager.RegisterSystem(inputSystem);
dependencyManager.RegisterSystem(physicsSystem);
dependencyManager.RegisterSystem(scriptSystem);
dependencyManager.RegisterSystem(networkSystem);
// 建立依赖关系
// 内存系统是最基础的,没有依赖
dependencyManager.AddDependency("FileSystem", "MemorySystem");
dependencyManager.AddDependency("ConfigSystem", "FileSystem");
dependencyManager.AddDependency("LogSystem", "FileSystem");
dependencyManager.AddDependency("RenderSystem", "ConfigSystem");
dependencyManager.AddDependency("AudioSystem", "ConfigSystem");
dependencyManager.AddDependency("InputSystem", "ConfigSystem");
dependencyManager.AddDependency("PhysicsSystem", "MemorySystem");
dependencyManager.AddDependency("ScriptSystem", "FileSystem");
dependencyManager.AddDependency("NetworkSystem", "ConfigSystem");
// 计算初始化顺序并初始化所有系统
if (!dependencyManager.InitializeAll()) {
return false;
}
initialized = true;
return true;
}
// 关闭引擎
void Shutdown() {
if (!initialized) {
return;
}
// 按依赖顺序的逆序关闭所有系统
dependencyManager.ShutdownAll();
initialized = false;
}
// 更新引擎状态
void Update(float deltaTime) {
if (!initialized) {
return;
}
// 更新各子系统
// 注意:这里的更新顺序可能与初始化顺序不同
networkSystem->Update(deltaTime);
inputSystem->Update(deltaTime);
scriptSystem->Update(deltaTime);
physicsSystem->Update(deltaTime);
audioSystem->Update(deltaTime);
renderSystem->Update(deltaTime);
}
// 获取各种子系统
MemorySystem* GetMemorySystem() const { return memorySystem; }
FileSystem* GetFileSystem() const { return fileSystem; }
ConfigSystem* GetConfigSystem() const { return configSystem; }
LogSystem* GetLogSystem() const { return logSystem; }
RenderSystem* GetRenderSystem() const { return renderSystem; }
AudioSystem* GetAudioSystem() const { return audioSystem; }
InputSystem* GetInputSystem() const { return inputSystem; }
PhysicsSystem* GetPhysicsSystem() const { return physicsSystem; }
ScriptSystem* GetScriptSystem() const { return scriptSystem; }
NetworkSystem* GetNetworkSystem() const { return networkSystem; }
};
5.1.3 热重载系统
热重载允许在不重启游戏的情况下更新资源或代码,提高开发效率:
cpp
// 可热重载的资源接口
class IReloadable {
public:
virtual ~IReloadable() = default;
// 重新加载资源
virtual bool Reload() = 0;
// 获取资源ID
virtual uint32_t GetResourceId() const = 0;
};
// 热重载管理器
class HotReloadManager {
private:
std::unordered_map<uint32_t, IReloadable*> resources;
std::unordered_map<std::string, std::vector<uint32_t>> fileToResources;
FileWatcher fileWatcher;
public:
HotReloadManager() {
// 设置文件变化回调
fileWatcher.SetCallback([this](const std::string& path) {
OnFileChanged(path);
});
}
// 注册可重载资源
void RegisterResource(IReloadable* resource, const std::string& filePath) {
uint32_t resourceId = resource->GetResourceId();
resources[resourceId] = resource;
fileToResources[filePath].push_back(resourceId);
// 添加文件监控
fileWatcher.AddWatch(filePath);
}
// 注销资源
void UnregisterResource(uint32_t resourceId) {
auto it = resources.find(resourceId);
if (it != resources.end()) {
// 查找并从文件到资源的映射中移除
for (auto& pair : fileToResources) {
auto& resourceIds = pair.second;
auto idIt = std::find(resourceIds.begin(), resourceIds.end(), resourceId);
if (idIt != resourceIds.end()) {
resourceIds.erase(idIt);
// 如果文件不再关联任何资源,移除监控
if (resourceIds.empty()) {
fileWatcher.RemoveWatch(pair.first);
fileToResources.erase(pair.first);
}
break;
}
}
resources.erase(it);
}
}
// 手动重载资源
bool ReloadResource(uint32_t resourceId) {
auto it = resources.find(resourceId);
if (it != resources.end()) {
return it->second->Reload();
}
return false;
}
// 更新文件监控
void Update() {
fileWatcher.Update();
}
private:
// 文件变化回调
void OnFileChanged(const std::string& path) {
auto it = fileToResources.find(path);
if (it != fileToResources.end()) {
for (uint32_t resourceId : it->second) {
auto resourceIt = resources.find(resourceId);
if (resourceIt != resources.end()) {
if (resourceIt->second->Reload()) {
// 记录重载成功
std::cout << "Successfully reloaded resource " << resourceId << std::endl;
} else {
// 记录重载失败
std::cout << "Failed to reload resource " << resourceId << std::endl;
}
}
}
}
}
};
// 文件监控类实现
class FileWatcher {
private:
struct WatchedFile {
std::string path;
std::filesystem::file_time_type lastWriteTime;
};
std::vector<WatchedFile> watchedFiles;
std::function<void(const std::string&)> callback;
public:
// 设置文件变化回调
void SetCallback(std::function<void(const std::string&)> cb) {
callback = cb;
}
// 添加监控
void AddWatch(const std::string& path) {
if (std::filesystem::exists(path)) {
WatchedFile file;
file.path = path;
file.lastWriteTime = std::filesystem::last_write_time(path);
watchedFiles.push_back(file);
}
}
// 移除监控
void RemoveWatch(const std::string& path) {
auto it = std::find_if(watchedFiles.begin(), watchedFiles.end(),
[&path](const WatchedFile& file) { return file.path == path; });
if (it != watchedFiles.end()) {
watchedFiles.erase(it);
}
}
// 更新检查文件变化
void Update() {
for (auto& file : watchedFiles) {
if (std::filesystem::exists(file.path)) {
auto currentTime = std::filesystem::last_write_time(file.path);
if (currentTime != file.lastWriteTime) {
file.lastWriteTime = currentTime;
if (callback) {
callback(file.path);
}
}
}
}
}
};
5.1.4 系统初始化与资源预加载
游戏启动时通常需要预加载常用资源,以避免游戏过程中的加载延迟:
cpp
// 资源管理器
class ResourceManager : public ISystem {
private:
struct PreloadEntry {
std::string path;
ResourceType type;
};
FileSystem* fileSystem;
MemorySystem* memorySystem;
std::unordered_map<std::string, Resource*> resources;
std::vector<PreloadEntry> preloadList;
bool preloadComplete;
public:
ResourceManager()
: fileSystem(nullptr), memorySystem(nullptr), preloadComplete(false) {
}
~ResourceManager() {
// 清理所有资源
for (auto& pair : resources) {
delete pair.second;
}
}
// 实现ISystem接口
virtual bool Initialize() override {
// 获取依赖系统
Engine* engine = Engine::GetInstance();
fileSystem = engine->GetFileSystem();
memorySystem = engine->GetMemorySystem();
if (!fileSystem || !memorySystem) {
return false;
}
// 加载预加载列表
LoadPreloadList();
return true;
}
virtual void Shutdown() override {
// 释放所有资源
for (auto& pair : resources) {
delete pair.second;
}
resources.clear();
preloadList.clear();
preloadComplete = false;
}
virtual void Update(float deltaTime) override {
// 可以在这里处理异步加载逻辑
}
virtual const char* GetName() const override {
return "ResourceManager";
}
// 开始预加载
void StartPreload(std::function<void()> onComplete) {
if (preloadComplete || preloadList.empty()) {
onComplete();
return;
}
// 异步预加载
std::thread preloadThread([this, onComplete]() {
for (const auto& entry : preloadList) {
LoadResource(entry.path, entry.type);
}
preloadComplete = true;
onComplete();
});
preloadThread.detach();
}
// 获取资源
template<typename T>
T* GetResource(const std::string& path) {
auto it = resources.find(path);
if (it != resources.end()) {
return dynamic_cast<T*>(it->second);
}
// 资源不存在,加载它
ResourceType type = GetResourceTypeFromTemplate<T>();
Resource* resource = LoadResource(path, type);
return dynamic_cast<T*>(resource);
}
private:
// 加载预加载列表
void LoadPreloadList() {
// 从配置文件加载预加载列表
std::string preloadConfigPath = "config/preload.json";
if (!fileSystem->FileExists(preloadConfigPath)) {
return;
}
std::string jsonData = fileSystem->ReadAllText(preloadConfigPath);
// 解析JSON
// 这里使用一个简化的示例,实际中应使用JSON库
// ...
// 添加到预加载列表
preloadList.push_back({"textures/common.png", ResourceType::Texture});
preloadList.push_back({"models/player.obj", ResourceType::Model});
preloadList.push_back({"sounds/background.wav", ResourceType::Sound});
}
// 加载资源
Resource* LoadResource(const std::string& path, ResourceType type) {
// 检查资源是否已加载
auto it = resources.find(path);
if (it != resources.end()) {
return it->second;
}
// 创建适当类型的资源
Resource* resource = nullptr;
switch (type) {
case ResourceType::Texture:
resource = new Texture();
break;
case ResourceType::Model:
resource = new Model();
break;
case ResourceType::Sound:
resource = new Sound();
break;
case ResourceType::Shader:
resource = new Shader();
break;
// 其他资源类型...
default:
return nullptr;
}
// 加载资源
if (!resource->Load(path, fileSystem)) {
delete resource;
return nullptr;
}
// 添加到资源映射
resources[path] = resource;
return resource;
}
// 从模板类型获取资源类型
template<typename T>
ResourceType GetResourceTypeFromTemplate() {
if (std::is_same<T, Texture>::value) return ResourceType::Texture;
if (std::is_same<T, Model>::value) return ResourceType::Model;
if (std::is_same<T, Sound>::value) return ResourceType::Sound;
if (std::is_same<T, Shader>::value) return ResourceType::Shader;
// 其他类型...
return ResourceType::Unknown;
}
};
5.1.5 系统终止和资源清理
游戏退出时需要有序地关闭系统并释放资源:
cpp
// 游戏应用程序类
class GameApplication {
private:
Engine* engine;
bool running;
// 系统性能计时器
PerformanceTimer timer;
// 应用程序退出处理
std::vector<std::function<void()>> shutdownHandlers;
public:
GameApplication() : engine(nullptr), running(false) {
}
~GameApplication() {
Shutdown();
delete engine;
}
// 初始化应用程序
bool Initialize() {
// 创建引擎
engine = new Engine();
if (!engine->Initialize()) {
return false;
}
// 设置关闭处理
SetupShutdownHandlers();
// 注册信号处理
RegisterSignalHandlers();
// 开始预加载资源
ResourceManager* resourceManager =
static_cast<ResourceManager*>(engine->GetSystem("ResourceManager"));
if (resourceManager) {
resourceManager->StartPreload([this]() {
// 预加载完成后启动游戏
StartGame();
});
} else {
// 无资源管理器,直接启动游戏
StartGame();
}
running = true;
return true;
}
// 运行游戏主循环
void Run() {
while (running) {
// 计算帧时间
float deltaTime = timer.GetElapsedTime();
timer.Reset();
// 处理输入
ProcessInput();
// 更新游戏逻辑
Update(deltaTime);
// 渲染
Render();
// 帧率限制
LimitFrameRate();
}
}
// 关闭应用程序
void Shutdown() {
if (!running) {
return;
}
running = false;
// 执行所有关闭处理器
for (auto it = shutdownHandlers.rbegin(); it != shutdownHandlers.rend(); ++it) {
(*it)();
}
// 关闭引擎
if (engine) {
engine->Shutdown();
}
// 保存配置
SaveConfiguration();
}
// 请求退出
void RequestExit() {
running = false;
}
private:
// 设置关闭处理器
void SetupShutdownHandlers() {
// 保存游戏状态
shutdownHandlers.push_back([]() {
std::cout << "Saving game state..." << std::endl;
// 保存游戏状态逻辑
});
// 关闭网络连接
shutdownHandlers.push_back([]() {
std::cout << "Closing network connections..." << std::endl;
// 关闭网络连接逻辑
});
// 释放资源
shutdownHandlers.push_back([]() {
std::cout << "Releasing resources..." << std::endl;
// 释放资源逻辑
});
}
// 注册信号处理
void RegisterSignalHandlers() {
// 设置SIGINT处理(Ctrl+C)
std::signal(SIGINT, [](int) {
GameApplication::GetInstance()->RequestExit();
});
// 其他信号处理...
}
// 启动游戏
void StartGame() {
std::cout << "Game starting..." << std::endl;
// 游戏启动逻辑
}
// 处理输入
void ProcessInput() {
InputSystem* inputSystem = engine->GetInputSystem();
inputSystem->Update(0.0f);
// 检查退出按键
if (inputSystem->IsKeyPressed(Key::Escape)) {
RequestExit();
}
}
// 更新游戏逻辑
void Update(float deltaTime) {
// 更新引擎
engine->Update(deltaTime);
// 更新游戏状态
// ...
}
// 渲染
void Render() {
RenderSystem* renderSystem = engine->GetRenderSystem();
renderSystem->BeginFrame();
// 执行渲染命令
// ...
renderSystem->EndFrame();
}
// 帧率限制
void LimitFrameRate() {
const float targetFrameTime = 1.0f / 60.0f; // 60 FPS
float frameTime = timer.GetElapsedTime();
if (frameTime < targetFrameTime) {
float sleepTime = (targetFrameTime - frameTime) * 1000.0f;
std::this_thread::sleep_for(std::chrono::milliseconds(static_cast<int>(sleepTime)));
}
}
// 保存配置
void SaveConfiguration() {
ConfigSystem* configSystem = engine->GetConfigSystem();
configSystem->SaveConfig("config/settings.json");
}
// 单例访问
static GameApplication* instance;
public:
static GameApplication* GetInstance() {
if (!instance) {
instance = new GameApplication();
}
return instance;
}
};
// 初始化静态成员
GameApplication* GameApplication::instance = nullptr;
5.2 内存管理
游戏对内存管理有着严格的要求,需要高效、可预测和低碎片化的内存分配策略。
5.2.1 内存分配器
自定义内存分配器可以针对游戏的特定需求优化内存使用:
cpp
// 内存分配器接口
class IAllocator {
public:
virtual ~IAllocator() = default;
// 分配内存
virtual void* Allocate(size_t size, size_t alignment = DEFAULT_ALIGNMENT) = 0;
// 释放内存
virtual void Deallocate(void* ptr) = 0;
// 获取已分配内存大小
virtual size_t GetAllocatedSize() const = 0;
// 内存对齐默认值
static constexpr size_t DEFAULT_ALIGNMENT = 16;
};
// 线性分配器 - 适合短生命周期的一次性分配
class LinearAllocator : public IAllocator {
private:
void* memoryBlock;
size_t blockSize;
size_t offset;
public:
LinearAllocator(size_t size) : blockSize(size), offset(0) {
memoryBlock = std::malloc(size);
}
~LinearAllocator() {
std::free(memoryBlock);
}
void* Allocate(size_t size, size_t alignment = DEFAULT_ALIGNMENT) override {
// 计算对齐后的偏移
size_t alignedOffset = AlignForward(offset, alignment);
// 检查是否有足够空间
if (alignedOffset + size > blockSize) {
return nullptr; // 内存不足
}
// 返回地址并更新偏移
void* ptr = static_cast<char*>(memoryBlock) + alignedOffset;
offset = alignedOffset + size;
return ptr;
}
void Deallocate(void* ptr) override {
// 线性分配器不支持单独释放,忽略
(void)ptr;
}
size_t GetAllocatedSize() const override {
return offset;
}
// 重置分配器,允许重用内存
void Reset() {
offset = 0;
}
private:
// 计算对齐后的地址
size_t AlignForward(size_t address, size_t alignment) {
return (address + (alignment - 1)) & ~(alignment - 1);
}
};
// 池分配器 - 适合固定大小对象的频繁分配/释放
class PoolAllocator : public IAllocator {
private:
struct FreeBlock {
FreeBlock* next;
};
void* memoryBlock;
size_t blockSize;
size_t chunkSize;
size_t chunksPerBlock;
FreeBlock* freeList;
size_t allocatedChunks;
public:
PoolAllocator(size_t totalSize, size_t chunkSize)
: blockSize(totalSize), chunkSize(AlignForward(chunkSize, sizeof(FreeBlock))),
allocatedChunks(0) {
memoryBlock = std::malloc(totalSize);
chunksPerBlock = blockSize / this->chunkSize;
// 初始化空闲列表
freeList = nullptr;
Reset();
}
~PoolAllocator() {
std::free(memoryBlock);
}
void* Allocate(size_t size, size_t alignment = DEFAULT_ALIGNMENT) override {
// 检查请求的大小是否超过块大小
if (size > chunkSize) {
return nullptr;
}
// 检查是否还有空闲块
if (!freeList) {
return nullptr;
}
// 分配一个块
FreeBlock* block = freeList;
freeList = block->next;
allocatedChunks++;
return block;
}
void Deallocate(void* ptr) override {
// 检查指针是否在内存池范围内
if (ptr < memoryBlock ||
ptr >= static_cast<char*>(memoryBlock) + blockSize) {
return;
}
// 将块放回空闲列表
FreeBlock* block = static_cast<FreeBlock*>(ptr);
block->next = freeList;
freeList = block;
allocatedChunks--;
}
size_t GetAllocatedSize() const override {
return allocatedChunks * chunkSize;
}
// 重置池,释放所有分配
void Reset() {
// 将所有块链接到空闲列表
char* start = static_cast<char*>(memoryBlock);
// 初始化所有块
freeList = nullptr;
for (size_t i = 0; i < chunksPerBlock; i++) {
size_t index = chunksPerBlock - i - 1;
FreeBlock* block = reinterpret_cast<FreeBlock*>(start + index * chunkSize);
block->next = freeList;
freeList = block;
}
allocatedChunks = 0;
}
private:
// 计算对齐后的大小
size_t AlignForward(size_t size, size_t alignment) {
return (size + (alignment - 1)) & ~(alignment - 1);
}
};
// 栈分配器 - 适合后进先出分配模式
class StackAllocator : public IAllocator {
private:
struct AllocationHeader {
size_t size;
size_t adjustment;
};
void* memoryBlock;
size_t blockSize;
size_t offset;
public:
StackAllocator(size_t size) : blockSize(size), offset(0) {
memoryBlock = std::malloc(size);
}
~StackAllocator() {
std::free(memoryBlock);
}
void* Allocate(size_t size, size_t alignment = DEFAULT_ALIGNMENT) override {
// 计算头部大小和必要的对齐调整
const size_t headerSize = sizeof(AllocationHeader);
const size_t totalSize = size + headerSize;
// 计算当前地址和调整
uintptr_t currentAddress = reinterpret_cast<uintptr_t>(memoryBlock) + offset;
uintptr_t alignedAddress = AlignForward(currentAddress + headerSize, alignment);
size_t adjustment = alignedAddress - currentAddress;
// 检查是否有足够空间
if (offset + adjustment + size > blockSize) {
return nullptr;
}
// 存储分配头部
AllocationHeader* header = reinterpret_cast<AllocationHeader*>(
reinterpret_cast<char*>(memoryBlock) + offset + adjustment - headerSize);
header->size = size;
header->adjustment = adjustment;
// 更新偏移
offset += totalSize + adjustment - headerSize;
// 返回对齐后的地址
return reinterpret_cast<void*>(alignedAddress);
}
void Deallocate(void* ptr) override {
// 从指针获取头部
uintptr_t address = reinterpret_cast<uintptr_t>(ptr);
AllocationHeader* header = reinterpret_cast<AllocationHeader*>(
address - sizeof(AllocationHeader));
// 计算新的偏移
offset = address - header->adjustment - reinterpret_cast<uintptr_t>(memoryBlock) -
sizeof(AllocationHeader) + header->adjustment;
}
size_t GetAllocatedSize() const override {
return offset;
}
// 弹出最后一次分配
void Pop(void* ptr) {
Deallocate(ptr);
}
// 重置栈
void Reset() {
offset = 0;
}
private:
// 计算对齐后的地址
uintptr_t AlignForward(uintptr_t address, size_t alignment) {
return (address + (alignment - 1)) & ~(alignment - 1);
}
};
// 自由列表分配器 - 通用分配器,管理任意大小的内存块
class FreeListAllocator : public IAllocator {
private:
struct AllocationHeader {
size_t size;
size_t adjustment;
};
struct FreeBlock {
size_t size;
FreeBlock* next;
};
void* memoryBlock;
size_t blockSize;
FreeBlock* freeList;
public:
FreeListAllocator(size_t size) : blockSize(size) {
memoryBlock = std::malloc(size);
// 初始化为单个大块
freeList = reinterpret_cast<FreeBlock*>(memoryBlock);
freeList->size = size;
freeList->next = nullptr;
}
~FreeListAllocator() {
std::free(memoryBlock);
}
void* Allocate(size_t size, size_t alignment = DEFAULT_ALIGNMENT) override {
// 计算总大小和调整
const size_t headerSize = sizeof(AllocationHeader);
const size_t minBlockSize = sizeof(FreeBlock);
// 查找合适的块
FreeBlock* prev = nullptr;
FreeBlock* block = freeList;
while (block) {
// 计算块开始的地址
uintptr_t blockAddress = reinterpret_cast<uintptr_t>(block);
// 计算对齐调整
size_t adjustment = CalculateAdjustment(blockAddress + headerSize, alignment);
size_t totalSize = size + adjustment + headerSize;
// 检查块是否足够大
if (block->size >= totalSize) {
// 够大,进行分配
// 计算剩余大小
size_t remainingSize = block->size - totalSize;
// 检查是否应该分割块
if (remainingSize > minBlockSize) {
// 创建新的空闲块
FreeBlock* newBlock = reinterpret_cast<FreeBlock*>(
reinterpret_cast<char*>(block) + totalSize);
newBlock->size = remainingSize;
newBlock->next = block->next;
// 更新当前块大小
block->size = totalSize;
if (prev) {
prev->next = newBlock;
} else {
freeList = newBlock;
}
} else {
// 使用整个块
if (prev) {
prev->next = block->next;
} else {
freeList = block->next;
}
}
// 计算返回地址
uintptr_t alignedAddress = blockAddress + adjustment + headerSize;
// 存储头部信息
AllocationHeader* header = reinterpret_cast<AllocationHeader*>(
alignedAddress - headerSize);
header->size = size;
header->adjustment = adjustment;
return reinterpret_cast<void*>(alignedAddress);
}
prev = block;
block = block->next;
}
// 没有合适的块
return nullptr;
}
void Deallocate(void* ptr) override {
if (!ptr) {
return;
}
// 获取分配头部
uintptr_t address = reinterpret_cast<uintptr_t>(ptr);
AllocationHeader* header = reinterpret_cast<AllocationHeader*>(
address - sizeof(AllocationHeader));
// 计算块起始地址
uintptr_t blockStart = address - header->adjustment - sizeof(AllocationHeader);
size_t blockSize = header->size + header->adjustment + sizeof(AllocationHeader);
// 将块插入空闲列表,按地址排序
InsertFreeBlock(reinterpret_cast<FreeBlock*>(blockStart), blockSize);
}
size_t GetAllocatedSize() const override {
// 计算已分配内存大小(这只是粗略估计)
size_t freeSize = 0;
FreeBlock* block = freeList;
while (block) {
freeSize += block->size;
block = block->next;
}
return blockSize - freeSize;
}
private:
// 计算对齐调整
size_t CalculateAdjustment(uintptr_t address, size_t alignment) {
size_t adjustment = alignment - (address & (alignment - 1));
if (adjustment == alignment) {
adjustment = 0;
}
return adjustment;
}
// 将块插入空闲列表
void InsertFreeBlock(FreeBlock* block, size_t size) {
block->size = size;
// 按地址排序插入
FreeBlock* prev = nullptr;
FreeBlock* curr = freeList;
while (curr && curr < block) {
prev = curr;
curr = curr->next;
}
// 检查是否可以与前一个块合并
if (prev && reinterpret_cast<char*>(prev) + prev->size == reinterpret_cast<char*>(block)) {
prev->size += block->size;
block = prev;
} else if (prev) {
prev->next = block;
} else {
freeList = block;
}
// 检查是否可以与后一个块合并
if (curr && reinterpret_cast<char*>(block) + block->size == reinterpret_cast<char*>(curr)) {
block->size += curr->size;
block->next = curr->next;
} else {
block->next = curr;
}
}
};
5.2.2 内存跟踪与调试
内存跟踪工具可以帮助识别内存泄漏和其他内存问题:
cpp
// 内存跟踪系统
class MemoryTracker {
private:
struct AllocationInfo {
void* address;
size_t size;
const char* file;
int line;
const char* function;
bool isArray;
size_t alignmentPadding;
AllocationInfo(void* addr, size_t sz, const char* f, int ln,
const char* func, bool array, size_t padding)
: address(addr), size(sz), file(f), line(ln), function(func),
isArray(array), alignmentPadding(padding) {}
};
// 线程安全的分配映射
std::mutex mutex;
std::unordered_map<void*, AllocationInfo> allocations;
// 内存统计
size_t totalAllocated;
size_t peakAllocated;
size_t totalAllocations;
size_t activeAllocations;
// 静态实例
static MemoryTracker* instance;
// 私有构造函数(单例)
MemoryTracker()
: totalAllocated(0), peakAllocated(0),
totalAllocations(0), activeAllocations(0) {}
public:
// 获取单例实例
static MemoryTracker* GetInstance() {
if (!instance) {
instance = new MemoryTracker();
}
return instance;
}
// 销毁实例
static void DestroyInstance() {
delete instance;
instance = nullptr;
}
// 跟踪分配
void* TrackAllocation(size_t size, const char* file, int line,
const char* function, bool isArray, size_t padding) {
std::lock_guard<std::mutex> lock(mutex);
// 分配内存
void* ptr = malloc(size + padding);
if (ptr) {
// 更新统计
totalAllocated += size;
totalAllocations++;
activeAllocations++;
if (totalAllocated > peakAllocated) {
peakAllocated = totalAllocated;
}
// 记录分配信息
void* adjustedPtr = static_cast<char*>(ptr) + padding;
allocations[adjustedPtr] = AllocationInfo(ptr, size, file, line, function,
isArray, padding);
return adjustedPtr;
}
return nullptr;
}
// 跟踪释放
void TrackDeallocation(void* ptr, bool isArray) {
if (!ptr) {
return;
}
std::lock_guard<std::mutex> lock(mutex);
// 查找分配信息
auto it = allocations.find(ptr);
if (it != allocations.end()) {
const AllocationInfo& info = it->second;
// 检查释放类型是否匹配
if (info.isArray != isArray) {
std::cerr << "ERROR: Memory allocated with "
<< (info.isArray ? "new[]" : "new")
<< " but deallocated with "
<< (isArray ? "delete[]" : "delete")
<< " at " << info.file << ":" << info.line
<< std::endl;
}
// 更新统计
totalAllocated -= info.size;
activeAllocations--;
// 释放内存
void* actualPtr = info.address;
allocations.erase(it);
free(actualPtr);
} else {
std::cerr << "ERROR: Attempting to deallocate unallocated memory at "
<< ptr << std::endl;
}
}
// 打印内存报告
void PrintReport() {
std::lock_guard<std::mutex> lock(mutex);
std::cout << "=== Memory Report ===" << std::endl;
std::cout << "Total allocations: " << totalAllocations << std::endl;
std::cout << "Active allocations: " << activeAllocations << std::endl;
std::cout << "Current memory usage: " << totalAllocated << " bytes" << std::endl;
std::cout << "Peak memory usage: " << peakAllocated << " bytes" << std::endl;
// 打印泄漏
if (activeAllocations > 0) {
std::cout << "Memory leaks detected: " << activeAllocations << std::endl;
for (const auto& pair : allocations) {
const AllocationInfo& info = pair.second;
std::cout << " Leak: " << info.size << " bytes at "
<< pair.first
<< " allocated in " << info.function
<< " (" << info.file << ":" << info.line << ")"
<< std::endl;
}
} else {
std::cout << "No memory leaks detected." << std::endl;
}
std::cout << "=====================" << std::endl;
}
// 重置跟踪器
void Reset() {
std::lock_guard<std::mutex> lock(mutex);
// 警告:这不会释放已分配的内存,仅重置跟踪器
allocations.clear();
totalAllocated = 0;
peakAllocated = 0;
totalAllocations = 0;
activeAllocations = 0;
}
};
// 初始化静态实例
MemoryTracker* MemoryTracker::instance = nullptr;
// 重载全局 new 和 delete 操作符
void* operator new(size_t size, const char* file, int line, const char* function) {
return MemoryTracker::GetInstance()->TrackAllocation(size, file, line, function, false, 0);
}
void* operator new[](size_t size, const char* file, int line, const char* function) {
return MemoryTracker::GetInstance()->TrackAllocation(size, file, line, function, true, 0);
}
void operator delete(void* ptr) noexcept {
MemoryTracker::GetInstance()->TrackDeallocation(ptr, false);
}
void operator delete[](void* ptr) noexcept {
MemoryTracker::GetInstance()->TrackDeallocation(ptr, true);
}
// 宏定义,简化使用
#ifdef MEMORY_TRACKING_ENABLED
#define new new(__FILE__, __LINE__, __FUNCTION__)
#endif
5.2.3 内存对齐与缓存优化
内存对齐和缓存友好的数据结构可以显著提高性能:
cpp
// 内存对齐工具
class MemoryAlign {
public:
// 检查地址是否对齐
static bool IsAligned(const void* address, size_t alignment) {
return (reinterpret_cast<uintptr_t>(address) & (alignment - 1)) == 0;
}
// 计算对齐后的地址
static void* AlignForward(void* address, size_t alignment) {
uintptr_t addr = reinterpret_cast<uintptr_t>(address);
uintptr_t aligned = (addr + (alignment - 1)) & ~(alignment - 1);
return reinterpret_cast<void*>(aligned);
}
// 分配对齐内存
static void* AllocateAligned(size_t size, size_t alignment) {
// 分配额外空间用于存储原始指针和对齐调整
size_t totalSize = size + alignment + sizeof(void*);
void* rawMemory = std::malloc(totalSize);
if (!rawMemory) {
return nullptr;
}
// 计算对齐后的地址
void* alignedMemory = reinterpret_cast<void*>(
(reinterpret_cast<uintptr_t>(rawMemory) + sizeof(void*) + alignment)
& ~(alignment - 1));
// 存储原始指针
void** ptrToRawMemory = reinterpret_cast<void**>(
reinterpret_cast<uintptr_t>(alignedMemory) - sizeof(void*));
*ptrToRawMemory = rawMemory;
return alignedMemory;
}
// 释放对齐内存
static void FreeAligned(void* alignedMemory) {
if (!alignedMemory) {
return;
}
// 获取原始指针
void** ptrToRawMemory = reinterpret_cast<void**>(
reinterpret_cast<uintptr_t>(alignedMemory) - sizeof(void*));
void* rawMemory = *ptrToRawMemory;
std::free(rawMemory);
}
};
// 缓存友好的数据结构 - 紧凑数组
template<typename T, size_t CacheLineSize = 64>
class CacheFriendlyArray {
private:
T* data;
size_t count;
size_t capacity;
public:
CacheFriendlyArray(size_t initialCapacity = 16)
: count(0), capacity(initialCapacity) {
// 分配对齐内存
data = static_cast<T*>(MemoryAlign::AllocateAligned(
capacity * sizeof(T), CacheLineSize));
}
~CacheFriendlyArray() {
// 调用所有元素的析构函数
for (size_t i = 0; i < count; i++) {
data[i].~T();
}
// 释放对齐内存
MemoryAlign::FreeAligned(data);
}
// 移动构造函数
CacheFriendlyArray(CacheFriendlyArray&& other) noexcept
: data(other.data), count(other.count), capacity(other.capacity) {
other.data = nullptr;
other.count = 0;
other.capacity = 0;
}
// 移动赋值操作符
CacheFriendlyArray& operator=(CacheFriendlyArray&& other) noexcept {
if (this != &other) {
// 清理当前资源
for (size_t i = 0; i < count; i++) {
data[i].~T();
}
MemoryAlign::FreeAligned(data);
// 移动资源
data = other.data;
count = other.count;
capacity = other.capacity;
other.data = nullptr;
other.count = 0;
other.capacity = 0;
}
return *this;
}
// 禁用复制
CacheFriendlyArray(const CacheFriendlyArray&) = delete;
CacheFriendlyArray& operator=(const CacheFriendlyArray&) = delete;
// 添加元素
void Add(const T& value) {
if (count == capacity) {
Grow();
}
// 使用placement new在预分配内存上构造对象
new (&data[count]) T(value);
count++;
}
// 移除元素
void Remove(size_t index) {
if (index >= count) {
return;
}
// 调用要移除元素的析构函数
data[index].~T();
// 移动最后一个元素到移除位置
if (index < count - 1) {
new (&data[index]) T(std::move(data[count - 1]));
data[count - 1].~T();
}
count--;
}
// 清空数组
void Clear() {
for (size_t i = 0; i < count; i++) {
data[i].~T();
}
count = 0;
}
// 访问元素
T& operator[](size_t index) {
return data[index];
}
const T& operator[](size_t index) const {
return data[index];
}
// 获取大小
size_t Size() const {
return count;
}
// 获取容量
size_t Capacity() const {
return capacity;
}
private:
// 扩展数组容量
void Grow() {
size_t newCapacity = capacity * 2;
T* newData = static_cast<T*>(MemoryAlign::AllocateAligned(
newCapacity * sizeof(T), CacheLineSize));
// 移动现有元素
for (size_t i = 0; i < count; i++) {
new (&newData[i]) T(std::move(data[i]));
data[i].~T();
}
// 释放旧内存
MemoryAlign::FreeAligned(data);
data = newData;
capacity = newCapacity;
}
};
// 数据结构组件化设计(避免虚函数开销)
class EntityComponentSystem {
private:
// 紧凑存储每种类型的组件
struct TransformData {
std::vector<Vector3> positions;
std::vector<Quaternion> rotations;
std::vector<Vector3> scales;
std::vector<uint32_t> entityIds;
};
struct RenderData {
std::vector<uint32_t> meshIds;
std::vector<uint32_t> materialIds;
std::vector<uint32_t> entityIds;
};
struct PhysicsData {
std::vector<float> masses;
std::vector<Vector3> velocities;
std::vector<bool> isKinematic;
std::vector<uint32_t> entityIds;
};
// 组件存储
TransformData transforms;
RenderData renderers;
PhysicsData physics;
// 实体组件映射
std::unordered_map<uint32_t, size_t> entityToTransform;
std::unordered_map<uint32_t, size_t> entityToRenderer;
std::unordered_map<uint32_t, size_t> entityToPhysics;
// 下一个可用的实体ID
uint32_t nextEntityId;
public:
EntityComponentSystem() : nextEntityId(1) {}
// 创建新实体
uint32_t CreateEntity() {
return nextEntityId++;
}
// 添加变换组件
void AddTransform(uint32_t entityId, const Vector3& position,
const Quaternion& rotation, const Vector3& scale) {
size_t index = transforms.positions.size();
transforms.positions.push_back(position);
transforms.rotations.push_back(rotation);
transforms.scales.push_back(scale);
transforms.entityIds.push_back(entityId);
entityToTransform[entityId] = index;
}
// 添加渲染组件
void AddRenderer(uint32_t entityId, uint32_t meshId, uint32_t materialId) {
size_t index = renderers.meshIds.size();
renderers.meshIds.push_back(meshId);
renderers.materialIds.push_back(materialId);
renderers.entityIds.push_back(entityId);
entityToRenderer[entityId] = index;
}
// 添加物理组件
void AddPhysics(uint32_t entityId, float mass, const Vector3& velocity, bool isKinematic) {
size_t index = physics.masses.size();
physics.masses.push_back(mass);
physics.velocities.push_back(velocity);
physics.isKinematic.push_back(isKinematic);
physics.entityIds.push_back(entityId);
entityToPhysics[entityId] = index;
}
// 更新所有物理组件
void UpdatePhysics(float deltaTime) {
// 批量更新所有物理对象
for (size_t i = 0; i < physics.masses.size(); i++) {
if (physics.isKinematic[i]) {
continue;
}
uint32_t entityId = physics.entityIds[i];
auto transformIt = entityToTransform.find(entityId);
if (transformIt != entityToTransform.end()) {
size_t transformIndex = transformIt->second;
// 应用速度
transforms.positions[transformIndex] += physics.velocities[i] * deltaTime;
}
}
}
// 渲染所有实体
void Render(RenderSystem* renderer) {
// 按材质ID分组,减少状态切换
std::map<uint32_t, std::vector<size_t>> materialGroups;
for (size_t i = 0; i < renderers.materialIds.size(); i++) {
uint32_t materialId = renderers.materialIds[i];
materialGroups[materialId].push_back(i);
}
// 按材质ID批量渲染
for (const auto& group : materialGroups) {
uint32_t materialId = group.first;
renderer->BindMaterial(materialId);
for (size_t index : group.second) {
uint32_t entityId = renderers.entityIds[index];
uint32_t meshId = renderers.meshIds[index];
auto transformIt = entityToTransform.find(entityId);
if (transformIt != entityToTransform.end()) {
size_t transformIndex = transformIt->second;
// 构建变换矩阵
Matrix4x4 transform = Matrix4x4::CreateTransform(
transforms.positions[transformIndex],
transforms.rotations[transformIndex],
transforms.scales[transformIndex]);
// 渲染网格
renderer->DrawMesh(meshId, transform);
}
}
}
}
};
5.2.4 游戏资源加载与管理
游戏资源加载器需要高效地管理游戏资源的生命周期:
cpp
// 资源接口
class IResource {
public:
virtual ~IResource() = default;
// 加载资源
virtual bool Load(const std::string& path, FileSystem* fileSystem) = 0;
// 卸载资源
virtual void Unload() = 0;
// 获取资源路径
virtual const std::string& GetPath() const = 0;
// 获取资源大小(内存中)
virtual size_t GetMemoryUsage() const = 0;
};
// 资源管理器
class ResourceManager : public ISystem {
private:
// 资源缓存
std::unordered_map<std::string, std::shared_ptr<IResource>> resources;
// 资源类型工厂
std::unordered_map<std::string, std::function<IResource*()>> factories;
// 内存预算
size_t memoryBudget;
size_t currentMemoryUsage;
// 依赖系统
FileSystem* fileSystem;
MemorySystem* memorySystem;
// 资源加载器线程池
ThreadPool loadingThreadPool;
// 加载中的资源
std::mutex loadingMutex;
std::unordered_map<std::string, std::future<std::shared_ptr<IResource>>> loadingResources;
public:
ResourceManager()
: memoryBudget(1024 * 1024 * 1024), // 1GB 默认
currentMemoryUsage(0),
fileSystem(nullptr),
memorySystem(nullptr),
loadingThreadPool(4) // 4个加载线程
{
// 注册内置资源类型
RegisterResourceType<Texture>("texture");
RegisterResourceType<Model>("model");
RegisterResourceType<Sound>("sound");
RegisterResourceType<Shader>("shader");
RegisterResourceType<Material>("material");
}
// 实现ISystem接口
virtual bool Initialize() override {
Engine* engine = Engine::GetInstance();
fileSystem = engine->GetFileSystem();
memorySystem = engine->GetMemorySystem();
return fileSystem && memorySystem;
}
virtual void Shutdown() override {
// 等待所有加载完成
WaitForAllLoading();
// 卸载所有资源
UnloadAll();
// 清理资源缓存
resources.clear();
// 停止线程池
loadingThreadPool.Shutdown();
}
virtual void Update(float deltaTime) override {
// 检查异步加载完成的资源
CheckLoadingResources();
// 内存管理:如果超出预算,释放不常用资源
if (currentMemoryUsage > memoryBudget) {
ReleaseUnusedResources();
}
}
virtual const char* GetName() const override {
return "ResourceManager";
}
// 注册资源类型
template<typename T>
void RegisterResourceType(const std::string& extension) {
factories[extension] = []() { return new T(); };
}
// 同步加载资源
template<typename T>
std::shared_ptr<T> LoadResource(const std::string& path) {
// 检查资源是否已加载
auto it = resources.find(path);
if (it != resources.end()) {
return std::dynamic_pointer_cast<T>(it->second);
}
// 检查是否正在加载
{
std::lock_guard<std::mutex> lock(loadingMutex);
auto loadingIt = loadingResources.find(path);
if (loadingIt != loadingResources.end()) {
// 等待加载完成
auto resource = loadingIt->second.get();
return std::dynamic_pointer_cast<T>(resource);
}
}
// 提取扩展名
std::string extension = GetFileExtension(path);
// 查找工厂
auto factoryIt = factories.find(extension);
if (factoryIt == factories.end()) {
return nullptr;
}
// 创建资源
IResource* rawResource = factoryIt->second();
if (!rawResource) {
return nullptr;
}
// 加载资源
if (!rawResource->Load(path, fileSystem)) {
delete rawResource;
return nullptr;
}
// 更新内存使用
currentMemoryUsage += rawResource->GetMemoryUsage();
// 存储并返回
std::shared_ptr<IResource> resource(rawResource);
resources[path] = resource;
return std::dynamic_pointer_cast<T>(resource);
}
// 异步加载资源
template<typename T>
std::future<std::shared_ptr<T>> LoadResourceAsync(const std::string& path) {
// 检查资源是否已加载
auto it = resources.find(path);
if (it != resources.end()) {
std::promise<std::shared_ptr<T>> promise;
promise.set_value(std::dynamic_pointer_cast<T>(it->second));
return promise.get_future();
}
// 检查是否正在加载
{
std::lock_guard<std::mutex> lock(loadingMutex);
auto loadingIt = loadingResources.find(path);
if (loadingIt != loadingResources.end()) {
// 创建转换未来结果的任务
return std::async(std::launch::deferred, [future = loadingIt->second]() {
return std::dynamic_pointer_cast<T>(future.get());
});
}
}
// 提交加载任务
auto future = loadingThreadPool.Submit<std::shared_ptr<IResource>>([this, path]() {
// 提取扩展名
std::string extension = GetFileExtension(path);
// 查找工厂
auto factoryIt = factories.find(extension);
if (factoryIt == factories.end()) {
return std::shared_ptr<IResource>();
}
// 创建资源
IResource* rawResource = factoryIt->second();
if (!rawResource) {
return std::shared_ptr<IResource>();
}
// 加载资源
if (!rawResource->Load(path, fileSystem)) {
delete rawResource;
return std::shared_ptr<IResource>();
}
// 更新内存使用
currentMemoryUsage += rawResource->GetMemoryUsage();
// 创建共享指针
return std::shared_ptr<IResource>(rawResource);
});
// 存储加载任务
{
std::lock_guard<std::mutex> lock(loadingMutex);
loadingResources[path] = future;
}
// 创建转换未来结果的任务
return std::async(std::launch::deferred, [future, this, path]() {
auto resource = future.get();
// 从加载中列表移除
{
std::lock_guard<std::mutex> lock(loadingMutex);
loadingResources.erase(path);
}
// 如果加载成功,存储到资源缓存
if (resource) {
resources[path] = resource;
}
return std::dynamic_pointer_cast<T>(resource);
});
}
// 卸载资源
void UnloadResource(const std::string& path) {
auto it = resources.find(path);
if (it != resources.end()) {
// 更新内存使用
currentMemoryUsage -= it->second->GetMemoryUsage();
// 卸载并移除资源
it->second->Unload();
resources.erase(it);
}
}
// 卸载所有资源
void UnloadAll() {
for (auto& pair : resources) {
pair.second->Unload();
}
resources.clear();
currentMemoryUsage = 0;
}
// 设置内存预算
void SetMemoryBudget(size_t budget) {
memoryBudget = budget;
}
// 获取当前内存使用
size_t GetMemoryUsage() const {
return currentMemoryUsage;
}
private:
// 获取文件扩展名
std::string GetFileExtension(const std::string& path) {
size_t dotPos = path.find_last_of('.');
if (dotPos != std::string::npos) {
return path.substr(dotPos + 1);
}
return "";
}
// 检查异步加载完成的资源
void CheckLoadingResources() {
std::lock_guard<std::mutex> lock(loadingMutex);
std::vector<std::string> completed;
for (auto& pair : loadingResources) {
if (pair.second.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
try {
auto resource = pair.second.get();
if (resource) {
resources[pair.first] = resource;
}
} catch (const std::exception& e) {
// 处理加载错误
std::cerr << "Error loading resource " << pair.first
<< ": " << e.what() << std::endl;
}
completed.push_back(pair.first);
}
}
// 移除已完成的加载任务
for (const auto& path : completed) {
loadingResources.erase(path);
}
}
// 等待所有资源加载完成
void WaitForAllLoading() {
std::vector<std::string> paths;
{
std::lock_guard<std::mutex> lock(loadingMutex);
for (const auto& pair : loadingResources) {
paths.push_back(pair.first);
}
}
for (const auto& path : paths) {
try {
auto future = loadingResources[path];
auto resource = future.get();
if (resource) {
resources[path] = resource;
}
} catch (const std::exception& e) {
// 处理加载错误
std::cerr << "Error loading resource " << path
<< ": " << e.what() << std::endl;
}
std::lock_guard<std::mutex> lock(loadingMutex);
loadingResources.erase(path);
}
}
// 释放不常用资源
void ReleaseUnusedResources() {
// 在实际实现中,应该跟踪资源使用频率和最后访问时间
// 这里简单实现为释放一定比例的资源
// 按内存使用量排序资源
std::vector<std::pair<std::string, std::shared_ptr<IResource>>> resourceList;
for (const auto& pair : resources) {
// 检查是否只有资源管理器持有引用
if (pair.second.use_count() == 1) {
resourceList.push_back(pair);
}
}
// 按内存使用量排序(降序)
std::sort(resourceList.begin(), resourceList.end(),
[](const auto& a, const auto& b) {
return a.second->GetMemoryUsage() > b.second->GetMemoryUsage();
});
// 释放一定比例的资源,直到内存使用低于预算
for (const auto& pair : resourceList) {
if (currentMemoryUsage <= memoryBudget * 0.8) {
break;
}
// 卸载资源
currentMemoryUsage -= pair.second->GetMemoryUsage();
pair.second->Unload();
resources.erase(pair.first);
}
}
};
5.3 容器
游戏开发中需要使用各种专用容器来高效管理游戏对象和数据。
5.3.1 动态数组
游戏专用的动态数组实现,优化了内存分配和访问效率:
cpp
// 游戏专用动态数组
template<typename T, typename Allocator = std::allocator<T>>
class GameArray {
private:
T* data;
size_t size;
size_t capacity;
Allocator allocator;
public:
// 构造函数
explicit GameArray(size_t initialCapacity = 16, const Allocator& alloc = Allocator())
: data(nullptr), size(0), capacity(0), allocator(alloc) {
Reserve(initialCapacity);
}
// 析构函数
~GameArray() {
Clear();
if (data) {
allocator.deallocate(data, capacity);
data = nullptr;
}
}
// 移动构造函数
GameArray(GameArray&& other) noexcept
: data(other.data), size(other.size), capacity(other.capacity),
allocator(std::move(other.allocator)) {
other.data = nullptr;
other.size = 0;
other.capacity = 0;
}
// 移动赋值运算符
GameArray& operator=(GameArray&& other) noexcept {
if (this != &other) {
Clear();
if (data) {
allocator.deallocate(data, capacity);
}
data = other.data;
size = other.size;
capacity = other.capacity;
allocator = std::move(other.allocator);
other.data = nullptr;
other.size = 0;
other.capacity = 0;
}
return *this;
}
// 禁用拷贝构造和赋值
GameArray(const GameArray&) = delete;
GameArray& operator=(const GameArray&) = delete;
// 添加元素
void Add(const T& value) {
if (size >= capacity) {
Grow();
}
// 构造新元素
new (data + size) T(value);
size++;
}
// 通过移动添加元素
void Add(T&& value) {
if (size >= capacity) {
Grow();
}
// 移动构造新元素
new (data + size) T(std::move(value));
size++;
}
// 批量添加元素
void AddRange(const T* values, size_t count) {
if (size + count > capacity) {
Reserve(std::max(capacity * 2, size + count));
}
// 复制元素
for (size_t i = 0; i < count; i++) {
new (data + size + i) T(values[i]);
}
size += count;
}
// 插入元素
void Insert(size_t index, const T& value) {
if (index > size) {
return;
}
if (size >= capacity) {
Grow();
}
// 移动元素
for (size_t i = size; i > index; i--) {
new (data + i) T(std::move(data[i - 1]));
data[i - 1].~T();
}
// 插入新元素
new (data + index) T(value);
size++;
}
// 移除元素
void RemoveAt(size_t index) {
if (index >= size) {
return;
}
// 移动元素
data[index].~T();
for (size_t i = index; i < size - 1; i++) {
new (data + i) T(std::move(data[i + 1]));
data[i + 1].~T();
}
size--;
}
// 移除指定值
bool Remove(const T& value) {
for (size_t i = 0; i < size; i++) {
if (data[i] == value) {
RemoveAt(i);
return true;
}
}
return false;
}
// 通过交换最后一个元素的方式快速移除
void RemoveSwap(size_t index) {
if (index >= size) {
return;
}
data[index].~T();
if (index < size - 1) {
new (data + index) T(std::move(data[size - 1]));
data[size - 1].~T();
}
size--;
}
// 清空数组
void Clear() {
// 调用所有元素的析构函数
for (size_t i = 0; i < size; i++) {
data[i].~T();
}
size = 0;
}
// 调整数组大小
void Resize(size_t newSize) {
if (newSize > capacity) {
Reserve(newSize);
}
if (newSize > size) {
// 构造新元素
for (size_t i = size; i < newSize; i++) {
new (data + i) T();
}
} else if (newSize < size) {
// 销毁多余元素
for (size_t i = newSize; i < size; i++) {
data[i].~T();
}
}
size = newSize;
}
// 预留容量
void Reserve(size_t newCapacity) {
if (newCapacity <= capacity) {
return;
}
// 分配新内存
T* newData = allocator.allocate(newCapacity);
// 移动现有元素
for (size_t i = 0; i < size; i++) {
new (newData + i) T(std::move(data[i]));
data[i].~T();
}
// 释放旧内存
if (data) {
allocator.deallocate(data, capacity);
}
data = newData;
capacity = newCapacity;
}
// 收缩容量以适应当前大小
void ShrinkToFit() {
if (size == capacity) {
return;
}
if (size == 0) {
if (data) {
allocator.deallocate(data, capacity);
data = nullptr;
}
capacity = 0;
return;
}
// 分配新内存
T* newData = allocator.allocate(size);
// 移动现有元素
for (size_t i = 0; i < size; i++) {
new (newData + i) T(std::move(data[i]));
data[i].~T();
}
// 释放旧内存
if (data) {
allocator.deallocate(data, capacity);
}
data = newData;
capacity = size;
}
// 访问元素
T& operator[](size_t index) {
return data[index];
}
const T& operator[](size_t index) const {
return data[index];
}
// 获取第一个元素
T& First() {
return data[0];
}
const T& First() const {
return data[0];
}
// 获取最后一个元素
T& Last() {
return data[size - 1];
}
const T& Last() const {
return data[size - 1];
}
// 获取大小
size_t Size() const {
return size;
}
// 获取容量
size_t Capacity() const {
return capacity;
}
// 检查是否为空
bool IsEmpty() const {
return size == 0;
}
// 迭代器
T* begin() { return data; }
const T* begin() const { return data; }
T* end() { return data + size; }
const T* end() const { return data + size; }
private:
// 扩展容量
void Grow() {
size_t newCapacity = capacity == 0 ? 16 : capacity * 2;
Reserve(newCapacity);
}
};
5.3.2 哈希表
游戏中常用的哈希表实现,针对游戏特定需求进行了优化:
cpp
// 简单的哈希表实现
template<typename Key, typename Value, typename HashFunc = std::hash<Key>>
class HashMap {
private:
struct Node {
Key key;
Value value;
Node* next;
Node(const Key& k, const Value& v, Node* n = nullptr)
: key(k), value(v), next(n) {}
Node(const Key& k, Value&& v, Node* n = nullptr)
: key(k), value(std::move(v)), next(n) {}
};
Node** buckets;
size_t bucketCount;
size_t elementCount;
HashFunc hasher;
public:
// 构造函数
explicit HashMap(size_t initialBuckets = 16, const HashFunc& hash = HashFunc())
: buckets(nullptr), bucketCount(0), elementCount(0), hasher(hash) {
Rehash(initialBuckets);
}
// 析构函数
~HashMap() {
Clear();
delete[] buckets;
}
// 移动构造函数
HashMap(HashMap&& other) noexcept
: buckets(other.buckets), bucketCount(other.bucketCount),
elementCount(other.elementCount), hasher(std::move(other.hasher)) {
other.buckets = nullptr;
other.bucketCount = 0;
other.elementCount = 0;
}
// 移动赋值运算符
HashMap& operator=(HashMap&& other) noexcept {
if (this != &other) {
Clear();
delete[] buckets;
buckets = other.buckets;
bucketCount = other.bucketCount;
elementCount = other.elementCount;
hasher = std::move(other.hasher);
other.buckets = nullptr;
other.bucketCount = 0;
other.elementCount = 0;
}
return *this;
}
// 禁用拷贝构造和赋值
HashMap(const HashMap&) = delete;
HashMap& operator=(const HashMap&) = delete;
// 添加或更新键值对
void Set(const Key& key, const Value& value) {
// 检查是否需要扩容
if (elementCount >= bucketCount * 0.75) {
Rehash(bucketCount * 2);
}
size_t index = hasher(key) % bucketCount;
// 查找现有节点
Node* current = buckets[index];
while (current) {
if (current->key == key) {
// 更新现有值
current->value = value;
return;
}
current = current->next;
}
// 添加新节点
buckets[index] = new Node(key, value, buckets[index]);
elementCount++;
}
// 通过移动添加或更新键值对
void Set(const Key& key, Value&& value) {
// 检查是否需要扩容
if (elementCount >= bucketCount * 0.75) {
Rehash(bucketCount * 2);
}
size_t index = hasher(key) % bucketCount;
// 查找现有节点
Node* current = buckets[index];
while (current) {
if (current->key == key) {
// 更新现有值
current->value = std::move(value);
return;
}
current = current->next;
}
// 添加新节点
buckets[index] = new Node(key, std::move(value), buckets[index]);
elementCount++;
}
// 获取值
bool Get(const Key& key, Value& outValue) const {
if (bucketCount == 0) {
return false;
}
size_t index = hasher(key) % bucketCount;
Node* current = buckets[index];
while (current) {
if (current->key == key) {
outValue = current->value;
return true;
}
current = current->next;
}
return false;
}
// 检查键是否存在
bool Contains(const Key& key) const {
if (bucketCount == 0) {
return false;
}
size_t index = hasher(key) % bucketCount;
Node* current = buckets[index];
while (current) {
if (current->key == key) {
return true;
}
current = current->next;
}
return false;
}
// 移除键值对
bool Remove(const Key& key) {
if (bucketCount == 0) {
return false;
}
size_t index = hasher(key) % bucketCount;
Node* prev = nullptr;
Node* current = buckets[index];
while (current) {
if (current->key == key) {
// 移除节点
if (prev) {
prev->next = current->next;
} else {
buckets[index] = current->next;
}
delete current;
elementCount--;
return true;
}
prev = current;
current = current->next;
}
return false;
}
// 清空哈希表
void Clear() {
for (size_t i = 0; i < bucketCount; i++) {
Node* current = buckets[i];
while (current) {
Node* next = current->next;
delete current;
current = next;
}
buckets[i] = nullptr;
}
elementCount = 0;
}
// 获取元素数量
size_t Size() const {
return elementCount;
}
// 检查是否为空
bool IsEmpty() const {
return elementCount == 0;
}
// 获取所有键
GameArray<Key> GetKeys() const {
GameArray<Key> keys;
keys.Reserve(elementCount);
for (size_t i = 0; i < bucketCount; i++) {
Node* current = buckets[i];
while (current) {
keys.Add(current->key);
current = current->next;
}
}
return keys;
}
// 获取所有值
GameArray<Value> GetValues() const {
GameArray<Value> values;
values.Reserve(elementCount);
for (size_t i = 0; i < bucketCount; i++) {
Node* current = buckets[i];
while (current) {
values.Add(current->value);
current = current->next;
}
}
return values;
}
// 迭代器支持
class Iterator {
private:
const HashMap* hashMap;
size_t bucketIndex;
Node* current;
public:
Iterator(const HashMap* map, size_t index, Node* node)
: hashMap(map), bucketIndex(index), current(node) {
// 如果当前位置为空,移动到下一个有效位置
if (current == nullptr && hashMap) {
MoveToNextNode();
}
}
std::pair<const Key&, Value&> operator*() const {
return {current->key, current->value};
}
Iterator& operator++() {
if (current) {
current = current->next;
if (current == nullptr) {
MoveToNextNode();
}
}
return *this;
}
bool operator==(const Iterator& other) const {
return hashMap == other.hashMap &&
bucketIndex == other.bucketIndex &&
current == other.current;
}
bool operator!=(const Iterator& other) const {
return !(*this == other);
}
private:
void MoveToNextNode() {
while (++bucketIndex < hashMap->bucketCount) {
if (hashMap->buckets[bucketIndex]) {
current = hashMap->buckets[bucketIndex];
return;
}
}
current = nullptr; // 到达末尾
}
};
Iterator begin() const {
if (bucketCount == 0 || IsEmpty()) {
return end();
}
// 找到第一个非空桶
for (size_t i = 0; i < bucketCount; i++) {
if (buckets[i]) {
return Iterator(this, i, buckets[i]);
}
}
return end();
}
Iterator end() const {
return Iterator(this, bucketCount, nullptr);
}
private:
// 重新哈希表
void Rehash(size_t newBucketCount) {
if (newBucketCount < 1) {
newBucketCount = 1;
}
// 分配新桶数组
Node** newBuckets = new Node*[newBucketCount]();
// 将现有元素重新分配到新桶
for (size_t i = 0; i < bucketCount; i++) {
Node* current = buckets[i];
while (current) {
Node* next = current->next;
// 计算新的桶索引
size_t newIndex = hasher(current->key) % newBucketCount;
// 将节点插入新桶
current->next = newBuckets[newIndex];
newBuckets[newIndex] = current;
current = next;
}
}
// 释放旧桶数组
delete[] buckets;
buckets = newBuckets;
bucketCount = newBucketCount;
}
};
5.3.3 对象池
对象池用于高效管理频繁创建和销毁的游戏对象:
cpp
// 对象池模板
template<typename T>
class ObjectPool {
private:
struct PoolItem {
T* object;
bool inUse;
};
GameArray<PoolItem> pool;
size_t growSize;
public:
// 构造函数
explicit ObjectPool(size_t initialSize = 32, size_t growAmount = 16)
: growSize(growAmount) {
// 预分配对象
Grow(initialSize);
}
// 析构函数
~ObjectPool() {
// 销毁所有对象
for (auto& item : pool) {
delete item.object;
}
}
// 获取对象
T* Acquire() {
// 查找未使用的对象
for (auto& item : pool) {
if (!item.inUse) {
item.inUse = true;
return item.object;
}
}
// 所有对象都在使用中,扩展池
Grow(growSize);
// 获取新创建的对象
PoolItem& item = pool[pool.Size() - growSize];
item.inUse = true;
return item.object;
}
// 释放对象
void Release(T* object) {
for (auto& item : pool) {
if (item.object == object) {
// 重置对象状态
item.object->Reset();
item.inUse = false;
return;
}
}
}
// 获取总对象数
size_t TotalObjects() const {
return pool.Size();
}
// 获取活动对象数
size_t ActiveObjects() const {
size_t count = 0;
for (const auto& item : pool) {
if (item.inUse) {
count++;
}
}
return count;
}
private:
// 扩展对象池
void Grow(size_t amount) {
size_t oldSize = pool.Size();
pool.Resize(oldSize + amount);
for (size_t i = oldSize; i < pool.Size(); i++) {
pool[i].object = new T();
pool[i].inUse = false;
}
}
};
// 使用对象池的粒子系统示例
class ParticleSystem {
private:
struct Particle {
Vector3 position;
Vector3 velocity;
float lifetime;
float maxLifetime;
float size;
Color color;
// 重置粒子状态
void Reset() {
position = Vector3();
velocity = Vector3();
lifetime = 0.0f;
maxLifetime = 0.0f;
size = 1.0f;
color = Color(1.0f, 1.0f, 1.0f, 1.0f);
}
};
ObjectPool<Particle> particlePool;
GameArray<Particle*> activeParticles;
Vector3 emitterPosition;
public:
ParticleSystem(const Vector3& position, size_t maxParticles = 1000)
: emitterPosition(position), particlePool(maxParticles) {
activeParticles.Reserve(maxParticles);
}
// 发射粒子
void Emit(int count, const Vector3& direction, float spread,
float minSpeed, float maxSpeed, float minLifetime, float maxLifetime) {
for (int i = 0; i < count; i++) {
Particle* particle = particlePool.Acquire();
// 设置粒子属性
particle->position = emitterPosition;
// 计算随机速度方向
Vector3 velocity = direction;
if (spread > 0.0f) {
// 添加随机偏移
float angle = spread * (rand() / static_cast<float>(RAND_MAX));
float yaw = 2.0f * M_PI * (rand() / static_cast<float>(RAND_MAX));
// 围绕方向向量创建随机偏移
Vector3 up = (std::abs(direction.y) < 0.99f) ?
Vector3(0.0f, 1.0f, 0.0f) : Vector3(1.0f, 0.0f, 0.0f);
Vector3 right = Vector3::Cross(direction, up).Normalized();
up = Vector3::Cross(right, direction).Normalized();
// 计算偏移方向
float cosAngle = std::cos(angle);
float sinAngle = std::sin(angle);
float cosYaw = std::cos(yaw);
float sinYaw = std::sin(yaw);
velocity = direction * cosAngle +
(right * cosYaw + up * sinYaw) * sinAngle;
}
// 设置随机速度
float speed = minSpeed + (maxSpeed - minSpeed) *
(rand() / static_cast<float>(RAND_MAX));
particle->velocity = velocity * speed;
// 设置寿命
particle->maxLifetime = minLifetime + (maxLifetime - minLifetime) *
(rand() / static_cast<float>(RAND_MAX));
particle->lifetime = particle->maxLifetime;
// 设置大小和颜色
particle->size = 0.5f + 1.0f * (rand() / static_cast<float>(RAND_MAX));
particle->color = Color(1.0f, 1.0f, 1.0f, 1.0f);
// 添加到活动粒子列表
activeParticles.Add(particle);
}
}
// 更新粒子系统
void Update(float deltaTime) {
for (int i = activeParticles.Size() - 1; i >= 0; i--) {
Particle* particle = activeParticles[i];
// 更新寿命
particle->lifetime -= deltaTime;
if (particle->lifetime <= 0.0f) {
// 粒子生命周期结束
particlePool.Release(particle);
activeParticles.RemoveSwap(i);
continue;
}
// 更新位置
particle->position += particle->velocity * deltaTime;
// 更新颜色(透明度衰减)
float lifeRatio = particle->lifetime / particle->maxLifetime;
particle->color.a = lifeRatio;
// 更新大小(可以随时间变化)
particle->size = particle->size * 0.99f;
}
}
// 渲染粒子
void Render(Renderer* renderer) {
for (Particle* particle : activeParticles) {
renderer->DrawBillboard(
particle->position,
particle->size,
particle->color
);
}
}
// 设置发射器位置
void SetEmitterPosition(const Vector3& position) {
emitterPosition = position;
}
// 获取活动粒子数量
size_t GetActiveParticleCount() const {
return activeParticles.Size();
}
};
5.3.4 树形结构
树结构在游戏中常用于场景图、UI层次结构等:
cpp
// 树节点接口
template<typename T>
class TreeNode {
private:
T data;
TreeNode* parent;
GameArray<TreeNode*> children;
public:
// 构造函数
explicit TreeNode(const T& value)
: data(value), parent(nullptr) {}
// 析构函数
~TreeNode() {
// 销毁所有子节点
for (TreeNode* child : children) {
delete child;
}
}
// 添加子节点
TreeNode* AddChild(const T& value) {
TreeNode* child = new TreeNode(value);
child->parent = this;
children.Add(child);
return child;
}
// 添加现有节点作为子节点
void AddChild(TreeNode* child) {
if (child) {
// 从原父节点移除
if (child->parent) {
child->parent->RemoveChild(child);
}
child->parent = this;
children.Add(child);
}
}
// 移除子节点
bool RemoveChild(TreeNode* child) {
for (size_t i = 0; i < children.Size(); i++) {
if (children[i] == child) {
children[i]->parent = nullptr;
children.RemoveAt(i);
return true;
}
}
return false;
}
// 移除并销毁子节点
bool DestroyChild(TreeNode* child) {
for (size_t i = 0; i < children.Size(); i++) {
if (children[i] == child) {
delete children[i];
children.RemoveAt(i);
return true;
}
}
return false;
}
// 获取数据
T& GetData() { return data; }
const T& GetData() const { return data; }
// 设置数据
void SetData(const T& value) { data = value; }
// 获取父节点
TreeNode* GetParent() const { return parent; }
// 获取子节点列表
const GameArray<TreeNode*>& GetChildren() const { return children; }
// 获取子节点数量
size_t GetChildCount() const { return children.Size(); }
// 获取特定索引的子节点
TreeNode* GetChild(size_t index) const {
if (index < children.Size()) {
return children[index];
}
return nullptr;
}
// 获取树的深度
int GetDepth() const {
int maxChildDepth = 0;
for (TreeNode* child : children) {
int childDepth = child->GetDepth();
if (childDepth > maxChildDepth) {
maxChildDepth = childDepth;
}
}
return 1 + maxChildDepth;
}
// 获取节点的深度(从根到此节点的距离)
int GetNodeDepth() const {
int depth = 0;
TreeNode* current = parent;
while (current) {
depth++;
current = current->parent;
}
return depth;
}
// 遍历树
void Traverse(std::function<void(TreeNode*)> callback) {
callback(this);
for (TreeNode* child : children) {
child->Traverse(callback);
}
}
};
// 场景图实现示例
class SceneNode {
public:
enum class NodeType {
Empty,
Mesh,
Light,
Camera,
Particle,
Group
};
private:
std::string name;
NodeType type;
Transform localTransform;
Transform worldTransform;
bool worldTransformDirty;
SceneNode* parent;
GameArray<SceneNode*> children;
// 节点特定数据
union {
struct {
uint32_t meshId;
uint32_t materialId;
} mesh;
struct {
LightType type;
Color color;
float intensity;
float range;
} light;
struct {
float fov;
float nearPlane;
float farPlane;
} camera;
struct {
ParticleSystem* system;
} particle;
};
public:
SceneNode(const std::string& nodeName, NodeType nodeType)
: name(nodeName), type(nodeType), worldTransformDirty(true), parent(nullptr) {
// 初始化特定类型数据
switch (type) {
case NodeType::Mesh:
mesh.meshId = 0;
mesh.materialId = 0;
break;
case NodeType::Light:
light.type = LightType::Point;
light.color = Color(1.0f, 1.0f, 1.0f, 1.0f);
light.intensity = 1.0f;
light.range = 10.0f;
break;
case NodeType::Camera:
camera.fov = 60.0f;
camera.nearPlane = 0.1f;
camera.farPlane = 1000.0f;
break;
case NodeType::Particle:
particle.system = nullptr;
break;
default:
break;
}
}
~SceneNode() {
// 清理子节点
for (SceneNode* child : children) {
delete child;
}
// 清理特定资源
if (type == NodeType::Particle && particle.system) {
delete particle.system;
}
}
// 添加子节点
void AddChild(SceneNode* child) {
if (child && child != this) {
// 从原父节点移除
if (child->parent) {
child->parent->RemoveChild(child);
}
child->parent = this;
children.Add(child);
// 标记世界变换为脏
child->SetWorldTransformDirty();
}
}
// 移除子节点
bool RemoveChild(SceneNode* child) {
for (size_t i = 0; i < children.Size(); i++) {
if (children[i] == child) {
children[i]->parent = nullptr;
children.RemoveAt(i);
return true;
}
}
return false;
}
// 设置局部变换
void SetLocalTransform(const Transform& transform) {
localTransform = transform;
SetWorldTransformDirty();
}
// 获取局部变换
const Transform& GetLocalTransform() const {
return localTransform;
}
// 获取世界变换
const Transform& GetWorldTransform() {
if (worldTransformDirty) {
UpdateWorldTransform();
}
return worldTransform;
}
// 标记世界变换为脏(需要更新)
void SetWorldTransformDirty() {
worldTransformDirty = true;
// 传播到所有子节点
for (SceneNode* child : children) {
child->SetWorldTransformDirty();
}
}
// 更新世界变换
void UpdateWorldTransform() {
if (parent) {
// 组合父节点的世界变换和本地变换
worldTransform = parent->GetWorldTransform() * localTransform;
} else {
// 根节点,世界变换等于局部变换
worldTransform = localTransform;
}
worldTransformDirty = false;
}
// 更新节点和所有子节点
void Update(float deltaTime) {
// 更新自身
if (worldTransformDirty) {
UpdateWorldTransform();
}
// 节点类型特定更新
switch (type) {
case NodeType::Particle:
if (particle.system) {
// 更新粒子系统位置
particle.system->SetEmitterPosition(worldTransform.GetPosition());
particle.system->Update(deltaTime);
}
break;
// 其他类型更新...
default:
break;
}
// 更新子节点
for (SceneNode* child : children) {
child->Update(deltaTime);
}
}
// 渲染节点和所有子节点
void Render(Renderer* renderer) {
// 根据节点类型执行渲染
switch (type) {
case NodeType::Mesh:
renderer->DrawMesh(mesh.meshId, mesh.materialId, worldTransform.ToMatrix());
break;
case NodeType::Light:
renderer->AddLight(light.type, worldTransform.GetPosition(),
light.color, light.intensity, light.range);
break;
case NodeType::Particle:
if (particle.system) {
particle.system->Render(renderer);
}
break;
default:
break;
}
// 渲染子节点
for (SceneNode* child : children) {
child->Render(renderer);
}
}
// 获取节点名称
const std::string& GetName() const { return name; }
// 获取节点类型
NodeType GetType() const { return type; }
// 获取父节点
SceneNode* GetParent() const { return parent; }
// 获取子节点
const GameArray<SceneNode*>& GetChildren() const { return children; }
// 特定类型节点的设置方法
void SetMeshData(uint32_t meshId, uint32_t materialId) {
if (type == NodeType::Mesh) {
mesh.meshId = meshId;
mesh.materialId = materialId;
}
}
void SetLightData(LightType lightType, const Color& color, float intensity, float range) {
if (type == NodeType::Light) {
light.type = lightType;
light.color = color;
light.intensity = intensity;
light.range = range;
}
}
void SetCameraData(float fov, float nearPlane, float farPlane) {
if (type == NodeType::Camera) {
camera.fov = fov;
camera.nearPlane = nearPlane;
camera.farPlane = farPlane;
}
}
void SetParticleSystem(ParticleSystem* system) {
if (type == NodeType::Particle) {
// 释放现有系统
if (particle.system) {
delete particle.system;
}
particle.system = system;
}
}
};
5.3.5 事件队列
事件队列用于处理游戏内事件的传递和处理:
cpp
// 事件类型枚举
enum class EventType {
None,
KeyPress,
KeyRelease,
MouseMove,
MouseButtonPress,
MouseButtonRelease,
WindowResize,
WindowClose,
GameObjectCreated,
GameObjectDestroyed,
LevelLoaded,
PlayerDamage,
PlayerDeath,
GamePause,
GameResume,
Custom
};
// 基础事件类
class Event {
private:
EventType type;
double timestamp;
public:
Event(EventType eventType)
: type(eventType), timestamp(GetCurrentTime()) {}
virtual ~Event() = default;
// 获取事件类型
EventType GetType() const { return type; }
// 获取事件时间戳
double GetTimestamp() const { return timestamp; }
// 事件克隆方法(用于事件队列)
virtual Event* Clone() const {
return new Event(*this);
}
private:
// 获取当前时间(秒)
static double GetCurrentTime() {
auto now = std::chrono::high_resolution_clock::now();
auto duration = now.time_since_epoch();
return std::chrono::duration_cast<std::chrono::duration<double>>(duration).count();
}
};
// 键盘事件
class KeyEvent : public Event {
private:
int keyCode;
int modifiers;
public:
KeyEvent(EventType eventType, int key, int mods)
: Event(eventType), keyCode(key), modifiers(mods) {}
// 获取按键代码
int GetKeyCode() const { return keyCode; }
// 获取修饰键(Shift, Ctrl, Alt 等)
int GetModifiers() const { return modifiers; }
// 克隆事件
virtual Event* Clone() const override {
return new KeyEvent(*this);
}
};
// 鼠标移动事件
class MouseMoveEvent : public Event {
private:
float x;
float y;
float deltaX;
float deltaY;
public:
MouseMoveEvent(float posX, float posY, float dx, float dy)
: Event(EventType::MouseMove), x(posX), y(posY), deltaX(dx), deltaY(dy) {}
// 获取鼠标位置
float GetX() const { return x; }
float GetY() const { return y; }
// 获取鼠标移动增量
float GetDeltaX() const { return deltaX; }
float GetDeltaY() const { return deltaY; }
// 克隆事件
virtual Event* Clone() const override {
return new MouseMoveEvent(*this);
}
};
// 自定义事件基类
class CustomEvent : public Event {
private:
std::string name;
public:
CustomEvent(const std::string& eventName)
: Event(EventType::Custom), name(eventName) {}
// 获取自定义事件名称
const std::string& GetName() const { return name; }
// 克隆事件
virtual Event* Clone() const override {
return new CustomEvent(*this);
}
};
// 事件队列
class EventQueue {
private:
// 事件队列
std::queue<Event*> events;
std::mutex queueMutex;
// 事件处理器
std::unordered_map<EventType,
std::vector<std::function<void(const Event&)>>> handlers;
std::unordered_map<std::string,
std::vector<std::function<void(const CustomEvent&)>>> customHandlers;
public:
~EventQueue() {
ClearQueue();
}
// 添加事件到队列
void EnqueueEvent(const Event& event) {
std::lock_guard<std::mutex> lock(queueMutex);
events.push(event.Clone());
}
// 处理队列中的所有事件
void ProcessEvents() {
std::queue<Event*> eventsCopy;
{
std::lock_guard<std::mutex> lock(queueMutex);
eventsCopy = std::move(events);
}
while (!eventsCopy.empty()) {
Event* event = eventsCopy.front();
eventsCopy.pop();
// 分发事件
DispatchEvent(*event);
// 释放事件
delete event;
}
}
// 注册事件处理器
template<typename T>
void RegisterHandler(EventType type, std::function<void(const T&)> handler) {
handlers[type].push_back(
[handler](const Event& e) {
handler(static_cast<const T&>(e));
}
);
}
// 注册自定义事件处理器
template<typename T>
void RegisterCustomHandler(const std::string& eventName, std::function<void(const T&)> handler) {
customHandlers[eventName].push_back(
[handler](const CustomEvent& e) {
handler(static_cast<const T&>(e));
}
);
}
// 清空事件队列
void ClearQueue() {
std::lock_guard<std::mutex> lock(queueMutex);
while (!events.empty()) {
delete events.front();
events.pop();
}
}
private:
// 分发事件
void DispatchEvent(const Event& event) {
EventType type = event.GetType();
// 处理标准事件
auto it = handlers.find(type);
if (it != handlers.end()) {
for (const auto& handler : it->second) {
handler(event);
}
}
// 处理自定义事件
if (type == EventType::Custom) {
const CustomEvent& customEvent = static_cast<const CustomEvent&>(event);
auto customIt = customHandlers.find(customEvent.GetName());
if (customIt != customHandlers.end()) {
for (const auto& handler : customIt->second) {
handler(customEvent);
}
}
}
}
};
5.4 字符串
游戏开发中的字符串处理需要特别已关注性能和国际化支持。
5.4.1 字符串类
自定义的游戏字符串类,针对游戏开发优化:
cpp
// 游戏字符串类
class GameString {
private:
char* data;
size_t length;
size_t capacity;
// 小字符串优化 (SSO)
static constexpr size_t SSO_CAPACITY = 16;
char ssoBuffer[SSO_CAPACITY];
// 是否使用小字符串优化
bool UsingSso() const {
return data == ssoBuffer;
}
public:
// 构造函数
GameString() : data(ssoBuffer), length(0), capacity(SSO_CAPACITY) {
ssoBuffer[0] = '';
}
GameString(const char* str) : data(ssoBuffer), length(0), capacity(SSO_CAPACITY) {
if (str) {
length = strlen(str);
if (length < SSO_CAPACITY) {
// 使用小字符串优化
memcpy(ssoBuffer, str, length + 1);
} else {
// 分配堆内存
capacity = length + 1;
data = new char[capacity];
memcpy(data, str, length + 1);
}
} else {
ssoBuffer[0] = '';
}
}
GameString(const char* str, size_t len) : data(ssoBuffer), length(0), capacity(SSO_CAPACITY) {
if (str && len > 0) {
length = len;
if (length < SSO_CAPACITY) {
// 使用小字符串优化
memcpy(ssoBuffer, str, length);
ssoBuffer[length] = '';
} else {
// 分配堆内存
capacity = length + 1;
data = new char[capacity];
memcpy(data, str, length);
data[length] = '';
}
} else {
ssoBuffer[0] = '';
}
}
// 拷贝构造函数
GameString(const GameString& other) : data(ssoBuffer), length(other.length), capacity(SSO_CAPACITY) {
if (other.length < SSO_CAPACITY) {
// 使用小字符串优化
memcpy(ssoBuffer, other.data, length + 1);
} else {
// 分配堆内存
capacity = length + 1;
data = new char[capacity];
memcpy(data, other.data, length + 1);
}
}
// 移动构造函数
GameString(GameString&& other) noexcept : data(ssoBuffer), length(other.length), capacity(SSO_CAPACITY) {
if (other.UsingSso()) {
// 源字符串使用SSO,拷贝内容
memcpy(ssoBuffer, other.ssoBuffer, length + 1);
} else {
// 源字符串在堆上,移动指针
data = other.data;
capacity = other.capacity;
other.data = other.ssoBuffer;
other.length = 0;
other.capacity = SSO_CAPACITY;
other.ssoBuffer[0] = '';
}
}
// 析构函数
~GameString() {
if (!UsingSso()) {
delete[] data;
}
}
// 拷贝赋值运算符
GameString& operator=(const GameString& other) {
if (this != &other) {
// 释放现有资源
if (!UsingSso()) {
delete[] data;
}
length = other.length;
if (other.length < SSO_CAPACITY) {
// 使用小字符串优化
data = ssoBuffer;
capacity = SSO_CAPACITY;
memcpy(ssoBuffer, other.data, length + 1);
} else {
// 分配堆内存
capacity = length + 1;
data = new char[capacity];
memcpy(data, other.data, length + 1);
}
}
return *this;
}
// 移动赋值运算符
GameString& operator=(GameString&& other) noexcept {
if (this != &other) {
// 释放现有资源
if (!UsingSso()) {
delete[] data;
}
length = other.length;
if (other.UsingSso()) {
// 源字符串使用SSO,拷贝内容
data = ssoBuffer;
capacity = SSO_CAPACITY;
memcpy(ssoBuffer, other.ssoBuffer, length + 1);
} else {
// 源字符串在堆上,移动指针
data = other.data;
capacity =
cpp
// 源字符串在堆上,移动指针
data = other.data;
capacity = other.capacity;
other.data = other.ssoBuffer;
other.length = 0;
other.capacity = SSO_CAPACITY;
other.ssoBuffer[0] = '';
}
}
return *this;
}
// 字符串连接
GameString operator+(const GameString& other) const {
GameString result;
result.length = length + other.length;
if (result.length < SSO_CAPACITY) {
// 结果可以使用SSO
memcpy(result.ssoBuffer, data, length);
memcpy(result.ssoBuffer + length, other.data, other.length + 1);
} else {
// 结果需要堆分配
result.capacity = result.length + 1;
result.data = new char[result.capacity];
memcpy(result.data, data, length);
memcpy(result.data + length, other.data, other.length + 1);
}
return result;
}
// 添加字符串
GameString& operator+=(const GameString& other) {
size_t newLength = length + other.length;
if (newLength < capacity) {
// 有足够空间,直接追加
memcpy(data + length, other.data, other.length + 1);
} else {
// 需要重新分配
size_t newCapacity = std::max(capacity * 2, newLength + 1);
char* newData = new char[newCapacity];
memcpy(newData, data, length);
memcpy(newData + length, other.data, other.length + 1);
if (!UsingSso()) {
delete[] data;
}
data = newData;
capacity = newCapacity;
}
length = newLength;
return *this;
}
// 访问字符
char& operator[](size_t index) {
return data[index];
}
const char& operator[](size_t index) const {
return data[index];
}
// 比较运算符
bool operator==(const GameString& other) const {
if (length != other.length) {
return false;
}
return memcmp(data, other.data, length) == 0;
}
bool operator!=(const GameString& other) const {
return !(*this == other);
}
// 获取C风格字符串
const char* CStr() const {
return data;
}
// 获取长度
size_t Length() const {
return length;
}
// 获取容量
size_t Capacity() const {
return capacity;
}
// 是否为空
bool IsEmpty() const {
return length == 0;
}
// 清空字符串
void Clear() {
if (!UsingSso()) {
delete[] data;
data = ssoBuffer;
capacity = SSO_CAPACITY;
}
length = 0;
ssoBuffer[0] = '';
}
// 子字符串
GameString Substring(size_t start, size_t len = SIZE_MAX) const {
if (start >= length) {
return GameString();
}
len = std::min(len, length - start);
return GameString(data + start, len);
}
// 查找字符
size_t Find(char c, size_t start = 0) const {
if (start >= length) {
return SIZE_MAX;
}
for (size_t i = start; i < length; i++) {
if (data[i] == c) {
return i;
}
}
return SIZE_MAX;
}
// 查找子字符串
size_t Find(const GameString& str, size_t start = 0) const {
if (start >= length || str.length > length - start) {
return SIZE_MAX;
}
if (str.length == 0) {
return start;
}
for (size_t i = start; i <= length - str.length; i++) {
if (memcmp(data + i, str.data, str.length) == 0) {
return i;
}
}
return SIZE_MAX;
}
// 替换字符
void Replace(char oldChar, char newChar) {
for (size_t i = 0; i < length; i++) {
if (data[i] == oldChar) {
data[i] = newChar;
}
}
}
// 替换子字符串
void Replace(const GameString& oldStr, const GameString& newStr) {
if (oldStr.IsEmpty() || oldStr == newStr) {
return;
}
size_t pos = 0;
while ((pos = Find(oldStr, pos)) != SIZE_MAX) {
// 计算替换后的新长度
size_t newLength = length - oldStr.length + newStr.length;
if (newLength < capacity) {
// 有足够空间进行替换
// 移动后面的内容
if (oldStr.length != newStr.length) {
memmove(data + pos + newStr.length,
data + pos + oldStr.length,
length - pos - oldStr.length + 1);
}
// 复制新字符串
memcpy(data + pos, newStr.data, newStr.length);
length = newLength;
} else {
// 需要重新分配
size_t newCapacity = std::max(capacity * 2, newLength + 1);
char* newData = new char[newCapacity];
// 复制前半部分
memcpy(newData, data, pos);
// 复制新字符串
memcpy(newData + pos, newStr.data, newStr.length);
// 复制后半部分
memcpy(newData + pos + newStr.length,
data + pos + oldStr.length,
length - pos - oldStr.length + 1);
if (!UsingSso()) {
delete[] data;
}
data = newData;
capacity = newCapacity;
length = newLength;
}
pos += newStr.length;
}
}
// 转换为小写
GameString ToLower() const {
GameString result(*this);
for (size_t i = 0; i < result.length; i++) {
if (result.data[i] >= 'A' && result.data[i] <= 'Z') {
result.data[i] += 32;
}
}
return result;
}
// 转换为大写
GameString ToUpper() const {
GameString result(*this);
for (size_t i = 0; i < result.length; i++) {
if (result.data[i] >= 'a' && result.data[i] <= 'z') {
result.data[i] -= 32;
}
}
return result;
}
// 修剪字符串前后的空白字符
GameString Trim() const {
if (IsEmpty()) {
return GameString();
}
size_t start = 0;
while (start < length && IsWhitespace(data[start])) {
start++;
}
if (start >= length) {
return GameString();
}
size_t end = length - 1;
while (end > start && IsWhitespace(data[end])) {
end--;
}
return Substring(start, end - start + 1);
}
// 分割字符串
GameArray<GameString> Split(char delimiter) const {
GameArray<GameString> result;
size_t start = 0;
size_t pos = 0;
while ((pos = Find(delimiter, start)) != SIZE_MAX) {
result.Add(Substring(start, pos - start));
start = pos + 1;
}
result.Add(Substring(start));
return result;
}
private:
// 检查字符是否为空白字符
static bool IsWhitespace(char c) {
return c == ' ' || c == ' ' || c == '
' || c == '
';
}
};
// 字符串格式化函数
template<typename... Args>
GameString Format(const char* format, Args... args) {
// 计算所需的缓冲区大小
int size = snprintf(nullptr, 0, format, args...);
if (size <= 0) {
return GameString();
}
// 分配缓冲区
char* buffer = new char[size + 1];
// 格式化字符串
snprintf(buffer, size + 1, format, args...);
// 创建结果字符串
GameString result(buffer);
// 释放缓冲区
delete[] buffer;
return result;
}
5.4.2 字符串哈希与池化
字符串哈希和池化技术可以提高字符串处理性能:
cpp
// 字符串哈希和池化
class StringPool {
private:
struct PooledString {
char* data;
size_t length;
size_t refCount;
size_t hash;
PooledString(const char* str, size_t len, size_t h)
: length(len), refCount(1), hash(h) {
data = new char[length + 1];
memcpy(data, str, length);
data[length] = '';
}
~PooledString() {
delete[] data;
}
};
// 哈希到字符串的映射
std::unordered_map<size_t, std::list<PooledString*>> stringMap;
// 互斥锁保证线程安全
std::mutex poolMutex;
// 单例实例
static StringPool* instance;
// 私有构造函数
StringPool() {}
public:
// 获取单例实例
static StringPool& GetInstance() {
if (!instance) {
instance = new StringPool();
}
return *instance;
}
// 清理单例
static void Cleanup() {
delete instance;
instance = nullptr;
}
// 析构函数
~StringPool() {
// 释放所有池化字符串
for (auto& pair : stringMap) {
for (auto* str : pair.second) {
delete str;
}
}
}
// 从池中获取字符串
const char* Intern(const char* str, size_t* outHash = nullptr) {
if (!str) {
return nullptr;
}
size_t length = strlen(str);
size_t hash = ComputeHash(str, length);
if (outHash) {
*outHash = hash;
}
std::lock_guard<std::mutex> lock(poolMutex);
// 查找已有字符串
auto it = stringMap.find(hash);
if (it != stringMap.end()) {
for (auto* pooledStr : it->second) {
if (pooledStr->length == length &&
memcmp(pooledStr->data, str, length) == 0) {
// 找到匹配的字符串,增加引用计数
pooledStr->refCount++;
return pooledStr->data;
}
}
}
// 没有找到,创建新条目
PooledString* pooledStr = new PooledString(str, length, hash);
stringMap[hash].push_back(pooledStr);
return pooledStr->data;
}
// 释放字符串引用
void Release(const char* str) {
if (!str) {
return;
}
std::lock_guard<std::mutex> lock(poolMutex);
for (auto& pair : stringMap) {
auto& list = pair.second;
for (auto it = list.begin(); it != list.end(); ++it) {
PooledString* pooledStr = *it;
if (pooledStr->data == str) {
pooledStr->refCount--;
if (pooledStr->refCount == 0) {
delete pooledStr;
list.erase(it);
// 如果列表为空,移除键
if (list.empty()) {
stringMap.erase(pair.first);
}
}
return;
}
}
}
}
// 获取字符串哈希
static size_t ComputeHash(const char* str, size_t length) {
// FNV-1a哈希算法
const size_t FNV_PRIME = 1099511628211ULL;
const size_t FNV_OFFSET_BASIS = 14695981039346656037ULL;
size_t hash = FNV_OFFSET_BASIS;
for (size_t i = 0; i < length; i++) {
hash ^= static_cast<size_t>(str[i]);
hash *= FNV_PRIME;
}
return hash;
}
// 获取当前池中字符串数量
size_t GetStringCount() const {
std::lock_guard<std::mutex> lock(poolMutex);
size_t count = 0;
for (const auto& pair : stringMap) {
count += pair.second.size();
}
return count;
}
// 获取当前池内存使用量
size_t GetMemoryUsage() const {
std::lock_guard<std::mutex> lock(poolMutex);
size_t usage = 0;
for (const auto& pair : stringMap) {
for (const auto* str : pair.second) {
usage += str->length + 1 + sizeof(PooledString);
}
}
return usage;
}
};
// 初始化静态成员
StringPool* StringPool::instance = nullptr;
// 池化字符串类
class PooledString {
private:
const char* data;
size_t hash;
public:
// 默认构造函数
PooledString() : data(nullptr), hash(0) {}
// 从C字符串构造
PooledString(const char* str) : data(nullptr), hash(0) {
if (str) {
data = StringPool::GetInstance().Intern(str, &hash);
}
}
// 拷贝构造函数
PooledString(const PooledString& other) : data(other.data), hash(other.hash) {
if (data) {
data = StringPool::GetInstance().Intern(data);
}
}
// 移动构造函数
PooledString(PooledString&& other) noexcept : data(other.data), hash(other.hash) {
other.data = nullptr;
other.hash = 0;
}
// 析构函数
~PooledString() {
if (data) {
StringPool::GetInstance().Release(data);
}
}
// 拷贝赋值运算符
PooledString& operator=(const PooledString& other) {
if (this != &other) {
if (data) {
StringPool::GetInstance().Release(data);
}
data = other.data;
hash = other.hash;
if (data) {
data = StringPool::GetInstance().Intern(data);
}
}
return *this;
}
// 移动赋值运算符
PooledString& operator=(PooledString&& other) noexcept {
if (this != &other) {
if (data) {
StringPool::GetInstance().Release(data);
}
data = other.data;
hash = other.hash;
other.data = nullptr;
other.hash = 0;
}
return *this;
}
// 从C字符串赋值
PooledString& operator=(const char* str) {
if (data) {
StringPool::GetInstance().Release(data);
data = nullptr;
hash = 0;
}
if (str) {
data = StringPool::GetInstance().Intern(str, &hash);
}
return *this;
}
// 转换为C字符串
const char* CStr() const {
return data ? data : "";
}
// 获取哈希值
size_t GetHash() const {
return hash;
}
// 获取长度
size_t Length() const {
return data ? strlen(data) : 0;
}
// 是否为空
bool IsEmpty() const {
return data == nullptr || data[0] == '';
}
// 比较运算符
bool operator==(const PooledString& other) const {
// 相同的哈希和指针意味着相同的字符串
return hash == other.hash && data == other.data;
}
bool operator!=(const PooledString& other) const {
return !(*this == other);
}
// 用于STL容器的哈希函数
struct Hasher {
size_t operator()(const PooledString& str) const {
return str.GetHash();
}
};
};
5.4.3 字符串国际化
游戏国际化需要完善的字符串处理系统:
cpp
// 国际化文本管理
class LocalizationManager : public ISystem {
private:
struct LocalizedText {
PooledString key;
std::unordered_map<PooledString, GameString, PooledString::Hasher> translations;
};
// 当前语言
PooledString currentLanguage;
// 支持的语言列表
GameArray<PooledString> supportedLanguages;
// 本地化文本数据
std::unordered_map<PooledString, LocalizedText, PooledString::Hasher> localizedTexts;
// 文件系统
FileSystem* fileSystem;
public:
LocalizationManager() : fileSystem(nullptr) {
// 添加默认语言
supportedLanguages.Add(PooledString("en")); // 英语
currentLanguage = supportedLanguages[0];
}
// 实现ISystem接口
virtual bool Initialize() override {
Engine* engine = Engine::GetInstance();
fileSystem = engine->GetFileSystem();
if (!fileSystem) {
return false;
}
// 加载支持的语言列表
LoadSupportedLanguages();
// 加载系统语言或默认语言
PooledString systemLanguage = GetSystemLanguage();
if (IsSupportedLanguage(systemLanguage)) {
SetCurrentLanguage(systemLanguage);
}
return true;
}
virtual void Shutdown() override {
// 清理资源
localizedTexts.clear();
supportedLanguages.Clear();
}
virtual void Update(float deltaTime) override {
// 本地化系统通常不需要每帧更新
}
virtual const char* GetName() const override {
return "LocalizationManager";
}
// 获取系统语言
PooledString GetSystemLanguage() const {
// 实际实现中应获取操作系统语言设置
#ifdef _WIN32
// Windows平台获取系统语言
WCHAR localeName[LOCALE_NAME_MAX_LENGTH];
int result = GetUserDefaultLocaleName(localeName, LOCALE_NAME_MAX_LENGTH);
if (result > 0) {
char narrowLocale[LOCALE_NAME_MAX_LENGTH];
WideCharToMultiByte(CP_UTF8, 0, localeName, -1, narrowLocale, LOCALE_NAME_MAX_LENGTH, NULL, NULL);
// 从完整的区域设置中提取语言代码
char langCode[3] = {0};
strncpy(langCode, narrowLocale, 2);
return PooledString(langCode);
}
#elif defined(__APPLE__)
// macOS/iOS平台获取系统语言
CFLocaleRef locale = CFLocaleCopyCurrent();
CFStringRef localeIdentifier = CFLocaleGetIdentifier(locale);
CFStringRef langCodeIdentifier = CFLocaleCreateComponentsFromLocaleIdentifier(NULL, localeIdentifier, kCFLocaleLanguageCode);
char langCode[3] = {0};
CFStringGetCString(langCodeIdentifier, langCode, sizeof(langCode), kCFStringEncodingUTF8);
CFRelease(langCodeIdentifier);
CFRelease(locale);
return PooledString(langCode);
#elif defined(__ANDROID__)
// Android平台获取系统语言
// 在实际应用中,需要通过JNI调用Android API
return PooledString("en");
#else
// 其他平台的默认实现
return PooledString("en");
#endif
}
// 加载支持的语言列表
void LoadSupportedLanguages() {
// 从配置文件加载支持的语言
if (fileSystem->FileExists("localization/languages.json")) {
std::string jsonData = fileSystem->ReadAllText("localization/languages.json");
// 解析JSON
// 这里使用简化的示例,实际中应使用JSON库
// ...
// 添加支持的语言
supportedLanguages.Clear();
supportedLanguages.Add(PooledString("en")); // 英语
supportedLanguages.Add(PooledString("es")); // 西班牙语
supportedLanguages.Add(PooledString("fr")); // 法语
supportedLanguages.Add(PooledString("de")); // 德语
supportedLanguages.Add(PooledString("zh")); // 中文
supportedLanguages.Add(PooledString("ja")); // 日语
}
}
// 设置当前语言
bool SetCurrentLanguage(const PooledString& languageCode) {
if (!IsSupportedLanguage(languageCode)) {
return false;
}
// 如果语言已经是当前语言,无需切换
if (currentLanguage == languageCode) {
return true;
}
currentLanguage = languageCode;
// 加载当前语言的翻译
LoadTranslations(currentLanguage);
return true;
}
// 获取当前语言
PooledString GetCurrentLanguage() const {
return currentLanguage;
}
// 获取支持的语言列表
const GameArray<PooledString>& GetSupportedLanguages() const {
return supportedLanguages;
}
// 检查语言是否被支持
bool IsSupportedLanguage(const PooledString& languageCode) const {
for (const auto& lang : supportedLanguages) {
if (lang == languageCode) {
return true;
}
}
return false;
}
// 加载语言翻译
void LoadTranslations(const PooledString& languageCode) {
GameString filePath = Format("localization/%s.json", languageCode.CStr());
if (!fileSystem->FileExists(filePath.CStr())) {
// 语言文件不存在
return;
}
std::string jsonData = fileSystem->ReadAllText(filePath.CStr());
// 解析JSON
// 这里使用简化的示例,实际中应使用JSON库
// ...
// 假设JSON结构为:
// {
// "key1": "翻译1",
// "key2": "翻译2",
// ...
// }
// 添加翻译
AddTranslation(PooledString("MENU_START"), languageCode, "Start Game");
AddTranslation(PooledString("MENU_OPTIONS"), languageCode, "Options");
AddTranslation(PooledString("MENU_EXIT"), languageCode, "Exit");
// 添加特定语言的翻译
if (languageCode == PooledString("es")) {
AddTranslation(PooledString("MENU_START"), languageCode, "Iniciar Juego");
AddTranslation(PooledString("MENU_OPTIONS"), languageCode, "Opciones");
AddTranslation(PooledString("MENU_EXIT"), languageCode, "Salir");
} else if (languageCode == PooledString("fr")) {
AddTranslation(PooledString("MENU_START"), languageCode, "Commencer Jeu");
AddTranslation(PooledString("MENU_OPTIONS"), languageCode, "Options");
AddTranslation(PooledString("MENU_EXIT"), languageCode, "Quitter");
}
}
// 添加翻译
void AddTranslation(const PooledString& key, const PooledString& languageCode, const GameString& text) {
// 如果键不存在,创建一个新条目
if (localizedTexts.find(key) == localizedTexts.end()) {
LocalizedText newText;
newText.key = key;
localizedTexts[key] = newText;
}
// 添加或更新翻译
localizedTexts[key].translations[languageCode] = text;
}
// 获取翻译文本
GameString GetText(const PooledString& key) const {
auto it = localizedTexts.find(key);
if (it == localizedTexts.end()) {
// 键不存在,返回键本身
return GameString(key.CStr());
}
const LocalizedText& localizedText = it->second;
auto translationIt = localizedText.translations.find(currentLanguage);
if (translationIt != localizedText.translations.end()) {
// 返回当前语言的翻译
return translationIt->second;
}
// 如果当前语言没有翻译,尝试使用英语
translationIt = localizedText.translations.find(PooledString("en"));
if (translationIt != localizedText.translations.end()) {
return translationIt->second;
}
// 如果没有任何翻译,返回键本身
return GameString(key.CStr());
}
// 格式化翻译文本
template<typename... Args>
GameString FormatText(const PooledString& key, Args... args) const {
GameString text = GetText(key);
// 简单的格式化实现,实际中可能需要更复杂的处理
char* buffer = new char[1024];
snprintf(buffer, 1024, text.CStr(), args...);
GameString result(buffer);
delete[] buffer;
return result;
}
};
5.4.4 文本渲染
游戏中的文本渲染需要处理多种字体和布局:
cpp
// 字体管理和文本渲染
class FontManager : public ISystem {
private:
struct Font {
uint32_t id;
std::string name;
std::string path;
int size;
// 实际字体数据(简化示例)
void* fontData;
Font() : id(0), size(0), fontData(nullptr) {}
~Font() {
// 释放字体资源
if (fontData) {
// 实际实现中应调用适当的释放函数
fontData = nullptr;
}
}
};
// 字体缓存
std::unordered_map<uint32_t, Font*> fonts;
// 默认字体ID
uint32_t defaultFontId;
// 渲染系统
RenderSystem* renderSystem;
// 文件系统
FileSystem* fileSystem;
// 下一个字体ID
uint32_t nextFontId;
public:
FontManager() : defaultFontId(0), renderSystem(nullptr), fileSystem(nullptr), nextFontId(1) {}
~FontManager() {
// 释放所有字体
for (auto& pair : fonts) {
delete pair.second;
}
}
// 实现ISystem接口
virtual bool Initialize() override {
Engine* engine = Engine::GetInstance();
renderSystem = engine->GetRenderSystem();
fileSystem = engine->GetFileSystem();
if (!renderSystem || !fileSystem) {
return false;
}
// 加载默认字体
defaultFontId = LoadFont("fonts/default.ttf", "Default", 16);
return defaultFontId != 0;
}
virtual void Shutdown() override {
// 释放所有字体
for (auto& pair : fonts) {
delete pair.second;
}
fonts.clear();
defaultFontId = 0;
}
virtual void Update(float deltaTime) override {
// 字体管理器通常不需要每帧更新
}
virtual const char* GetName() const override {
return "FontManager";
}
// 加载字体
uint32_t LoadFont(const std::string& path, const std::string& name, int size) {
// 检查文件是否存在
if (!fileSystem->FileExists(path)) {
return 0;
}
// 创建新字体
Font* font = new Font();
font->id = nextFontId++;
font->name = name;
font->path = path;
font->size = size;
// 加载字体数据
std::vector<uint8_t> fontFileData = fileSystem->ReadAllBytes(path);
// 初始化字体
// 这里应该使用实际的字体库(如FreeType)进行初始化
// 下面是简化的示例
font->fontData = new uint8_t[fontFileData.size()];
memcpy(font->fontData, fontFileData.data(), fontFileData.size());
// 存储字体
fonts[font->id] = font;
return font->id;
}
// 卸载字体
void UnloadFont(uint32_t fontId) {
if (fontId == defaultFontId) {
// 不允许卸载默认字体
return;
}
auto it = fonts.find(fontId);
if (it != fonts.end()) {
delete it->second;
fonts.erase(it);
}
}
// 获取字体
Font* GetFont(uint32_t fontId) const {
auto it = fonts.find(fontId);
if (it != fonts.end()) {
return it->second;
}
// 如果找不到指定字体,返回默认字体
it = fonts.find(defaultFontId);
return it != fonts.end() ? it->second : nullptr;
}
// 获取默认字体ID
uint32_t GetDefaultFontId() const {
return defaultFontId;
}
// 绘制文本
void DrawText(const GameString& text, float x, float y, uint32_t fontId = 0,
const Color& color = Color(1.0f, 1.0f, 1.0f, 1.0f)) {
// 如果未指定字体ID,使用默认字体
if (fontId == 0) {
fontId = defaultFontId;
}
Font* font = GetFont(fontId);
if (!font) {
return;
}
// 调用渲染系统绘制文本
renderSystem->DrawText(text.CStr(), x, y, font->fontData, font->size, color);
}
// 计算文本尺寸
Vector2 MeasureText(const GameString& text, uint32_t fontId = 0) {
// 如果未指定字体ID,使用默认字体
if (fontId == 0) {
fontId = defaultFontId;
}
Font* font = GetFont(fontId);
if (!font) {
return Vector2(0, 0);
}
// 计算文本尺寸
// 这里应该使用实际的字体库计算尺寸
// 下面是简化的示例
float width = text.Length() * font->size * 0.6f; // 粗略估计
float height = font->size;
return Vector2(width, height);
}
// 绘制带有边界的文本
void DrawTextWithBounds(const GameString& text, const Rect& bounds, uint32_t fontId = 0,
TextAlignment alignment = TextAlignment::Left,
const Color& color = Color(1.0f, 1.0f, 1.0f, 1.0f)) {
// 如果未指定字体ID,使用默认字体
if (fontId == 0) {
fontId = defaultFontId;
}
Font* font = GetFont(fontId);
if (!font) {
return;
}
// 计算文本尺寸
Vector2 textSize = MeasureText(text, fontId);
// 计算起始位置
float startX = bounds.x;
float startY = bounds.y;
// 根据对齐方式调整位置
switch (alignment) {
case TextAlignment::Center:
startX = bounds.x + (bounds.width - textSize.x) / 2;
break;
case TextAlignment::Right:
startX = bounds.x + bounds.width - textSize.x;
break;
default: // Left
break;
}
// 垂直居中
startY = bounds.y + (bounds.height - textSize.y) / 2;
// 绘制文本
DrawText(text, startX, startY, fontId, color);
}
// 文本对齐枚举
enum class TextAlignment {
Left,
Center,
Right
};
};
5.5 引擎配置
游戏引擎配置系统负责管理游戏设置和参数。
5.5.1 配置文件处理
处理各种格式的配置文件:
cpp
// 配置值类型
enum class ConfigValueType {
None,
Boolean,
Integer,
Float,
String,
Array,
Object
};
// 配置值
class ConfigValue {
private:
ConfigValueType type;
union {
bool boolValue;
int intValue;
float floatValue;
};
GameString stringValue;
std::vector<ConfigValue> arrayElements;
std::unordered_map<GameString, ConfigValue> objectMembers;
public:
// 默认构造函数
ConfigValue() : type(ConfigValueType::None) {}
// 析构函数
~ConfigValue() {
Clear();
}
// 拷贝构造函数
ConfigValue(const ConfigValue& other) : type(ConfigValueType::None) {
*this = other;
}
// 移动构造函数
ConfigValue(ConfigValue&& other) noexcept : type(ConfigValueType::None) {
*this = std::move(other);
}
// 拷贝赋值运算符
ConfigValue& operator=(const ConfigValue& other) {
if (this != &other) {
Clear();
type = other.type;
switch (type) {
case ConfigValueType::Boolean:
boolValue = other.boolValue;
break;
case ConfigValueType::Integer:
intValue = other.intValue;
break;
case ConfigValueType::Float:
floatValue = other.floatValue;
break;
case ConfigValueType::String:
stringValue = other.stringValue;
break;
case ConfigValueType::Array:
arrayElements = other.arrayElements;
break;
case ConfigValueType::Object:
objectMembers = other.objectMembers;
break;
default:
break;
}
}
return *this;
}
// 移动赋值运算符
ConfigValue& operator=(ConfigValue&& other) noexcept {
if (this != &other) {
Clear();
type = other.type;
switch (type) {
case ConfigValueType::Boolean:
boolValue = other.boolValue;
break;
case ConfigValueType::Integer:
intValue = other.intValue;
break;
case ConfigValueType::Float:
floatValue = other.floatValue;
break;
case ConfigValueType::String:
stringValue = std::move(other.stringValue);
break;
case ConfigValueType::Array:
arrayElements = std::move(other.arrayElements);
break;
case ConfigValueType::Object:
objectMembers = std::move(other.objectMembers);
break;
default:
break;
}
other.type = ConfigValueType::None;
}
return *this;
}
// 布尔值构造函数
ConfigValue(bool value) : type(ConfigValueType::Boolean), boolValue(value) {}
// 整数构造函数
ConfigValue(int value) : type(ConfigValueType::Integer), intValue(value) {}
// 浮点数构造函数
ConfigValue(float value) : type(ConfigValueType::Float), floatValue(value) {}
// 字符串构造函数
ConfigValue(const GameString& value) : type(ConfigValueType::String), stringValue(value) {}
// C字符串构造函数
ConfigValue(const char* value) : type(ConfigValueType::String), stringValue(value) {}
// 获取类型
ConfigValueType GetType() const {
return type;
}
// 判断是否为指定类型
bool IsBoolean() const { return type == ConfigValueType::Boolean; }
bool IsInteger() const { return type == ConfigValueType::Integer; }
bool IsFloat() const { return type == ConfigValueType::Float; }
bool IsString() const { return type == ConfigValueType::String; }
bool IsArray() const { return type == ConfigValueType::Array; }
bool IsObject() const { return type == ConfigValueType::Object; }
// 获取值
bool GetBoolean(bool defaultValue = false) const {
return IsBoolean() ? boolValue : defaultValue;
}
int GetInteger(int defaultValue = 0) const {
return IsInteger() ? intValue : defaultValue;
}
float GetFloat(float defaultValue = 0.0f) const {
if (IsFloat()) return floatValue;
if (IsInteger()) return static_cast<float>(intValue);
return defaultValue;
}
const GameString& GetString(const GameString& defaultValue = GameString()) const {
return IsString() ? stringValue : defaultValue;
}
// 设置值
void SetBoolean(bool value) {
Clear();
type = ConfigValueType::Boolean;
boolValue = value;
}
void SetInteger(int value) {
Clear();
type = ConfigValueType::Integer;
intValue = value;
}
void SetFloat(float value) {
Clear();
type = ConfigValueType::Float;
floatValue = value;
}
void SetString(const GameString& value) {
Clear();
type = ConfigValueType::String;
stringValue = value;
}
// 数组操作
void SetArray() {
Clear();
type = ConfigValueType::Array;
}
size_t GetArraySize() const {
return IsArray() ? arrayElements.size() : 0;
}
ConfigValue& AddArrayElement() {
if (!IsArray()) {
SetArray();
}
arrayElements.emplace_back();
return arrayElements.back();
}
void AddArrayElement(const ConfigValue& value) {
if (!IsArray()) {
SetArray();
}
arrayElements.push_back(value);
}
ConfigValue& GetArrayElement(size_t index) {
static ConfigValue nullValue;
if (!IsArray() || index >= arrayElements.size()) {
return nullValue;
}
return arrayElements[index];
}
const ConfigValue& GetArrayElement(size_t index) const {
static const ConfigValue nullValue;
if (!IsArray() || index >= arrayElements.size()) {
return nullValue;
}
return arrayElements[index];
}
// 对象操作
void SetObject() {
Clear();
type = ConfigValueType::Object;
}
bool HasMember(const GameString& name) const {
if (!IsObject()) {
return false;
}
return objectMembers.find(name) != objectMembers.end();
}
ConfigValue& AddMember(const GameString& name) {
if (!IsObject()) {
SetObject();
}
return objectMembers[name];
}
void SetMember(const GameString& name, const ConfigValue& value) {
if (!IsObject()) {
SetObject();
}
objectMembers[name] = value;
}
ConfigValue& GetMember(const GameString& name) {
static ConfigValue nullValue;
if (!IsObject()) {
return nullValue;
}
auto it = objectMembers.find(name);
if (it == objectMembers.end()) {
return nullValue;
}
return it->second;
}
const ConfigValue& GetMember(const GameString& name) const {
static const ConfigValue nullValue;
if (!IsObject()) {
return nullValue;
}
auto it = objectMembers.find(name);
if (it == objectMembers.end()) {
return nullValue;
}
return it->second;
}
// 清除当前值
void Clear() {
stringValue.Clear();
arrayElements.clear();
objectMembers.clear();
type = ConfigValueType::None;
}
};
// 配置系统
class ConfigSystem : public ISystem {
private:
// 根配置对象
ConfigValue rootConfig;
// 配置文件路径
GameString configFilePath;
// 文件系统
FileSystem* fileSystem;
public:
ConfigSystem() : fileSystem(nullptr) {}
// 实现ISystem接口
virtual bool Initialize() override {
Engine* engine = Engine::GetInstance();
fileSystem = engine->GetFileSystem();
if (!fileSystem) {
return false;
}
// 设置默认配置文件路径
configFilePath = "config/settings.json";
// 加载配置
if (fileSystem->FileExists(configFilePath.CStr())) {
return LoadConfig(configFilePath);
}
// 如果配置文件不存在,创建默认配置
CreateDefaultConfig();
SaveConfig(configFilePath);
return true;
}
virtual void Shutdown() override {
// 保存配置
SaveConfig(configFilePath);
// 清理资源
rootConfig.Clear();
}
virtual void Update(float deltaTime) override {
// 配置系统通常不需要每帧更新
}
virtual const char* GetName() const override {
return "ConfigSystem";
}
// 加载配置文件
bool LoadConfig(const GameString& filepath) {
// 检查文件是否存在
if (!fileSystem->FileExists(filepath.CStr())) {
return false;
}
configFilePath = filepath;
// 读取文件内容
std::string jsonData = fileSystem->ReadAllText(filepath.CStr());
// 解析JSON
// 这里使用简化的示例,实际中应使用JSON库
// ...
// 成功加载后,更新当前配置路径
configFilePath = filepath;
// 以下为示例配置,实际应从JSON解析
CreateDefaultConfig();
return true;
}
// 保存配置文件
bool SaveConfig(const GameString& filepath) {
// 确保目录存在
std::string directory = GetDirectoryPath(filepath.CStr());
fileSystem->CreateDirectory(directory);
// 序列化为JSON
// 这里使用简化的示例,实际中应使用JSON库
std::string jsonData = SerializeToJson(rootConfig);
// 写入文件
return fileSystem->WriteAllText(filepath.CStr(), jsonData);
}
// 获取配置值
template<typename T>
T GetValue(const GameString& path, const T& defaultValue) const {
ConfigValue value = GetConfigValue(path);
if constexpr (std::is_same_v<T, bool>) {
return value.IsBoolean() ? value.GetBoolean() : defaultValue;
} else if constexpr (std::is_same_v<T, int>) {
return value.IsInteger() ? value.GetInteger() : defaultValue;
} else if constexpr (std::is_same_v<T, float>) {
return value.IsFloat() ? value.GetFloat() :
value.IsInteger() ? static_cast<float>(value.GetInteger()) : defaultValue;
} else if constexpr (std::is_same_v<T, GameString>) {
return value.IsString() ? value.GetString() : defaultValue;
} else {
return defaultValue;
}
}
// 设置配置值
template<typename T>
void SetValue(const GameString& path, const T& value) {
ConfigValue configValue;
if constexpr (std::is_same_v<T, bool>) {
configValue.SetBoolean(value);
} else if constexpr (std::is_same_v<T, int>) {
configValue.SetInteger(value);
} else if constexpr (std::is_same_v<T, float>) {
configValue.SetFloat(value);
} else if constexpr (std::is_same_v<T, const char*> ||
std::is_same_v<T, GameString>) {
configValue.SetString(value);
}
SetConfigValue(path, configValue);
}
// 获取或创建配置部分
ConfigValue& GetOrCreateSection(const GameString& path) {
GameArray<GameString> parts = path.Split('.');
ConfigValue* current = &rootConfig;
for (const auto& part : parts) {
current = ¤t->GetMember(part);
if (current->GetType() == ConfigValueType::None) {
current->SetObject();
} else if (current->GetType() != ConfigValueType::Object) {
// 已存在但不是对象,重置为对象
current->SetObject();
}
}
return *current;
}
private:
// 创建默认配置
void CreateDefaultConfig() {
rootConfig.SetObject();
// 图形设置
ConfigValue& graphics = rootConfig.AddMember("graphics");
graphics.SetObject();
graphics.SetMember("resolution", ConfigValue("1920x1080"));
graphics.SetMember("fullscreen", ConfigValue(false));
graphics.SetMember("vsync", ConfigValue(true));
graphics.SetMember("quality", ConfigValue("high"));
// 音频设置
ConfigValue& audio = rootConfig.AddMember("audio");
audio.SetObject();
audio.SetMember("masterVolume", ConfigValue(1.0f));
audio.SetMember("musicVolume", ConfigValue(0.8f));
audio.SetMember("sfxVolume", ConfigValue(1.0f));
audio.SetMember("mute", ConfigValue(false));
// 游戏设置
ConfigValue& game = rootConfig.AddMember("game");
game.SetObject();
game.SetMember("difficulty", ConfigValue("normal"));
game.SetMember("language", ConfigValue("en"));
game.SetMember("tutorialCompleted", ConfigValue(false));
// 控制设置
ConfigValue& controls = rootConfig.AddMember("controls");
controls.SetObject();
controls.SetMember("mouseSensitivity", ConfigValue(0.5f));
controls.SetMember("invertY", ConfigValue(false));
// 玩家设置
ConfigValue& player = rootConfig.AddMember("player");
player.SetObject();
player.SetMember("name", ConfigValue("Player"));
// 键位绑定
ConfigValue& keybindings = controls.AddMember("keybindings");
keybindings.SetObject();
keybindings.SetMember("moveForward", ConfigValue("W"));
keybindings.SetMember("moveBackward", ConfigValue("S"));
keybindings.SetMember("moveLeft", ConfigValue("A"));
keybindings.SetMember("moveRight", ConfigValue("D"));
keybindings.SetMember("jump", ConfigValue("Space"));
}
// 获取配置路径对应的值
ConfigValue GetConfigValue(const GameString& path) const {
GameArray<GameString> parts = path.Split('.');
const ConfigValue* current = &rootConfig;
for (const auto& part : parts) {
if (!current->IsObject()) {
return ConfigValue();
}
current = ¤t->GetMember(part);
}
return *current;
}
// 设置配置路径对应的值
void SetConfigValue(const GameString& path, const ConfigValue& value) {
GameArray<GameString> parts = path.Split('.');
if (parts.IsEmpty()) {
return;
}
ConfigValue* current = &rootConfig;
// 导航到倒数第二个部分
for (size_t i = 0; i < parts.Size() - 1; i++) {
const GameString& part = parts[i];
if (!current->IsObject()) {
current->SetObject();
}
current = ¤t->GetMember(part);
if (current->GetType() == ConfigValueType::None) {
current->SetObject();
}
}
// 设置最后一个部分的值
if (current->IsObject()) {
current->SetMember(parts.Last(), value);
}
}
// 序列化为JSON (简化实现)
std::string SerializeToJson(const ConfigValue& value, int indent = 0) const {
std::string result;
switch (value.GetType()) {
case ConfigValueType::None:
result = "null";
break;
case ConfigValueType::Boolean:
result = value.GetBoolean() ? "true" : "false";
break;
case ConfigValueType::Integer:
result = std::to_string(value.GetInteger());
break;
case ConfigValueType::Float:
result = std::to_string(value.GetFloat());
// 移除尾随的0
result.erase(result.find_last_not_of('0') + 1, std::string::npos);
if (result.back() == '.') {
result.push_back('0');
}
break;
case ConfigValueType::String:
result = """ + EscapeJsonString(value.GetString().CStr()) + """;
break;
case ConfigValueType::Array: {
result = "[
";
size_t size = value.GetArraySize();
for (size_t i = 0; i < size; i++) {
// 添加缩进
result += std::string(indent + 2, ' ');
result += SerializeToJson(value.GetArrayElement(i), indent + 2);
if (i < size - 1) {
result += ",";
}
result += "
";
}
result += std::string(indent, ' ') + "]";
break;
}
case ConfigValueType::Object: {
result = "{
";
// 这里应该遍历对象的所有成员
// 但为了简化,我们假设有一些成员
std::vector<std::pair<GameString, ConfigValue>> members;
// 假设value.GetAllMembers(members)能获取所有成员
// 下面是示例成员,实际应从value获取
if (value.HasMember("resolution")) {
members.push_back({"resolution", value.GetMember("resolution")});
}
if (value.HasMember("fullscreen")) {
members.push_back({"fullscreen", value.GetMember("fullscreen")});
}
// 添加其他成员...
for (size_t i = 0; i < members.size(); i++) {
// 添加缩进
result += std::string(indent + 2, ' ');
result += """ + std::string(members[i].first.CStr()) + "": ";
result += SerializeToJson(members[i].second, indent + 2);
if (i < members.size() - 1) {
result += ",";
}
result += "
";
}
result += std::string(indent, ' ') + "}";
break;
}
}
return result;
}
// 转义JSON字符串
std::string EscapeJsonString(const char* str) const {
std::string result;
for (const char* c = str; *c != ''; c++) {
switch (*c) {
case '"': result += "\""; break;
case '\': result += "\\"; break;
case '/': result += "\/"; break;
case '': result += "\b"; break;
case 'f': result += "\f"; break;
case '
': result += "\n"; break;
case '
': result += "\r"; break;
case ' ': result += "\t"; break;
default: result += *c; break;
}
}
return result;
}
// 获取目录路径
std::string GetDirectoryPath(const char* filePath) const {
std::string path(filePath);
size_t pos = path.find_last_of("/\");
if (pos != std::string::npos) {
return path.substr(0, pos);
}
return "";
}
};
5.5.2 命令行解析
命令行参数解析用于处理游戏启动选项:
cpp
// 命令行参数解析器
class CommandLineParser {
private:
// 命令行参数
std::unordered_map<GameString, GameString> args;
// 标志(不带值的参数)
std::unordered_set<GameString> flags;
public:
// 解析命令行参数
void Parse(int argc, char* argv[]) {
// 跳过程序名称
for (int i = 1; i < argc; i++) {
std::string arg = argv[i];
// 检查是否是选项
if (arg.size() > 1 && arg[0] == '-') {
// 移除前导的'-'
arg = arg.substr(arg.find_first_not_of('-'));
// 检查是否包含等号
size_t equalsPos = arg.find('=');
if (equalsPos != std::string::npos) {
// 带值的参数
std::string key = arg.substr(0, equalsPos);
std::string value = arg.substr(equalsPos + 1);
args[GameString(key.c_str())] = GameString(value.c_str());
} else {
// 检查下一个参数是否是值
if (i + 1 < argc && argv[i + 1][0] != '-') {
// 带值的参数
args[GameString(arg.c_str())] = GameString(argv[i + 1]);
i++; // 跳过下一个参数
} else {
// 标志(不带值的参数)
flags.insert(GameString(arg.c_str()));
}
}
}
}
}
// 检查标志是否存在
bool HasFlag(const GameString& name) const {
return flags.find(name) != flags.end();
}
// 获取参数值
bool GetValue(const GameString& name, GameString& outValue) const {
auto it = args.find(name);
if (it != args.end()) {
outValue = it->second;
return true;
}
return false;
}
// 获取整数值
bool GetIntValue(const GameString& name, int& outValue) const {
GameString strValue;
if (GetValue(name, strValue)) {
try {
outValue = std::stoi(strValue.CStr());
return true;
} catch (...) {
return false;
}
}
return false;
}
// 获取浮点值
bool GetFloatValue(const GameString& name, float& outValue) const {
GameString strValue;
if (GetValue(name, strValue)) {
try {
outValue = std::stof(strValue.CStr());
return true;
} catch (...) {
return false;
}
}
return false;
}
// 获取布尔值
bool GetBoolValue(const GameString& name, bool& outValue) const {
GameString strValue;
if (GetValue(name, strValue)) {
// 转换为小写
std::string lowerValue = strValue.CStr();
std::transform(lowerValue.begin(), lowerValue.end(), lowerValue.begin(),
[](unsigned char c) { return std::tolower(c); });
outValue = lowerValue == "true" || lowerValue == "1" || lowerValue == "yes";
return true;
}
return flags.find(name) != flags.end();
}
// 获取所有参数
const std::unordered_map<GameString, GameString>& GetAllArgs() const {
return args;
}
// 获取所有标志
const std::unordered_set<GameString>& GetAllFlags() const {
return flags;
}
};
5.5.3 游戏设置系统
游戏设置系统统一管理游戏中各类配置:
cpp
// 游戏设置系统
class GameSettings : public ISystem {
private:
// 设置分类
enum class SettingCategory {
Graphics,
Audio,
Gameplay,
Controls,
Advanced
};
// 设置值类型
enum class SettingType {
Boolean,
Integer,
Float,
String,
Enum
};
// 设置定义
struct SettingDefinition {
GameString key;
GameString displayName;
GameString description;
SettingCategory category;
SettingType type;
// 值范围(对于数值类型)
union {
struct {
int minValue;
int maxValue;
int stepValue;
} intRange;
struct {
float minValue;
float maxValue;
float stepValue;
} floatRange;
};
// 枚举值选项(对于枚举类型)
std::vector<GameString> enumOptions;
// 默认值
ConfigValue defaultValue;
// 是否需要重启游戏生效
bool requiresRestart;
// 显示条件(依赖于其他设置)
GameString displayCondition;
};
// 设置定义列表
std::vector<SettingDefinition> settingDefinitions;
// 当前设置值
ConfigValue settings;
// 配置系统
ConfigSystem* configSystem;
// 观察者列表
std::vector<std::function<void(const GameString&)>> observers;
public:
GameSettings() : configSystem(nullptr) {}
// 实现ISystem接口
virtual bool Initialize() override {
Engine* engine = Engine::GetInstance();
configSystem = static_cast<ConfigSystem*>(engine->GetSystem("ConfigSystem"));
if (!configSystem) {
return false;
}
// 定义所有设置
DefineSettings();
// 从配置系统加载设置
LoadSettings();
return true;
}
virtual void Shutdown() override {
// 保存设置
SaveSettings();
// 清理资源
settingDefinitions.clear();
observers.clear();
}
virtual void Update(float deltaTime) override {
// 设置系统通常不需要每帧更新
}
virtual const char* GetName() const override {
return "GameSettings";
}
// 注册设置变化观察者
void RegisterObserver(std::function<void(const GameString&)> observer) {
observers.push_back(observer);
}
// 获取设置值
template<typename T>
T GetValue(const GameString& key, const T& defaultValue = T()) const {
ConfigValue value = settings.GetMember(key);
if (value.GetType() == ConfigValueType::None) {
// 尝试获取默认值
for (const auto& def : settingDefinitions) {
if (def.key == key) {
if constexpr (std::is_same_v<T, bool>) {
return def.defaultValue.GetBoolean(defaultValue);
} else if constexpr (std::is_same_v<T, int>) {
return def.defaultValue.GetInteger(defaultValue);
} else if constexpr (std::is_same_v<T, float>) {
return def.defaultValue.GetFloat(defaultValue);
} else if constexpr (std::is_same_v<T, GameString>) {
return def.defaultValue.GetString(defaultValue);
}
}
}
return defaultValue;
}
if constexpr (std::is_same_v<T, bool>) {
return value.GetBoolean(defaultValue);
} else if constexpr (std::is_same_v<T, int>) {
return value.GetInteger(defaultValue);
} else if constexpr (std::is_same_v<T, float>) {
return value.GetFloat(defaultValue);
} else if constexpr (std::is_same_v<T, GameString>) {
return value.GetString(defaultValue);
}
return defaultValue;
}
// 设置值
template<typename T>
void SetValue(const GameString& key, const T& value) {
ConfigValue oldValue = settings.GetMember(key);
ConfigValue newValue;
if constexpr (std::is_same_v<T, bool>) {
newValue.SetBoolean(value);
} else if constexpr (std::is_same_v<T, int>) {
newValue.SetInteger(value);
} else if constexpr (std::is_same_v<T, float>) {
newValue.SetFloat(value);
} else if constexpr (std::is_same_v<T, GameString> ||
std::is_same_v<T, const char*>) {
newValue.SetString(value);
}
// 验证值是否在范围内
for (const auto& def : settingDefinitions) {
if (def.key == key) {
if (def.type == SettingType::Integer) {
int intValue = newValue.GetInteger();
if (intValue < def.intRange.minValue || intValue > def.intRange.maxValue) {
// 值超出范围,截断到有效范围
intValue = std::max(def.intRange.minValue, std::min(intValue, def.intRange.maxValue));
newValue.SetInteger(intValue);
}
} else if (def.type == SettingType::Float) {
float floatValue = newValue.GetFloat();
if (floatValue < def.floatRange.minValue || floatValue > def.floatRange.maxValue) {
// 值超出范围,截断到有效范围
floatValue = std::max(def.floatRange.minValue, std::min(floatValue, def.floatRange.maxValue));
newValue.SetFloat(floatValue);
}
} else if (def.type == SettingType::Enum) {
// 验证枚举值是否有效
GameString strValue = newValue.GetString();
bool valid = false;
for (const auto& option : def.enumOptions) {
if (strValue == option) {
valid = true;
break;
}
}
if (!valid && !def.enumOptions.empty()) {
// 使用第一个有效选项
newValue.SetString(def.enumOptions[0]);
}
}
break;
}
}
// 更新设置
settings.SetMember(key, newValue);
// 通知观察者
for (const auto& observer : observers) {
observer(key);
}
}
// 重置设置为默认值
void ResetToDefault(const GameString& key) {
for (const auto& def : settingDefinitions) {
if (def.key == key) {
settings.SetMember(key, def.defaultValue);
// 通知观察者
for (const auto& observer : observers) {
observer(key);
}
break;
}
}
}
// 重置所有设置为默认值
void ResetAllToDefault() {
for (const auto& def : settingDefinitions) {
settings.SetMember(def.key, def.defaultValue);
}
// 通知观察者
for (const auto& observer : observers) {
observer(GameString("all"));
}
}
// 保存设置
void SaveSettings() {
// 将设置保存到配置系统
configSystem->SetValue("settings", settings);
configSystem->SaveConfig("config/settings.json");
}
// 获取设置定义
const std::vector<SettingDefinition>& GetSettingDefinitions() const {
return settingDefinitions;
}
// 获取设置定义
const SettingDefinition* GetSettingDefinition(const GameString& key) const {
for (const auto& def : settingDefinitions) {
if (def.key == key) {
return &def;
}
}
return nullptr;
}
private:
// 定义所有设置
void DefineSettings() {
// 图形设置
{
SettingDefinition resolution;
resolution.key = "graphics.resolution";
resolution.displayName = "Resolution";
resolution.description = "Screen resolution";
resolution.category = SettingCategory::Graphics;
resolution.type = SettingType::Enum;
resolution.enumOptions = {
"1280x720", "1366x768", "1600x900", "1920x1080", "2560x1440", "3840x2160"
};
resolution.defaultValue.SetString("1920x1080");
resolution.requiresRestart = false;
settingDefinitions.push_back(resolution);
SettingDefinition fullscreen;
fullscreen.key = "graphics.fullscreen";
fullscreen.displayName = "Fullscreen";
fullscreen.description = "Run the game in fullscreen mode";
fullscreen.category = SettingCategory::Graphics;
fullscreen.type = SettingType::Boolean;
fullscreen.defaultValue.SetBoolean(false);
fullscreen.requiresRestart = false;
settingDefinitions.push_back(fullscreen);
SettingDefinition vsync;
vsync.key = "graphics.vsync";
vsync.displayName = "V-Sync";
vsync.description = "Synchronize with monitor refresh rate";
vsync.category = SettingCategory::Graphics;
vsync.type = SettingType::Boolean;
vsync.defaultValue.SetBoolean(true);
vsync.requiresRestart = false;
settingDefinitions.push_back(vsync);
SettingDefinition quality;
quality.key = "graphics.quality";
quality.displayName = "Graphics Quality";
quality.description = "Overall graphics quality preset";
quality.category = SettingCategory::Graphics;
quality.type = SettingType::Enum;
quality.enumOptions = {"low", "medium", "high", "ultra"};
quality.defaultValue.SetString("high");
quality.requiresRestart = false;
settingDefinitions.push_back(quality);
}
// 音频设置
{
SettingDefinition masterVolume;
masterVolume.key = "audio.masterVolume";
masterVolume.displayName = "Master Volume";
masterVolume.description = "Overall volume level";
masterVolume.category = SettingCategory::Audio;
masterVolume.type = SettingType::Float;
masterVolume.floatRange.minValue = 0.0f;
masterVolume.floatRange.maxValue = 1.0f;
masterVolume.floatRange.stepValue = 0.01f;
masterVolume.defaultValue.SetFloat(1.0f);
masterVolume.requiresRestart = false;
settingDefinitions.push_back(masterVolume);
SettingDefinition musicVolume;
musicVolume.key = "audio.musicVolume";
musicVolume.displayName = "Music Volume";
musicVolume.description = "Volume level for music";
musicVolume.category = SettingCategory::Audio;
musicVolume.type = SettingType::Float;
musicVolume.floatRange.minValue = 0.0f;
musicVolume.floatRange.maxValue = 1.0f;
musicVolume.floatRange.stepValue = 0.01f;
musicVolume.defaultValue.SetFloat(0.8f);
musicVolume.requiresRestart = false;
settingDefinitions.push_back(musicVolume);
SettingDefinition sfxVolume;
sfxVolume.key = "audio.sfxVolume";
sfxVolume.displayName = "SFX Volume";
sfxVolume.description = "Volume level for sound effects";
sfxVolume.category = SettingCategory::Audio;
sfxVolume.type = SettingType::Float;
sfxVolume.floatRange.minValue = 0.0f;
sfxVolume.floatRange.maxValue = 1.0f;
sfxVolume.floatRange.stepValue = 0.01f;
sfxVolume.defaultValue.SetFloat(1.0f);
sfxVolume.requiresRestart = false;
settingDefinitions.push_back(sfxVolume);
SettingDefinition mute;
mute.key = "audio.mute";
mute.displayName = "Mute";
mute.description = "Mute all game audio";
mute.category = SettingCategory::Audio;
mute.type = SettingType::Boolean;
mute.defaultValue.SetBoolean(false);
mute.requiresRestart = false;
settingDefinitions.push_back(mute);
}
// 游戏设置
{
SettingDefinition difficulty;
difficulty.key = "game.difficulty";
difficulty.displayName = "Difficulty";
difficulty.description = "Game difficulty level";
difficulty.category = SettingCategory::Gameplay;
difficulty.type = SettingType::Enum;
difficulty.enumOptions = {"easy", "normal", "hard", "nightmare"};
difficulty.defaultValue.SetString("normal");
difficulty.requiresRestart = false;
settingDefinitions.push_back(difficulty);
SettingDefinition language;
language.key = "game.language";
language.displayName = "Language";
language.description = "Game language";
language.category = SettingCategory::Gameplay;
language.type = SettingType::Enum;
language.enumOptions = {"en", "es", "fr", "de", "zh", "ja"};
language.defaultValue.SetString("en");
language.requiresRestart = true;
settingDefinitions.push_back(language);
SettingDefinition tutorialEnabled;
tutorialEnabled.key = "game.tutorialEnabled";
tutorialEnabled.displayName = "Tutorial";
tutorialEnabled.description = "Show tutorial messages";
tutorialEnabled.category = SettingCategory::Gameplay;
tutorialEnabled.type = SettingType::Boolean;
tutorialEnabled.defaultValue.SetBoolean(true);
tutorialEnabled.requiresRestart = false;
settingDefinitions.push_back(tutorialEnabled);
}
// 控制设置
{
SettingDefinition mouseSensitivity;
mouseSensitivity.key = "controls.mouseSensitivity";
mouseSensitivity.displayName = "Mouse Sensitivity";
mouseSensitivity.description = "Sensitivity of mouse movement";
mouseSensitivity.category = SettingCategory::Controls;
mouseSensitivity.type = SettingType::Float;
mouseSensitivity.floatRange.minValue = 0.1f;
mouseSensitivity.floatRange.maxValue = 5.0f;
mouseSensitivity.floatRange.stepValue = 0.1f;
mouseSensitivity.defaultValue.SetFloat(1.0f);
mouseSensitivity.requiresRestart = false;
settingDefinitions.push_back(mouseSensitivity);
SettingDefinition invertY;
invertY.key = "controls.invertY";
invertY.displayName = "Invert Y-Axis";
invertY.description = "Invert vertical mouse movement";
invertY.category = SettingCategory::Controls;
invertY.type = SettingType::Boolean;
invertY.defaultValue.SetBoolean(false);
invertY.requiresRestart = false;
settingDefinitions.push_back(invertY);
}
// 高级设置
{
SettingDefinition fov;
fov.key = "advanced.fov";
fov.displayName = "Field of View";
fov.description = "Horizontal field of view in degrees";
fov.category = SettingCategory::Advanced;
fov.type = SettingType::Integer;
fov.intRange.minValue = 60;
fov.intRange.maxValue = 120;
fov.intRange.stepValue = 1;
fov.defaultValue.SetInteger(90);
fov.requiresRestart = false;
settingDefinitions.push_back(fov);
SettingDefinition maxFps;
maxFps.key = "advanced.maxFps";
maxFps.displayName = "FPS Limit";
maxFps.description = "Maximum frames per second (0 = unlimited)";
maxFps.category = SettingCategory::Advanced;
maxFps.type = SettingType::Integer;
maxFps.intRange.minValue = 0;
maxFps.intRange.maxValue = 240;
maxFps.intRange.stepValue = 10;
maxFps.defaultValue.SetInteger(60);
maxFps.requiresRestart = false;
settingDefinitions.push_back(maxFps);
}
}
// 从配置系统加载设置
void LoadSettings() {
// 从配置系统获取设置
ConfigValue configSettings = configSystem->GetValue<ConfigValue>("settings", ConfigValue());
if (configSettings.GetType() == ConfigValueType::Object) {
settings = configSettings;
} else {
// 创建默认设置
settings.SetObject();
for (const auto& def : settingDefinitions) {
settings.SetMember(def.key, def.defaultValue);
}
}
}
};
本章介绍了游戏引擎中的核心支持系统,包括子系统的启动和终止流程、内存管理策略、各种专用容器实现、字符串处理技术以及引擎配置系统。这些支持系统为游戏提供了稳定可靠的基础设施,使游戏开发者能够专注于游戏逻辑和创意实现,而不必过多已关注底层细节。随着游戏技术的不断发展,这些支持系统也在不断改进,以满足现代游戏对性能、可靠性和开发效率的更高要求。















暂无评论内容