SDL游戏开发之六-简单的SDL程序

AI权益加码!Claude Code、Cursor等20+工具免费用! 购周边限时加赠Coding Plan Lite,畅享主流AI工具!学习进阶更高效! 阅读详情

1.最简单的SDL程序

一般的游戏在运行过程中的大部分操作都是在一个大循环里,在这个循环里进行着事件监听、绘制以及逻辑处理等。而像网络通信或者是文件读取等这些比较耗时或者堵塞的操作一般会放到子线程里面。流程图如下:

图1-游戏流程图
  1.  先创建窗口和渲染器;如果创建成功,则进入大循环里;否则则直接退出;
  2. 进行逻辑处理、绘制、事件处理等(注意:以上三个是不分先后的);
  3. 如果发现有退出信号,则退出大循环,然后释放内存;游戏结束。否则则重复步骤2。

每一次循环都会进行绘制,所以一次循环也可以广义地称为一帧。另外,由于人眼的视觉残留,游戏的帧数需要在一秒超过24帧才会感觉到流畅,而一般的游戏的帧数是30或者是60帧(Frame Per Second,FPS)时,就会感觉到比较流畅;除此之外,帧数稳定也是重中之重,比如这一秒有30帧,下一秒是60帧,如果没有考虑到帧数,无论是精灵(Sprite)的位移或者是动画,都会有一种不流畅的感觉。解决办法如下:

  • 不要把耗时处理放在主循环中;
  • 依赖于每一帧的持续时间。

游戏在运行过程中,每一帧的持续时间多多少少会有些变化,当位移的时候如果加上帧的持续时间,会让人有着流畅的感觉。

#include "SDL.h"
 
int main(int argc, char** argv)
{
    //创建窗口和渲染器
        SDL_Init(SDL_INIT_EVERYTHING);
	SDL_Window* win = SDL_CreateWindow("FirstProject", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 600, 480, SDL_WINDOW_SHOWN);
	SDL_Renderer* ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED);
	bool running = true;
	SDL_Event event = {};
        //大循环
	while (running)
	{
                //绘制
		SDL_RenderClear(ren);
		//draw here
		SDL_RenderPresent(ren);
	        //事件处理
		while (SDL_PollEvent(&event))
		{
			switch (event.type)
			{
			case SDL_QUIT:
				running = false;
				break;
			}
		}
	}
        //释放内存
	SDL_DestroyRenderer(ren);
	SDL_DestroyWindow(win);
 
	return 0;
}

注:SDL的main函数必须为int main(int argc, char* argv[]) 。原因:SDL作为一个跨平台的开发库,上述的main是SDL提供的统一的入口。

1.1 创建窗口和渲染器

在使用SDL所提供的大部分函数之前,需要先调用SDL_Init函数来初始化SDL库。官方例子如下:

#include "SDL.h"

int main(int argc, char* argv[])
{
    if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO) != 0) {
        SDL_Log("Unable to initialize SDL: %s", SDL_GetError());
        return 1;
    }

    /* ... */

    SDL_Quit();

    return 0;
}

SDL_Init的参数可以是表1中的一个或几个。

表1 SDL_Init的参数

SDL_INIT_TIMER

定时器子系统

SDL_INIT_AUDIO

音频子系统

SDL_INIT_VIDEO

视频子系统,会自动初始化事件子系统

SDL_INIT_JOYSTICK

摇杆子系统,会自动初始化事件子系统

SDL_INIT_HAPTIC

触摸屏子系统

SDL_INIT_GAMECONTROLLER

控制器子系统,会自动初始化摇杆子系统

SDL_INIT_EVENTS

事件子系统

SDL_INIT_EVERYTHING

以上的所有子系统的和

SDL_INIT_NOPARACHUTE

忽略初始化错误

 除了SDL_INIT_EVERYTHING之外,其余的是可以自由组合的,组合使用的为二元操作符 | 位或。一般情况下为了方便,也可以直接使用SDL_INIT_EVERYTHING。

SDL_Init的返回值如果为0表示操作成功,否则为失败。

 1.2 绘制

为了避免画面产生闪烁或者撕裂感,SDL提供了双缓冲机制。

其实对于SDL来说,跟绘制有关的函数并没有几个,最常用的有4个。

  1.2.1 SDL_RenderClear()

根据绘制颜色清除当前的渲染目标。可以简单地认为该函数是清除画布,当调用该函数后,画布则刷新成SDL_SetRenderDrawColor()所设置的颜色,默认为黑色(0, 0, 0)。

