Chinaunix首页 | 论坛 | 博客
  • 博客访问: 3518351
  • 博文数量: 864
  • 博客积分: 14125
  • 博客等级: 上将
  • 技术积分: 10634
  • 用 户 组: 普通用户
  • 注册时间: 2007-07-27 16:53
个人简介

https://github.com/zytc2009/BigTeam_learning

文章分类

全部博文(864)

文章存档

2023年(1)

2021年(1)

2019年(3)

2018年(1)

2017年(10)

2015年(3)

2014年(8)

2013年(3)

2012年(69)

2011年(103)

2010年(357)

2009年(283)

2008年(22)

分类: C/C++

2010-12-27 09:43:08

最近几篇教程基本上都是参考着Lazy Foo的教程顺序来的。因为我也觉得他的顺序很实用。所不同的是,新的类型我都添加在了之前建立起来的surface类的基础之上。所以,如果你觉得单独 看这些教程完全搞不明白,最好从头按照顺序来学习。另外,为了复习C++知识,也为了遵循C++的理念,我有意的将程序风格向C++靠拢。如果你更喜欢C 风格,相信你在其他地方可以找到更适合你的教程。

1.1:一个小细节,SDL窗口的名称

        因为涉及到文本的显示了,我们提一个一直以来忽略的问题——SDL建立起来的窗口的名字。因为我们所建立起来的Screen Surface是唯一和特殊的。所以窗口名字这个行为是可以绑定在这个唯一的Screen Surface对象上的。SDL中的相关函数是:
void SDL_WM_SetCaption(const char *title, const char *icon);
        一般icon还暂时用不上,我们设置为空指针。我们修改一下Screen Surface的数据成员与构造函数。在数据成员里面添加一个windowName,并且修改构造函数
class ScreenSurface
{
private:
    
//
    char* windowName;
public:
   //
   ScreenSurface(int w, int h, char* window_name = 0, int b = 0, Uint32 f = 0); 
};

ScreenSurface::ScreenSurface():
width(
640), height(480), bpp(32), flags(0), windowName(0)
{
    
if ( screenNum > 0 )
        
throw ErrorInfo("DONOT create more than ONE screen!");
    
if ( SDL_Init(SDL_INIT_VIDEO < 0 ) )
        
throw ErrorInfo(SDL_GetError());
    pScreen 
= SDL_SetVideoMode(width, height, bpp, flags);
    screenNum
++;
}

ScreenSurface::ScreenSurface(
int w, int h, char* window_name, int b, Uint32 f):
width(w), height(h), bpp(b), flags(f)
{
    
if ( screenNum > 0 )
        
throw ErrorInfo("DONOT create more than ONE screen!");
    
if ( SDL_Init(SDL_INIT_VIDEO < 0 ) )
        
throw ErrorInfo(SDL_GetError());
    pScreen 
= SDL_SetVideoMode(width, height, bpp, flags);
    screenNum
++;
    
if ( window_name != 0 ) {
        windowName 
= window_name;
        SDL_WM_SetCaption(windowName, 
0);
    }
    
else
        windowName 
= 0;
}

这样,我们在创建SceenSurface的时候,第三个参数如果指定,则可以用字符串表示窗口名称。

1.2:使用*.ttf文件

        SDL使用*.ttf文件,仍然需要扩展库的支持。相关的下载和SDL_image的类似,大家可以参考前面的教程。下载地址如下:

        使用ttf扩展库的程序如下:
(1)装载扩展库:TTF_Init();
(2)打开字库:TTF_OpenFont(const char* ttf_fileName, int ttf_size);
(3)构建显示文本的surface:TTF_RenderText_Solid(TTF_Font* pFont, const char* message, SDL_Color textColor);
(4)显示(blit)文本surface;
(5)关闭字库:TTF_CloseFont();
(6)退出扩展库:TTF_Quit();
(7)释放显示文本的surface:SDL_FreeSurface();
        我们考虑下这个TextSurface与之前的DisplaySurface之间的关系,希望通过类将二者有所联系。

1.3:构建TextSurface类

        我们分析下TextSurface与DisplaySurface的关系:他们都依赖于一个ScreenSurface对象,至少具有两个一样的私有数据 成员pSurface和pScreen;他们有一致的行为blit();他们的构造前提条件不同,析构做的“善后”也不一样。
        我在水木社区的CPP版请教有这样关系的两个类应该是什么关系。有前辈指教说,一个类,用不同的flag加以区分。而我并不愿意多增加一个构造函数的参 数,所以,我用构造函数的重载实现构造的不同;用继承类实现方法代码的重用;用继承类的析构函数为TextSurface类做额外的析构工作。
        考虑到应在第一次建立TextSurface对象的时候装载ttf扩展库,并在最后一个对象使用完毕后关闭ttf扩展库,所以,在基类 DisplaySurface中添加静态私有成员作为计数器,并添加相应的方法为派生类使用。这些方法,以及专门为派生类创建的基类构造函数,我们并不希 望能被外部使用,所以,使用了关键字proteced。

