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

C语言SDL开发:文本按钮显示消失且仅响应点击区域问题求助

问题原因分析

你的问题核心是主循环只渲染背景图,没有重复绘制文本和START按钮:

  • 文本通过render_text逐字显示后,纹理被直接销毁,主循环里没法重新绘制这些文本
  • START按钮的绘制代码只在主循环执行前跑了一次,进入循环后每次SDL_RenderClear清空屏幕,只画背景图,自然看不到文本和按钮
  • 按钮点击区域还能触发,是因为你在事件处理里依然用了原来的坐标判断,和画面渲染无关
修复步骤及代码调整

1. 修改render_text函数,保存最终文本纹理

让函数完成逐字动画后返回最终的文本纹理,方便主循环重复渲染:

SDL_Texture* render_text(SDL_Renderer* renderer, TTF_Font* font, const char* text, SDL_Color color, int x, int y, int delay) {
    int len = strlen(text);
    char buffer[len + 1];
    memset(buffer, '\0', sizeof(buffer));
    int i = 0;
    Uint32 ticks;
    SDL_Rect rect = { x, y, 0, 0 };

    // 逐字显示动画
    while (i < len) {
        ticks = SDL_GetTicks();
        strncat(buffer, &text[i], 1);
        
        SDL_Surface* surface = TTF_RenderText_Solid(font, buffer, color);
        SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface);
        rect.w = surface->w;
        rect.h = surface->h;

        // 每次动画先重绘背景,避免文本残影
        SDL_RenderClear(renderer);
        SDL_RenderCopy(renderer, image3.texture, NULL, NULL);
        SDL_RenderCopy(renderer, texture, NULL, &rect);
        SDL_RenderPresent(renderer);

        SDL_FreeSurface(surface);
        SDL_DestroyTexture(texture);
        i++;

        SDL_Delay(delay - (SDL_GetTicks() - ticks));
    }

    // 创建并保存最终的文本纹理
    SDL_Surface* final_surface = TTF_RenderText_Solid(font, text, color);
    SDL_Texture* final_texture = SDL_CreateTextureFromSurface(renderer, final_surface);
    SDL_FreeSurface(final_surface);

    // 最后重绘一次完整画面
    SDL_RenderClear(renderer);
    SDL_RenderCopy(renderer, image3.texture, NULL, NULL);
    SDL_QueryTexture(final_texture, NULL, NULL, &rect.w, &rect.h);
    SDL_RenderCopy(renderer, final_texture, NULL, &rect);
    SDL_RenderPresent(renderer);

    return final_texture;
}

2. 在main中保存文本信息

定义结构体存储文本纹理和位置,调用render_text时记录这些数据:

// 新增:保存已渲染文本的结构体
typedef struct {
    SDL_Texture* texture;
    int x;
    int y;
} RenderedText;

int main(int argc, char* argv[]) {
    // ... 原有初始化代码不变

    RenderedText story_texts[4];
    int text_count = 0;
    SDL_Color color1 = {255, 0, 0, 255}; // 修正alpha值为不透明

    // 逐字显示并保存文本纹理
    story_texts[text_count].texture = render_text(renderer, font1, "You are caught in this castle!", color, 370, 300, delay);
    story_texts[text_count].x = 370;
    story_texts[text_count].y = 300;
    text_count++;

    int y_pos = 350;
    story_texts[text_count].texture = render_text(renderer, font2,"To escape", color, 470, y_pos, delay);
    story_texts[text_count].x = 470;
    story_texts[text_count].y = y_pos;
    text_count++;

    y_pos += 50;
    story_texts[text_count].texture = render_text(renderer, font1, "You need to", color, 470, y_pos, delay);
    story_texts[text_count].x = 470;
    story_texts[text_count].y = y_pos;
    text_count++;

    y_pos += 50;
    story_texts[text_count].texture = render_text(renderer, font2,"WIN this game", color1, 430, y_pos, delay);
    story_texts[text_count].x = 430;
    story_texts[text_count].y = y_pos;
    text_count++;

    // START按钮相关代码不变,保留text_texture和坐标变量
    int oval_width = 100;
    int oval_height = 50;
    int oval_x = (SCREEN_WIDTH - oval_width) /2 +40;
    int oval_y = SCREEN_HEIGHT - oval_height - 10;
    SDL_Surface* text_surface = TTF_RenderText_Solid(font, "START", textColor);
    SDL_Texture* text_texture = SDL_CreateTextureFromSurface(renderer, text_surface);
    SDL_Rect text_rect = { oval_x + (oval_width - text_surface->w) / 2, oval_y + (oval_height - text_surface->h) / 2, text_surface->w, text_surface->h };

    // ... 事件循环前的其他代码不变

3. 修改主循环渲染逻辑,重复绘制文本和按钮

在主循环中,判断当前为初始界面时,重新绘制文本和START按钮:

SDL_Event event;
bool done = false;

while (!done)
{
    while (SDL_PollEvent(&event))
    {
        // 原有事件处理代码不变
    }

    SDL_RenderClear(renderer);
    SDL_RenderCopy(renderer, current_image.texture, NULL, NULL);

    // 只有在初始界面时才绘制文本和按钮
    if (current_image.texture == image3.texture) {
        // 绘制所有剧情文本
        for (int i = 0; i < text_count; i++) {
            SDL_Rect rect = { story_texts[i].x, story_texts[i].y, 0, 0 };
            SDL_QueryTexture(story_texts[i].texture, NULL, NULL, &rect.w, &rect.h);
            SDL_RenderCopy(renderer, story_texts[i].texture, NULL, &rect);
        }

        // 绘制START按钮
        SDL_SetRenderDrawColor(renderer, 190, 140, 255, 255);
        SDL_Rect oval_rect = { oval_x, oval_y, oval_width, oval_height };
        SDL_RenderFillRect(renderer, &oval_rect);
        SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
        SDL_RenderDrawRect(renderer, &oval_rect);

        // 绘制START文本
        SDL_RenderCopy(renderer, text_texture, NULL, &text_rect);
    }

    SDL_RenderPresent(renderer);
}

4. 补充资源释放

在程序末尾添加文本纹理的释放代码,避免内存泄漏:

// 释放剧情文本纹理
for (int i = 0; i < text_count; i++) {
    SDL_DestroyTexture(story_texts[i].texture);
}
// 释放START按钮的文本纹理和表面
SDL_DestroyTexture(text_texture);
SDL_FreeSurface(text_surface);

// 原有资源释放代码不变
free_image(&image1);
free_image(&image2);
// ...

额外注意点

  • 删掉没用的Render_text函数,里面的renderer和font都是NULL,会导致程序崩溃
  • 修正TEXT_COLOR的alpha值(如果需要不透明文本):#define TEXT_COLOR {0, 0, 0, 255}
  • 检查字体文件路径是否正确,确保arial.ttf在程序运行目录下

内容的提问来源于stack exchange,提问作者hoover

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 02:12:42