C++使用SFML 1.6如何实现无性能损耗的无限体素区块
问题修复与实现指导
一、现有代码问题修复
- 析构函数错误:
Chunk::~Chunk()中的delete[] chnk::m_blockgrid必须删除。m_blockgrid是全局命名空间下的静态数组,不是new[]申请的堆内存,调用delete[]会触发未定义行为。 - 全局共享数据错误:你将
m_blockgrid、m_block放在chnk全局命名空间中,会导致所有Chunk实例共享同一份方块数据,创建再多Chunk也只会显示同一份区块内容。正确做法是把m_blockgrid改为Chunk类的private非静态成员,每个实例独立持有自己的方块网格;Block对象可以做成全局静态实例,不需要每个Chunk都new一个,避免内存泄漏。 - 随机种子错误:你现在每个Chunk构造时都随机生成噪声种子,后续生成多区块时地形会完全不衔接,需要改为全局固定种子。
二、无限体素区块实现方案
使用unordered_map存储已加载区块是完全可行的,也是目前体素类游戏实现无限世界的主流方案,具体实现步骤如下:
1. 重构Chunk类
给Chunk类增加区块坐标成员,用于标识该区块在世界中的位置:
// chunk.hpp 新增成员 class Chunk { public: Chunk(int chunkX, int chunkZ); // 构造时传入区块坐标 // ... 原有其他方法 private: int m_chunkX, m_chunkZ; // 区块的全局坐标 int m_blockgrid[horiz_chunksize][vert_chunksize][horiz_chunksize]; // 移到类内作为成员 // ... 原有其他成员 };
2. 定义区块存储结构
使用区块的X、Z坐标作为唯一键,存储已加载的区块:
#include <unordered_map> // 将两个32位整数的区块坐标打包为64位整数作为key inline uint64_t getChunkKey(int cx, int cz) { return (static_cast<uint64_t>(cx) << 32) | static_cast<uint32_t>(cz); } // 全局已加载区块表,key是区块坐标打包值,value是Chunk实例指针 std::unordered_map<uint64_t, Chunk*> g_loadedChunks;
3. 实现动态加载卸载逻辑
每帧更新时执行以下逻辑:
- 计算玩家当前所在的区块坐标:
int blockSize = chnk::m_block->m_size; int playerChunkX = static_cast<int>(floor(p.m_position.x / horiz_chunksize / blockSize)); int playerChunkZ = static_cast<int>(floor(p.m_position.z / horiz_chunksize / blockSize)); - 加载渲染范围内的新区块:遍历以玩家区块为中心、渲染距离为半径的所有区块坐标,计算key后检查是否已在
g_loadedChunks中,不存在则new Chunk(cx, cz)生成地形后存入map。 - 卸载超出渲染范围的区块:遍历
g_loadedChunks所有条目,若区块与玩家区块的距离超过渲染距离,delete对应Chunk实例并从map中移除。
4. 补充坐标转换逻辑
实现世界坐标与区块局部坐标的转换:
- 已知世界坐标
wx, wy, wz,对应区块坐标为cx = floor(wx / horiz_chunksize)、cz = floor(wz / horiz_chunksize),对应区块内局部坐标为lx = wx - cx * horiz_chunksize、lz = wz - cz * horiz_chunksize。 - 渲染Chunk时,所有方块的世界位置需要加上偏移
cx * horiz_chunksize * blockSize、cz * horiz_chunksize * blockSize,避免所有区块堆叠在原点。 - 面剔除时如果方块在区块边界,需要查询相邻区块的对应位置方块是否为实心,避免区块边界出现多余的面。
三、优化建议
- 区块加载、地形生成逻辑可以放到独立线程执行,避免阻塞主线程导致玩家移动时卡顿,SFML 1.6可使用
sf::Thread实现。 - 现有逐方块逐面绘制的性能很低,可改为每个Chunk预生成顶点缓冲(VBO),仅当区块内方块修改时才更新缓冲,渲染时直接绘制整个缓冲,性能会有数量级提升。
内容的提问来源于stack exchange,提问作者rentheprogrammer
相关产品推荐
相关产品推荐

