7.SDL游戏开发:东窗事发--事件(一)

为了感谢开源中国社区,在测试中文使用了一个开源TTF,字体仍是蛮好看的! app

还记得在第3篇里的事件,总不能不了了之。如今接着分析,对我而讲这也是一个学习的过程,下面先讲键盘事件里的方向键入手。 ide

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

const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
const int SCREEN_BPP = 32;

//The surfaces
SDL_Surface *background = NULL;
SDL_Surface *upMessage = NULL;
SDL_Surface *downMessage = NULL;
SDL_Surface *leftMessage = NULL;
SDL_Surface *rightMessage = NULL;
SDL_Surface *message = NULL;
SDL_Surface *screen = NULL;

//The event structure
SDL_Event event;

//字体
TTF_Font *font = NULL;

//字体的颜色
SDL_Color textColor = { 0, 0, 0 };

SDL_Surface *load_image( std::string filename )
{
    /* 省略*/
}

void apply_surface( int x, int y, SDL_Surface* source, SDL_Surface* destination, SDL_Rect* clip = NULL )
{
    /*省略*/
}

bool init()
{
    //初始化全部的子系统
    if( SDL_Init( SDL_INIT_EVERYTHING ) == -1 ) {
        return false;
    }

    //Set up the screen
    screen = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SDL_SWSURFACE );

    //If there was an error in setting up the screen
    if( screen == NULL ) {
        return false;
    }

    //初始化 SDL_ttf
    if( TTF_Init() == -1 ) {
        return false;
    }

    //设置窗口标题 caption
    SDL_WM_SetCaption( "Press an Arrow Key", NULL );

    return true;
}

bool load_files()
{
    //Load the background image
    background = load_image( "background.png" );

    //打开字体
    font = TTF_OpenFont( "lazy.ttf", 72 );

    //If there was a problem in loading the background
    if( background == NULL ) {
        return false;
    }

    //If there was an error in loading the font
    if( font == NULL ) {
        return false;
    }

    return true;
}

void clean_up()
{
    //释放 surfaces
    SDL_FreeSurface( background );
    SDL_FreeSurface( upMessage );
    SDL_FreeSurface( downMessage );
    SDL_FreeSurface( leftMessage );
    SDL_FreeSurface( rightMessage );

    //Close the font
    TTF_CloseFont( font );
    TTF_Quit();
    SDL_Quit();
}

int main( int argc, char* args[] )
{
    //Quit flag
    bool quit = false;

    //Initialize
    if( init() == false ){
        return 1;
    }

    //Load the files
    if( load_files() == false ) {
        return 1;
    }

    //Generate the message surfaces
    upMessage = TTF_RenderText_Solid( font, "Up was pressed.", textColor );
    downMessage = TTF_RenderText_Solid( font, "Down was pressed.", textColor );
    leftMessage = TTF_RenderText_Solid( font, "Left was pressed", textColor );
    rightMessage = TTF_RenderText_Solid( font, "Right was pressed", textColor );

    //Apply the background
    apply_surface( 0, 0, background, screen );

    //While the user hasn't quit
    while( quit == false ) {
        //If there's an event to handle
        if( SDL_PollEvent( &event ) ) {
            //If a key was pressed
            if( event.type == SDL_KEYDOWN ) {
                //Set the proper message surface
                switch( event.key.keysym.sym )
                {
                    case SDLK_UP: message = upMessage; break;
                    case SDLK_DOWN: message = downMessage; break;
                    case SDLK_LEFT: message = leftMessage; break;
                    case SDLK_RIGHT: message = rightMessage; break;
                }
            }

            //If the user has Xed out the window
            else if( event.type == SDL_QUIT ) {
                //退出程序
                quit = true;
            }
        }

        //If a message needs to be displayed
        if( message != NULL ) {
            //Apply the background to the screen
            apply_surface( 0, 0, background, screen );

            //Apply the message centered on the screen
            apply_surface( ( SCREEN_WIDTH - message->w ) / 2, ( SCREEN_HEIGHT - message->h ) / 2, message, screen );

            //Null the surface pointer
            message = NULL;
        }

        //Update the screen
        if( SDL_Flip( screen ) == -1 ){
            return 1;
        }
    }
    clean_up();
    return 0;
}

