Lode 的计算机图形学教程

C++、SDL 与 QuickCG

目录

返回索引

C++、SDL 与 QuickCG

本教程附带了一个名为 QuickCG 的 SDL 1.2 代码库。文章中所有的 C++ 代码都使用 QuickCG 及其函数在屏幕上绘制图形。

本页将介绍如何使用 QuickCG 运行示例。其中提供了在 DevC++ IDE 以及 g++ 中配置 SDL 和 QuickCG 的方法。

接下来是一些 QuickCG 的示例脚本。

最后,页面提供了包含所有 QuickCG 函数、部分 C++ 函数和运算符、QuickCG 与 SDL 数据类型,以及所有 SDL 键盘按键名称的表格。

QuickCG 可在此处下载:

SDL 是一个可在 Windows、Linux 等多种平台上处理图形、音频、键盘、鼠标和手柄输入的 API。SDL 也可用于初始化并使用 OpenGL 进行 3D 图形渲染。本教程的代码库使用 SDL 处理图形和输入,但教程的重点在于图形算法本身,而非 SDL。在本教程中,SDL 的函数很少被直接调用(而是通过 QuickCG 间接使用),不过如果你想用 SDL 制作游戏,学习一些 SDL 知识总是有益的。

QuickCG 是专为本教程设计的,目标是尽可能易用、通用,使用起来有点像脚本语言。QuickCG 提供了用于设置屏幕、在屏幕上绘制像素和 2D 基本图形、处理输入、进行颜色模型转换、使用内置字体在屏幕上打印文字和数字、加载图片等功能。由于 QuickCG 并未针对性能进行优化,因此不太适合用于开发实际游戏。
本页后续提供了其包含的所有函数的完整列表。

DevC++

本节适用于想在 Windows 中使用 DevC++ 运行示例的用户。请注意,DevC++ 现在已经非常老旧了,在本教程编写时它很流行,但截至 2016 年已相当过时。你可以自由选择更现代的工具,例如 Code::Blocks、Visual Studio,或者(如果你有的话)带有 g++ 或 clang++ 的 POSIX 终端(见下一节)以及你喜欢的文本编辑器。本节的步骤在其他 IDE 中也可能有参考价值,请继续阅读。

DevC++ 是一款免费的 Windows IDE,使用 gcc 3.2 或更高版本的编译器。如需 DevC++ 的使用帮助,建议查阅帮助文件、尝试打开并编译一些内置示例、访问 bloodshed.net 网站,或直接继续阅读本文。DevC++ 可从 http://www.bloodshed.net/ 下载。

本章仅面向希望使用免费的 DevC++ IDE 编译 QuickCG 和示例的 Windows 用户。在其他平台上使用 SDL 和 QuickCG 也完全可行,但目前本文暂不作介绍。如果你不知道如何操作,可以访问 SDL 官网或通过搜索引擎查找如何在你的编译器中安装它,然后在编译器中新建一个项目并将 QuickCG 的 .cpp 和 .h 文件添加进去。

如果你尚未安装最新版本的 DevC++,请按照以下步骤将其与 SDL 配置好。如果已安装 DevC++ 但尚未安装 SDL 开发库,请从步骤 2) 开始。

为 DevC++ 安装 SDL 1.2 并不容易,但只要仔细按照以下步骤操作,可以让 SDL 1.2 的最新版本在 DevC++ 中正常工作的:

1)http://www.bloodshed.net/dev/devcpp.html 下载并安装最新版本的 DevCpp
2)http://www.libsdl.org/ 下载 SDL 1.2:下载适用于 Mingw32 的开发库(Windows 版)和 Windows 运行时库。解压 .tar.gz 文件可能需要 WinRAR。注意:本教程编写于 SDL 1.2 时代,不兼容最新的 SDL 2.0 及更高版本。
3) 运行时库中包含 SDL.DLL 文件,将其放入 C:\Windows\System32 文件夹,或放入你编译好的程序所在的文件夹。请记住,如果你希望没有该文件的其他人也能运行你的程序,必须始终将 SDL.DLL 随程序一起分发。针对最新版 SDL 编译的程序无法与旧版 DLL 兼容。
4) 解压 SDL 开发文件,但暂时不要放入 DevC++ 文件夹,先放到其他文件夹中。
5) 将开发文件中 include 文件夹内的 SDL 文件夹,复制到 DevC++ 的 include 文件夹中(这样所有 SDL 头文件就位于 DevC++ 的 include/SDL 目录下)。
6) 将开发文件的 lib 文件夹中的所有文件,复制到 DevC++ 的 lib 文件夹中。

