You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

我的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 03:45:08