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

拆分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,所有渲染操作实际在空指针上执行,自然看不到任何画面。

修复步骤:

  1. 修改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;
      }
      
  2. 修改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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 18:27:07