官方示例:SDL_RenderClear

  1.2.2 SDL_RenderPresent()

把后缓冲区的画面绘制到前缓冲区中。这个函数一般情况下是和SDL_RenderClear()配合使用的。由SDL_RenderClear()清屏,然后SDL_RenderPresent()进行画面呈现,在这两个函数之间进行绘制。

官方示例:SDL_RenderPresent

  1.2.3 扩展

  1. SDL_RenderCopy 把纹理绘制到当前的渲染目标中。
  2. SDL_RenderCopyEx SDL_RenderCopy的扩展。
  3. SDL_RenderDraw* 绘制点、线、矩形等。(根据SDL_SetRenderDrawColor所设置的颜色进行绘制,所以如果和清屏的颜色相同的话,那么应该看不到绘制的点、线或者是矩形)

 以上的几个函数就是SDL所提供的所有的绘制函数

1.2.4 渲染目标 render target

 SDL的渲染目标一般有两类,一个是SDL_Renderer渲染器,另一个是SDL_Texture纹理。渲染器是默认的缓冲区,即把后缓冲区绘制到屏幕上;另外一个是把后缓冲区绘制到对应的纹理上。关于渲染器和纹理,目前说的有点模糊,之后会专门说一个SDL_Renderer SDL_Texture SDL_Surface。可以简单地认为SDL_Renderer为渲染器,绘制需要用到它;SDL_Texture纹理是图片。

 1.3 事件处理

当有事件发生时,SDL会首先把事件放入事件队列中,等待被处理。用得比较多的就是SDL_PollEvent,一般的用法就是使用一个循环来抓取事件并进行处理:

while (1) {
    SDL_Event event;
    while (SDL_PollEvent(&event)) {
        //事件处理
    }
    //逻辑处理
    //绘制处理
}

SDL_PollEvent是非阻塞式的,它会判断事件队列中是否存在事件,如果有,则返回true,并把数据写入到SDL_Event中,否则返回false,事件处理结束。

使用循环的一大部分原因是为了能在这一帧内处理完事件队列。

SDL_Event是一个联合体,它囊括了各种事件,包括鼠标事件、键盘事件、摇杆事件等,然后通过event.type来判断当前的事件是什么类型的。

注:除了外部发送事件外,还可以在程序中手动发送事件到事件队列中。

2.对主程序的封装

可以简单地根据流程图把之前的代码进行一个封装。

#ifndef __Game_H__
#define __Game_H__

#include <vector>
#include <string>
#include <iostream>
#include <stdexcept>

#include "SDL.h"

class Game
{
private:
	static Game*s_pInstance;
	Game();
public:
     static Game* getInstance();
     //初始化
     bool init(const char *title, int xpos, int ypos, int width, int height, int flags);
     void render();
	 void update();
	 void handleEvents();
	 void clean();

	 SDL_Renderer* getRenderer() const { return m_pRenderer; }
	 bool running() const { return m_bRunning; }

	 int getGameWidth() const { return m_gameWidth; }
	 int getGameHeight() const { return m_gameHeight; }
private:
	//SDL窗口 渲染器
	SDL_Window* m_pWindow;
	SDL_Renderer* m_pRenderer;
	//是否运行
	bool m_bRunning;
	//屏幕大小
	int m_gameWidth;
	int m_gameHeight;
};
typedef Game TheGame;
#endif

Game作为单例类,方便获取渲染器和窗口的尺寸。在有了这个类后,main函数就比较简单了:

#include<iostream>
#include<string>

#include "SDL.h"

#include "Game.h"

int main(int argc,char**argv)
{
	if (TheGame::getInstance()->init("Shot Stick"
		,SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED
		,960,640,SDL_WINDOW_SHOWN))
	{
		while (TheGame::getInstance()->running())
		{
			TheGame::getInstance()->update();
			TheGame::getInstance()->render();
			TheGame::getInstance()->handleEvents();
		}
	}
	else
	{
	    std::cout<<"error:"<<SDL_GetError()<<std::endl;
		return -1;
	}
	TheGame::getInstance()->clean();

	return 0;
}

SDL_WINDOWPOS_CENTERED 是一个宏,表示窗口显示在屏幕的中央。

在封装之后,main.cpp中的代码和流程图的功能是一致的,接下来则是Game中函数的实现了。

#include "Game.h"

