linux下C实现打转块小游戏(二)

/*
fun.c源文件
*/
#include <curses.h>
#include <signal.h>
#include <sys/time.h>
#include "play.h"
#include <stdio.h>
#include <stdlib.h>

void init(void);
void exit_a(void);
void paint_boat(int);
void paint_table(int, int, int);
int settimer(int);
void move_person(int);
void win(void);
void lost(void);
struct person p1;
int beg_boat;
void main(void)
{
    long ch;

    init();
    signal(SIGINT, SIG_IGN);
    /*
    设置定时器,单位出发时间初始化为20毫秒。
    小球水平,垂直方向运动,以单位定时器的倍数为准,加入为x:5,则触发五次定时器,则小球横向移动一个单元格,
    加速,是通过减少相应方向定时器的倍数。
    */
    signal(SIGALRM, move_person );
    settimer(20);
    while ((ch = getch()) != 'q'){
        if (ch == KEY_LEFT)
            paint_boat(1);
        if (ch == KEY_RIGHT)
            paint_boat(-1);
        if (ch == ' ')
            signal(SIGALRM, SIG_IGN);
        if (ch == 'c') {
            signal(SIGALRM, move_person);
            settimer(20);
        }
        if (ch == 'w') {
            if (p1.y_ttm > SPEED_MIN)
                p1.y_ttm--;    
        }
        if (ch == 's') {
            if (p1.y_ttm < SPEED_MAX)
                p1.y_ttm++;
        }
        if (ch == 'a') {
            if (p1.x_ttm > SPEED_MIN)
                p1.x_ttm--;
        }
        if (ch == 'd') {
            if (p1.x_ttm < SPEED_MAX)
                p1.x_ttm++;
        }
    }
}
/*
    退出时调用,用于恢复终端属性
*/
void exit_a(void)
{
    endwin();
}
/*
    初始化
*/
void init(void)
{
    int n, m; 
    //初始化小球基本信息
    p1.remain = (MINE_BOT - MINE_TOP + 1)*(MINE_RIGHT - MINE_LEFT + 1);
    p1.score = 0;
    //init the person
    p1.pos_x = (LEFT_COL + RIGHT_COL)/2;
    p1.pos_y = BOT_LINE;
    p1.dir_x = LEFT;
    p1.dir_y = UP;
    p1.x_ttm = p1.x_ttg = 4;
    p1.y_ttm = p1.y_ttg = 4;
    p1.per = CHAR_PERSON;
    //设置终端属性,函数来自与curses库
    atexit(exit_a);
    initscr();
    noecho();
    keypad(stdscr, TRUE);
    crmode();
    //paint the edge 
    for (n = TOP_LINE - 1; n <= (BOT_LINE + 1); n++) {
        mvaddch(n, LEFT_COL - 1, CHAR_EDGE);
        mvaddch(n, RIGHT_COL + 1, CHAR_EDGE);
        mvaddch(n, LEFT_COL - 2, CHAR_EDGE);
        mvaddch(n, RIGHT_COL + 2, CHAR_EDGE);
    }
    
    for (n = LEFT_COL - 1; n <= (RIGHT_COL + 1); n++) {
        mvaddch(TOP_LINE - 1, n, CHAR_EDGE);
        mvaddch(TOP_LINE - 2, n, CHAR_EDGE);
    }
    //paint table
    paint_table( RIGHT_COL + 5, TOP_LINE + 5, 0);
    //paint mine
    for(n = MINE_TOP ; n <= MINE_BOT; n++)
        for (m = MINE_LEFT; m <= MINE_RIGHT; m++)
            mvaddch(n, m, CHAR_MINE);    
    
    // paint boat
    beg_boat = (LEFT_COL + RIGHT_COL)/2 - LENGTH_BOAT/2;
    paint_boat(1);
    //paint the person
    mvaddch(p1.pos_y, p1.pos_x, p1.per);
    refresh();
}
//打印信息表,分数等,x,y为打印位置,how:0擦除,1打印
void paint_table(int x, int y, int how)
{
    
    char tot[15];
    char rem[15];
    char sco[15];
    char spe_x[15];
    char spe_y[15];
    //char s_p_x[15];    
    //char s_p_y[15];
    //char s_d_x[15];
    //char s_d_y[15];
    static int flag  = 0;
    if (how == 0) {
        mvaddstr(y,     x, "            ");
        mvaddstr(y + 1, x, "            ");
        mvaddstr(y + 2, x, "            ");
        mvaddstr(y + 3, x, "            ");
        mvaddstr(y + 4, x, "            ");
        //mvaddstr(y + 5, x, "            ");
        //mvaddstr(y + 6, x, "            ");
        //mvaddstr(y + 7, x, "            ");
        
    } else {
        sprintf(tot, "TOTAL: %d", (MINE_BOT - MINE_TOP + 1)*(MINE_RIGHT - MINE_LEFT + 1));
        sprintf(rem, "REMAIN:%d", p1.remain);
        sprintf(spe_x, "SPEED_X: %d", SPEED_MAX - p1.x_ttm);
        sprintf(spe_y, "SPEED_Y: %d", SPEED_MAX - p1.y_ttm);
        sprintf(sco, "SCORE: %d", p1.score);
        //sprintf(s_p_x, "P_X: %d", p1.pos_x);
        //sprintf(s_p_y, "P_Y: %d", p1.pos_y);
        //sprintf(s_d_x, "D_X: %d", p1.dir_x);
        //sprintf(s_d_y, "D_Y: %d", p1.dir_y);
        mvaddstr(y,     x, tot);
        mvaddstr(y + 1, x, rem);
        mvaddstr(y + 2, x, spe_x);
        mvaddstr(y + 3, x, spe_y);
        mvaddstr(y + 4, x, sco);
        //mvaddstr(y + 4, x, s_p_x);
        //mvaddstr(y + 5, x, s_p_y);
        //mvaddstr(y + 6, x, s_d_x);
        //mvaddstr(y + 7, x, s_d_y);
    }
}
//打印短板,dir表示方向,1向左,-1向右
void paint_boat(int dir)
{
    int n;

    for ( n = 0; n < LENGTH_BOAT; n++)
        mvaddch(BOT_LINE + 1, n + beg_boat, BLANK );
    if (dir == 1 && beg_boat > LEFT_COL) 
        beg_boat--;
    if (dir == -1 && beg_boat < (RIGHT_COL +1- LENGTH_BOAT))
        beg_boat++;
    for ( n = 0; n < LENGTH_BOAT; n++)
        mvaddch(BOT_LINE + 1, n + beg_boat, CHAR_BOAT );
    refresh();

}
//设置定时器
int settimer(int msec)
{
    struct itimerval new;
    long n_sec, n_usec;
    
    n_sec = msec/1000;
    n_usec = (msec%1000)*1000L;
    new.it_interval.tv_sec = n_sec;//下次触发时间
    new.it_interval.tv_usec = n_usec;    
    new.it_value.tv_sec = n_sec;//定时器间隔时间
    new.it_value.tv_usec = n_usec;
    return setitimer(ITIMER_REAL, &new, NULL);
}
/*
    查看小球是否触碰到砖块
    大砖块,分为两类,一类小球贴在砖块上,一类小球打在砖块上,不同方式对小球的运动影响不同
*/
void dig_mine(void)
{
    int n_x, n_y;
    static int min_val[MINE_BOT - MINE_TOP + 1][MINE_RIGHT - MINE_LEFT + 1];
    
    n_y = p1.pos_y - MINE_TOP;
    n_x = p1.pos_x - MINE_LEFT;
    //打, 小球位置恰好为砖块位置,根据小球目前运动方向,四周砖块情况,决定怎么改变小球的运动状态(方向),并消除砖块,增加积分等。
    if (n_x >= 0 && n_x <= (MINE_RIGHT - MINE_LEFT) && n_y >= 0 && n_y <= (MINE_BOT - MINE_TOP))
        if (min_val[n_y][n_x] == MINE_HIDE) {
            if (n_y - 1 >=0 && min_val[n_y - 1][n_x] == MINE_HIDE)
                p1.dir_y = -p1.dir_y;
            if (n_y + 1 <= (MINE_BOT - MINE_TOP) && min_val[n_y + 1][n_x] == MINE_HIDE)
                p1.dir_y = -p1.dir_y;
            if (n_x - 1 >= 0 && min_val[n_y][n_x - 1] == MINE_HIDE)
                p1.dir_x = -p1.dir_x;
            if (n_x + 1 <= (MINE_RIGHT - MINE_LEFT) && min_val[n_y][n_x + 1] == MINE_HIDE)
                p1.dir_x = -p1.dir_x;
            min_val[n_y][n_x] = MINE_DIG;
            mvaddch(p1.pos_y, p1.pos_x, BLANK);
            p1.remain--;
            p1.score += (SPEED_MAX - p1.x_ttm)*(SPEED_MAX - p1.y_ttm)/10;
            return;
        }
        //贴,小球运动方向上,下一个位置,恰好是砖块位置(重点),根据四周情况,改变小球运动状态
    if (n_x + 1 >= 0 && n_x - 1 <= (MINE_RIGHT - MINE_LEFT) && n_y + 1 >= 0 && n_y - 1<= (MINE_BOT - MINE_TOP)) {
        if (n_y - 1 >=0 && n_x >= 0 && n_x <= MINE_RIGHT - MINE_LEFT)
            if (min_val[n_y - 1][n_x] == MINE_HIDE&& p1.dir_y == UP) {
                min_val[n_y -1 ][n_x] = MINE_DIG;
                mvaddch(p1.pos_y - 1, p1.pos_x, BLANK);
                p1.remain--;
                p1.score += (SPEED_MAX - p1.x_ttm)*(SPEED_MAX - p1.y_ttm)/10;
                p1.dir_y = -p1.dir_y;
            }
        if (n_y + 1 <= MINE_BOT - MINE_TOP && n_x >= 0 && n_x <= MINE_RIGHT - MINE_LEFT)
            if (min_val[n_y + 1][n_x] == MINE_HIDE&& p1.dir_y == DOWN) {
                min_val[n_y + 1][n_x] = MINE_DIG;
                mvaddch(p1.pos_y + 1, p1.pos_x, BLANK);
                p1.remain--;
                p1.score += (SPEED_MAX - p1.x_ttm)*(SPEED_MAX - p1.y_ttm)/10;
                p1.dir_y = -p1.dir_y;
            }
        if (n_x - 1 >= 0 && n_y >= 0 && n_y <= MINE_BOT - MINE_TOP)
            if (min_val[n_y][n_x - 1] == MINE_HIDE&& p1.dir_x == LEFT) {
                min_val[n_y][n_x - 1] = MINE_DIG;
                mvaddch(p1.pos_y, p1.pos_x - 1, BLANK);
                p1.remain--;
                p1.score += (SPEED_MAX - p1.x_ttm)*(SPEED_MAX - p1.y_ttm)/10;
                p1.dir_x = -p1.dir_x;
            }    
        if (n_x + 1 <= MINE_RIGHT - MINE_LEFT && n_y >= 0 && n_y <= MINE_BOT - MINE_TOP)
            if (min_val[n_y][n_x + 1] == MINE_HIDE&& p1.dir_x == RIGHT) {
                min_val[n_y][n_x + 1] = MINE_DIG;
                mvaddch(p1.pos_y, p1.pos_x + 1, BLANK);
                p1.remain--;
                p1.score += (SPEED_MAX - p1.x_ttm)*(SPEED_MAX - p1.y_ttm)/10;
                p1.dir_x = -p1.dir_x;
            }
    }
}
/*
    小球运行判定函数
*/
void move_person(int signo)
{
    signal(SIGALRM, SIG_IGN);
    int flag = 0, bef_x, bef_y;
    bef_x = p1.pos_x;
    bef_y = p1.pos_y;
    //指定次数定时器是否触发
    if (p1.x_ttm > 0 && p1.x_ttg-- == 1) {
        p1.x_ttg = p1.x_ttm;
        flag += 2;
    }
    if (p1.y_ttm > 0 && p1.y_ttg-- == 1) {
        p1.y_ttg = p1.y_ttm;
        flag += 1;
    }
    if (flag > 0) {
        //lost 判定小球是否越出下边界,是,则失败,结束
        if (p1.dir_y == DOWN && bef_y == BOT_LINE) 
            if (bef_x < beg_boat || bef_x >= (beg_boat + LENGTH_BOAT)) {
                paint_table(RIGHT_COL + 5, TOP_LINE + 5, 0);
                paint_table(LEFT_COL + 6, TOP_LINE + 4, 1);    
                lost();
                return;
            }
            else
                p1.dir_y = -p1.dir_y;
        //win 判定砖块被全打光,是 ,胜利,游戏结束
        if (p1.remain == 0) {
            paint_table(RIGHT_COL + 5, TOP_LINE + 5, 0);
            paint_table(LEFT_COL + 6, TOP_LINE + 4, 1);    
            win();
            return;
        }
        //小球在砖块潜在位置,才进行砖块判定
        if (p1.pos_x >= MINE_LEFT - 1 && p1.pos_x <= MINE_RIGHT+1 && p1.pos_y >= MINE_TOP - 1 && p1.pos_y <= MINE_BOT+1)
            dig_mine();
        if (flag == 1)
            p1.pos_x += p1.dir_x;
        else if (flag == 2)
            p1.pos_y += p1.dir_y;
        else {
            p1.pos_x += p1.dir_x;
            p1.pos_y += p1.dir_y;    
        }
        //打印信息表
        paint_table(RIGHT_COL + 5, TOP_LINE + 5, 0);
        paint_table(RIGHT_COL + 5, TOP_LINE + 5, 1);
        mvaddch(bef_y, bef_x, BLANK);
        //当小球,遇到上,左,右边界时,改变运行方向
        if ( p1.dir_x == LEFT &&p1.pos_x == LEFT_COL)     
            p1.dir_x = -p1.dir_x;
        if (p1.dir_x == RIGHT && p1.pos_x == RIGHT_COL) 
            p1.dir_x = -p1.dir_x;
        if (p1.dir_y == UP &&p1.pos_y == TOP_LINE)      
            p1.dir_y = -p1.dir_y;
        mvaddch(p1.pos_y, p1.pos_x, CHAR_PERSON);
        move(LINES - 1, COLS -1);
        refresh();
    }
    signal(SIGALRM, move_person);
}
//成功时,打印
void win(void)
{
    move(TOP_LINE + 3, LEFT_COL + 20);
    printw("%s", "                                          ");
    move(TOP_LINE + 4, LEFT_COL + 20);
    printw("%s", "*   *   ***   *   *   *  *  *  *  **   *  ");
    move(TOP_LINE + 5, LEFT_COL + 20);
    printw("%s", " * *   *   *  *   *   *  *  *  *  * *  *  ");
    move(TOP_LINE + 6, LEFT_COL + 20);
    printw("%s", "  *    *   *  *   *   *  *  *  *  *  * *  ");
    move(TOP_LINE + 7, LEFT_COL + 20);
    printw("%s", "  *    *   *  *   *   * * * *  *  *   **  ");
    move(TOP_LINE + 8, LEFT_COL + 20);
    printw("%s", "  *     ***    ***     *   *   *  *    *  ");
    move(TOP_LINE + 9, LEFT_COL + 20);
    printw("%s", "                                          ");
    refresh();
}
//失败时打印
void lost(void)
{

    move(TOP_LINE + 3, LEFT_COL + 20);
    printw("%s", "                                                 ");
    move(TOP_LINE + 4, LEFT_COL + 20);
    printw("%s", "*   *  ***  *   *   *     ***   ****  ***** ");
    move(TOP_LINE + 5, LEFT_COL + 20);
    printw("%s", " * *  *   * *   *   *    *   * *        *   ");
    move(TOP_LINE + 6, LEFT_COL + 20);
    printw("%s", "  *   *   * *   *   *    *   *  ****    *   ");
    move(TOP_LINE + 7, LEFT_COL + 20);
    printw("%s", "  *   *   * *   *   *    *   *      *   *   ");
    move(TOP_LINE + 8, LEFT_COL + 20);
    printw("%s", "  *    ***   ***    ****  ***   ****    *   ");
    move(TOP_LINE + 9, LEFT_COL + 20);
    printw("%s", "                                                 ");
    refresh();
}

算法未经允许,请勿转载,谢谢。

你可能感兴趣的:(linux下C实现打转块小游戏(二))