Raylib游戏地图绘制异常求助:仅显示背景色无地图内容
你的代码存在多个关键问题,导致地图无法正常渲染,以下是具体问题和修复方案:
1. 文件读取逻辑错误:仅读取一次地图
你把文件读取的do-while循环放在了Raylib的主渲染循环内。第一次执行时,fgetc会一直读到文件末尾(EOF),之后每次主循环执行时,文件指针停留在EOF位置,不会再读取任何内容,自然无法绘制地图。
修复方式:
提前将地图数据加载到内存(比如二维数组),避免在渲染循环中重复读取文件,既提升效率也能保证每次渲染都能获取到地图数据。
2. 换行符处理逻辑冲突
代码中case '\n'分支仅做了break操作,后续又单独判断if(caracter == '\n')来更新坐标,导致遇到换行符时,先执行x += TAMANHO,再重置x和y,造成换行后第一个格子的x坐标偏移错误。
修复方式:
去掉case '\n'分支,直接在switch结构外处理换行逻辑;或者在case分支内完成坐标更新,避免重复执行x偏移。
3. DrawRectangle参数顺序错误
默认分支中的DrawRectangle(LARGURA, ALTURA, x, y, DARKGRAY)参数顺序完全错误,Raylib的DrawRectangle接口定义为DrawRectangle(int posX, int posY, int width, int height, Color color),你把宽高和坐标位置搞反了,导致绘制的矩形不在预期区域。
修复方式:
改为DrawRectangle(x, y, TAMANHO, TAMANHO, DARKGRAY),匹配格子的尺寸。
4. 角色移动后未重新绘制
你仅在读取地图时绘制了一次初始位置的角色,后续移动角色更新坐标后,没有在主循环中重新绘制角色,所以移动操作无法在画面上体现。
修复方式:
在主渲染循环的地图绘制完成后,添加角色绘制代码,使用更新后的坐标重新绘制。
5. 文件打开失败后的错误处理缺失
文件打开失败时,仅打印错误信息但程序继续执行后续代码,会导致fclose(file)操作空指针,引发程序崩溃。
修复方式:
文件打开失败后直接终止程序,避免后续错误操作。
修复后的完整代码
#include "raylib.h" #include <stdio.h> #define LARGURA 1200 #define ALTURA 500 #define LINE 100 #define PAREDE 'W' #define PAREDEDESTRUTIVEL 'D' #define POCAO 'P' #define POSINICIALMAGO 'J' #define POSISINICIALMONSTRO 'M' #define POSINICIALCRIATURA 'K' #define TAMANHO 40 #define MAP_ROWS (ALTURA / TAMANHO) #define MAP_COLS (LARGURA / TAMANHO) // 存储地图数据的二维数组 char map[MAP_ROWS][MAP_COLS]; int main(void){ FILE *file; char path[] = "Mapa/mapa1.txt"; int x,y, posInicialMago[2], posMago[2], posInicialCriatura[2], posCriatura[2], posInicialMonstro[2], posMonstro[2]; char caracter; file = fopen(path,"r"); if(file == NULL) { printf("Erro na abertura do arquivo! \n"); return 1; // 文件打开失败,直接终止程序 } // 提前加载地图数据到内存 x = y = 0; while((caracter = fgetc(file)) != EOF) { if(caracter == '\n') { y++; x = 0; continue; } if(y < MAP_ROWS && x < MAP_COLS) { map[y][x] = caracter; // 记录各类角色初始位置 switch(caracter) { case POSINICIALMAGO: posInicialMago[0] = posMago[0] = x * TAMANHO; posInicialMago[1] = posMago[1] = y * TAMANHO; break; case POSINICIALCRIATURA: posInicialCriatura[0] = x * TAMANHO; posInicialCriatura[1] = y * TAMANHO; break; case POSISINICIALMONSTRO: posInicialMonstro[0] = x * TAMANHO; posInicialMonstro[1] = y * TAMANHO; break; default: break; } x++; } } fclose(file); // 提前关闭文件,无需保持打开状态 InitWindow(LARGURA, ALTURA, "Jogo"); SetTargetFPS(60); // 加载纹理资源 Texture2D mage = LoadTexture("./Texturas/mage (1).png"); Texture2D fairy = LoadTexture("./Texturas/fairy (1).png"); Texture2D potion = LoadTexture("./Texturas/potion (1).png"); Texture2D monster = LoadTexture("./Texturas/monster (1).png"); Texture2D wall = LoadTexture("./Texturas/wall (1).png"); Texture2D indestructibleWall = LoadTexture("./Texturas/wall (1).png"); while (!WindowShouldClose()) { // 处理角色移动输入 if (IsKeyPressed(KEY_RIGHT)) posMago[0] += TAMANHO; if (IsKeyPressed(KEY_LEFT)) posMago[0] -= TAMANHO; if (IsKeyPressed(KEY_UP)) posMago[1] -= TAMANHO; if (IsKeyPressed(KEY_DOWN)) posMago[1] += TAMANHO; BeginDrawing(); ClearBackground(RAYWHITE); // 绘制地图 for(y = 0; y < MAP_ROWS; y++) { for(x = 0; x < MAP_COLS; x++) { caracter = map[y][x]; int drawX = x * TAMANHO; int drawY = y * TAMANHO; switch(caracter) { case PAREDE: DrawTexture(indestructibleWall, drawX, drawY, BROWN); break; case PAREDEDESTRUTIVEL: DrawTexture(wall, drawX, drawY, BROWN); break; case POCAO: DrawTexture(potion, drawX, drawY, BLUE); break; case POSINICIALCRIATURA: DrawTexture(fairy, drawX, drawY, PURPLE); break; case POSISINICIALMONSTRO: DrawTexture(monster, drawX, drawY, BLACK); break; default: DrawRectangle(drawX, drawY, TAMANHO, TAMANHO, DARKGRAY); break; } } } // 绘制移动后的法师角色 DrawTexture(mage, posMago[0], posMago[1], RAYWHITE); EndDrawing(); } // 卸载纹理资源,避免内存泄漏 UnloadTexture(mage); UnloadTexture(fairy); UnloadTexture(potion); UnloadTexture(monster); UnloadTexture(wall); UnloadTexture(indestructibleWall); CloseWindow(); return 0; }
额外优化建议
- 添加纹理加载失败判断:比如通过
if(mage.id == 0)检测纹理是否加载成功,避免绘制空纹理。 - 限制角色移动范围,防止角色移出窗口边界。
- 将常量、结构体等封装到独立头文件中,提升代码可读性和维护性。
内容的提问来源于stack exchange,提问作者Mateus