Game*Game::s_pInstance = NULL;

Game::Game()
	:m_pWindow(nullptr)
	,m_pRenderer(nullptr)
	,m_bRunning(true)
	,m_gameWidth(0)
	,m_gameHeight(0)
{
}

Game* Game::getInstance()
{
	if (s_pInstance == NULL)
		s_pInstance = new Game();

	return s_pInstance;
}

所谓单例类,就是只有一个实例,把构造函数作为私有函数,并提供一个静态共有函数来获取唯一实例。

bool Game::init(const char *title, int xpos, int ypos, int width, int height, int flags)
{
    m_bRunning = false;
	if (SDL_Init(SDL_INIT_EVERYTHING) == 0)
	{
		/// if succeeded create our window
		m_pWindow = SDL_CreateWindow(title, xpos, ypos, width, height, flags);
		if (m_pWindow != NULL)
			m_pRenderer = SDL_CreateRenderer(m_pWindow, -1,SDL_RENDERER_ACCELERATED|SDL_RENDERER_PRESENTVSYNC);
		if (m_pRenderer != NULL)
			SDL_SetRenderDrawColor(m_pRenderer,210,250,255,255);
		else
			return false;
	}
	else
		return false;

	m_bRunning = true;
	std::string platform = SDL_GetPlatform();
	// init
	if (platform == "Android") {
		SDL_GetWindowSize(m_pWindow,&m_gameWidth,&m_gameHeight);
	}
	else {
		m_gameWidth = width;
		m_gameHeight = height;
	}
	SDL_Log("width=%d, height=%d\n", m_gameWidth, m_gameHeight);

	return true;
}

在Game::init函数中进行初始化操作,创建窗口和渲染器。在这之后,判断当前的平台,因为在android等嵌入式设备中,一个应用的窗口一般就是手机分辨率的大小。所以如果是在android下,则获取实际的窗口大小,而不是预设的窗口大小。

不过需要注意的是,还是可以设置窗口为我们所设置的大小的,可以调用SDL_RenderSetScale对整个窗口进行拉伸,以铺满整个屏幕,这样做的优点是不用操心分辨率的问题,缺点就是在不同分辨率下的手机上会有不同程度的拉伸,有时候甚至导致变形。

void Game::render()
{
	SDL_SetRenderDrawColor(m_pRenderer,210,250,255,255);
	///clear the renderer to the draw color
	SDL_RenderClear(m_pRenderer);
	///draw
    SDL_SetRenderDrawColor(m_pRenderer,0, 0, 0);
    SDL_Rect rect = { 0, 0, 200, 200 };
	SDL_RenderDrawRect(m_pRenderer, &rect);

	///draw to the screen
	SDL_RenderPresent(m_pRenderer);
}

Game::draw函数进行实际的绘制操作,目前在这里只是绘制一个黑色的不填充矩形。

void Game::handleEvents()
{
	SDL_Event event;
	while (SDL_PollEvent(&event))
	{
		switch (event.type)
		{
		case SDL_QUIT:
			m_bRunning = false;
			break;
		}
	}
}

Game::handleEvents函数进行事件处理,目前仅仅判断是否有退出信号,如果有则退出大循环。

void Game::clean()
{
	SDL_DestroyRenderer(m_pRenderer);
	SDL_DestroyWindow(m_pWindow);
	SDL_Quit();
}

void Game::update()
{
}

Game::clean函数的功能是释放内存。

运行结果:

SDL2 简单介绍以及Windows开发环境搭建 SDL(Simple DirectMedia Layer)是一个跨平台的多媒体开发库,使用C语言写成,用于实现音频、图形、输入以及窗口功能的处理。它提供了一个简单、易用的API,可以帮助开发者快速构建跨平台的多媒体应用程序SDL库分为 Video、Audio、CD-ROM、Joystick 和 Timer 等若干子系统。Video(图像)—图像控制以及线程(thread)和事件管理(event)。Audio(声音)—声音控制Joystick(摇杆)—游戏摇杆控制。 阅读详情

相关推荐

0. SDL游戏开发

文章目录环境准备还是hello world简单解释 环境准备 IDE选用codeblock带mingw(跨平台, 可定制, 轻量), 编译器gcc. SDL库编译(或下载预编译的库) 这里不教怎么搭环境, 任何语言开发, 自己都应该学会如何搭环境. 自行搜索资料 还是hello world #include &amp;amp;amp;amp;lt;SDL.h&amp;amp;amp;amp;gt; #include &amp;amp;amp;amp;lt;ios

