SDL游戏教程《Lazy Foo' Productions - Beginning Game Programming v2.0》中文版(2)

本文翻译自《Lazy Foo' Productions - Beginning Game Programming v2.0》,为原创翻译,转载请注明出处。

原地址 http://lazyfoo.net/tutorials/SDL/02_getting_an_image_on_the_screen/index.php


现在你已经打开了一个窗口,让我们在窗口上显示一张图片吧。

注意:从现在开始,这个教程只写出关键部分的代码。如果要得到全部代码,你需要下载完整的源代码。



在第一个教程中,我们把所有东西都塞到main函数中。因为这是一个小程序所以没有太大问题,但在现实编程中(比如说视频游戏),你应该尽可能把你的代码模块化。这意味着你需要把你的代码写的更整洁,这能令调试和代码重用变得简单。

//初始化SDL并创建一个窗口
bool init();
//加载媒体 (media)
bool loadMedia();
//释放媒体并关闭SDL
void close();


在上面的代码中,我们看到了三个函数声明,他们分别用来初始化SDL、加载媒体和关闭SDL应用。我们在源文件的很靠前的位置声明了这三个函数。

 

//我们用来展示的窗口
SDL_Window* gWindow = NULL;
//包含在窗口中的一个表面(surface)
SDL_Surface* gScreenSurface = NULL;
//我们将要在屏幕上加载和显示的图片
SDL_Surface* gHelloWorld = NULL;

 

在这里,我们声明了一些全局变量。通常我们要避免在大程序中使用全局变量。在这里声明全局变量的原因是我们希望源代码尽可能的简单,但是在大的项目中,全局变量会使得事情变得复杂。这是一个单文件程序,我们不用为此过于担心。

 

在这里有一个名为SDL_Surface的新数据类型。一个SDL_Surface 是一种图片数据类型,它包含了一张图片的像素以及所有需要渲染的数据。SDL_Surface使用软件渲染,这意味着是由CPU来处理的。使用硬件来处理是可以做到的,但这实现起来难度较大,所以我们在一开始从简单的方法开始学习。在后面的教程中,我们将会教你如何使用GPU加速处理图像。

 

我们将要处理的图像是屏幕图片(screen image,也就是我们在窗口中看到的内容),和将要从文件中加载进来的图片。

 

注意:这里有以下指向SDL_Surface的指针。原因是:

(1) 我们将会动态分配内存用于加载图片

(2)用内存位置来引用图片的做法更好。想象你有一个游戏,里面有一道砖墙,墙体是由许许多多相同的砖头的图片组成(比如说超级马里奥兄弟)。如果我们使用一大堆图片的副本把砖墙显示出来,这将会造成巨大的浪费。

 

同样地,记得给指针初始化。当我们声明一个指针的时候,把它们设置为空(NULL)

 

bool init()
{
    //成功初始化的标志
    bool success = true;
 
    //初始化SDL
    if( SDL_Init( SDL_INIT_VIDEO ) < 0 )
    {
        printf( "SDL could not initialize! SDL_Error: %s\n", SDL_GetError() );
        success = false;
    }
    else
    {
        //创建建一个窗口
        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
        {
            //获取窗体表面(windos surface)
            gScreenSurface  =  SDL_GetWindowSurface( gWindow );
        }
    }
 
    return success;
}

在这里你可以看到,我们已经写好了SDL初始化和创建窗口的代码并将其放到了我们的函数中。这里出现了一个新的函数调用:SDL_GetWindowSurface.

我们希望显示窗口里面的图片,为此我们需要获取窗口里面的图片。因此我们调用SDL_GetWindowsSurface以获取窗口(window)中的表面(surface).

 

bool loadMedia()
{
    //成功加载的标志
    bool success = true;
 
    //加载启动界面
    gHelloWorld = SDL_LoadBMP( "02_getting_an_image_on_the_screen/hello_world.bmp" );
    if( gHelloWorld == NULL )
    {
        printf("Unable to load image %s! SDL Error: %s\n", "02_getting_an_image_on_the_screen/hello_world.bmp", SDL_GetError() );
        success = false;
    }
 
    return success;
}


 

在加载媒体的函数中我们用SDL_LoadBMP载入了图像。SDL_LoadBMP以一个BMP文件路径为参数。如果成功加载,返回加载好的表面(surface)。如果函数返回NULL,说明加载失败,这时候我们在控制台上用SDL_GetError打印一个错误信息。

 

在这里有一个重要的事情就是这一部分的代码假设你在工作目录”02_getting_an_image_on_the_screen”中有一张名为”hello_world.bmp”的图片。工作目录是指你希望你的程序运行的位置。通常的,你的工作目录是的可执行文件的位置,但一些软件比如说Visual Studio把工作目录改变到vcxproj文件所处的位置。因此如果程序找不到图像,你应该确认它被放在了正确的位置。

 

void close()
{
    //回收表面
    SDL_FreeSurface( gHelloWorld );
    gHelloWorld = NULL;
 
    //销毁窗口
    SDL_DestroyWindow( gWindow );
    gWindow = NULL;
 
//退出SDL子系统
    SDL_Quit();
}

在我们的清理代码中,我们像之前一样销毁了窗口并退出了SDL,但我们也需要对我们加载的图像加以注意。我们调用SDL_FreeSurface释放了图像。不用担心屏幕表面,SDL_DistoryWindows会处理好它。

请养成把不指向任何东西的指针赋值为空(NULL)的习惯。

 

int main( int argc, char* args[] )
{
    //初始化SDL并创建窗口
    if( !init() )
    {
        printf( "Failed to initialize!\n" );
    }
    else
    {
        //加载媒体
        if( !loadMedia() )
        {
            printf( "Failed to load media!\n" );
        }
        else
        {
            //应用图像
            SDL_BlitSurface( gHelloWorld, NULL, gScreenSurface, NULL );
 


在主函数中我们初始化SDL并加载图像,如果成功的话,我们将会把加载好的图像blit(将一个平面的一部分或全部图象整块从这个平面复制到另一个平面)到目标表面中。SDL_BlitSurface 的第一个参数是源图像。第三个参数是目标表面。在以后的教程中,我们不需理会第2和第4个参数。

如果以上就是所有代码,我们仍然不能在屏幕上看到图像。要看到图像我们还需要一个步骤。

//更新表面
SDL_UpdateWindowSurface( gWindow );

在把所有东西绘制到屏幕之后,如果我们想把它显示出来,我们就要用SDL_UpdateWindowSurface()函数来更新屏幕。看看当你把东西绘制到屏幕的时候,通常地,你绘制的不是你看到的图像。默认地,大部分渲染系统采用双缓冲机制。分别是前台缓冲和后台缓冲。

当你draw call的时候,比如说SDL_BlitSurface,你渲染的是后台缓冲。你在屏幕上看到的是前台缓冲。我们这样做的原因是大部分架构在屏幕上绘制多个对象。如果我们只有前台缓冲,我们将会看到不完整的架构。所以我们做的是首先在后台缓冲区绘制好所有的对象到屏幕上,一旦我们完成了绘制,我们就把前后换缓冲交换。因此用户就可以使用完成后的架构了。

 

这同时表明你不需要在每次blit之后调用SDL_UpdateWindowSurface,只需要在所有blit完成后调用就可以了。

            //等待2秒
            SDL_Delay( 2000 );
        }
    }
    //释放资源并关闭SDL
    close();
 
    return 0;
}


 
  

现在哦我们已经把所有东西渲染到了窗口中,为了窗口不会马上关闭我们延时了两秒。延时结束我们将关闭程序。

你可能感兴趣的:(游戏编程,翻译,SDL)