Cxxdroid 中文文档 下载 App

SDL2 基础绘图 —— 矩形、圆、线条怎么画

渲染器(Renderer)的概念

SDL2 的图形渲染用的是渲染器模式——你所有的绘制操作都发往一个 SDL_Renderer,它会把这些操作批量提交给 GPU 硬件加速执行。

核心流程:

1. 创建窗口和渲染器
2. 每帧循环:
   a. 清空上一帧
   b. 画所有图形
   c. Present(提交到屏幕)
3. 销毁渲染器和窗口

画点

SDL_SetRenderDrawColor(ren, 255, 255, 255, 255);  // 白色
SDL_RenderDrawPoint(ren, 160, 240);               // 在屏幕中央画一个白点

批量画点效率更高:

SDL_Point points[] = {{100, 100}, {150, 150}, {200, 100}};
SDL_RenderDrawPoints(ren, points, 3);

画直线

SDL_SetRenderDrawColor(ren, 0, 255, 0, 255);  // 绿色
SDL_RenderDrawLine(ren, 50, 50, 200, 300);

画矩形

矩形边框:

SDL_SetRenderDrawColor(ren, 0, 0, 255, 255);
SDL_Rect rect = {50, 50, 100, 80};  // x, y, w, h
SDL_RenderDrawRect(ren, &rect);

矩形填充:

SDL_RenderFillRect(ren, &rect);

批量矩形(适合粒子效果或网格):

SDL_Rect rects[100];
// ... 填充 rects 数组 ...
SDL_RenderFillRects(ren, rects, 100);

画圆(需要 SDL_gfx)

SDL2 核心库不直接提供圆的绘制——需要额外的扩展库 SDL_gfx。

如果 Cxxdroid 仓库里有 SDL_gfx(部分版本预装),可以这样画圆:

#include <SDL2/SDL2_gfxPrimitives.h>

circleRGBA(ren, 160, 240, 50, 255, 200, 0, 255);

如果没有 SDL_gfx,自己实现一个简单的圆填充也不难:用 Bresenham 算法算圆上每个点,然后调用 SDL_RenderDrawPoint 批量画出来。

设置颜色

每个绘制调用前都需要设置一次绘制颜色:

SDL_SetRenderDrawColor(ren, R, G, B, A);

R/G/B/A 各占 0-255,A 是透明度(255 = 不透明)。后续所有绘制操作都用这个颜色,直到下次修改。

清屏

每帧开头通常要清空上一帧的内容:

SDL_SetRenderDrawColor(ren, 0, 0, 0, 255);  // 黑色背景
SDL_RenderClear(ren);

如果不清空直接在上面画,会产生残影(拖尾效果)——有时候这是你想要的(星空效果),但大多数游戏需要先清屏。

Present:提交帧

所有绘制操作完成后,调用一次:

SDL_RenderPresent(ren);

这一步才会真正把绘制内容提交到屏幕。如果忘记 present,屏幕上什么都不会显示。

完整示例:画一面小旗

#include <SDL2/SDL.h>

int main() {
    SDL_Init(SDL_INIT_VIDEO);
    SDL_Window *win = SDL_CreateWindow("Flag",
        0, 0, 320, 480, SDL_WINDOW_SHOWN);
    SDL_Renderer *ren = SDL_CreateRenderer(win, -1, 0);

    // 背景
    SDL_SetRenderDrawColor(ren, 240, 240, 240, 255);
    SDL_RenderClear(ren);

    // 旗杆
    SDL_SetRenderDrawColor(ren, 80, 80, 80, 255);
    SDL_RenderDrawLine(ren, 80, 40, 80, 440);

    // 红旗
    SDL_SetRenderDrawColor(ren, 220, 30, 30, 255);
    SDL_Rect flag = {80, 40, 150, 100};
    SDL_RenderFillRect(ren, &flag);

    SDL_RenderPresent(ren);
    SDL_Delay(3000);

    SDL_DestroyRenderer(ren);
    SDL_DestroyWindow(win);
    SDL_Quit();
    return 0;
}