creambean的博客 8659

Game:使用SDL2设计的游戏

游戏 使用SDL2设计的游戏 如何建造 在克隆的存储库中,已经有一个CMakeLists。 在控制台上,您可以直接: mkdir build # will create a new directory cd build cmake .. # will build the makefile and all the dependances on your build directory. make # will build your executable ./Game # to run the program 然后,我们在推送之前删除构建文件夹。

SDL解析——SDL简介

SDL是什么?它是一个集输入控制,音频处理,视频处理于一身的跨平台底层函数库。SDL的一个主要应用领域就是游戏开发。很多知名的游戏都是以它为基础的。由于它的易用,高性能以及跨平台等诸多优点。被广泛的应用在各种操作系统之中。    SDL本身是使用C语言写成的。对C/C++语言具有原生的支持。与此同时,它也被绑定到了其他编程语言之中,这些语言包括Ada, C#, D, Eiffel, Erlang, Euphoria, Guile, Haskell, Java, Lisp, Lua, ML, Object

桃李无言 1万+

SDL教程零基础入门 简单操作 day1

sdl 教程零基础从新手到大佬,从大佬到萌新

ylh的博客 5036

四、Renderer学习

因为游戏的图像大多是实时显示的,所以每次渲染的过程都会有一个标准的流程: 清除背景 渲染图像 显示图像 这个流程几乎适合任何一款游戏的渲染。

GBEDC的博客 1732

SDL2常用函数&结构分析:SDL_Event&SDL_PollEvent

SDL_Event SDL_Event是个联合体,是SDL中所有事件处理的核心。 SDL_Event是SDL中使用的所有事件结构的并集。 只要知道了那个事件类型对应SDL_Event结构的那个成员,使用它是一个简单的事情。 下表罗列了所有SDL_Event的所有成员和对应类型。 Uint32 type event type, shared with all events SDL_C...

SuperLi 5876

SDL游戏开发之一-SDL的简介

本教程为一个长系列,旨在于从零开始边学习SDL边开发游戏。 一.什么是SDLSDL(Simple DirectMedia Layer)是一套开放源代码的跨平台多媒体开发库,使用C语言写成。SDL提供了数种控制图像、声音、输出入的函数,让开发者只要用相同或是相似的代码就可以开发出跨多个平台(Linux、Windows、Mac OS X等)的应用软件。目前SDL多用于开发游戏、模拟器、媒体播放...

bull521的博客 1万+

C语言游戏开发:Pygame、SDL、OpenGL深度解析

C语言游戏开发技术解析 本文深入探讨了C语言游戏开发中的三大核心技术框架:Pygame、SDL和OpenGL。文章首先阐述了游戏开发作为C语言重要技能的价值,包括其在高性能游戏开发领域的核心地位。 在技术实现层面,详细分析了: Pygame框架:基于SDL的Python游戏库,介绍了窗口管理、事件处理、图形渲染等核心架构,并提供了窗口创建和图形绘制的代码示例。 SDL框架:跨平台多媒体库,讲解了其窗口系统、事件处理和渲染机制,展示了C语言下的SDL窗口创建和图形绘制实现。 文章通过具体代码示例演示了各框架的

编程世界如山海,探索不止。 2万+

深入探索SDL游戏开发

"深入探索SDL游戏开发

热爱编程的小K的博客 4592

【Linux】使用SDL进行游戏开发:如何在Linux上使用SDL库进行2D/3D游戏开发

Simple DirectMedia Layer (SDL) 是一个跨平台的多媒体库,广泛用于2D和3D游戏开发SDL提供了对音频、键盘、鼠标、游戏控制器、图像和窗口的访问。本文将介绍如何在Linux上配置和使用SDL库进行2D/3D游戏开发

科技改变人类,技术成就未来 1395

如何在Linux平台使用SDL库进行2D/3D游戏开发

Simple DirectMedia Layer (SDL) 是一个跨平台的多媒体库,广泛用于2D和3D游戏开发SDL提供了对音频、键盘、鼠标、游戏控制器、图像和窗口的访问。本文将介绍如何在Linux上配置和使用SDL库进行2D/3D游戏开发???? 1. 环境准备 ???? 1.1 安装SDLSDL库在大多数Linux发...

cnzzs的博客 1498

C++面向对象封装SDL游戏开发实战教程

