【SDL游戏编程入门第七卷】基本几何体渲染

一、前言

除了新的纹理 API,SDL 还在其渲染 API 中提供了新的基元渲染调用。 因此,如果您需要渲染一些基本形状,并且不想为它们创建其他图形,SDL 可以为您节省精力。

// 加载媒体资源,这里不加载媒体资源
//if (!LoadMedia())
//	std::cout << "[Error]: Failed to load media!" << std::endl;

因此,我们不加载任何其他媒体。

二、渲染基本几何体

// 窗口循环
SDL_Event e;
bool quit = false;
while (quit == false)
{
    // 处理事件
    while (SDL_PollEvent(&e))
    {
        if (e.type == SDL_QUIT)
            quit = true;
    }

    // --- rendering -----------------------------------------------------------------------
    // 设置渲染器绘制颜色(黑色)
    SDL_SetRenderDrawColor(gRenderer, 0, 0, 0, 255);
    // 清屏
    SDL_RenderClear(gRenderer);

    // 填充红色矩形
    SDL_Rect redRect{ SCREEN_WIDTH / 4, SCREEN_HEIGHT / 4, SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2 };
    SDL_SetRenderDrawColor(gRenderer, 255, 0, 0, 255);
    SDL_RenderFillRect(gRenderer, &redRect);

    // 绘制绿色矩形线宽
    SDL_Rect greenRect{ SCREEN_WIDTH / 6, SCREEN_HEIGHT / 6, SCREEN_WIDTH * 2 / 3, SCREEN_HEIGHT * 2 / 3 };
    SDL_SetRenderDrawColor(gRenderer, 0, 255, 0, 255);
    SDL_RenderDrawRect(gRenderer, &greenRect);

    // 绘制蓝色过中心水平轴
    SDL_SetRenderDrawColor(gRenderer, 0, 0, 255, 255);
    SDL_RenderDrawLine(gRenderer, 0, SCREEN_HEIGHT / 2, SCREEN_WIDTH, SCREEN_HEIGHT / 2);

    // 绘制黄色过中心的竖直的点序列
    SDL_SetRenderDrawColor(gRenderer, 255, 255, 0, 255);
    for (int i = 0; i < SCREEN_HEIGHT; i += 5)
    {
        SDL_RenderDrawPoint(gRenderer, SCREEN_WIDTH / 2, i);
    }

    // 更新屏幕
    SDL_RenderPresent(gRenderer);
}

这里的函数非常简单,看注释应该能够明白,还有 ✨官方文档 可以参考

注意到,我们将 SDL_SetRenderDrawColor 放在了循环体内

这里注意 SDL 中的坐标系,以客户区左上角(不包含标题栏),X 轴向右为正,Y 轴向下为正

三、示例代码

/* 此源代码版权归 AnnihilateSword (2022-*)所有,未经书面许可不得转载。*/

// 使用 SDL 和 iostream
#include <SDL.h>
#include <SDL_image.h>
#include <iostream>

// 链接库
#pragma comment(lib, "SDL2.lib")
#pragma comment(lib, "SDL2main.lib")
#pragma comment(lib, "SDL2_image.lib")

// 屏幕尺寸常量
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;

bool Init();								// 启动 SDL 并创建窗口
bool LoadMedia();							// 加载媒体
SDL_Texture* LoadTexture(const char* path);	// 加载纹理
void Close();								// 清理资源,关闭窗口以及SDL

SDL_Window* gWindow = nullptr;				// 主窗口
SDL_Renderer* gRenderer = nullptr;			// 主窗口渲染器

SDL_Texture* gTexture = nullptr;			// 需要加载的纹理(表面)