现在你已经安装好带有 SDL 1.2 的 DevC++ 了!不过你还需要了解如何创建一个使用 SDL 的可运行项目。开发包中的其他文件包含完整的 SDL 文档、示例和测试,以及二进制文件。你的 DevC++ 文件夹结构现在应如下图所示,其中 SDL 文件夹是新增的,lib 文件夹中也包含了来自 SDL 开发包的新文件。

如果你使用本教程提供的 SDL 1.2 代码库(QuickCG),请将其解压到你的代码文件夹(即存放所有 DevC++ 项目和代码的文件夹,最好不要放在不可靠的 Windows"我的文档"文件夹中),然后用 Dev-C++ 打开其 *.dev 文件,即可正常编译和运行。编译时,请使用菜单中的"执行 -> 编译"。生成的 exe 文件将出现在代码所在的同一文件夹中。你可以通过"执行 -> 运行"来运行它,也可以按 F9 直接编译并运行项目。如果无法正常工作,请继续往下查看可能的解决方案列表。强烈建议在本教程中使用 QuickCG,因为教程的其余部分聚焦于其命令,而非 SDL 本身。

但如果你想在 DevC++ 中创建自己的新 SDL 项目(本教程不需要此操作):

7) 启动 DevC++ 并新建一个项目,将所需的 .cpp 和 .h 文件添加进去。
8) 在菜单中打开"项目 -> 项目选项",找到链接器命令设置(在 DevC++ 5 Beta 8.10 中位于"参数"选项卡下),添加以下内容:
-lmingw32
-mwindows
-lSDLmain
-lSDL
注意顺序非常重要!如果先写 -lSDL 再写 -lSDLmain,将无法正常工作!



9) 在你的 cpp 文件中,添加 #include <SDL/SDL.h>
10) 在链接器选项中,关闭控制台。
11) 在"项目选项"的"编译器"选项卡以及通用编译器选项中,开启所有优化设置,因为这些设置真的会带来很大的性能差异!你还可以在链接器参数中添加 -s 来减小生成的 *.exe 文件大小;如果不这样做,即使关闭了调试设置,生成的 exe 文件中也会包含大量调试信息(截至 DevC++ 5 Beta 8.10)。

如果在编译 SDL 项目时遇到编译错误,请检查以下几点:

一旦配置成功,你就可以用 DevC++ 打开 quickcg.dev 文件,进入 main.cpp 文件输入代码,从而运行教程中的示例代码。下图是打开后 main.cpp 文件的截图。



g++

本节适用于想使用 g++ 运行示例的用户。

使用 g++ 非常简单:将 QuickCG 的所有 .cpp 和 .h 文件放在同一目录下,把教程的示例代码放入 main.cpp 文件,然后使用以下命令进行编译:

g++ *.cpp -lSDL -O3

其中 -O3 是可选的编译器优化选项,-lSDL 用于链接 SDL 库。这要求你的发行版中已安装 SDL(请查找 sdl 和 sdl-devel 等相关软件包)。

使用 QuickCG

QuickCG 目前由以下代码文件和一个 .dev 文件组成:
main.cpp 文件是放置本教程示例代码的地方。如果某个代码示例中没有提到 main 函数,请自行创建一个,并将示例代码放在 main 函数内部。

main.cpp 文件中通常包含一个小示例:

int main(int argc, char *argv[]) 
{
screen(256, 256, 0, "Small Test Script");
for(int x = 0; x < w; x++)
for(int y = 0; y < h; y++)
{
pset(x, y, ColorRGB(x, y, 128));
}
redraw();
sleep();
}

以下是代码的功能说明:
编译并运行此代码后,输出结果如下:



现在尝试对程序做一些修改,例如将以下内容复制粘贴到 main 函数中(在 DevC++5 中可使用 CTRL+SHIFT+I 进行缩进):