保存为sdl07.cpp 编译运行 学习

g++ -o sdl07 sdl07.cpp -lSDL -lSDL_image -lSDL_ttf            ./sdl07

赶忙按上下左右键试试,想一想贪吃蛇,你有没有这种感受能实现其中某些功能了呢,那就是控制方向,对于软件开发来讲,方法都是相通,只不过有些是通过层层的封装而已。 要作几点说明:event.type 和event.type.keysym.sym,这么变态,前一个仍是好理解,而对于event.type.keysym.sym,若是看过内核代码确定会很清楚,里面是结构体嵌套,接下找到SDL_KeyboardEvent结构体。 测试

typedef struct{
  Uint8 type;   /*SDL_KEYDOWN or SDL_KEYUP */
  Uint8 state;  /* 状态:SDL_PRESSED or SDL_RELEASED */
  SDL_keysym keysym;  
} SDL_KeyboardEvent;

继续深究SDL_keysym 字体

typedef struct{
  Uint8 scancode;  /*  硬件专用,但不知道与驱动有没有关系*/
  SDLKey sym;      /* SDL虚拟键 */
  SDLMod mod;      /* 当前状态的存储 */
  Uint16 unicode;  /* UNICODE使用 */
} SDL_keysym;

SDLKey:: SDLK_LEFT,SDLK_UP……SDLKey的值能够查阅SDL_keysym.h(代码就不帖了)文件,SDLMOD的值也能够在这里面找到。这样sdl07.cpp这个程序就没有问题了,差很少键盘的问题均可以解决了,比起Windows下面HOOK处理是否是要爽不少,键盘事件是解决了,鼠标确定不能错过下面接着讲。 ui

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

//Screen attributes
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
const int SCREEN_BPP = 32;

//The button states in the sprite sheet
const int CLIP_MOUSEOVER = 0;
const int CLIP_MOUSEOUT = 1;
const int CLIP_MOUSEDOWN = 2;
const int CLIP_MOUSEUP = 3;

//The surfaces
SDL_Surface *buttonSheet = NULL;
SDL_Surface *screen = NULL;

//The event structure
SDL_Event event;

//The clip regions of the sprite sheet
SDL_Rect clips[ 4 ];

// Button类
class Button
{
private:
    //The attributes of the button
    SDL_Rect box;

    //The part of the button sprite sheet that will be shown
    SDL_Rect* clip;

public:
    //Button初始化的值
    Button( int x, int y, int w, int h );

    //Handles events and set the button's sprite region
    void handle_events();

    //Shows the button on the screen
    void show();
};

SDL_Surface *load_image( std::string filename )
{
    /*省略*/
}

void apply_surface( int x, int y, SDL_Surface* source, SDL_Surface* destination, SDL_Rect* clip = NULL )
{
   /* 省略*/
}

bool init()
{
    if( SDL_Init( SDL_INIT_EVERYTHING ) == -1 ) {
        return false;
    }

    screen = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SDL_SWSURFACE );

    if( screen == NULL ){
        return false;
    }
    SDL_WM_SetCaption( "Button Test", NULL );

    return true;
}

bool load_files()
{
    buttonSheet = load_image( "button.png" );

    if( buttonSheet == NULL ){
        return false;
    }

    return true;
}

void clean_up()
{
    SDL_FreeSurface( buttonSheet );
    SDL_Quit();
}

void set_clips()
{
    //Clip the sprite sheet
    clips[ CLIP_MOUSEOVER ].x = 0;
    clips[ CLIP_MOUSEOVER ].y = 0;
    clips[ CLIP_MOUSEOVER ].w = 320;
    clips[ CLIP_MOUSEOVER ].h = 240;

    clips[ CLIP_MOUSEOUT ].x = 320;
    clips[ CLIP_MOUSEOUT ].y = 0;
    clips[ CLIP_MOUSEOUT ].w = 320;
    clips[ CLIP_MOUSEOUT ].h = 240;

    clips[ CLIP_MOUSEDOWN ].x = 0;
    clips[ CLIP_MOUSEDOWN ].y = 240;
    clips[ CLIP_MOUSEDOWN ].w = 320;
    clips[ CLIP_MOUSEDOWN ].h = 240;

    clips[ CLIP_MOUSEUP ].x = 320;
    clips[ CLIP_MOUSEUP ].y = 240;
    clips[ CLIP_MOUSEUP ].w = 320;
    clips[ CLIP_MOUSEUP ].h = 240;
}

