文档章节

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

一一无念
 一一无念
发布于 2012/11/06 20:00
字数 1549
阅读 685
收藏 6

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

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

#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处理是不是要爽很多,键盘事件是解决了,鼠标肯定不能错过下面接着讲。

#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种情况如下图

  

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

© 著作权归作者所有

一一无念
粉丝 58
博文 36
码字总数 18408
作品 0
长沙
私信 提问
加载中

评论(1)

独孤小败
独孤小败
加油楼主,给你打气!
Oracle 为 OS X 发布 Java 开发工具

2010年末的时候,苹果宣布终止对OS X的Java支持,当时乔布斯表示苹果的Java版本总是比Sun/Oracle发布落后,导致苹果比其他所有平台的Java版本都要老,所以继续支持没 有意义了。之后过了几周...

红薯
2012/04/27
2.1K
9
【北京】北京荣唐科技有限公司招聘技术开发人员

一、 FLASH+AS3 游戏高级开发工程师(2人) 工作职责: 从事SNS平台上flash webgame游戏开发 职位描述: 1. 至少1年以上FLASH+AS3游戏项目开发经验 2. 对as3的事件机制有深入认识,具有良好编...

frendy
2012/04/12
592
7
北京网页游戏公司年薪20万招聘主程序(java/flex)

职位一:java服务端主程序 岗位职责: 负责设计游戏功能架构、模块划分;对于难点提出相应的解决方案,负责核心系统设计与研发。 任职要求: 4年以上java开发经验,2年以上游戏服务端开发经验...

boweihr
2011/08/10
1K
8
Unity社交功能开发——移动端输入法回车事件响应

一、叙叙旧 最近工作比较忙好久没有更新博客了,笔者并没有忘记博客也没有忘记大家。游戏大概下月初就上线了,我会逐渐把做过的研究过的事情都分享出来。 二、回车事件 今天就先分享下Unity...

tj134679258
2016/06/11
0
0
微信小游戏即将开放?有我们在,你还赶得上!(如何在完全不懂服务器开发的情况下做一个实时联网对战的微信小游戏)

根据微信官方对外公开的消息,微信小游戏的脚步越来越接近了。它的开发者资格门槛和使用者门槛都很低,以后必将引爆一波"全民开发小游戏"浪潮。 官方的开发工具创建项目即可获取 的源码,这是...

大王12
2018/03/30
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Spring Cloud Sleuth 整合 feign 源码分析之修改span名称

org.springframework.cloud.sleuth.instrument.web.client.feign.TraceFeignClient 包括创建span一些参数 需求场景: 由于项目中有restful 风格的http请求,sleuth feign 的span名称默认是u...

xiaomin0322
30分钟前
4
0
Less 延伸

extend 是一个 Less 伪类,它通过使用 :extend 选择器在一个选择器中扩展其他选择器样式。 扩展语法 扩展可以是附加到选择器,也可以是集中放置在规则,看上去像是带有选择器参数的可选伪类,...

凌兮洛
30分钟前
4
0
RedHat 7.0系统中安装mysql 5.7.22

在安装之前,首先要查看的是,你的系统中有没有已经安装过的情况。键入rpm -qa|grep mysql,如果无任何显示,则表示没有安装过相关组件,如果有,则根据显示出来的名字,键入rpm -e --nodeps...

最菜最菜之小菜鸟
36分钟前
4
0
RPA:企业信息孤岛的“克星”

为了降本增效,近来世界范围内掀起一股流程优化的热潮,转型升级成为众多企业时刻挂在嘴边的热词。不过在企业数字化转型的过程中,信息孤岛的出现,往往成为了企业升级的绊脚石。 信息孤岛:...

UiBot
36分钟前
4
0
我的测试

我的测试

daiison
36分钟前
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部