int main(int argc, char *argv[]) 
{
screen(256, 256, 0, "Small Test Script");
for(int x = 0; x < w; x++)
for(int y = 0; y < h; y++)
{
pset(x, y, ColorRGB(0, 128 + 128 * sin(x / 8.0), 0));
}
print("Hello World!");
redraw();
sleep();
}

变化在于,你现在会看到一个绿色的正弦函数图案,以及文字"Hello World!",因为 print 函数的作用就是在屏幕上显示文字。输出结果应如下所示:



下面是另一个更简单的示例:

int main(int argc, char *argv[]) 
{
screen(256,256, 0, "A Face!");
drawDisk(128, 128, 100, colorRGB(255, 128, 200));
drawDisk(88, 100, 10, colorRGB(0, 0, 255));
drawDisk(168, 100, 10, colorRGB(0, 0, 255));
drawLine(88, 150, 168, 150, colorRGB(255, 0, 0));
redraw();
sleep();
}

drawDisk 命令将在指定位置绘制一个填充圆,具有指定的半径和 RGB 颜色。disk 函数被调用了 3 次:分别绘制一张脸和两只眼睛。
drawDine 命令将绘制一条直线。
redraw()sleep() 命令同样是必需的,前者使新绘制的像素得以显示,后者防止程序立即关闭。
输出结果应如下所示:



所有命令的完整列表见下方,下一章将通过大量简单示例介绍所有函数,帮助你学习使用 QuickCG。

完整函数列表

此列表包含 QuickCG 的所有函数、全局变量等。如果函数有默认参数,也会一并列出。

QuickCG 全局变量

全局变量通常不建议在大型编程项目中使用,但本教程的示例规模较小,使用全局变量会更方便。
变量 说明
w int w;
调用 screen 函数后,图形窗口的宽度。在本教程的示例中,w 最常用于遍历屏幕上每个像素的双重 for 循环中。
h int h;
调用 screen 函数后,图形窗口的高度。
font bool font[256][8][8];
这是 print 函数使用的字体。虽然可以在代码中访问和修改 font 变量,但通常不需要这样做。

QuickCG 数据类型

ColorRGB 一个包含 3 个整数(命名为 r、g、b)的简单结构体,构造函数如下:
ColorRGB(Uint8 r, Uint8 g, Uint8 b);
ColorRGB(ColorRGB8bit color);
ColorRGB();
此外还预定义了一些 RGB 颜色:
static const ColorRGB RGB_Black ( 0, 0, 0);
static const ColorRGB RGB_Red (255, 0, 0);
static const ColorRGB RGB_Green ( 0, 255, 0);
static const ColorRGB RGB_Blue ( 0, 0, 255);
static const ColorRGB RGB_Cyan ( 0, 255, 255);
static const ColorRGB RGB_Magenta (255, 0, 255);
static const ColorRGB RGB_Yellow (255, 255, 0);
static const ColorRGB RGB_White (255, 255, 255);
static const ColorRGB RGB_Gray (128, 128, 128);
static const ColorRGB RGB_Grey (192, 192, 192);
static const ColorRGB RGB_Maroon (128, 0, 0);
static const ColorRGB RGB_Darkgreen( 0, 128, 0);
static const ColorRGB RGB_Navy ( 0, 0, 128);
static const ColorRGB RGB_Teal ( 0, 128, 128);
static const ColorRGB RGB_Purple (128, 0, 128);
static const ColorRGB RGB_Olive (128, 128, 0);
ColorRGB 类还定义了 "+"、"-"、"*"、"/"、"==" 和 "!=" 运算符,以便更方便地进行颜色加法、与整数相乘等颜色运算。
ColorRGB8bit 一个包含 3 个 Uint8 类型(命名为 r、g、b)的简单结构体,构造函数如下:
ColorRGB8bit(Uint8 r, Uint8 g, Uint8 b);
ColorRGB8bit(ColorRGB color);
ColorRGB8bit();
ColorHSL 一个包含 3 个整数(命名为 h、s、l)的简单结构体,构造函数如下:
ColorHSL(Uint8 h, Uint8 s, Uint8 l);
ColorHSL();
ColorHSV 一个包含 3 个整数(命名为 h、s、v)的简单结构体,构造函数如下:
ColorHSV(Uint8 h, Uint8 s, Uint8 v);
ColorHSV();