Button::Button( int x, int y, int w, int h )
{
    //Set the button's attributes
    box.x = x;
    box.y = y;
    box.w = w;
    box.h = h;

    //Set the default sprite
    clip = &clips[ CLIP_MOUSEOUT ];
}

void Button::handle_events()
{

    int x = 0, y = 0;

    //If the mouse moved
    if( event.type == SDL_MOUSEMOTION )
    {
        //Get the mouse offsets
        x = event.motion.x;
        y = event.motion.y;

        //If the mouse is over the button
        if( ( x > box.x ) && ( x < box.x + box.w ) && ( y > box.y ) && ( y < box.y + box.h ) )
        {
            //Set the button sprite
            clip = &clips[ CLIP_MOUSEOVER ];
        }
        //If not
        else
        {
            //Set the button sprite
            clip = &clips[ CLIP_MOUSEOUT ];
        }
    }
    //If a mouse button was pressed
    if( event.type == SDL_MOUSEBUTTONDOWN )
    {
        //If the left mouse button was pressed
        if( event.button.button == SDL_BUTTON_LEFT )
        {
            //Get the mouse offsets
            x = event.button.x;
            y = event.button.y;

            //If the mouse is over the button
            if( ( x > box.x ) && ( x < box.x + box.w ) && ( y > box.y ) && ( y < box.y + box.h ) )
            {
                //Set the button sprite
                clip = &clips[ CLIP_MOUSEDOWN ];
            }
        }
    }
    //If a mouse button was released
    if( event.type == SDL_MOUSEBUTTONUP )
    {
        //If the left mouse button was released
        if( event.button.button == SDL_BUTTON_LEFT )
        {
            //Get the mouse offsets
            x = event.button.x;
            y = event.button.y;

            //If the mouse is over the button
            if( ( x > box.x ) && ( x < box.x + box.w ) && ( y > box.y ) && ( y < box.y + box.h ) )
            {
                //Set the button sprite
                clip = &clips[ CLIP_MOUSEUP ];
            }
        }
    }
}

void Button::show()
{
    //Show the button
    apply_surface( box.x, box.y, buttonSheet, screen, clip );
}

int main( int argc, char* args[] )
{
    //Quit flag
    bool quit = false;

    //Initialize
    if( init() == false )
    {
        return 1;
    }

    //Load the files
    if( load_files() == false )
    {
        return 1;
    }

    //Clip the sprite sheet
    set_clips();

    //Make the button
    Button myButton( 170, 120, 320, 240 );

    //While the user hasn't quit
    while( quit == false )
    {
        //If there's events to handle
        if( SDL_PollEvent( &event ) )
        {
            //Handle button events
            myButton.handle_events();

            //If the user has Xed out the window
            if( event.type == SDL_QUIT )
            {
                //Quit the program
                quit = true;
            }
        }

        //Fill the screen white
        SDL_FillRect( screen, &screen->clip_rect, SDL_MapRGB( screen->format, 0xFF, 0xFF, 0xFF ) );

        //Show the button
        myButton.show();

        //Update the screen
        if( SDL_Flip( screen ) == -1 )
        {
            return 1;
        }
    }

    //Clean up
    clean_up();

    return 0;
}
保存为sdl071.cpp 编译运行
g++ -o sdl071 sdl071.cpp -lSDL -lSDL_image -lSDL_ttf
 ./sdl071

赶忙用鼠标去点点试试,不过这里一共只有4种状况以下图 spa

  

这个程序里面见到类了,固然不能用类也能实现,不过会复杂点,关于这个代码的分析就放在下一篇里才讲了。还多罗嗦几句,有一个概念叫人机交互,你想能与你交互有那些东西:仍是键盘,鼠标,其次像工业应用比较多,传感器类,还图像图像(人脸识别),语言(如苹果的siri)……,可是当前最多仍是鼠标键盘吧! code

相关文章
相关标签/搜索