SDL(Simple DirectMedia Layer)是一个开源的跨平台多媒体开发库,专为高性能游戏和多媒体应用的底层开发而设计。它提供了对音频、键盘、鼠标、游戏手柄、图形硬件的低级访问接口,帮助开发者屏蔽不同操作系统之间的差异,实现一次编写、多平台运行。SDL支持的操作系统包括:- Windows- Linux- macOS- iOS- Android- 甚至嵌入式系统如Raspberry Pi。

weixin_28999139的博客 886

SDL3 游戏开发 Windows 环境搭建

本文档是一份关于在 Windows 系统上搭建 SDL3 游戏开发环境的详细笔记。首先,介绍了开发环境搭建所需的必备工具与库,包括 CMake、MinGW-w64、Ninja、Git、SDL3 及其扩展库,以及 VSCode 和相关插件,并提供了每个工具的安装步骤和验证方法。接着,详细说明了如何在 VSCode 中创建测试源文件、编写 CMakeLists.txt 文件和 CMakePresets.json 文件,以及如何进行编译和运行,以验证环境是否正确配置。最后,总结了整个搭建过程,强调了每一步操作的重

ymxyld的博客 4855

SDL库入门:掌握跨平台游戏开发和多媒体编程

SDL库入门:掌握跨平台游戏开发和多媒体编程

探索C++编程的奥秘,分享深入的技术见解和实践,旨在激发读者创造力与解决问题的思维。 5401

如何快速掌握SDL:跨平台游戏开发的完整教程

SDL(Simple DirectMedia Layer)是一个强大的跨平台多媒体开发库,广泛应用于游戏和多媒体应用程序开发。无论你是游戏开发新手还是想要扩展跨平台开发技能的程序员,本教程都将为你提供完整的SDL学习路径。 ## 🎯 为什么选择SDL进行游戏开发 SDL提供了对音频、键盘、鼠标、游戏杆和图形硬件的低级别硬件抽象层,让你能够专注于游戏逻辑而不是平台特定的细节。它的跨平台特性意味

gitblog_00762的博客 1004

SDL库的安装

SDL的介绍    SDL是Simple DirectMedia Layer(简易直控媒体层)的缩写。它是一个跨平台的多媒体库,以用于直接控制底层的多媒体硬件的接口。这些多媒体功能包括了音频、键盘和鼠标(事件)、游戏摇杆等。当然,最为重要的是提供了 2D图形帧缓冲(framebuffer)的接口,以及为 OpenGL 与各种操作系统之间提供了统一的标准接口以实现 3D图形。从这些属性我们可以

zhangliang_571的专栏 1万+

SDL游戏开发之五-解析并使用GIF

游戏开发中,使用的图片一般情况下的格式为PNG,在我看来PNG有着以下几个好处: 不错的压缩比 alpha通道(支持透明) 无损压缩 以上的几个特性使得PNG在游戏开发中大放异彩。另外,主流就是使用PNG+TexturePacker,把碎图整合成一张大的图片(一般是POT Power Of Two,图片的宽和高是2的幂),然后再在程序中使用。这样做的好处主要是为了兼容旧的设备、方便对齐处理...

bull521的博客 1625

windows下用mingw32+sdl进行简单2d游戏开发(c语言)

1、下载sdl库:http://www.libsdl.org/release/SDL-devel-1.2.15-mingw32.tar.gz 2、下载sdl_image库:http://www.libsdl.org/projects/SDL_image/release/SDL_image-devel-1.2.12-VC.zip 3、在mingw32/include下建立SDL文件夹。把sdl

沙舟狼客 1120

SDL+OpenGL+GLSL游戏开发框架指南

SDL(Simple DirectMedia Layer)是一个跨平台的开发库,用于提供低层次的访问音频、键盘、鼠标、游戏手柄和图形硬件。自从1998年发布以来,SDL已成为游戏和多媒体应用程序开发的事实标准之一。图形渲染管线是图形学领域的一个重要概念,它描述了从场景的数据表示到最终在屏幕上显示的像素的整个过程。OpenGL定义了一个抽象的图形渲染管线,它规定了应用程序如何将顶点、几何图形以及图像数据发送到图形硬件进行处理。渲染管线可以分为两个主要部分:顶点处理和片元处理。

weixin_31185473的博客 1250
上一篇: SDL游戏开发之五-解析并使用GIF
下一篇: 无监督学习 k-means算法
小牛_牛sky
博客等级 码龄12年 221粉丝 130原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值