通常,QuickCG 中使用的颜色应具有 8 位分量,即 0 到 255 之间的值。但这里使用整数而非 Uint8,是为了在结构体中存储计算的中间结果时不会发生数值溢出回绕。因此,你可以写出类似 "ColorRGB color3 = (color * opacity + color2 * (256 - opacity)) / 256;" 这样的表达式,并得到预期的结果。

之所以添加 ColorRGB8bit 类型,是因为 SDL 要求颜色分量使用 Uint8 类型,该类型仅在少数含有大量 SDL 代码的 QuickCG 函数内部使用。

SDL 基本数据类型

Uint8 无符号 8 位整数,本教程中用于颜色分量
Sint8 有符号 8 位整数
Uint16 无符号 16 位整数
Sint16 有符号 16 位整数
Uint32 无符号 32 位整数
Sint32 有符号 32 位整数
Uint64 无符号 64 位整数
Sint64 有符号 64 位整数

64 位类型并非在所有平台上都受支持。

QuickCG 函数

函数 说明
screen void screen(int width, int height, bool fullscreen, char* text=" ");
这可能是最重要的函数,因为它不仅创建图形屏幕,还初始化整个 SDL 上下文。即使不需要显示屏幕,也要在程序开始时调用此函数。整数 width 和 height 决定窗口的分辨率。如果 fullscreen 为 0,则以窗口模式运行;如果为 1,则全屏显示。text 可用于设置窗口标题。例如,要创建一个标题为"Hello"的 640*480 像素窗口,请使用: screen(640,480,0,"Hello");
keyDown bool keyDown(int key);
在当前帧调用 readKeys() 或 done() 函数之后,此函数可以检查每个按键是否被按下。例如,要检查"a"键是否被按下,可以判断 keyDown(SDLK_a) 是否为 true。所有按键的完整列表请参见下方的 SDL 按键表。
keyPressed bool keyPressed(int key);
与 keyDown() 类似,但区别在于:keyDown 在按键被按住期间持续返回 true,而 keyPressed 只在第一次检测时返回 true,只有当按键被释放后再次按下时才会再次返回 true。因此,keyDown 适合用于游戏中持续向前移动的按键,而 keyPressed 则适合用于选择武器等只需触发一次的按键。
redraw void redraw();
重新绘制屏幕。绘制像素、圆形和直线等内容后,在调用 redraw() 之前不会显示出来。此函数相对较慢,因此不要在每绘制一个像素后就调用它,而应在整个屏幕绘制完成后只调用一次。
cls void cls(int R = 0, int G = 0, int B = 0);
将屏幕清除为黑色。例如,在制作弹跳球程序时,每次都需要在新位置绘制圆形,如果不使用 cls(),旧位置的圆形仍然可见。也可以将屏幕清除为指定的 RGB 颜色。
pset void pset(int x, int y, ColorRGB color);
在屏幕的 x、y 位置(x 必须在 0 到 w-1 之间,y 必须在 0 到 h-1 之间)绘制一个指定 RGB 颜色的像素。ColorRGB 颜色包含 3 个分量 r、g、b,其值范围均为 0 到 255。
pget ColorRGB pget(int x, int y);
返回位置 x、y 处像素的颜色值。此操作需要从显卡内存中读取颜色,速度较慢。如果需要频繁调用此函数(例如处理透明度或填充操作时),最好使用缓冲区来保存颜色数据,从缓冲区中读取,并通过 drawBuffer 将缓冲区绘制到屏幕上。
drawBuffer void drawBuffer(Uint32 *buffer);
一次性将整个缓冲区绘制到屏幕上。缓冲区必须与屏幕大小完全相同,是一个二维数组。颜色值以 24 位格式存储在一个整数中,而非 3 个独立的 8 位变量。如果能使用缓冲区,其速度可能比逐像素绘制快得多。
onScreen bool onScreen(int x, int y);
检查坐标为 x、y 的点是否在屏幕范围内,即是否位于矩形 (0, 0) - ((w - 1), (h - 1)) 之内。
sleep void sleep();
调用此函数后,程序将暂停,直到你按下任意键。
waitFrame void waitFrame(double oldTime, double frameDuration);
此函数用于将效果限制在最大帧率以内。参数 oldTime 是上一帧调用 waitFrame 后的时间,frameDuration 是每帧的秒数(例如每帧 0.05 秒即为每秒 20 帧)。它会等待,直到距上一帧的最短时间间隔过去为止。
done bool done();
此函数返回是否应关闭程序,即当你按下 Escape 键或点击窗口关闭按钮时返回 true。在 while 循环中如下使用此函数:"while(!done()) {code goes here}"。循环将持续运行,直到你按下 Escape 键或点击窗口关闭按钮为止。
End 键 void end();
调用此函数将立即结束程序。
readKeys void readKeys();
此函数使用 SDL 事件检测哪些按键被按下,并将结果存入全局变量 inkeys[]。
getMouseState void getMouseState(int& mouseX, int& mouseY, bool& LMB, bool& RMB);
将鼠标的位置和按键状态存入给定的变量(通过引用传递):mouseX 为鼠标光标的 x 坐标,mouseY 为鼠标光标的 y 坐标,LMB 为 true 表示左键被按下,RMB 为 true 表示右键被按下。
getMouseState void getMouseState(int& mouseX, int& mouseY);
将鼠标位置存入给定的变量(通过引用传递):mouseX 为鼠标光标的 x 坐标,mouseY 为鼠标光标的 y 坐标。
getTicks long getTicks();
此函数返回程序启动以来经过的时间(以毫秒为单位)。
max max(x, y)
返回 x 和 y 中的较大值,适用于任意类型,通过预处理器命令定义。
min min(x, y)
返回 x 和 y 中的较小值,适用于任意类型,通过预处理器命令定义。
horLine bool horLine(int y, int x1, int x2, ColorRGB color);
从位置 x1、y 到 x2、y 绘制一条指定颜色的水平线。如果需要绘制水平线,此函数比 drawLine() 稍快。
verLine bool verLine(int x, int y1, int y2, ColorRGB color);
从位置 x1、y 到 x2、y 绘制一条指定颜色的垂直线。如果需要绘制垂直线,此函数比 drawLine() 稍快。
drawLine bool drawLine(int x1, int y1, int x2, int y2, ColorRGB color);
使用 Bresenham 直线绘制算法,从 x1、y1 到 x2、y2 绘制一条指定颜色的直线。注意所有坐标必须在屏幕范围内,否则程序会崩溃。如果需要绘制任意直线,可以结合使用 clipLine() 和 drawLine(),因为 drawLine 本身无法绘制超出屏幕范围的线段,当任意端点超出屏幕时将返回 0。
drawCircle bool drawCircle(int xc, int yc, int radius, ColorRGB color);
以 xc、yc 为圆心,绘制一个指定半径和 RGB 颜色的圆形。这是一个空心圆。
drawDisk bool drawCisk(int xc, int yc, int radius, ColorRGB color);
与 drawCircle 类似,但绘制的是填充圆。
drawRect bool drawRect(int x1, int y1, int x2, int y2, ColorRGB color);
以 x1、y1 和 x2、y2 为对角顶点,绘制一个指定颜色的矩形。
clipLine bool clipLine(int x1, int y1, int x2, int y2, int & x3, int & y3, int & x4, int & y4);
当需要将待绘制直线的端点裁剪到屏幕范围内时使用此函数。向函数传入坐标为 x1、y1-x2、y2 的直线,它将返回坐标为 x3、y3-x4、y4 的直线,该直线位于屏幕边缘或屏幕内部(即矩形 0、w-0、h 内)。x3、y3、x4 和 y4 需以引用方式传入,例如使用 "clipLine(x1, y1, x2, y2, x3, y3, x4, y4)",其中 x3、y3、x4 和 y4 是可被函数修改的普通整数,用于接收新直线的坐标。若直线在屏幕上则返回 1,否则返回 0。
RGBtoHSL ColorHSL RGBtoHSL(ColorRGB colorRGB);
将颜色从 RGB 色彩模型转换为 HSL 色彩模型。
HSLtoRGB ColorRGB HSLtoRGB(ColorHSL colorHSL);
将颜色从 HSL 色彩模型转换为 RGB 色彩模型。
RGBtoHSV ColorHSV RGBtoHSV(ColorRGB colorRGB);
将颜色从 RGB 色彩模型转换为 HSV 色彩模型。
HSVtoRGB ColorRGB HSVtoRGB(ColorHSV colorHSV);
将颜色从 HSV 色彩模型转换为 RGB 色彩模型。
RGBtoINT Uint32 RGBtoINT(ColorRGB colorRGB);
将颜色从 RGB 格式转换为适用于显存结构的单个整数。
INTtoRGB ColorRGB INTtoRGB(Uint32 colorINT);
将颜色从单个整数转换为 ColorRGB 结构体中的 3 个字节:r、g 和 b。
loadImage int loadImage(std::vector& out, unsigned long& w, unsigned long& h, const std::string& filename)
将指定文件名的 PNG 图像(不支持其他图像格式)加载到 std::vector 中,同时返回图像的宽度和高度。如果加载过程中出现问题,函数返回"1"表示"错误"。
loadImage int loadImage(std::vector& out, unsigned long& w, unsigned long& h, const std::string& filename)
与另一个 loadImage 函数相同,但将颜色存储为 Uint32 类型,这是 SDL 所使用的格式。
print template<typename T> int print(const T& val, int x = 0, int y = 0, const ColorRGB& color = RGB_White, bool bg = 0, const ColorRGB& color2 = RGB_Black);
使用标准 IBM ASCII 字体在屏幕上绘制文字,该字体由 256 个 8*8 像素的字符组成。
"*text" 是要输出的文字,"x" 和 "y" 是第一个字母左上角的位置(以像素为单位),"color" 是前景色,"color2" 是背景色,"bg" 控制背景是否可见:bg 为 0 时背景不可见,bg 为 1 时背景完全不透明。参数 forceLength 是最小打印长度,若字符串较短,则在其后补充打印 0 个字符(在启用背景且需要覆盖固定长度区域时很有用)。返回值为 h * x + y,其中 x 是下一个字母的 x 坐标,y 是下一个字母的 y 坐标,h 是屏幕高度。此返回值可用于确定下一个紧跟当前文字的 print 命令的起始位置:x 坐标为 returnvalue / h,y 坐标为 returnvalue % h。
getInputString void getInputString(std::string& text, const std::string& message = "", bool clear = false, int x = 0, int y = 0, const ColorRGB& color = RGB_White, bool bg = 0, const ColorRGB& color2 = RGB_Black);
打印提示信息,之后用户可以输入一个字符串,该字符串存储在 text 中。布尔值 "clear" 决定用户按下回车键后文字是否仍然可见。
getInput template<typename T> T getInput(const std::string& message = "", bool clear = false, int x = 0, int y = 0, const ColorRGB& color = RGB_White, bool bg = 0, const ColorRGB& color2 = RGB_Black);
将用户输入转换为任意类型的变量。

