实践教程--弹球游戏

弹球游戏有三个主要因素:球,墙,用户输入。

(1)球以一定的速度运行;

(2)球碰到墙或挡板会逆行;

(3)用户输入会改变球的运行状态:加速、减速或退出;向上、向下或斜行(二维)。

程序主要功能设计:

(1)计时器驱动

间隔计时器被设置为产生固定的SIGALRMS信号流。响应一个信号,球向前移动一步。

(2)等待键盘输入

程序阻塞等待键盘输入。根据用户按下的键,采取不同的动作。

(3)状态变量

变量记录了球的速度和方向。用户输入修改的变量值决定了小球的速度。计时器处理函数根据速度和位置变量来决定在何时何处画小球。

 

一维动画:一个信号,移动一个单位。

二维动画:两个计时器,斜着移动。如当直角边的比值为1/3时,构造两个自己的计时器:一个记录平行移动的计时器信号数,一个记录垂直移动的计时器信号数。每两个计时器信号向右移动一个单位,每六个计时器信号向上移动一个单位。如果时钟间隔单位分别是10和30的话,球移动的路径相同,就是慢些。

实现:为实现二维动画,同时在两个方向移动,用两个计数器充当计时器。每个计数器有两个属性:当前值和间隔。当前值表示在下次重画之前还要等待多少个计时信号。间隔指明两次移动之间所要等待的计时信号个数。分别命名为ttg和ttm。

 

代码:

/* bounce.h            */

#ifndef BOUNCH_H
#define BOUNCH_H

/* some settings for the game    */

#define    BLANK        ' '
#define    WALL        '.'
#define    USER_WALL    '='
#define    DFL_SYMBOL    'o'
#define    TOP_ROW        6
#define    BOT_ROW     19
#define    LEFT_EDGE    6
#define    RIGHT_EDGE    44
#define    X_INIT        10        /* starting col        */
#define    Y_INIT        10        /* starting row        */
#define    TICKS_PER_SEC    25        /* affects speed    */

#define    X_TTM        5
#define    Y_TTM        8

int score = 0;
int user_wall_pos = 5;
int user_wall_len = 9;

/** the ping pong ball **/

struct ppball {
        int    y_pos, x_pos,
                y_ttm, x_ttm,
                y_ttg, x_ttg,
                y_dir, x_dir;
        char    symbol ;

    } ;

#endif

#include    <stdio.h>
#include        <sys/time.h>
#include        <signal.h>

/*
 *      set_ticker.c
 *          set_ticker( number_of_milliseconds )
 *                   arranges for the interval timer to issue
 *                   SIGALRM's at regular intervals
 *          returns -1 on error, 0 for ok
 *
 *      arg in milliseconds, converted into micro seoncds
 */


set_ticker( n_msecs )
{
        struct itimerval new_timeset;
        long    n_sec, n_usecs;

        n_sec = n_msecs / 1000 ;
        n_usecs = ( n_msecs % 1000 ) * 1000L ;

        new_timeset.it_interval.tv_sec  = n_sec;        /* set reload  */
        new_timeset.it_interval.tv_usec = n_usecs;      /* new ticker value */
        new_timeset.it_value.tv_sec     = n_sec  ;      /* store this   */
        new_timeset.it_value.tv_usec    = n_usecs ;     /* and this     */

    return setitimer(ITIMER_REAL, &new_timeset, NULL);
}

/*  bounce2d.c 1.0
 *    bounce a character (default is 'o') around the screen
 *    defined by some parameters
 *
 *    user input:     s slow down x component, S: slow y component
 *                           f speed up x component,  F: speed y component
 *                          Q quit  a: user wall left   d: user wall right   
 *
 *    blocks on read, but timer tick sends SIGALRM caught by ball_move
 *    build:   cc bounce2d.c set_ticker.c -lcurses -o bounce2d
 */

#include    <curses.h>
#include    <signal.h>
#include    <stdlib.h>
#include    "bounce.h"

struct ppball the_ball ;

/**  the main loop  **/

void set_up();
void wrap_up();
void move_user_wall(int);
int main()
{
    int    c, dir = 0;

    set_up();
    
    while ( ( c = getchar()) != 'Q' ){
        if ( c == 'f' )         the_ball.x_ttm--;
        else if ( c == 's' ) the_ball.x_ttm++;
        else if ( c == 'F' ) the_ball.y_ttm--;
        else if ( c == 'S' ) the_ball.y_ttm++;
        else if ( c == 'a' ) { dir = -1; move_user_wall(dir); }
        else if ( c == 'd' ) { dir = 1; move_user_wall(dir); }
        else if ( c == 'j' ) { if ( --user_wall_len <= 1 ) user_wall_len = 1; }
        else if ( c == 'k' ) { if ( ++user_wall_len >= 15 ) user_wall_len = 15; }
    }

    wrap_up();
}

