以下是 sdl 2.0 中最重要的新功能:
- 全3D 硬件加速
- 在各种配置文件中支持 opengl 3.0 + (核心、兼容性、调试、健壮等)
- 支持 opengl es
- 支持多个窗口
- 支持多显示器
- 支持多个音频设备
- 录音支持
- android 和 ios 支持
- Emscripten 和本地客户端支持
- 简单的2D 渲染 api, 可以使用 Direct3D, opengl, opengl es, 或软件渲染
- XInput 和 XAudio2 对 windows 的支持
- 原子操作
- 电源管理 (暴露电池剩余寿命等)
- 异型窗
- 32位音频 (int 和浮点)
- 简化游戏控制器 api (操纵杆 api 仍然在这里!)
- 触摸支持 (多点触控, 手势等)
- 更好的全屏支持
- 更好的键盘支持 (scancodes vs keycodes 等)。
- 消息框
- 剪贴板支持
- 在 sdl 之上构建健壮的 gui 工具包的 api
- 基本的拖放支持
- 正确的 unicode 输入和 ime 支持
- 强大的断言宏
- zlib 许可证而不是 lgpl。
- 1.2 的老烦恼都消失了
- 许多其他的事情!
没有内置到 SDL2 的兼容层。如果 api 更改为 2.0, 我们已经改变或删除了旧的功能, 这是有意义的。如果将1.2 程序指向2.0 头, 它可能无法编译。这份文件将试图告诉你最重要的变化, 和那些最有可能绊倒你。
没有 SDL_main 嗯, 好了, 现在, 它做了什么, 它总是意味着: 是一小段代码, 隐藏主 () 和 winmain () 在 windows 上的区别。它没有初始化代码, 它是完全可选的。这意味着您可以不用它接管您的主线而使用 sdl, 这对于使用 sdl 的插件或用 sdl 模块编写脚本语言是很好的。所有的东西, 你想要的 1.2 SDL_main 是现在在 SDL_Init (), 它属于。
没有 sdl 降落伞了1.2 所谓的 SDL_INIT_NOPARACHUTE 是一个默认的和唯一的状态现在。这将导致问题, 如果不是主线程崩溃, 它会干扰应用程序设置自己的信号/异常处理程序。在缺点, 一些平台不清理全屏视频时, 崩溃。您应该安装自己的崩溃处理程序, 或调用 SDL_Quit () 在 atexit () 函数或诸如此类的事情, 如果这是一个关注。请注意, 在 unix 平台上, sdl 仍然捕获情报并将其映射到 SDL_QUIT 事件。
视频 api 是1.2 最引人注目的变化。由于 sdl 的 api 是在1990代末设计的, 因此需求发生了很大的变化。为了处理现代硬件和 os 功能, 我们几乎完全取代了旧的1.2 视频 api。
不要担心, 新的是相当伟大的, 一旦你明白什么是改变, 你会非常高兴的新功能, 它可以带到您的1.2 游戏。我们以后再讨论这些。
好消息是: 如果你的游戏使用 opengl, 你可能没有太多的事情要做: 把一些函数调用转换为 SDL2 等价的, 你就可以走了。
对于2D 图形, sdl 1.2 提供了一个称为 “曲面” 的概念, 它是像素的内存缓冲区。屏幕本身是一个 “表面”, 如果你在做2D 软件渲染, 我们提供了在曲面之间复制 (“blit”) 像素的函数, 必要时转换格式。你几乎总是在系统 ram 的 cpu, 而不是在 gpu 的视频内存。sdl 2.0 更改此项;您几乎总是现在得到硬件加速, 并且 api 已经更改以反映这一点。
如果你有一个2D 的游戏, 很可能你已经采取了三种方法之一渲染。我们会把它们都翻过去, 但首先, 让我们来谈谈介绍性的东西。
记得 SDL_SetVideoMode () 吗?完全消失了sdl 2.0 允许您拥有多个窗口, 因此旧功能不再有意义。
SDL_WM_SetCaption("My Game Window", "game");
SDL_Surface *screen = SDL_SetVideoMode(640, 480, 0, SDL_FULLSCREEN | SDL_OPENGL);
现在是这样的:
SDL_Window *screen = SDL_CreateWindow("My Game Window",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
640, 480,
SDL_WINDOW_FULLSCREEN | SDL_WINDOW_OPENGL);
你可以看到这个地图非常接近1.2。不同的是, 你可以有多个窗口 (如果你想), 你可以控制他们更多。SDL_WM_SetCaption () 消失了, 因为我们希望允许每个窗口都有自己的标题 (以后可以用 SDL_SetWindowTitle () 来更改它), 我们希望让您指定一个窗口位置 (或者, 在这种情况下, 使用 SDL_WINDOWPOS_UNDEFINED, 因为我们不关心系统的位置。SDL_WINDOWPOS_CENTERED 也是一个不错的选择)。
允许用户为窗口指定显示的额外信贷: SDL2 还使您可以管理具有多个监视器的系统。不过现在不要担心这个
现在你的窗口又回到屏幕上了, 我们来谈谈策略吧。SDL2 仍然有 SDL_Surface, 但你想要的, 如果可能的话, 是新的 SDL_Texture。表面现在总是在系统 ram 中, 并且总是由 cpu 操作, 所以我们想离开那里。SDL2 有一个新的渲染 api。它的意思是使用简单的2D 游戏, 但最值得注意的是, 它的意思是把所有的软件渲染到视频 ram 和 gpu 上。即使你只是想用它来让你的软件渲染器的工作在屏幕上, 它带来了一些非常好的好处: 如果可能的话, 它会使用 opengl 或 Direct3D 幕后, 这意味着你会得到更快的 blits, 工作蒸汽覆盖, 并免费缩放。
程序看起来像这样。
SDL_SetVideoMode () 成为 SDL_CreateWindow (), 正如我们之前讨论过的。但是我们该如何解决这个决议呢?如果你的游戏是硬编码到 640x480, 例如, 你可能会运行到监视器, 不能做到这一点全屏分辨率, 在窗口模式, 您的游戏可能看起来像一个动画邮票上真正的高端显示器。在 SDL2 有一个更好的解决方案。
我们不再叫 SDL_ListModes () 了。有一个等价的 SDL2 (调用 SDL_GetDisplayMode () 在一个循环, SDL_GetNumDisplayModes () 时间), 但相反, 我们将使用一个新的功能称为 “全屏桌面”, 这告诉 sdl “给我整个屏幕, 不要改变决议。对于我们假设的640x480 游戏, 它可能看起来像这样:
SDL_Window *sdlWindow = SDL_CreateWindow(title,
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
0, 0,
SDL_WINDOW_FULLSCREEN_DESKTOP);
请注意, 我们没有指定640或480…fullscreen 桌面为您提供整个显示并忽略您指定的任何维度。游戏窗口应该立即出现, 而无需等待显示器点击到一个新的分辨率, 我们将使用 gpu 缩放到桌面大小, 这往往是更快, 更清洁的前瞻比如果 lcd 是假装一个较低的分辨率。额外的奖金: 没有一个你的背景窗口正在调整自己的现在。
现在我们需要一个渲染上下文。
SDL_Renderer *renderer = SDL_CreateRenderer(sdlWindow, -1, 0);
渲染器隐藏了我们如何在窗口中绘制的细节。这可能是使用 Direct3D, opengl, opengl es, 或软件表面幕后, 取决于系统提供;不管 sdl 选择什么, 您的代码都不会更改 (尽管欢迎您强制使用一种或另一种渲染器)。如果要尝试强制 sync-to-vblank 以减少撕裂, 可以使用 SDL_RENDERER_PRESENTVSYNC 代替零作为第三个参数。您不应该在这里创建带有 SDL_WINDOW_OPENGL 标志的窗口。如果 SDL_CreateRenderer () 决定要使用 opengl, 它将为您适当地更新窗口。
现在你明白了这是如何工作的, 你也可以在 SDL_CreateWindowAndRenderer () 的一个步骤中完成这一切, 如果你不想要任何花哨的东西:
SDL_Window *sdlWindow;
SDL_Renderer *sdlRenderer;
SDL_CreateWindowAndRenderer(0, 0, SDL_WINDOW_FULLSCREEN_DESKTOP, &sdlWindow, &sdlRenderer);
假设这些函数没有失败 (总是检查空值), 您就可以开始绘制到屏幕上了。让我们开始把屏幕清除到黑色。
SDL_SetRenderDrawColor(sdlRenderer, 0, 0, 0, 255);
SDL_RenderClear(sdlRenderer);
SDL_RenderPresent(sdlRenderer);
这样的工作, 你可能会认为;用黑色绘制 (r、g、b 全部为零, alpha 满), 清除整个窗口, 将清除的窗口放在屏幕上。这是正确的, 如果您使用 SDL_UpdateRect () 或 SDL_Flip () 来获取您的位到屏幕, 渲染 api 使用 SDL_RenderPresent ()。
这里还有一个一般的东西由于我们使用的是 SDL_WINDOW_FULLSCREEN_DESKTOP, 我们实际上并不知道有多少屏幕需要绘制。幸运的是, 我们不需要知道。1.2 的好东西之一是, 你可以说: “我想要一个640x480 窗口, 我不在乎你怎么做,” 即使得到它意味着在一个更大的分辨率代表您的应用程序的窗口。
对于 2.0, 渲染 api 允许你这样做..。
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear"); // make the scaled rendering look smoother.
SDL_RenderSetLogicalSize(sdlRenderer, 640, 480);
它会为你做正确的事。这是很好的, 您可以更改逻辑呈现大小以实现各种效果, 但主要用途是: 而不是试图使系统使用您的呈现大小, 我们现在可以使您的渲染大小与系统一起工作。在我的1920x1200 监视器上, 这个应用程序认为它现在正在与640x480 分辨率对话, 但是 sdl 正在使用 gpu 来扩展它以使用所有这些像素。请注意, 640x480 和1920x1200 的纵横比并不相同: sdl 也会处理这一问题, 尽可能多地扩展并 letterboxing 差异。
现在, 我们已经准备好开始绘制真正的。
一个特殊的例子, 旧的教学示范渲染游戏: 应用程序要绘制每个像素本身, 并获得最后一组像素到屏幕上有效地在一个大 blit。像这样的一个游戏的例子是厄运或杜克公爵 3D或许多其他的。
为此, 您将需要一个单一的 SDL_Texture, 将代表屏幕。现在让我们为我们的640x480 游戏创建一个:
sdlTexture = SDL_CreateTexture(sdlRenderer,
SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STREAMING,
640, 480);
这表示 gpu 上的纹理。战术是通过将像素上传到该纹理, 将纹理绘制到窗口, 并将此绘图翻转到屏幕上来完成每个帧。通过SDL_TEXTUREACCESS_STREAMING 告诉 sdl, 此纹理的内容将经常更改。
在你可能有一个 SDL_Surface 的屏幕, 你的应用程序提请, 然后调用SDL_Flip () 放在屏幕上。现在, 您可以创建一个 SDL_Surface, 它总是在 ram 中, 而不是使用您从 SDL_SetVideoMode () 中得到的, 或者只是 malloc () 要写入的一个像素块。理想情况下, 你写一个 rgba 像素的缓冲区, 但如果你需要做一个转换, 也没关系。
extern Uint32 *myPixels; // maybe this is a surface->pixels, or a malloc()'d buffer, or whatever.
在框架的末尾, 我们要上传到这样的纹理:
SDL_UpdateTexture(sdlTexture, NULL, myPixels, 640 * sizeof (Uint32));
这将把你的像素上传到 gpu 内存。如果你想用肮脏的长方形来捣乱, 那么空可以是一个分区域, 但是现代的硬件可能会把整个帧吞下, 没有太大的麻烦。最后一个参数是音高–从一行开始到下一行的字节数–因为在这个例子中我们有一个线性的 rgba 缓冲区, 它只是640乘以 4 (r、g、b、a)。
现在把纹理带到屏幕上:
SDL_RenderClear(sdlRenderer);
SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL);
SDL_RenderPresent(sdlRenderer);
就这样。SDL_RenderClear () 擦除现有的视频帧 (以防说, 蒸汽覆盖写在它的最后一帧), SDL_RenderCopy () 移动纹理的内容, 以视频帧 (并感谢 SDL_RenderSetLogicalSize (), 它将被缩放/居中, 如果显示器是 640x480), 和 SDL_RenderPresent () 把它放在屏幕上。
这种情况下, 你的 sdl 1.2 游戏加载一堆图形从磁盘到一堆 SDL_Surfaces, 可能试图让他们进入视频 ram 与 SDL_HWSURFACE。你加载这些一次, 你 blit 他们在必要的帧, 但否则他们永远不会改变。一个简单的2D 游戏可能会这样做。如果你倾向于认为你的表面是 “精灵”, 而不是像素的缓冲器, 那么这可能就是你。
您可以构建单独的纹理 (生活在 gpu 内存中的曲面), 就像我们为这一大纹理所做的那样:
sdlTexture = SDL_CreateTexture(sdlRenderer,
SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STATIC,
myWidth, myHeight);
这是你所期望的我们使用 SDL_TEXTUREACCESS_STATIC, 因为我们要上传我们的像素一次, 而不是一遍又一遍。但更方便的解决方案可能是:
sdlTexture = SDL_CreateTextureFromSurface(sdlRenderer, mySurface);
使用这个, 你加载你的 SDL_Surface 像往常一样, 但在最后, 你做了一个纹理。一旦你有一个 SDL_Texture, 你可以释放原来的表面。
在这一点上, 你的1.2 游戏有一堆 SDL_Surfaces, 它会 SDL_BlitSurface () 到屏幕表面组成最后的帧, 并最终 SDL_Flip () 到屏幕。对于 sdl 2.0, 您有一堆 SDL_Textures, 您将 SDL_RenderCopy () 到渲染器以组成最终的帧, 并最终 SDL_RenderPresent () 到屏幕。就这么简单如果这些纹理不需要修改, 你可能会发现你的帧也刚刚经历了屋顶。
如果要 blit 曲面并修改帧中的单个像素, 则情况会稍微复杂一些。往返行程–从纹理中读取数据–可能会令人痛苦地昂贵;通常情况下, 您希望始终将数据推向一个方向。在这种情况下, 你最好是把所有的东西都放在软件中, 直到最后的屏幕上, 所以我们将结合前两种技术。
好消息是: 1.2 SDL_Surface 的 api 大部分仍然存在。因此, 请更改屏幕表
SDL_Surface *screen = SDL_SetVideoMode(640, 480, 32, 0);
变为:
// if all this hex scares you, check out SDL_PixelFormatEnumToMasks()!
SDL_Surface *screen = SDL_CreateRGBSurface(0, 640, 480, 32,
0x00FF0000,
0x0000FF00,
0x000000FF,
0xFF000000);
SDL_Texture *sdlTexture = SDL_CreateTexture(sdlRenderer,
SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STREAMING,
640, 480);
…, 并继续传输的东西和调整像素像以前一样, 组成您的最终帧到这个 SDL_Surface。一旦您准备好在屏幕上获取这些像素, 就像在我们的第一个场景中那样做:
SDL_UpdateTexture(sdlTexture, NULL, screen->pixels, screen->pitch);
SDL_RenderClear(sdlRenderer);
SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL);
SDL_RenderPresent(sdlRenderer);
请注意, 纹理创建可能使用既昂贵又有有限的资源: 不要每帧调用 SDL_CreateTextureFromSurface (),设置一个纹理和一个表面, 并从后者更新前者。
渲染 api 有更多的功能, 其中一些可以替换你的应用程序的代码: 缩放、线图等。如果您正在阅读本节, 因为您的需求超出了传输表面, 您可以停止戳单个像素并将所有内容移动到 gpu 上, 这将使您的程序大大提高速度, 并可能极大地简化您的代码。
您可以使用渲染 api 做一些简单的效果, 而不必直接进行像素操作。其中一些在1.2 表面上可用。
颜色 alpha: SDL_Color 现在包含第四, alpha 分量。处理 SDL_Colors 的1.2 代码可能不会复制/设置该值 (命名为 “未使用”)。在 2.0, 你应该。
alpha 混合: 使用 SDL_SetSurfaceAlphaMod 和 SDL_SetTextureAlphaMod 而不是 SDL_SetAlpha ()。通过 SDL_SetSurfaceBlendMode () 和纹理与 SDL_SetTextureBlendMode () 可以禁用表面上的 alpha 混合。
colorkey: 当打电话给 SDL_SetColorKey () 时, 你应该通过 SDL_TRUE 而不是 SDL_SRCCOLORKEY。
颜色调制: 某些器现在支持全局颜色更改 (民变 = 民变 * 颜色), 请检查 SDL_SetTextureColorMod () 以了解详细信息。
如果您已经直接使用了 opengl, 那么您的迁移非常简单。将您的 SDL_SetVideoMode () 调用更改为 SDL_CreateWindow (), 后跟 SDL_GL_CreateContext (), 并将您的 SDL_GL_SwapBuffers () 调用到 SDL_GL_SwapWindow (窗口)。所有到 gl 的实际调用都是完全相同的。
如果您使用的是 SDL_GL_SetAttribute (SDL_GL_SWAP_CONTROL, x), 这已经改变了。现在有一个 SDL_GL_SetSwapInterval (x) 调用, 因此您可以在现有的 gl 上下文上更改它。
请注意, sdl 2.0 可以在不丢失 gl 上下文的情况下切换窗口/全屏并返回 opengl 窗口 (万岁!为此, 请使用 SDL_SetWindowFullscreen ()。
好消息是, sdl 2.0 已使 unicode 输入可用。坏消息是, 它将对您的应用程序进行一些细微的更改。
在1.2 中, 许多只关心我们英语的应用程序仍然被称为 SDL_EnableUNICODE (1), 因为获取与按键关联的字符是很有用的。一旦你学到了英语, 这就不管用了, 一旦你得到了亚洲语言, 它就完全没有作用了。
事实证明, i18n 是很难的。
sdl 更改了此项。SDL_EnableUNICODE () 消失了, SDL_Keysym 的 unicode 字段也是如此。您不再从 SDL_KEYDOWN 事件中获取字符输入。使用 SDL_KEYDOWN 来处理键盘像一个101按钮游戏杆现在。文本输入来自其他地方。
新的事件是 SDL_TEXTINPUT。只要用户输入了新的文本, 就会触发此操作。请注意, 此文本可能来自按键, 也可能来自某种 ime (这是一种输入复杂的多文本的奇特方式)。此事件返回整个字符串, 可能是一个 char 长, 或者是多个代码的多数据。此字符串始终 UTF-8 编码。
如果你所关心的是用户是否按了某个键, 那仍然是 SDL_KEYDOWN, 但是我们已经把这个系统分成了1.2 个部分: keycodes 和 scancodes。
Scancodes 的意思是与布局无关。认为这是 “用户按下 q 键, 因为它会在美国 qwerty 键盘”, 无论这是实际上是一个欧洲键盘或伏都键盘或任何。扫描始终是相同的关键位置。
Keycodes 的意思是布局依赖。将其视为 “用户按下在特定键盘上标记为” q “的键。
例如, 如果按下钥匙, 这是美式qwerty 键盘上的大写锁的两个键, 它将报告扫描的 SDL_SCANCODE_S 和号码的 SDLK_S。在伏地键盘上的同一键, 将报告扫描的 SDL_SCANCODE_S 和号码的 SDLK_O。
请注意, keycodes 和 scancodes 现在都是32位, 并且使用的数字范围很广。没有 SDLK_LAST 了如果您的程序有一个 SDLK_LAST 元素的查找表, 要在 sdl 密钥和您的应用程序内部需要的任何内容之间进行映射, 则不再可行。请改用哈希表。std:: 地图会做。如果您要映射 scancodes 而不是 keycodes, 则有 SDL_NUM_SCANCODES, 您可以使用数组边界。现在是512
SDLMod 现在是 SDL_Keymod, 其 “元” 键 (“windows” 键) 现在被称为 “gui” 键。
SDL_GetKeyState () 已重命名为 SDL_GetKeyboardState ()。返回的数组现在应由 SDL_SCANCODE_ * 值 (请参见 SDL_SCANCODE) 而不是 SDL_Keysym 值进行索引。
现在, 对于鼠标输入。
第一个变化, 仅仅是足够的, 是滚轮不再是一个按钮。这是一个错误的历史, 我们更正了它在 sdl 2.0。寻找 SDL_MOUSEWHEEL 事件。我们支持垂直和水平的车轮, 和一些平台可以处理双手指滚动的触摸板作为车轮输入, 太。您将不再接收鼠标滚轮的 SDL_BUTTONDOWN 事件, 并且按钮4和5现在是真正的鼠标按钮。
如果你的游戏需要永远滚动鼠标在一个方向, 例如, 让一个球员在 fps 旋转周围没有鼠标击中屏幕边缘和停止, 你可能隐藏了鼠标光标和抓取输入:
SDL_ShowCursor(0);
SDL_WM_GrabInput(SDL_GRAB_ON);
在 SDL2, 这种方法的作用略有不同。你叫..。
SDL_SetRelativeMouseMode(SDL_TRUE);
其余的则由 sdl 来做。
SDL_PushEvent () 现在返回1成功, 而不是0。
事件掩码现在使用范围指定:
SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_EVENTMASK(SDL_MOUSEBUTTONDOWN));
成为:
SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_MOUSEBUTTONDOWN, SDL_MOUSEBUTTONDOWN);
音频的好消息是, 有一个例外, 它完全向后兼容1.2。如果您想要这些新功能, 它们可供您使用, 但您可能只是编译并运行而没有它们。
这是一个非常重要的例外: 音频回调不再以完全初始化的缓冲区开始。在所有情况下都必须完全写入缓冲区。如果你没有足够的音频, 你的回调应该写沉默。如果你不这样做, 你会听到重复的音频, 或者可能是音频损坏。如果要恢复无条件初始化缓冲区的旧行为, 只需在回调开始时放置一个 SDL_memset (流、0、len)。
游戏杆事件现在指的是 SDL_JoystickID。这是因为 sdl 2.0 可以处理控制杆的进出 , 因为在游戏的生命周期中 , 设备入并拉出 , 因此 , 1 . 2 使用的设备列表中的索引将毫无意义 , 因为可用的设备列表会发生更改。
要获得您打开的 SDL_Joystick * 的 SDL_JoystickID, 请致电:
SDL_JoystickID myID = SDL_JoystickInstanceID(myOpenedStick);
并且比较操纵杆事件,哪个领域反对 myid。如果您没有使用事件队列的游戏杆, SDL_JoystickGetAxis () 和朋友的工作就像 sdl 1.2。
你也应该检查出新的游戏控制器 api, 因为它很酷, 也许你做了很多踢踏舞与 1.2 api, 这一新的代码将解决更干净。你可以在 SDL_gamecontroller 找到它。游戏控制器 api 真的很好地结合了蒸汽大图片模式: 你得到了大多数控制器的自动配置, 以及一个不错的 ui, 如果你必须手动配置它。无论是哪种情况, 蒸汽都将此配置传递给您的 sdl 应用程序。
支持旧的操纵杆 api (/开发/输入/js ) 为 linux 已经从 SDL2 下降。SDL2 只支持新的事件 api (/开发/输入/事件 ) 的操纵杆。对于普通用户帐户, 这些事件通常是不可读的, 因此即使操纵杆插入, 也可能没有检测到。这是最终用户必须为自己配置的东西。
SDL_KillThread () 不见了。这是从来没有安全或可靠的。最好的替换是设置一个标志, 告知线程应该退出。该线程应该检查标志与一些频率, 然后 “杀死” 线程调用 SDL_WaitThread () 清理。
SDL_CreateThread () 现在需要一个额外的参数, 这个线程的名称可以由调试器用来识别它。如果你不关心, 只是在你的函数调用额外的空。
1.2 cd api 完全消失了。没有替代品在这一点上, 如果您正在传送光盘, 那么您就不会将您的音乐作为 cd 音频曲目传送到光盘上。您可以使用 ogg vorbis 或其他一些音频文件格式的音乐, 其中许多是由 SDL_mixer 提供的。
我们撕开了一堆旧平台, 比如 OS/2 和 mac os 9。更容易列出我们仍然支持的部分: windows (xp 和更高版本)、linux、mac os x、ios、android。在 sdl 的传统中, 还有其他人在外围工作, 但却没有得到大力支持, 比如俳句和索尼 psp。我们将添加任何平台, 有人发送补丁, 但它似乎是时间向一些老朋友告别时, 移动到新的版本。
多年来, sdl 1.2 的非官方扩展一直是 ios 和 android。sdl 现在直接支持这些平台, 而 2.0 api 更适合它们。您在本文档其他地方得到的大多数建议都适用, 但还有其他一些值得注意的事项。
首先, 有些事件只适用于移动设备, 或者更好地说, 适用于移动设备操作系统在 post-iPhone 的世界中运行的方式。我们最初尝试将这些项目映射到现有的 sdl 事件 (如 “您的应用程序正在进入后台” 被视为桌面窗口失去焦点), 但还有一个更紧迫的问题: 这些事件中的大多数需要立即响应, 如果应用程序没有给出一个, 操作系统将会杀死您的应用程序。
因此, 我们已经为一些 android 和 ios 的具体细节添加了新的 sdl 事件, 但是您应该设置一个 sdl 事件过滤器, 以便在操作系统报告它们时立即捕获它们, 因为等待您的下一个 SDL_PollEvent () 循环将为时已晚。
例如, 有 SDL_APP_WILLENTERBACKGROUND, 这是 ios 的 applicationWillResignActive (), 如果您在这个事件到达后绘制到屏幕上, ios 将终止您的进程。所以你要立即抓住这个:
int SDLCALL myEventFilter(void *userdata, SDL_Event * event)
{
if (event->type == SDL_APP_WILLENTERBACKGROUND) {
// free up resources, DON'T DRAW ANY MORE until you're in the foreground again!
}
// etc
return 1;
}
在初创公司附近..。
这将在生成事件后立即调用 myEventFilter (数据、事件)。
SDL_AddEventWatch (myEventFilter, 数据);
第二, 现在有真正的触摸事件, 而不是试图映射到鼠标输入。您可以跟踪触摸, 多个手指, 甚至复杂的手势。你可能想用那些有关这些函数的列表, 请参阅 SDL_touch h. SDL_Finger SDL_events。
请注意, sdl 还会将简单的触摸图映射成鼠标事件 (将鼠标事件的 “” 字段设置为 SDL_TOUCH_MOUSEID), 这意味着, 如果你不关心更复杂的触摸界面, 你现有的桌面应用程序可能仍然在手机上的框中工作, 用户用手指戳屏幕。这样: 移动感知应用程序应该忽略 SDL_TOUCH_MOUSEID 事件, 但仍然尊重 “真正的” 鼠标事件除了触摸事件-一些移动设备支持 usb 和蓝牙小鼠, 毕竟!–但是当你在 SDL2 上运行时, 当你开始擦亮你的应用程序时, 这是一个更深层次的考虑。
还有其他一些移动友好的功能, 如 SDL_StartTextInput (), 这将显示 on-screen 键盘。利用它们。
此外, 还有 android 和 ios 的特定功能, 让您能够访问在通用 api 中没有意义的平台特定功能。有关这些函数的列表, 请参阅 SDL_system. h。
SDL_RWread () 和 SDL_RWwrite () 现在返回0错误而不是-1。
如果您编写了自己的 SDL_RWops 实现, 则函数签名已更改。函数现在使用 Sint64 和 size_t 而不是 int, 这样他们就可以处理大文件。在许多情况下, 您可以只更新您的功能签名, 并继续像以前一样工作, 但如果您遇到了这些限制, 您可能会很高兴有一个解决方案。调用应用程序应该知道返回值已更改。
还有一个大小的方法来 RWops, 现在。它被称为 SDL_RWsize ()。这可以让 RWops 报告流的大小, 而不必使应用程序从末尾到零字节;换言之, 您可以报告无法查找的流的总大小。对于那些甚至不能这样做的流, 你仍然可以返回-1。
SDL_image、SDL_ttf、SDL_mixer 和 SDL_net 的官方扩展有一个专用于 sdl 2.0 的版本: SDL2_image、SDL2_ttf、SDL2_mixer 和 SDL2_net。您可能需要从善变的存储库中下载最新的修补程序。随后, 当然, 你将不得不链接, 如 SDL2_image, 而不是 SDL_image, 编译你的程序。
这些库将不支持1.2 向前迈进, 与1.2 的任何兼容性可能会在某些时候从较新版本中消失。
SDL_gfx 也可以编译与2.0 从 2.0.21 (2010年5月) 开始。
某些重命名或替换的内容的摘要
一个简短的作弊表, 其中一些旧的功能和其他的东西去:
在 sdl 2.0 中有大量新的和有趣的功能, 1.2 的人甚至做梦也没想到。我们只是试图解释你可能要做什么, 让你的1.2 程序运行在2.0 这里, 但你应该探索的文件, 你可能一直希望的东西, 直到现在, 没有。例如, 我所移植的每一个游戏都以一个消息框函数的结尾为例:
#if USING_SDL
fprintf(stderr, "MSGBOX: %s\n%s\n", title, text); // oh well.
#endif
现在有 SDL_ShowSimpleMessageBox ()。不客气!
如果你跳过前面, 回去看看所有的新功能在概述!