我的Chunk加载与卸载函数无法正常工作,请求技术排查
区块加载/卸载与体素逻辑实现问题
我实现了Chunk加载、卸载、updateWorld函数及体素相关逻辑,核心逻辑是:获取玩家周围9个区块的位置,打开对应区块文件;若文件不存在则生成区块及体素,若文件已有内容则加载区块,之后卸载所有区块。我调整过文件读写逻辑,但对这部分知识掌握不足,怀疑问题出在文件读写环节。
实现代码
void generateVoxels(Chunk *chunk) { chunk -> voxels = (Voxel *)malloc(sizeof(Voxel) * CHUNK_SIZE * CHUNK_SIZE); int colorRand = 5; for(int i = 0; i < CHUNK_SIZE; i++) { for(int j = 0; j < CHUNK_SIZE; j++) { chunk -> voxels[i * CHUNK_SIZE + j].position[0] = chunk -> position[0] + j; chunk -> voxels[i * CHUNK_SIZE + j].position[1] = chunk -> position[1] + i; chunk -> voxels[i * CHUNK_SIZE + j].material = MaterialList[rand() % 2]; for(int k = 0; k < 3; k++) { chunk -> voxels[i * CHUNK_SIZE + j].material.color[k] += rand() % (colorRand * 2 + 1) - colorRand; } } } } void generateChunk(Chunk *chunk, Vector chunkPosition) { chunk -> position[0] = chunkPosition[0]; chunk -> position[1] = chunkPosition[1]; generateVoxels(chunk); } Chunk *loadChunk(FILE *file, Vector chunkPosition) { Chunk *chunk = (Chunk *) malloc(sizeof(Chunk) + sizeof(Voxel) * CHUNK_SIZE * CHUNK_SIZE); if(file == NULL) { generateChunk(chunk, chunkPosition); } else { if (fread(chunk -> position, sizeof(Vector), 1, file) != 1) { fprintf(stderr, "Error reading position from file\n"); } if (fread(chunk -> voxels, sizeof(Voxel), CHUNK_SIZE * CHUNK_SIZE, file) != CHUNK_SIZE * CHUNK_SIZE) { fprintf(stderr, "Error reading voxel data from file\n"); } } return chunk; } void unloadChunk(FILE *file, Chunk *chunk) { if (fwrite(chunk -> position, sizeof(Vector), 1, file) != 1) { fprintf(stderr, "Error writing position to file\n"); } if (fwrite(chunk -> voxels, sizeof(Voxel), CHUNK_SIZE * CHUNK_SIZE, file) != CHUNK_SIZE * CHUNK_SIZE) { fprintf(stderr, "Error writing voxel data to file\n"); } fclose(file); if (fclose(file) != 0) { fprintf(stderr, "Error closing file\n"); } free(chunk); } void drawVoxel(Voxel voxel, Vector offset) { SDL_Rect voxelRect = {(int) (SCREEN_WIDTH / 2 - GAME_WIDTH / 2 ) + (int) voxel.position[0] + offset[0], (int) voxel.position[1] + offset[1], VOXEL_SIZE + 1 + offset[0], VOXEL_SIZE + 1 + offset[1]}; setDrawColor(voxel.material.color); SDL_RenderFillRect(renderer, &voxelRect); } void updateWorld() { Vector positionChange; positionChange[0] = PLAYER_DEFAULT_POS[0] - player -> position[0]; positionChange[1] = PLAYER_DEFAULT_POS[1] - player -> position[1]; for(int i = -1; i < 1; i++) { for(int j = -1; j < 1; j++) { loadedChunks[(i + 1) * 3 + j + 1][0] = player -> position[0] + j * CHUNK_SIZE; loadedChunks[(i + 1) * 3 + j + 1][1] = player -> position[1] + i * CHUNK_SIZE; } } for(int i = 0; i < 9; i++) { loadedChunks[i][0] = roundf(loadedChunks[i][0] / CHUNK_SIZE) * CHUNK_SIZE; loadedChunks[i][1] = roundf(loadedChunks[i][1] / CHUNK_SIZE) * CHUNK_SIZE; char *fileName = malloc(strlen(CHUNK_FILE) + 6 + sizeof(loadedChunks[i][0]) + sizeof(loadedChunks[i][1])); sprintf(fileName, "%s/x%dy%d", CHUNK_FILE, (int)loadedChunks[i][0], (int)loadedChunks[i][1]); FILE *file = fopen(fileName, "rb+"); Chunk *chunk = loadChunk(file, loadedChunks[i]); if (chunk != NULL) { for (int j = 0; j < CHUNK_SIZE * CHUNK_SIZE; j++) { drawVoxel(chunk->voxels[j], positionChange); } unloadChunk(file, chunk); } else { fprintf(stderr, "Error loading chunk\n"); } free(fileName); } }
文件读写环节的问题点
- 重复关闭文件:
unloadChunk中连续调用两次fclose(file),第一次关闭后文件指针已失效,第二次调用会触发未定义行为,需删除其中一次。 - 文件打开模式错误:用
rb+打开不存在的文件会返回NULL,但生成新区块后没有创建文件写入数据,应先判断文件是否存在,不存在则用wb+模式创建并写入。 - 内存分配逻辑错误:
loadChunk中一次性分配Chunk+体素的内存,但如果Chunk结构体中voxels是指针类型,需要单独为voxels分配内存,或改用柔性数组定义Chunk,否则会导致内存访问越界。 - 文件名内存计算错误:
malloc时用sizeof(loadedChunks[i][0])计算的是变量字节数,不是数字的字符串长度,应改用snprintf预计算所需长度,或直接分配足够大的缓冲区(如256字节)避免溢出。 - 新生成区块未写入文件:当文件不存在时,
loadChunk生成了新区块,但unloadChunk使用的是NULL文件指针,fwrite会失败,需在生成区块后创建文件并写入数据。
内容的提问来源于stack exchange,提问作者Tesseract
相关产品推荐
相关产品推荐

