SDL2 笔记

《SDL Game Development》笔记

坐标系
原点:左上角

SDL扩展
SDL_image
支持多种格式图片加载:BMP GIF PNG TGA PCX …
SDL_net
跨平台网络库
SDL_mixer
audio mixer library. 支持MP3 MIDI OGG
SDL_ttf
支持TrueType字体
SDL_rtf
support the rendering of the Rich Text Format (RTF).

SDL_Init()
初始化标识

1
2
3
4
5
6
7
SDL_INIT_HAPTIC      Force feedback subsystem  力反馈
SDL_INIT_AUDIO Audio subsystem
SDL_INIT_VIDEO Video subsystem
SDL_INIT_TIMER Timer subsystem
SDL_INIT_JOYSTICK Joystick subsystem
SDL_INIT_EVERYTHING All subsystems
SDL_INIT_noparachute Don't catch fatal signals

查看一个子系统是否已被初始化:

1
2
if (SDL_WasInit(SDL_INIT_VIDEO) != 0)
cout << "video was initialized";
1
2
3
4
5
SDL_CreateRenderer()
SDL_RENDERER_SOFTWARE Use software rendering
SDL_RENDERER_ACCELERATED Use hardware acceleration
SDL_RENDERER_PRESENTVSYNC Synchronize renderer update with screen's refresh rate
SDL_RENDERER_TARGETTEXTURE Supports render to texture

游戏程序结构
初始化
游戏循环:获取输入 物理运算 渲染
退出

window flags

1
2
3
4
5
6
7
8
9
10
11
12
SDL_WINDOW_FULLSCREEN      Make the window fullscreen
SDL_WINDOW_OPENGL Window can be used with as an OpenGL context
SDL_WINDOW_SHOWN The window is visible
SDL_WINDOW_HIDDEN Hide the window
SDL_WINDOW_BORDERLESS No border on the window
SDL_WINDOW_RESIZABLE Enable resizing of the window
SDL_WINDOW_MINIMIZED Minimize the window
SDL_WINDOW_MAXIMIZED Maximize the window
SDL_WINDOW_INPUT_GRABBED Window has grabbed input focus
SDL_WINDOW_INPUT_FOCUS Window has input focus
SDL_WINDOW_MOUSE_FOCUS Window has mouse focus
SDL_WINDOW_FOREIGN The window was not created using SDL

程序基本结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include <SDL.h>

SDL_Window* g_pWindow = 0;
SDL_Renderer* g_pRenderer = 0;

int main(int argc, char* argv[])
{
// initialize SDL
if (SDL_Init(SDL_INIT_EVERYTHING) >= 0)
{
// if succeeded create our window
g_pWindow = SDL_CreateWindow("Chapter 1: Setting up SDL",
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
640, 480,
SDL_WINDOW_SHOWN);

// if the window creation succeeded create our renderer
if (g_pWindow != 0)
{
g_pRenderer = SDL_CreateRenderer(g_pWindow, -1, 0);
}
}
else
return 1; // sdl could not initialize

// everything succeeded lets draw the window
bool bQuit = false;
while (true)
{
SDL_Event event;
if (SDL_PollEvent(&event))
{
switch (event.type)
{
case SDL_QUIT:
bQuit = true;
break;
}
}
if (bQuit)
break;

// set to black
// This function expects Red, Green, Blue and Alpha as color values
SDL_SetRenderDrawColor(g_pRenderer, 0, 0, 0, 255);

// clear the window to black
SDL_RenderClear(g_pRenderer);

// show the window
SDL_RenderPresent(g_pRenderer);
}

// set a delay before quitting
//SDL_Delay(5000);

// clean up SDL
SDL_Quit();

return 0;
}

绘制图片过程

  1. 加载图片获得SDL_Surface
  2. 根据Surface获得SDL_Texture
  3. 获得纹理尺寸:SDL_QueryTexture
  4. 渲染:SDL_RenderCopy/SDL_RenderCopyEx 需要Renderer参数

SDL使用两种数据结构渲染到屏幕
SDL_Surface 像素集 使用软件渲染(not GPU)
SDL_Texture 使用硬件加速

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
SDL_Texture* m_pTexture
SDL_Rect m_sourceRectangle;
SDL_Rect m_destinationRectangle;

// 根据图片创建SDL_Texture
SDL_Surface* pTempSurface = SDL_LoadBMP("asserts/rider.bmp");
m_pTexture = SDL_CreateTextureFromSurface(m_pRenderer, pTempSurface);
SDL_FreeSurface(pTempSurface);

// 获得图片的大小
SDL_QueryTexture(m_pTexture, NULL, NULL,
&m_sourceRectangle.w, &m_sourceRectangle.h);

SDL_RenderClear();
SDL_RenderCopy(m_pRenderer, m_pTexture,
&m_sourceRectangle, &m_destinationRectangle);
SDL_RenderPresent();

源矩形 目标矩形 参数传入0 将整个纹理渲染到整个窗口。

SDL_GetTicks() 毫秒

SDL_RenderCopyEx() 支持旋转和翻转Flip