int main(int argc, char* argv[])			// 必须要填写此参数,不然会出现链接错误
{
	// 初始化 SDL
	if (Init())
	{
		// 加载媒体资源,这里不加载媒体资源
		//if (!LoadMedia())
		//	std::cout << "[Error]: Failed to load media!" << std::endl;
		
		// 窗口循环
		SDL_Event e;
		bool quit = false;
		while (quit == false)
		{
			// 处理事件
			while (SDL_PollEvent(&e))
			{
				if (e.type == SDL_QUIT)
					quit = true;
			}

			// --- rendering -----------------------------------------------------------------------
			// 设置渲染器绘制颜色(黑色)
			SDL_SetRenderDrawColor(gRenderer, 0, 0, 0, 255);
			// 清屏
			SDL_RenderClear(gRenderer);

			// 填充红色矩形
			SDL_Rect redRect{ SCREEN_WIDTH / 4, SCREEN_HEIGHT / 4, SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2 };
			SDL_SetRenderDrawColor(gRenderer, 255, 0, 0, 255);
			SDL_RenderFillRect(gRenderer, &redRect);

			// 绘制绿色矩形线宽
			SDL_Rect greenRect{ SCREEN_WIDTH / 6, SCREEN_HEIGHT / 6, SCREEN_WIDTH * 2 / 3, SCREEN_HEIGHT * 2 / 3 };
			SDL_SetRenderDrawColor(gRenderer, 0, 255, 0, 255);
			SDL_RenderDrawRect(gRenderer, &greenRect);

			// 绘制蓝色过中心水平轴
			SDL_SetRenderDrawColor(gRenderer, 0, 0, 255, 255);
			SDL_RenderDrawLine(gRenderer, 0, SCREEN_HEIGHT / 2, SCREEN_WIDTH, SCREEN_HEIGHT / 2);

			// 绘制黄色过中心的竖直的点序列
			SDL_SetRenderDrawColor(gRenderer, 255, 255, 0, 255);
			for (int i = 0; i < SCREEN_HEIGHT; i += 5)
			{
				SDL_RenderDrawPoint(gRenderer, SCREEN_WIDTH / 2, i);
			}

			// 更新屏幕
			SDL_RenderPresent(gRenderer);
		}
	}
	// 清理资源
	Close();
	return 0;
}

/**
 * @brief 启动 SDL 并创建窗口
 */
bool Init()
{
	// 初始化 SDL
	if (SDL_Init(SDL_INIT_VIDEO) < 0)
	{
		std::cout << "[Error]: SDL could not initialize! SDL_Error: " << SDL_GetError() << std::endl;
		return false;
	}
	else
	{
		// 设置纹理线性过滤
		if (!SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1"))
			std::cout << "[Warning]: Linear texture filtering not enabled!" << std::endl;

		// 创建窗口
		gWindow = SDL_CreateWindow("HelloSDL", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
		if (!gWindow)
		{
			std::cout << "[Error]: Window could not be created! SDL_Error: " << SDL_GetError() << std::endl;
			return false;
		}
		else
		{
			// 创建窗口渲染器
			gRenderer = SDL_CreateRenderer(gWindow, -1, SDL_RENDERER_ACCELERATED);  // -1 初始化支持所请求标志的第一个
			if (!gRenderer)
			{
				std::cout << "[Error]: Renderer could not bo created! SDL_Error: " << SDL_GetError() << std::endl;
				return false;
			}
			else
			{
				// 初始化渲染器绘制颜色(蓝色),这次在主循环中设置
				//SDL_SetRenderDrawColor(gRenderer, 51, 76, 204, 255);

				// 初始化 PNG 加载
				int imgFlags = IMG_INIT_PNG;
				if (!(IMG_Init(imgFlags) & imgFlags))
				{
					std::cout << "[Error]: SDL_image could not initialize! SDL_image Error: " << IMG_GetError() << std::endl;
					return false;
				}
			}
		}
	}
	return true;
}

/**
 * @brief 加载媒体
 */
bool LoadMedia()
{
	gTexture = LoadTexture(R"(res\textures\awesomeface.png)");
	if (!gTexture)
	{
		std::cout << "[Error]: Failed to load texture!" << std::endl;
		return false;
	}
	return true;
}

/**
 * @brief 加载纹理
 * @param path:资源路径
 */
SDL_Texture* LoadTexture(const char* path)
{
	// 使用这个一步到位
	return IMG_LoadTexture(gRenderer, path);
}

/**
 * @brief 清理资源,关闭窗口以及SDL
 */
void Close()
{
	// 清理纹理资源
	if (gTexture)
	{
		SDL_DestroyTexture(gTexture);
		gTexture = nullptr;
	}
	// 销毁窗口渲染器
	if (gRenderer)
	{
		SDL_DestroyRenderer(gRenderer);
		gRenderer = nullptr;
	}
	// 销毁窗口
	if (gWindow)
	{
		SDL_DestroyWindow(gWindow);
		gWindow = nullptr;
	}
	// 退出 IMG 和 SDL
	IMG_Quit();
	SDL_Quit();
}

1. 运行结果



本节内容就到这里了,下卷会继续分享 SDL 的基本使用

The End.

posted @ 2022-12-08 16:48  AnnihilateSword  阅读(50)  评论(0编辑  收藏  举报