对初学者,用SDL做简单的sdl小游戏戏,应该...

SDL游戏教程第二课 坐标与块复制
SDL游戏教程第二课 坐标与块复制
发布时间: 9:08:41
编辑:www.fx114.net
本篇文章主要介绍了"SDL游戏教程第二课 坐标与块复制",主要涉及到SDL游戏教程第二课 坐标与块复制方面的内容,对于SDL游戏教程第二课 坐标与块复制感兴趣的同学可以参考一下。
翻译声明:
&&& 本系列教程来自,一切解释权归原作者。我只是出自个人爱好,才翻译了本系列教程。因为本人也是个初学者,而且英语水平有限,错误难免,望各路高手指正。
本课原文地址:/sdl-coordinates-and-blitting/
有第一节课做基础,我们将深入研究SDL表面世界。正如我在上节课所述,SDL表面就是存储在内存中的图像。假想我们有一个空白的320*240像素的表面。SDL坐标系统如下图所示:
这里的坐标系统和你熟悉的可能不大一样。注意,Y坐标向下递增,X坐标向右递增。了解SDL的坐标系统对于正确地向屏幕绘制图像很重要。
既然我们已经搞定了主表面(Surf_Display),那就需要一种方式来在其上绘制图像了。这个过程就叫做&块复制&(译者注:英文是Blitting),由此我们可以把一个图像迁移到另一幅图像。但在此之前,我们需要一种方式来把图像加载到内存。SDL提供了一个简单的函数来实现,那就是SDL_LoadBMP()。一些伪代码可能是这样的:
SDL_Surface* Surf_T
if((Surf_Temp = SDL_LoadBMP(&mypicture.bmp&)) == NULL) {
&&& //Error!
超简单,SDL_LoadBMP()只需要一个参数,就是你要加载的文件,并且返回一个表面。如果文件找不到,已损坏,或其他什么错误,此函数就会返回NULL。不幸的是,有时这种方法还不够。加载图片的像素格式往往和要显示的不一致。这样的话,当我们想显示器绘制图像的时候会导致性能损失、图像颜色失真、或是别的什么。但是,多亏了SDL,它还为此提供了一个快捷的解决方法,SDL_DisplayFormat()。此函数需要一个已经加载的表面,然后返回一个和显示器格式一致的新表面。
让我们完成这个过程,并把它放在一个可再用的类里。使用SDL课程1作为基础代码,然后添加以下两个新文件:CSurface.h,CSurface.cpp。打开CSurface.h,增加如下:
#ifndef&_CSURFACE_H_#define&_CSURFACE_H_#include&&SDL.h&class&CSurface&{&&&&public:&&&&&&&&CSurface();&&&&public:&&&&&&&&static&SDL_Surface*&OnLoad(char*&File);};#endif
我们已经创建了一个简单的静态函数,OnLoad,它会为我们加载一个表面。现在打开CSurface.cpp:
#include &CSurface.h&
CSurface::CSurface()&{}SDL_Surface*&CSurface::OnLoad(char*&File)&{&&&&SDL_Surface*&Surf_Temp&=&NULL;&&&&SDL_Surface*&Surf_Return&=&NULL;&&&&if((Surf_Temp&=&SDL_LoadBMP(File))&==&NULL)&{&&&&&&&&return&NULL;&&&&}&&&&Surf_Return&=&SDL_DisplayFormat(Surf_Temp);&&&&SDL_FreeSurface(Surf_Temp);&&&&return&Surf_R}
在此有两件事需要注意。首先,切记在创建一个指针的时候一定要把它设置为NULL或0。不然,稍后你会遇到很多的麻烦。其次,注意SDL_DisplayFormat()是如何返回一个新表面,但并不覆盖原有的表面。这个一定要牢记,因为它创建了一个新的表面,我们必须释放那个旧表面。否则,我们会有一个表面还留在内存里(译者注:如果不释放旧资源,容易造成内存泄漏)。
现在我们有了把表面加载到内存的方法,我们还需要一个把他们绘制到其他表面的方法。就像SDL提供了一个函数来加载图像,它也提供了一个函数来绘制(blit)图像:SDL_BlitSurface()。不幸的是,此函数并不像SDL_LoadBMP()那么简单,尽管如此,它还是很简单的。打开CSurface.h添加如下函数原型:
#ifndef&_CSURFACE_H_#define&_CSURFACE_H_#include&&SDL.h&class&CSurface&{&&&&public:&&&&&&&&CSurface();&&&&public:&&&&&&&&static&SDL_Surface*&OnLoad(char*&File);&&&&&&&&static&bool&OnDraw(SDL_Surface*&Surf_Dest,&SDL_Surface*&Surf_Src,&int&X,&int&Y);};#endif
现在打开CSurface.cpp,添加如下:
#include&&CSurface.h&CSurface::CSurface()&{}SDL_Surface*&CSurface::OnLoad(char*&File)&{&&&&SDL_Surface*&Surf_Temp&=&NULL;&&&&SDL_Surface*&Surf_Return&=&NULL;&&&&if((Surf_Temp&=&SDL_LoadBMP(File))&==&NULL)&{&&&&&&&&return&NULL;&&&&}&&&&Surf_Return&=&SDL_DisplayFormat(Surf_Temp);&&&&SDL_FreeSurface(Surf_Temp);&&&&return&Surf_R}bool&CSurface::OnDraw(SDL_Surface*&Surf_Dest,&SDL_Surface*&Surf_Src,&int&X,&int&Y)&{&&&&if(Surf_Dest&==&NULL&||&Surf_Src&==&NULL)&{&&&&&&&&return&false;&&&&}&&&&SDL_Rect&DestR;&&&&DestR.x&=&X;&&&&DestR.y&=&Y;&&&&SDL_BlitSurface(Surf_Src,&NULL,&Surf_Dest,&&DestR);&&&&return&true;}
首先,看看传递给OnDraw()的参数。两个表面和两个整型。第一个表面为目标表面,或是我们要在其上进行绘制的表面。第二个表面是源表面,或是我们要将其绘制到另一个表面的表面。基本上是这样,我们把Surf_Src放到Surf_Dest的上面。其中X,Y变量是在Surf_Dest上要绘制表面的位置。
函数的开始确保我们得到的是有效的表面,否则,返回false。然后,就是SDL_Rect。他是一个SDL结构体,基本包含4个成员:x,y,w,h。这个,当然是创建一个特定规格的矩形了。我们仅关心要在哪画,并不是绘制的大小。所以,我们把X,Y坐标分配到目标表面上。如果你想知道SDL_BlitSurface里的那个NULL是什么意思,它也是一个SDL_Rect的参数。本课后面还会在提到。
最后,我们可以调用这个函数来绘制图像,并返回true。
现在,为了确保所有这些可以运行,就让我们创建一个测试表面。打开CApp.h,然后创建一个新的表面,并包含进新创建的CSurface.h:
#ifndef&_CAPP_H_#define&_CAPP_H_#include&&SDL.h&#include&&CSurface.h&class&CApp&{&&&&private:&&&&&&&&bool&&&&&&&&&&&&R&&&&&&&&SDL_Surface*&&&&Surf_D&&&&&&&&SDL_Surface*&&&&Surf_T&&&&public:&&&&&&&&CApp();&&&&&&&&int&OnExecute();&&&&public:&&&&&&&&bool&OnInit();&&&&&&&&void&OnEvent(SDL_Event*&Event);&&&&&&&&void&OnLoop();&&&&&&&&void&OnRender();&&&&&&&&void&OnCleanup();};#endif
同样的,在构造函数里初始化这个表明为NULL:
CApp::CApp() {
&&& Surf_Test = NULL;
&&& Surf_Display = NULL;
&&& Running =
并且,还要记得清除:
#include&&CApp.h&void&CApp::OnCleanup()&{&&&&SDL_FreeSurface(Surf_Test);&&&&SDL_FreeSurface(Surf_Display);&&&&SDL_Quit();}
现在,让我们实际加载一幅图像。打开CApp_OnInit.cpp,然后添加代码来加载一个表面:
#include&&CApp.h&bool&CApp::OnInit()&{&&&&if(SDL_Init(SDL_INIT_EVERYTHING)&&&0)&{&&&&&&&&return&false;&&&&}&&&&if((Surf_Display&=&SDL_SetVideoMode(640,&480,&32,&SDL_HWSURFACE&|&SDL_DOUBLEBUF))&==&NULL)&{&&&&&&&&return&false;&&&&}&&&&if((Surf_Test&=&CSurface::OnLoad(&myimage.bmp&))&==&NULL)&{&&&&&&&&return&false;&&&&}&&&&return&true;}
确保要把&myimage.bmp&改成一幅实际存在的位图文件。如果你没,那就打开画图,随便画点什么东西上去,保存到和可执行文件同目录下。
现在我们已经加载了图片,让我们绘制它。打开CApp_OnRender.cpp,添加如下:
#include&&CApp.h&void&CApp::OnRender()&{&&&&CSurface::OnDraw(Surf_Display,&Surf_Test,&0,&0);
&&&&SDL_Flip(Surf_Display);}
注意这里的一个新函数SDL_Flip()。它只是更新缓冲区,然后显示Surf_Display到屏幕。这就叫做双缓存。整个过程就是把所有东西绘制到内存,然后把所有东西最终绘制到屏幕。若不这么做,我们会看到图像在屏幕上闪烁。还记得SDL_DOUBLEFUL标志位吗?这就是我们为什么要打开双缓存的原因。
编译代码,然后确保一切运行正常。你应该可以在屏幕左上角可以看到你的图像。若是这样,祝贺你,你离一个真实的游戏更近了一步。若不然,确保在你的可执行文件夹里有myimage.bmp存在。也要保证它是一个有效的位图文件。
现在让我们把这个过程进行的更深远点。尽管它可以很好并足够把一幅图像绘制到屏幕上了,通常我们仅需要绘制一幅图像的一部分。例如,一个贴图集合:
尽管这只是一单幅图像,我们只想绘制其中一部分。打开CSurface.h,添加如下代码:
#ifndef&_CSURFACE_H_#define&_CSURFACE_H_#include&&SDL.h&class&CSurface&{&&&&public:&&&&&&&&CSurface();&&&&public:&&&&&&&&static&SDL_Surface*&OnLoad(char*&File);&&&&&&&&static&bool&OnDraw(SDL_Surface*&Surf_Dest,&SDL_Surface*&Surf_Src,&int&X,&int&Y);&&&&&&&&static&bool&OnDraw(SDL_Surface*&Surf_Dest,&SDL_Surface*&Surf_Src,&int&X,&int&Y,&int&X2,&int&Y2,&int&W,&int&H);};#endif
打开CSurface.cpp,添加如下函数:
bool CSurface::OnDraw(SDL_Surface* Surf_Dest, SDL_Surface* Surf_Src, int X, int Y, int X2, int Y2, int W, int H) {
&&& if(Surf_Dest == NULL || Surf_Src == NULL) {
&&& SDL_Rect DestR;
&&& DestR.x = X;
&&& DestR.y = Y;
&&& SDL_Rect SrcR;
&&& SrcR.x = X2;
&&& SrcR.y = Y2;
&&& SrcR.w = W;
&&& SrcR.h = H;
&&& SDL_BlitSurface(Surf_Src, &SrcR, Surf_Dest, &DestR);
注意下,它基本上和前一个函数一样,只不过我们增加了另一个SDL_Rect。我们通过这个源矩形指定从源中要拷贝那些像素到目标。如果我们指定了0,0,50,50作为X2,Y2,W,H的参数,那么只有源的左上角(一个50*50的方形)被绘制。
我们同样试试这个新函数,打开CApp_OnRender.cpp,然后添加:
#include&&CApp.h&void&CApp::OnRender()&{&&&&CSurface::OnDraw(Surf_Display,&Surf_Test,&0,&0);&&&&CSurface::OnDraw(Surf_Display,&Surf_Test,&100,&100,&0,&0,&50,&50);&&&&SDL_Flip(Surf_Display);}
你应该能看到你的图片会被在100,100处绘制,且仅显示了一部分。你应该搞清楚这一切是怎么运行的,以及SDL的坐标系统是如何建立的,这将会很有用。
跳到下一课,在那我们会看到更多的SDL消息,以及如何使那个过程更简单。
SDL 坐标和块复制 ---- 课程文件:
Linux:(感谢Gaten)
一、不得利用本站危害国家安全、泄露国家秘密,不得侵犯国家社会集体的和公民的合法权益,不得利用本站制作、复制和传播不法有害信息!
二、互相尊重,对自己的言论和行为负责。
本文标题:
本页链接:

参考资料

 

随机推荐