class DisplaySurface
{
private:
    
//
    
//for TextSurafce
    static int textNum;
    TTF_Font
* pFont;
public:
    
//
protected:
    
//for TextSurface
    DisplaySurface(const std::string& msg_name, const std::string& message, const ScreenSurface& screen,
                    Uint8 r, Uint8 g, Uint8 b, 
                    
const std::string& ttf_fileName, int ttf_size);
    
int tellTextNum() const;
    
void reduceTextNum();
    
void deleteFontPoint();
};
pFont是TextSurface会用到的私有数据,构造基类的时候,直接设置成空指针就可以了。
保护成员的实现如下:
//for TextSurface
DisplaySurface::DisplaySurface(const std::string& msg_name, const std::string& message, const ScreenSurface& screen,
                    Uint8 r, Uint8 g , Uint8 b, 
                    
const std::string& ttf_fileName, int ttf_size):
fileName(msg_name)
{
    
if ( textNum == 0 )
        
if ( TTF_Init() < 0 )
            
throw ErrorInfo("TTF_Init() failed!");
    
    SDL_Color textColor;
    textColor.r 
= r;
    textColor.g 
= g;
    textColor.b 
= b;

    pFont 
= TTF_OpenFont(ttf_fileName.c_str(), ttf_size);
    
if ( pFont == 0 )
        
throw ErrorInfo("TTF_OpenFont() failed!");

    pSurface 
= TTF_RenderText_Solid(pFont, message.c_str(), textColor);
    
if ( pSurface == 0 )
        
throw ErrorInfo("TTF_RenderText_solid() failed!");
    pScreen 
= screen.point();

    textNum
++;
}

int DisplaySurface::tellTextNum() const
{
    
return textNum;
}

void DisplaySurface::reduceTextNum()
{
    textNum
--;
}

void DisplaySurface::deleteFontPoint()
{
    TTF_CloseFont(pFont);
}
有了这些数据成员和方法,我们可以构建TextSurface类了。
class TextSurface: public DisplaySurface
{
public:
    TextSurface(
const std::string& msg_name, const std::string& message, const ScreenSurface& screen,
                    Uint8 r 
= 0xFF, Uint8 g = 0xFF, Uint8 b = 0xFF
                    
const std::string& ttf_fileName = "lazy.ttf"int ttf_size = 28);
    
~TextSurface();
};
可以看到,我们仅仅增添了派生类的构造函数和析构函数,实现如下:
//class TextSurface

TextSurface::TextSurface(
const std::string& msg_name, const std::string& message, const ScreenSurface& screen,
                    Uint8 r, Uint8 g, Uint8 b, 
                    
const std::string& ttf_fileName, int ttf_size):
DisplaySurface(msg_name, message, screen, r, g, b, ttf_fileName, ttf_size)
{}

TextSurface::
~TextSurface()
{
    deleteFontPoint();
    reduceTextNum();
    
if ( tellTextNum() == 0 )
        TTF_Quit();
}
我们在下节给出完整的代码以及一个用于演示的例子。
//FileName: SurfaceClass.h

#ifndef SURFACE_CLASS_H
#define SURFACE_CLASS_H

#include 
<iostream>
#include 
<string>
#include 
"SDL/SDL.h"
#include 
"SDL/SDL_image.h"
#include 
"SDL/SDL_ttf.h"

