拆分C/SDL2代码后渲染器失效,窗口仅显示黑色
SDL2多文件拆分后渲染器无法正常工作的问题
问题背景
按照Pikuma教程完成单文件C/SDL2基础游戏循环,运行完全正常。但将代码拆分为多文件后(原教程除常量声明外逻辑均写在main函数中),出现渲染异常:窗口能正常创建和销毁,渲染函数也能被调用,但渲染器完全失效——原本应显示灰色背景与红色斜线,现在窗口仅显示纯黑色。尝试过无参数声明渲染函数、直接传递SDL_Renderer参数,问题均未解决。
文件结构与代码
main.c
#include <stdio.h> #include <SDL2/SDL.h> #include "./constants.h" #include "./init_and_destroy.h" #include "./render.h" // 全局变量 int game_is_running = FALSE; SDL_Window* my_window = NULL; SDL_Renderer* my_renderer = NULL; int last_frame_time = 0; void setup() { } void process_input() { SDL_Event event; SDL_PollEvent(&event); // 事件引用 switch (event.type) { case SDL_QUIT: game_is_running = FALSE; break; case SDL_KEYDOWN: if(event.key.keysym.sym == SDLK_ESCAPE) game_is_running = FALSE; break; } } void update() { // --------------------------FPS与DELTA_TIME逻辑-------------------------- // 帧率限制 int time_to_wait = FRAME_TARGET_TIME - (SDL_GetTicks() - last_frame_time); if (time_to_wait > 0 && time_to_wait <= FRAME_TARGET_TIME) { SDL_Delay(time_to_wait); } // 秒为单位的delta时间 float delta_time = (SDL_GetTicks() - last_frame_time) / 1000.0f; last_frame_time = SDL_GetTicks(); // ---------------------------------------------------------------------- // 更新逻辑写在这里 } int main() { game_is_running = initialize_window(my_window, my_renderer); setup(); while(game_is_running) { process_input(); update(); render(my_renderer); } destroy_window(my_window, my_renderer); return 0; }
init_and_destroy.c
#include <stdio.h> #include <SDL2/SDL.h> #include "./constants.h" #include "./init_and_destroy.h" int initialize_window(SDL_Window* window, SDL_Renderer* renderer) { if (SDL_Init(SDL_INIT_EVERYTHING) != 0) { fprintf(stderr, "SDL初始化错误。\n"); return FALSE; } window = SDL_CreateWindow( "我的窗口", SDL_WINDOWPOS_CENTERED, // x位置 SDL_WINDOWPOS_CENTERED, // y位置 WINDOW_WIDTH, WINDOW_HEIGHT, 0 ); if(!window) { fprintf(stderr, "创建SDL窗口错误。\n"); return FALSE; } renderer = SDL_CreateRenderer(window, -1, 0); if(!renderer) { fprintf(stderr, "创建SDL渲染器错误。\n"); return FALSE; } return TRUE; } void destroy_window(SDL_Window* window, SDL_Renderer* renderer) { SDL_DestroyRenderer(renderer); SDL_DestroyWindow(window); SDL_Quit(); }
render.c
#include <stdio.h> #include <SDL2/SDL.h> #include "./constants.h" #include "./render.h" void render(SDL_Renderer* renderer) { SDL_SetRenderDrawColor(renderer, 50, 50, 50, 255); SDL_RenderClear(renderer); // 绘制红色斜线 SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255); for(int i = 0; i < WINDOW_WIDTH; i++) { SDL_RenderDrawPoint(renderer, i, i); } SDL_RenderPresent(renderer); // 交换缓冲区 }
头文件
render.h
#ifndef RENDER #define RENDER void render(SDL_Renderer* renderer); #endif
init_and_destroy.h
#ifndef INIT_AND_DESTROY #define INIT_AND_DESTROY int initialize_window(SDL_Window* window, SDL_Renderer* renderer); void destroy_window(SDL_Window* window, SDL_Renderer* renderer); #endif
问题现象
窗口显示为纯黑色,无预期的灰色背景和红色斜线。
解决方案
核心问题是**initialize_window函数的参数传递方式错误**:你传递的是指针的副本,函数内对window和renderer的赋值不会修改全局变量my_window和my_renderer,导致main函数中的my_renderer始终为NULL,所有渲染操作实际在空指针上执行,自然看不到任何画面。
修复步骤:
- 修改
initialize_window的参数为双重指针,这样才能修改全局的指针变量:- 更新
init_and_destroy.h的函数声明:int initialize_window(SDL_Window** window, SDL_Renderer** renderer); - 更新
init_and_destroy.c的函数实现:int initialize_window(SDL_Window** window, SDL_Renderer** renderer) { if (SDL_Init(SDL_INIT_EVERYTHING) != 0) { fprintf(stderr, "SDL初始化错误。\n"); return FALSE; } *window = SDL_CreateWindow( "我的窗口", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, WINDOW_WIDTH, WINDOW_HEIGHT, 0 ); if(!*window) { fprintf(stderr, "创建SDL窗口错误。\n"); return FALSE; } *renderer = SDL_CreateRenderer(*window, -1, 0); if(!*renderer) { fprintf(stderr, "创建SDL渲染器错误。\n"); return FALSE; } return TRUE; }
- 更新
- 修改
main中调用initialize_window的方式,传入全局变量的地址:game_is_running = initialize_window(&my_window, &my_renderer);
额外优化建议
- 全局变量虽方便,但大型项目中建议尽量避免,可将窗口、渲染器等封装成
GameState结构体,通过指针传递,代码更整洁易维护。 process_input中的SDL_PollEvent应放在循环中,否则会漏掉多个待处理事件:void process_input() { SDL_Event event; while (SDL_PollEvent(&event)) { // 用while循环处理所有待处理事件 switch (event.type) { case SDL_QUIT: game_is_running = FALSE; break; case SDL_KEYDOWN: if(event.key.keysym.sym == SDLK_ESCAPE) game_is_running = FALSE; break; } } }
内容的提问来源于stack exchange,提问作者Eujota
相关产品推荐
相关产品推荐

