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

相關文章
相關標籤/搜索