class ScreenSurface
{
private:
    
static int screenNum;
    
int width;
    
int height;
    
int bpp;
    Uint32 flags;
    SDL_Surface
* pScreen;
    
char* windowName;
public:
    ScreenSurface();
    ScreenSurface(
int w, int h, char* window_name = 0int b = 0, Uint32 f = 0);
    
~ScreenSurface();
    SDL_Surface
* point() const;
    
void flip() const;
    
void fillColor(Uint8 r = 0, Uint8 g = 0, Uint8 b = 0const;
};

class DisplaySurface
{
private:
    std::
string fileName;
    SDL_Surface
* pSurface;
    SDL_Surface
* pScreen;
    
//for TextSurafce
    static int textNum;
    TTF_Font
* pFont;
public:
    DisplaySurface(
const std::string& file_name, const ScreenSurface& screen);
    
~DisplaySurface();
    SDL_Surface
* point() const;
    
void blit() const;
    
void blit(int at_x, int at_y) const;
    
void blit(int at_x, int at_y,
                
int from_x, int from_y, int w, int h,
                
int delta_x = 0int delta_y = 0const;
    
void colorKey(Uint8 r = 0, Uint8 g = 0xFF, Uint8 b = 0xFF, Uint32 flag = SDL_SRCCOLORKEY);
protected:
    
//for TextSurface
    DisplaySurface(const std::string& msg_name, const std::string& message, const ScreenSurface& screen,
                    Uint8 r, Uint8 g, Uint8 b, 
                    
const std::string& ttf_fileName, int ttf_size);
    
int tellTextNum() const;
    
void reduceTextNum();
    
void deleteFontPoint();
};

class TextSurface: public DisplaySurface
{
public:
    TextSurface(
const std::string& msg_name, const std::string& message, const ScreenSurface& screen,
                    Uint8 r 
= 0xFF, Uint8 g = 0xFF, Uint8 b = 0xFF
                    
const std::string& ttf_fileName = "lazy.ttf"int ttf_size = 28);
    
~TextSurface();
};

class ErrorInfo
{
private:
    std::
string info;
public:
    ErrorInfo():info(
"Unknown ERROR!")
    {}
    ErrorInfo(
const char* c_str)
    {
        info 
= std::string(c_str);
    }
    ErrorInfo(
const std::string& str):info(str)
    {}
    
void show() const
    {
        std::cerr 
<< info << std::endl;
    }
};

#endif
//UVi Soft (2008)
//Long Fei (lf426), E-mail: zbln426@163.com

#include 
"SurfaceClass.h"

//VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
//class ScreenSurface

int ScreenSurface::screenNum = 0;

ScreenSurface::ScreenSurface():
width(
640), height(480), bpp(32), flags(0), windowName(0)
{
    
if ( screenNum > 0 )
        
throw ErrorInfo("DONOT create more than ONE screen!");
    
if ( SDL_Init(SDL_INIT_VIDEO < 0 ) )
        
throw ErrorInfo(SDL_GetError());
    pScreen 
= SDL_SetVideoMode(width, height, bpp, flags);
    screenNum
++;
}

ScreenSurface::ScreenSurface(
int w, int h, char* window_name, int b, Uint32 f):
width(w), height(h), bpp(b), flags(f)
{
    
if ( screenNum > 0 )
        
throw ErrorInfo("DONOT create more than ONE screen!");
    
if ( SDL_Init(SDL_INIT_VIDEO < 0 ) )
        
throw ErrorInfo(SDL_GetError());
    pScreen 
= SDL_SetVideoMode(width, height, bpp, flags);
    screenNum
++;
    
if ( window_name != 0 ) {
        windowName 
= window_name;
        SDL_WM_SetCaption(windowName, 
0);
    }
    
else
        windowName 
= 0;
}

ScreenSurface::
~ScreenSurface()
{
    SDL_Quit();
}

SDL_Surface
* ScreenSurface::point() const
{
    
return pScreen;
}

void ScreenSurface::flip() const
{
    
if ( SDL_Flip(pScreen) < 0 )
        
throw ErrorInfo(SDL_GetError());
}


void ScreenSurface::fillColor(Uint8 r, Uint8 g, Uint8 b) const
{
     
if ( SDL_FillRect(pScreen, 0, SDL_MapRGB(pScreen->format, r, g, b)) < 0 )
         
throw ErrorInfo(SDL_GetError());
}

//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

//VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
//class DisplaySurface

int DisplaySurface::textNum = 0;

DisplaySurface::DisplaySurface(
const std::string& file_name, const ScreenSurface& screen):
fileName(file_name), pFont(
0)
{
    SDL_Surface
* pSurfaceTemp = IMG_Load(file_name.c_str());
    
if ( pSurfaceTemp == 0 )
        
throw ErrorInfo(SDL_GetError());
    pSurface 
= SDL_DisplayFormat(pSurfaceTemp);
    
if ( pSurface == 0 )
        
throw ErrorInfo(SDL_GetError());
    SDL_FreeSurface(pSurfaceTemp);
    pScreen 
= screen.point();
}

DisplaySurface::
~DisplaySurface()
{
    SDL_FreeSurface(pSurface);
}

SDL_Surface
* DisplaySurface::point() const
{
    
return pSurface;
}

void DisplaySurface::blit() const
{
    
if ( SDL_BlitSurface(pSurface, 0, pScreen, 0< 0 )
        
throw ErrorInfo(SDL_GetError());
}


void DisplaySurface::blit(int at_x, int at_y) const
{
    SDL_Rect offset;
    offset.x 
= at_x;
    offset.y 
= at_y;

    
if ( SDL_BlitSurface(pSurface, 0, pScreen, &offset) < 0 )
        
throw ErrorInfo(SDL_GetError());
}

void DisplaySurface::blit(int at_x, int at_y,
                          
int from_x, int from_y, int w, int h,
                          
int delta_x, int delta_y) const
{
    SDL_Rect offset;
    offset.x 
= at_x - delta_x;
    offset.y 
= at_y - delta_y;

    SDL_Rect dest;
    dest.x 
= from_x - delta_x;
    dest.y 
= from_y - delta_y;
    dest.w 
= w + delta_x*2;
    dest.h 
= h + delta_y*2;

    
if ( SDL_BlitSurface(pSurface, &dest, pScreen, &offset) < 0 )
        
throw ErrorInfo(SDL_GetError());
}

void DisplaySurface::colorKey(Uint8 r, Uint8 g, Uint8 b, Uint32 flag)
{
    Uint32 colorkey 
= SDL_MapRGB(pSurface->format, r, g, b);
    
if ( SDL_SetColorKey(pSurface, flag, colorkey ) < 0 )
        
throw ErrorInfo(SDL_GetError());
}

//for TextSurface
DisplaySurface::DisplaySurface(const std::string& msg_name, const std::string& message, const ScreenSurface& screen,
                    Uint8 r, Uint8 g , Uint8 b, 
                    
const std::string& ttf_fileName, int ttf_size):
fileName(msg_name)
{
    
if ( textNum == 0 )
        
if ( TTF_Init() < 0 )
            
throw ErrorInfo("TTF_Init() failed!");
    
    SDL_Color textColor;
    textColor.r 
= r;
    textColor.g 
= g;
    textColor.b 
= b;

    pFont 
= TTF_OpenFont(ttf_fileName.c_str(), ttf_size);
    
if ( pFont == 0 )
        
throw ErrorInfo("TTF_OpenFont() failed!");

    pSurface 
= TTF_RenderText_Solid(pFont, message.c_str(), textColor);
    
if ( pSurface == 0 )
        
throw ErrorInfo("TTF_RenderText_solid() failed!");
    pScreen 
= screen.point();

    textNum
++;
}

int DisplaySurface::tellTextNum() const
{
    
return textNum;
}

void DisplaySurface::reduceTextNum()
{
    textNum
--;
}

void DisplaySurface::deleteFontPoint()
{
    TTF_CloseFont(pFont);
}

//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

//VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
//class TextSurface

TextSurface::TextSurface(
const std::string& msg_name, const std::string& message, const ScreenSurface& screen,
                    Uint8 r, Uint8 g, Uint8 b, 
                    
const std::string& ttf_fileName, int ttf_size):
DisplaySurface(msg_name, message, screen, r, g, b, ttf_fileName, ttf_size)
{}

TextSurface::
~TextSurface()
{
    deleteFontPoint();
    reduceTextNum();
    
if ( tellTextNum() == 0 )
        TTF_Quit();
}

//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

//UVi Soft (2008)
//Long Fei (lf426), E-mail: zbln426@163.com

#include 
"SurfaceClass.h"

int game(int argc, char* argv[]);
int main(int argc ,char* argv[])
{
    
int mainRtn = 0;
    
try {
        mainRtn 
= game(argc, argv);
    }
    
catch ( const ErrorInfo& info ) {
        info.show();
        
return -1;
    }
    
    
return mainRtn;
}

int game(int argc ,char* argv[])
{
    
//Create a SDL screen.
    const int SCREEN_WIDTH = 640;
    
const int SCREEN_HEIGHT = 480;
    ScreenSurface screen(SCREEN_WIDTH, SCREEN_HEIGHT, 
"Font");
    
//Fill background with white.(default is black)
    screen.fillColor(0xFF0xFF0xFF);

    
//Load a textSurface
    TextSurface myText("logo""UVi Soft", screen, 000xFF"times.ttf"80);
    TextSurface lazy(
"lazy""by lf426 (zbln426@163.com)", screen, 0xff00);
    
//Display text
    myText.blit(170180);
    lazy.blit(
150,400);
    screen.flip();
    
    
//press ESC or click X to quit.
    bool gameOver = false;
    SDL_Event gameEvent;
    
while( gameOver == false ){
        
while ( SDL_PollEvent(&gameEvent) != 0 ){
            
if ( gameEvent.type == SDL_QUIT ){
                gameOver 
= true;
            }
            
if ( gameEvent.type == SDL_KEYUP ){
                
if ( gameEvent.key.keysym.sym == SDLK_ESCAPE ){
                    gameOver 
= true;
                }
            }
        }
    }

    
return 0;
}

阅读(1429) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~