本文翻译自《Lazy Foo’ Productions - Beginning Game Programming v2.0》,为原创翻译,转载请注明出处。
注:因为我懒,所以翻译可能各种不靠谱(手动微笑)
原文链接:Event Driven Programming
前言
上个教程中已经成功的显示了一个图片啦~但是这太tm无聊了,既然是游戏编程所以肯定要有交互啊~对不对。没关系,SDL提供了事件处理系统来处理用户的输入。
完整代码
/*This source code copyrighted by Lazy Foo' Productions (2004-2015)
and may not be redistributed without written permission.*/
//Using SDL and standard IO
#include <SDL.h>
#include <stdio.h>
//Screen dimension constants
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
//Starts up SDL and creates window
bool init();
//Loads media
bool loadMedia();
//Frees media and shuts down SDL
void close();
//The window we'll be rendering to
SDL_Window* gWindow = NULL;
//The surface contained by the window
SDL_Surface* gScreenSurface = NULL;
//The image we will load and show on the screen
SDL_Surface* gXOut = NULL;
bool init()
{
//Initialization flag
bool success = true;
//Initialize SDL
if( SDL_Init( SDL_INIT_VIDEO ) < 0 )
{
printf( "SDL could not initialize! SDL_Error: %s\n", SDL_GetError() );
success = false;
}
else
{
//Create window
gWindow = SDL_CreateWindow( "SDL Tutorial", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN );
if( gWindow == NULL )
{
printf( "Window could not be created! SDL_Error: %s\n", SDL_GetError() );
success = false;
}
else
{
//Get window surface
gScreenSurface = SDL_GetWindowSurface( gWindow );
}
}
return success;
}
bool loadMedia()
{
//Loading success flag
bool success = true;
//Load splash image
gXOut = SDL_LoadBMP( "../03_event_driven_programming/x.bmp" );
if( gXOut == NULL )
{
printf( "Unable to load image %s! SDL Error: %s\n", "03_event_driven_programming/x.bmp", SDL_GetError() );
success = false;
}
return success;
}
void close()
{
//Deallocate surface
SDL_FreeSurface( gXOut );
gXOut = NULL;
//Destroy window
SDL_DestroyWindow( gWindow );
gWindow = NULL;
//Quit SDL subsystems
SDL_Quit();
}
int main( int argc, char* args[] )
{
//Start up SDL and create window
if( !init() )
{
printf( "Failed to initialize!\n" );
}
else
{
//Load media
if( !loadMedia() )
{
printf( "Failed to load media!\n" );
}
else
{
//Main loop flag
bool quit = false;
//Event handler
SDL_Event e;
//While application is running
while( !quit )
{
//Handle events on queue
while( SDL_PollEvent( &e ) != 0 )
{
//User requests quit
if( e.type == SDL_QUIT )
{
quit = true;
}
}
//Apply the image
SDL_BlitSurface( gXOut, NULL, gScreenSurface, NULL );
//Update the surface
SDL_UpdateWindowSurface( gWindow );
}
}
}
//Free resources and close SDL
close();
return 0;
}
正文
//Main loop flag
bool quit = false;
//Event handler
SDL_Event e;
我们从main函数开始讲起,首先和上一个教程一样我们初始化SDL并读取媒体文件。然后这里声明了一个退出标志,看名字就知道这东西是干嘛的,对吧。由于我们的程序才刚刚开始,所以肯定要设置成false。
同时还声明了一个SDL Event共用体。SDL Event用来记录发生的事件,比如按个键盘啦,动个鼠标啦什么的。我们这个程序呢,就是要找到退出事件并结束程序(好像有点无聊)。
//While application is running
while( !quit )
{
记得上一个程序么,那里我们用了Delay函数让程序在关闭之前苟延残喘了两秒。现在这个程序会一直运行到地老天荒,直到你关掉它。
怎么做呢,只要用户没有关掉它,我们就让程序一直循环,这种循环就叫做主循环或者游戏循环,就和你打开了一个游戏不关掉它,它就一直开着是一样的道理。
//Handle events on queue
while( SDL_PollEvent( &e ) != 0 )
{
//User requests quit
if( e.type == SDL_QUIT )
{
quit = true;
}
}
在主循环的开始呢,我们放上了事件循环,事件循环会一直处理事件队列,直到事件队列为空。
当你按下键盘,移动鼠标,事件队列就会按照时间顺序储存这些事件,是一个先进先出队列。
当你想要处理下一个事件,那就需要先从队列里取出这个事件,SDL_PollEvent会帮你从事件队列里取出一个事件,并将这个事件传递给参数。
当事件队列为空,SDL_PollEvent将会返回0,当事件循环读取到SDL_QUIT事件的时候,程序会将退出标志quit设置为true。(SDL_QUIT事件是什么?当然就是点击窗口右上方的小xx了)
//Apply the image
SDL_BlitSurface( gXOut, NULL, gScreenSurface, NULL );
//Update the surface
SDL_UpdateWindowSurface( gWindow );
}
别忘了我们最开始在屏幕上显示了一个图片,所以需要在主循环中渲染这个图片,还有更新窗口显示框。