void set_up()
/*
 *    init structure and other stuff
 */
{
    void    ball_move(int);

    the_ball.y_pos = Y_INIT;
    the_ball.x_pos = X_INIT;
    the_ball.y_ttg = the_ball.y_ttm = Y_TTM ;
    the_ball.x_ttg = the_ball.x_ttm = X_TTM ;
    the_ball.y_dir = 1  ;
    the_ball.x_dir = 1  ;
    the_ball.symbol = DFL_SYMBOL ;

    initscr();
    noecho();
    crmode();

    signal( SIGINT , SIG_IGN );
    /* draw wall */
    mvhline(5, 5, WALL, 40);
    mvvline(5, 5, WALL, 15);
    mvvline(5, 45, WALL, 15);

    mvprintw( 4, 5, "score:%d left:s right:d -speed:s +speed:f +wall_len:j -wall_len:k quit:Q", 0);    /* infomation */
    mvaddch( the_ball.y_pos, the_ball.x_pos, the_ball.symbol  );    /* init ball */    
    mvhline(20, user_wall_pos, '=', user_wall_len);                    /* init user_wall */
    refresh();

    signal( SIGALRM, ball_move );
    set_ticker( 1000 / TICKS_PER_SEC );    /* send millisecs per tick */
}

void wrap_up()
{
    set_ticker( 0 );
    mvaddstr(15, 15, "GAME OVER!.....");
    mvaddstr(16, 15, "Q:quit");    
    refresh();
    while(1)    
        if ( getchar() == 'Q') break;
    endwin();
    exit(0);        /* put back to normal    */
}

void ball_move(int signum)
{
    int    y_cur, x_cur, moved;

    signal( SIGALRM , SIG_IGN );        /* dont get caught now     */
    y_cur = the_ball.y_pos ;        /* old spot        */
    x_cur = the_ball.x_pos ;
    moved = 0 ;

    if ( the_ball.y_ttm > 0 && the_ball.y_ttg-- == 1 ){
        the_ball.y_pos += the_ball.y_dir ;    /* move    */
        the_ball.y_ttg = the_ball.y_ttm  ;    /* reset*/
        moved = 1;
    }

    if ( the_ball.x_ttm > 0 && the_ball.x_ttg-- == 1 ){
        the_ball.x_pos += the_ball.x_dir ;    /* move    */
        the_ball.x_ttg = the_ball.x_ttm  ;    /* reset*/
        moved = 1;
    }

    if ( moved ){
        mvaddch( y_cur, x_cur, BLANK );
        mvaddch( y_cur, x_cur, BLANK );
        mvaddch( the_ball.y_pos, the_ball.x_pos, the_ball.symbol );
        bounce_or_lose( &the_ball );
        move(LINES-1,COLS-1);
        refresh();
    }

    signal( SIGALRM, ball_move);        /* for unreliable systems */

}

int bounce_or_lose(struct ppball *bp)
{
    int    return_val = 0 ;
    int user_wall_left = user_wall_pos,
        user_wall_right = user_wall_pos + user_wall_len - 1;

    if ( bp->y_pos == TOP_ROW ){
        bp->y_dir = 1 ;
        return_val = 1 ;
    } else if ( (bp->y_pos == BOT_ROW) && (bp->x_pos >= user_wall_left && bp->x_pos <= user_wall_right) ){
        bp->y_dir = -1;
        mvprintw( 4, 5, "score:%d", score++);
        return_val = 1;
    } else if (bp->y_pos > BOT_ROW)
        wrap_up();
        
    if ( bp->x_pos == LEFT_EDGE ){
        bp->x_dir = 1 ;
        return_val = 1 ;
    } else if ( bp->x_pos == RIGHT_EDGE ){
        bp->x_dir = -1;
        return_val = 1;
    }

    return return_val;
}

void move_user_wall(int dir)
{
    int user_wall_left = user_wall_pos,
        user_wall_right = user_wall_pos + user_wall_len - 1;    
    int wall_left = 5,
        wall_right = 45;    
        
    user_wall_pos += dir;
    
    if(user_wall_pos <= wall_left)
        user_wall_pos = wall_left;
    if( user_wall_pos >= wall_right - user_wall_len + 1 )
        user_wall_pos = wall_right - user_wall_len;

    mvhline( 20, user_wall_pos, USER_WALL, user_wall_len + 1 );
    
    if (dir == 1 && user_wall_right < wall_right -1 )    
        mvhline( 20, user_wall_left, BLANK, 1 );
    if (dir == -1 && user_wall_left > wall_left )        
        mvhline( 20, user_wall_right+1, BLANK, 1 );
    
    move(LINES - 1, COLS - 1);
    refresh();
}

 

/*
 *      set_ticker.c
 *          set_ticker( number_of_milliseconds )
 *                   arranges for the interval timer to issue
 *                   SIGALRM's at regular intervals
 *          returns -1 on error, 0 for ok
 *
 *      arg in milliseconds, converted into micro seoncds
 */
#include    <stdio.h>
#include        <sys/time.h>
#include        <signal.h>

set_ticker( n_msecs )
{
        struct itimerval new_timeset;
        long    n_sec, n_usecs;

        n_sec = n_msecs / 1000 ;
        n_usecs = ( n_msecs % 1000 ) * 1000L ;

        new_timeset.it_interval.tv_sec  = n_sec;        /* set reload  */
        new_timeset.it_interval.tv_usec = n_usecs;      /* new ticker value */
        new_timeset.it_value.tv_sec     = n_sec  ;      /* store this   */
        new_timeset.it_value.tv_usec    = n_usecs ;     /* and this     */

    return setitimer(ITIMER_REAL, &new_timeset, NULL);
}

 

想实现R:重新开始游戏的功能,可是没能成功,希望有知道如何实现的牛人给指点一下啊~

你可能感兴趣的:(timer,struct,user,UP,Signal,Intervals)