C++ 运算符

运算符 说明
+, -, *, / 加、减、乘、除。其中部分运算符也为 QuickCG 的矩阵和向量定义了重载。
% 取模除法
& 按位与
| 按位或
^ 按位异或
= 赋值
条件运算符
&&, || 逻辑与和逻辑或(用于条件判断)
== 是否相等?
!= 不等于
>,<, >=, <= 大于、小于、大于等于、小于等于

C++ 函数

其中一些函数来自标准头文件 <cmath>,因此属于 std 命名空间。不过由于代码顶部已添加了 "using namespace std;" 语句,所以无需在函数前加 "std::" 前缀。本教程聚焦于算法和数学,如果数学函数前没有 "std::",会更易于辨认。

函数 说明
sqrt(x) x 的平方根
cos(x), sin(x), tan(x) 余弦、正弦和正切(以弧度为单位)
acos(x), asin(x), atan(x) 余弦、正弦和正切的反函数
pow(x, y) 一个实数的另一个实数次幂
ln(x) 自然对数
exp(x) 实数的指数函数值
int(x), float(x), double(x) 转换为整数或浮点数。两个整数相除时,结果将是整数,除非将其中一个转换为浮点数。
floor(x) 返回不大于该数的最大整数,例如 3.1 变为 3.0。仅适用于浮点数和双精度浮点数。
ceil(x) 返回不小于该数的最小整数,例如 3.1 变为 4.0。仅适用于浮点数和双精度浮点数。
abs(x), fabs(x) 返回 x 的绝对值。abs 用于整数,fabs 用于浮点数和双精度浮点数。