SDL_image
sdl2_image.lib

1
2
#include <sdl_image.h>
SDL_Surface* pTempSurface = IMG_Load("animate.png");

Fixed frames per second (FPS) is
not necessarily always a good option, especially when your game includes more
advanced physics. It is worth bearing this in mind when you move on from this
book and start developing your own games. Fixed FPS will, however, be fine for
the small 2D games, which we will work towards in this book.

固定帧频

1
2
3
4
5
6
7
8
9
10
const int FPS = 60;
const int DELAY_TIME = 1000.0f / FPS; // 1000毫秒
while (...)
{
frameStart = SDL_GetTicks(); // 毫秒
...
frameTime = SDL_GetTicks() - frameStart;
if (frameTime < DELAY_TIME)
SDL_Delay((int)(DELAY_TIME - frameTime));
}
1
2
3
4
5
6
7
8
9
10
11
12
SDL joystick event
SDL_JoyAxisEvent Axis motion information
SDL_JoyButtonEvent Button press and release information
SDL_JoyBallEvent Trackball event motion information
SDL_JoyHatEvent Joystick hat position change

SDL joystick event Type value
SDL_JoyAxisEvent SDL_JOYAXISMOTION
SDL_JoyButtonEvent SDL_JOYBUTTONDOWN or
SDL_JOYBUTTONUP
SDL_JoyBallEvent SDL_JOYBALLMOTION
SDL_JoyHatEvent SDL_JOYHATMOTION

不同的游戏控制器 按钮和轴可能有不同的值 比如Xbox360 controller, PS3 controller
Xbox360 controller:
Two analog sticks
Analog sticks press as buttons
Start and Select buttons
Four face buttons: A, B, X, and Y
Four triggers: two digital and two analog
A digital directional pad

1
2
3
4
5
6
7
8
9
10
11
12
13
14
if (SDL_WasInit(SDL_INIT_JOYSTICK) == 0)
SDL_InitSubSystem(SDL_INIT_JOYSTICK);
if (SDL_NumJoysticks() > 0)
{
for (int i=0; i<SDL_NumJoysticks(); ++i)
{
SDL_Joystick* joy = SDL_JoystickOpen(i);
if (SDL_JoystickOpened(i) == 1)
m_joysticks.push_back(joy);
}
SDL_JoystickEventState(SDL_ENABLE);
}

SDL_JoystickClose(joy);

分辨是哪个控制器的事件

1
2
if (event.type == SDL_JOYAXISMOTION)
int whichOne = event.jaxis.which;

控制器按钮
SDL_JoystickNumButtons
event.jbutton.button // 按钮ID

鼠标事件

1
2
3
4
5
6
7
8
9
SDL Mouse Event        Purpose
SDL_MouseButtonEvent A button on the mouse has been pressed or released
SDL_MouseMotionEvent The mouse has been moved
SDL_MouseWheelEvent The mouse wheel has moved

SDL Mouse Event Type Value
SDL_MouseButtonEvent SDL_MOUSEBUTTONDOWN or SDL_MOUSEBUTTONUP
SDL_MouseMotionEvent SDL_MOUSEMOTION
SDL_MouseWheelEvent SDL_MOUSEWHEEL
1
2
3
4
5
// 鼠标按钮
// SDL numbers these as 0 for left, 1 for middle, and 2 for right.

if (event.type == SDL_MOUSEBUTTONDOWN)
if (event.button.button == SDL_BUTTON_LEFT)

event.type SDL_MOUSEMOTION
event.motion.x
event.motion.y

// 键盘
1 表示按下 0 表示没有按下
SDL_GetKeyboardState(int* numkeys)
Uint8* m_keystates;
m_keystates = SDL_GetKeyboardState(0);
SDL_Scancode key;
if (m_keysttes[key] == 1)

有限状态机
需要能够处理以下情况:
Removing one state and adding another
Adding one state without removing the previous state
Removing one state without adding another

Game
GameObject
TextureManager // 负责加载图片文件,负责绘制,纹理ID
InputHandler
GameState
GameStateMachine
GameObjectFactory
StateParser

Distributed Factory
class GameObjectFactory
std::map<std::string, BaseCreator*> m_creators;
registerType(std::string typeID, BaseCreator* pCreator);

https://github.com/ReneNyffenegger/development_misc/tree/master/base64.
The base64.h and base64.cpp files can be added directly to the project.

1
2
3
4
5
6
7
8
9
10
11
12
SDL_Mixer
Mix_OpenAudio(int frequency, Uint16 format, int channels, int chunksize)
Mix_OpenAudio(22050, AUDIO_S16, 2, 4096);
std::map<std::string, Mix_Chunk*> mSfxs;
std::map<std::string, Mix_Chunk*> mMusic;

Mix_Music* music = Mix_LoadMUS(filename); // ogg
Mix_Chunk* chunk = Mix_LoadWAV(filename); // wav

Mix_PlayMusic() // Mix_Music
Mix_PlayChannel() // Mix_Chunk
Mix_CloseAudio();

SDL_SetTextureAlphaMod()