C++ 数组与指针

如果你对 C++ 不太熟悉,以下指针相关内容可能会有所帮助:

变量的地址
  • int variableName 创建变量
  • &variableName 获取其地址
创建指向变量的指针
  • int variableName 创建变量
  • int* pointerName 创建指针
  • pointerName = variableName 将指针指向该变量的地址
  • 现在可以通过指针用 *pointerName = 100 将 variableName 设置为 100
创建一个 80 * 90 * 100 的三维数组 float arrayName[80][90][100];
访问 80 * 90 * 100 三维数组中下标为 10、20、30 的元素 arrayName[10][20][30]arrayName[90 * 100 * 10 + 100 * 20 + 30]
以"地址传递"方式传递变量,使函数能够修改它
  • 将函数定义为 void functionName(int* pointerName)
  • functionName(&pointerName) 调用该函数
  • 在函数内用 &pointerName 使用该变量
以"引用传递"方式传递变量,使函数能够修改它
  • 将函数定义为 void functionName(int& variableName)
  • functionName(variableName) 调用该函数
  • 在函数内直接用 variableName 使用该变量
以"const 引用"方式传递变量,使函数可以读取而无需复制(传递大型数据结构时复制会很低效)
  • 将函数定义为 void functionName(const int& variableName)
  • functionName(variableName) 调用该函数
  • 在函数内直接用 variableName 使用该变量
向函数传递一维数组,使函数可以读取和修改它
  • 将函数定义为 void functionName(int* arrayName)
  • functionName(arrayName) 调用该函数
  • 在函数内用 arrayName[index] 使用该数组
向函数传递三维数组
  • 将函数定义为 void functionName(int* arrayName)
  • functionname(arrayName[0][0]) 调用该函数
  • 在函数内用 arrayName[index] 使用该数组
  • 因此,尽管是三维数组,传递给函数时需要使用两个 [][],而在函数内部只能使用一个 []。
  • 在函数内部,将该数组当作一维数组处理。使用本表第三行第二种方式访问其元素。
std::vectors 对于动态大小的数组,C++ 标准库中的 std::vectors<Type> 更加实用。包含头文件 <vector> 即可使用。它提供了调整大小、获取大小、清空、在末尾追加元素等函数,成员也可以像 C 风格数组一样用 [] 访问。由于它是大型数据结构,向函数传递时应使用(const)引用。

SDL 按键列表(摘自 SDL 参考文档)

SDLKey ASCII 值 常用名称
SDLK_BACKSPACE '\b' 退格键
SDLK_TAB '\t' 制表键
SDLK_CLEAR
清除键
SDLK_RETURN '\r' 回车键
SDLK_PAUSE
暂停键
SDLK_ESCAPE '^[' Escape 键
SDLK_SPACE ' ' 空格键
SDLK_EXCLAIM '!' 感叹号
SDLK_QUOTEDBL '"' 双引号
SDLK_HASH '#' 井号
SDLK_DOLLAR '$' 美元符号
SDLK_AMPERSAND '&' 与号
SDLK_QUOTE ''' 单引号
SDLK_LEFTPAREN '(' 左括号
SDLK_RIGHTPAREN ')' 右括号
SDLK_ASTERISK '*' 星号
SDLK_PLUS '+' 加号
SDLK_COMMA ',' 逗号
SDLK_MINUS '-' 减号
SDLK_PERIOD '.' 句点
SDLK_SLASH '/' 正斜杠
SDLK_0 '0' 0
SDLK_1 '1' 1
SDLK_2 '2' 2
SDLK_3 '3' 3
SDLK_4 '4' 4
SDLK_5 '5' 5
SDLK_6 '6' 6
SDLK_7 '7' 7
SDLK_8 '8' 8
SDLK_9 '9' 9
SDLK_COLON ':' 冒号
SDLK_SEMICOLON ';' 分号
SDLK_LESS '<' 小于号
SDLK_EQUALS '=' 等号
SDLK_GREATER '>' 大于号
SDLK_QUESTION '?' 问号
SDLK_AT '@' at 符号
SDLK_LEFTBRACKET '[' 左方括号
SDLK_BACKSLASH '\' 反斜杠
SDLK_RIGHTBRACKET ']' 右方括号
SDLK_CARET '^' 脱字符
SDLK_UNDERSCORE '_' 下划线
SDLK_BACKQUOTE '`' 重音符
SDLK_a 'a' a
SDLK_b 'b' b
SDLK_c 'c' c
SDLK_d 'd' d
SDLK_e 'e' e
SDLK_f 'f' f
SDLK_g 'g' g
SDLK_h 'h' h
SDLK_i 'i' i
SDLK_j 'j' j
SDLK_k 'k' k
SDLK_l 'l' l
SDLK_m 'm' m
SDLK_n 'n' n
SDLK_o 'o' o
SDLK_p 'p' p
SDLK_q 'q' q
SDLK_r 'r' r
SDLK_s 's' s
SDLK_t 't' t
SDLK_u 'u' u
SDLK_v 'v' v
SDLK_w 'w' w
SDLK_x 'x' x
SDLK_y 'y' y
SDLK_z 'z' z
SDLK_DELETE '^?' Delete 键
SDLK_KP0
小键盘 0
SDLK_KP1
小键盘 1
SDLK_KP2
小键盘 2
SDLK_KP3
小键盘 3
SDLK_KP4
小键盘 4
SDLK_KP5
小键盘 5
SDLK_KP6
小键盘 6
SDLK_KP7
小键盘 7
SDLK_KP8
小键盘 8
SDLK_KP9
小键盘 9
SDLK_KP_PERIOD '.' 小键盘句点
SDLK_KP_DIVIDE '/' 小键盘除号
SDLK_KP_MULTIPLY '*' 小键盘乘号
SDLK_KP_MINUS '-' 小键盘减号
SDLK_KP_PLUS '+' 小键盘加号
SDLK_KP_ENTER '\r' 小键盘回车
SDLK_KP_EQUALS '=' 小键盘等号
SDLK_UP
上方向键
SDLK_DOWN
下方向键
SDLK_RIGHT
右方向键
SDLK_LEFT
左方向键
SDLK_INSERT
Insert 键
SDLK_HOME
Home 键
SDLK_END
End 键
SDLK_PAGEUP
Page Up 键
SDLK_PAGEDOWN
Page Down 键
SDLK_F1
F1
SDLK_F2
F2
SDLK_F3
F3
SDLK_F4
F4
SDLK_F5
F5
SDLK_F6
F6
SDLK_F7
F7
SDLK_F8
F8
SDLK_F9
F9
SDLK_F10
F10
SDLK_F11
F11
SDLK_F12
F12
SDLK_F13
F13
SDLK_F14
F14
SDLK_F15
F15
SDLK_NUMLOCK
数字锁定键
SDLK_CAPSLOCK
大写锁定键
SDLK_SCROLLOCK
滚动锁定键
SDLK_RSHIFT
右 Shift 键
SDLK_LSHIFT
左 Shift 键
SDLK_RCTRL
右 Ctrl 键
SDLK_LCTRL
左 Ctrl 键
SDLK_RALT
右 Alt 键
SDLK_LALT
左 Alt 键
SDLK_RMETA
右 Meta 键
SDLK_LMETA
左 Meta 键
SDLK_LSUPER
左 Windows 键
SDLK_RSUPER
右 Windows 键
SDLK_MODE
模式切换键
SDLK_HELP
帮助键
SDLK_PRINT
截屏键
SDLK_SYSREQ
SysRq
SDLK_BREAK
Break 键
SDLK_MENU
菜单键
SDLK_POWER
电源键
SDLK_EURO
欧元符号键

SDL 修饰键 含义
KMOD_NONE 无修饰键
KMOD_NUM 数字锁定键已按下
KMOD_CAPS 大写锁定键已按下
KMOD_LCTRL 左 Ctrl 键已按下
KMOD_RCTRL 右 Ctrl 键已按下
KMOD_RSHIFT 右 Shift 键已按下
KMOD_LSHIFT 左 Shift 键已按下
KMOD_RALT 右 Alt 键已按下
KMOD_LALT 左 Alt 键已按下
KMOD_CTRL 某个 Ctrl 键已按下
KMOD_SHIFT 某个 Shift 键已按下
KMOD_ALT 某个 Alt 键已按下


最后编辑:2007 年 8 月 21 日

版权所有 (c) 2004-2007 Lode Vandevenne,保留所有权利。