分享自己写的一个贪吃蛇的游戏(Linux)

本文介绍了一个使用ncurses库实现的蛇游戏。详细解释了游戏的运行原理、关键代码逻辑及游戏界面设计。游戏包含两个窗口,分别用于显示游戏区域和日志信息。通过键盘输入控制蛇的方向移动,收集食物增加长度,达到特定条件时可提升等级并增加速度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转载请注明出处。http://www.cnblogs.com/dave_cn/

本程序需要ncurses库,ubuntu下安装ncurses可以执行下面命令:

sudo apt-get install libncurses5-dev 

关于ncurses的用法,读者可以Google之。

程序运行的效果如下:

其中包含两个窗口,一个为game窗口,一个为日志窗口。 

 

 

 代码如下:


/**

 * Snake

 * author: dave_cn

 * date  : 2010/7/14

 * info  :

 *        @ ...... food

 */

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <sys/time.h>

#include <sys/types.h>

#include <unistd.h>

#include <ncurses.h>

 

#define TBool            int

#define True             1

#define False            0   

#define SHAPE_FOOD       '@'

#define SHAPE_SNAKE      '*'

#define GAMEWIN_YLEN     15

#define GAMEWIN_XLEN     60

#define LOGWIN_YLEN      7

#define LOGWIN_XLEN      (GAMEWIN_XLEN)

#define LOGBUF_NUM       (LOGWIN_YLEN-2)

#define LOGBUF_LEN       (GAMEWIN_XLEN-2)

#define MAXLEVEL         12

 

#define GetSnakeTail(s)  ((s)->head->front)

 

WINDOW *logwin;

#define INITRUNLOG()     logwin = newlogw()

#define RUNLOG(str)      runlog(logwin, str)

#define DESTROYRUNLOG()  delwin(logwin)

 

int g_level;

 

enum TDirection {

    DIR_UP,

    DIR_DOWN,

    DIR_LEFT,

    DIR_RIGHT

};

 

struct TFood {

    int y;

    int x;

};

 

struct TSnakeNode {

    int y;

    int x;

    struct TSnakeNode *front;

};

 

struct TSnake {

    int    length;

    struct TSnakeNode *head;

    enum   TDirection  dir;

};

 

int refreshgamew(WINDOW *win, struct TSnake *psnake);

void movesnake(struct TSnake *psnake);

int checksnake(struct TFood *pfood, struct TSnake *psnake);

void snakegrowup(struct TFood *pfood, struct TSnake *psnake);

void gameover(WINDOW *win, char *str);

struct TSnakeNode *newsnakenode(struct TSnakeNode **ppsnode, int y, int x);

WINDOW* newgamew();

struct TSnake* initsnake();

void destroysnake(struct TSnake *psnake);

void drawsnakew(WINDOW *win, struct TSnake *psnake);

void drawfoodw(WINDOW *win, struct TFood *pfood, struct TSnake *psnake);

TBool checkfood(struct TFood *pfood, struct TSnake *psnake);

WINDOW* newlogw();

void runlog(WINDOW *win, char *str);

void cleanline(WINDOW *win, int y, int x);

 

int main()

{

    initscr();

    raw();

    noecho();

    keypad(stdscr, TRUE);

    curs_set(0);

    refresh();

 

    g_level = 1;

    INITRUNLOG();

    RUNLOG("  Press 'q' or 'Q' to quit.");

    RUNLOG("  Press 'w/s/a/d' or 'W/S/A/D' to move the snake.");

    RUNLOG("Info:");

     

    WINDOW *gwin = newgamew();

    struct TSnake *psnake = initsnake();

    drawsnakew(gwin, psnake);

     

    while (refreshgamew(gwin, psnake) >= 0) ;

     

    getch();

     

    destroysnake(psnake);

    delwin(gwin);

    DESTROYRUNLOG();

    endwin();

     

    return 0;

}

 

int refreshgamew(WINDOW *win, struct TSnake *psnake)

{

    static TBool ffood = False;

    struct TFood pfood;

     

    if (!ffood) {

        drawfoodw(win, &pfood, psnake);

        ffood = True;

    }

 

    int key = -1;

     

    fd_set set;

    FD_ZERO(&set);

    FD_SET(0, &set);

     

    struct timeval timeout;

    timeout.tv_sec = 0;

    timeout.tv_usec= (6 - (int)(g_level/3)) * 100*1000;

     

    if (select(1, &set, NULL, NULL, &timeout) < 0)

        return -1;

     

    if (FD_ISSET(0, &set)) {

        while ((key = getch()) == -1) ;

     

        switch (key) {

        case 'w':

        case 'W':

            (psnake->dir == DIR_DOWN) ? : (psnake->dir = DIR_UP);

            break;

         

        case 's':

        case 'S':

            (psnake->dir == DIR_UP) ? : (psnake->dir = DIR_DOWN);

            break;

         

        case 'a':

        case 'A':

            (psnake->dir == DIR_RIGHT) ? : (psnake->dir = DIR_LEFT);

            break;

         

        case 'd':

        case 'D':

            (psnake->dir == DIR_LEFT) ? : (psnake->dir = DIR_RIGHT);

            break;

         

        case 'q':

        case 'Q':

            RUNLOG("Quit Game!");

            gameover(win, "Quit Game!");

            return -1;

         

        default:

            break;

        }

    }

 

    movesnake(psnake);

    drawsnakew(win, psnake);

    switch (checksnake(&pfood, psnake)) {

    case 0:

        break;

         

    case 1:

        ffood = False;

        if (++g_level > MAXLEVEL) {

            RUNLOG("Win!!!");

            gameover(win, "Win!!!");

            return -1;

        }

        mvwprintw(win, GAMEWIN_YLEN-1, 2, " Level: %d ", g_level);

        mvwprintw(win, GAMEWIN_YLEN-1, 30, " Speed: %d ", (int)(g_level/3));

        wrefresh(win);

        RUNLOG("Level UP!");

        snakegrowup(&pfood, psnake);

        break;

         

    default:

        RUNLOG("Game over!");

        gameover(win, "Game over!");

        return -1;

    }

     

    return 1;

}

 

/**

 * stuct TSnake是一个倒置的首尾相连的链表,head->front指向snake的尾部

 * 如: [a]<-[b]<-[c]<-[d]    a为head

 *      |              ^     snake移动的时候,只用head指向d,

 *      `--------------'     并且修改d的(y,x)为snake头移动到的位置.

 */

void movesnake(struct TSnake *psnake)

{

    int hy = psnake->head->y;

    int hx = psnake->head->x;

     

    psnake->head = GetSnakeTail(psnake);

     

    switch (psnake->dir) {

    case DIR_UP:

        psnake->head->y = hy - 1;

        psnake->head->x = hx;

        break;

     

    case DIR_DOWN:

        psnake->head->y = hy + 1;

        psnake->head->x = hx;

        break;

     

    case DIR_LEFT:

        psnake->head->y = hy;

        psnake->head->x = hx - 1;

        break;

     

    case DIR_RIGHT:

        psnake->head->y = hy;

        psnake->head->x = hx + 1;

        break;

         

    default:

        break;

    }

}

 

int checksnake(struct TFood *pfood, struct TSnake *psnake)

{

    if ( psnake->head->y <= 0 || psnake->head->y >= GAMEWIN_YLEN

      || psnake->head->x <= 0 || psnake->head->x >= GAMEWIN_XLEN)

    {

        return -1;

    }

 

    struct TSnakeNode *pnode = GetSnakeTail(psnake);

    int i = 0;

    for (; i < psnake->length - 1; ++i, pnode = pnode->front)

        if (psnake->head->y == pnode->y && psnake->head->x == pnode->x)

            return -1;

 

    if (psnake->head->y == pfood->y && psnake->head->x == pfood->x)

        return 1;

     

    return 0;

}

 

void snakegrowup(struct TFood *pfood, struct TSnake *psnake)

{

    struct TSnakeNode *pnode = (struct TSnakeNode *)malloc(sizeof(struct TSnakeNode));

     

    switch (psnake->dir) {

    case DIR_UP:

        pnode->y = psnake->head->y - 1;

        pnode->x = psnake->head->x;

        break;

     

    case DIR_DOWN:

        pnode->y = psnake->head->y + 1;

        pnode->x = psnake->head->x;

        break;

     

    case DIR_LEFT:

        pnode->y = psnake->head->y;

        pnode->x = psnake->head->x - 1;

        break;

     

    case DIR_RIGHT:

        pnode->y = psnake->head->y;

        pnode->x = psnake->head->x + 1;

        break;

         

    default:

        break;

    }

     

    pnode->front = GetSnakeTail(psnake);

    psnake->head->front = pnode;

    psnake->head = pnode;

    ++psnake->length;

}

 

void gameover(WINDOW *win, char *str)

{

    mvwprintw(win, (int)(GAMEWIN_YLEN/2), (GAMEWIN_XLEN/2 - strlen(str)/2), str);

    mvwprintw(win, (int)(GAMEWIN_YLEN/2 + 1), 20, "Press any key to quit...");

    wrefresh(win);

}

 

WINDOW* newgamew()

{

    WINDOW *win = newwin(GAMEWIN_YLEN, GAMEWIN_XLEN, 1, 3);

    box(win, 0, 0);

    mvwprintw(win, 0, 2, " GAME ");

    mvwprintw(win, GAMEWIN_YLEN-1, 2, " Level: %d ", g_level);

    mvwprintw(win, GAMEWIN_YLEN-1, 30, " Speed: %d ", (int)(g_level/3));

    wrefresh(win);

     

    return win;

}

 

struct TSnake* initsnake()

{

    struct TSnake *psnake = (struct TSnake *)malloc(sizeof(struct TSnake));

 

    psnake->dir    = DIR_LEFT;

    psnake->length = 4;

     

    newsnakenode (

        &newsnakenode (

            &newsnakenode (

                &newsnakenode( &psnake->head, 4, 50 )->front, 4, 53

            )->front, 4, 52

        )->front, 4, 51

    )->front = psnake->head;

 

    return psnake;

}

 

struct TSnakeNode *newsnakenode(struct TSnakeNode **ppsnode, int y, int x)

{

    *ppsnode = (struct TSnakeNode *)malloc(sizeof(struct TSnakeNode));

    (*ppsnode)->y = y;

    (*ppsnode)->x = x;

    (*ppsnode)->front = NULL;

     

    return *ppsnode;

}

 

void destroysnake(struct TSnake *psnake)

{

    struct TSnakeNode *psnode = GetSnakeTail(psnake);

    struct TSnakeNode *ptmp   = NULL;

     

    int i = 0;

    for (; i < psnake->length; ++i) {

        ptmp   = psnode;

        psnode = psnode->front;

        free(ptmp);

    }

     

    free(psnake);

    psnake = NULL;

}

 

void drawsnakew(WINDOW *win, struct TSnake *psnake)

{

    static int taily = 0;

    static int tailx = 0;

    if (taily != 0 && tailx != 0) {

        mvwaddch(win, taily, tailx, ' ');

    }

     

    struct TSnakeNode *psnode = GetSnakeTail(psnake);

     

    int i = 0;

    for (; i < psnake->length; ++i) {

        mvwaddch(win, psnode->y, psnode->x, SHAPE_SNAKE);

        psnode = psnode->front;

    }

     

    taily = GetSnakeTail(psnake)->y;

    tailx = GetSnakeTail(psnake)->x;

 

    wrefresh(win);

}

 

void drawfoodw(WINDOW *win, struct TFood *pfood, struct TSnake *psnake)

{

    do {

        pfood->y = random() % (GAMEWIN_YLEN - 1) + 1;

        pfood->x = random() % (GAMEWIN_XLEN - 1) + 1;

    } while (False == checkfood(pfood, psnake));

    checkfood(pfood, psnake);

     

    mvwaddch(win, pfood->y, pfood->x, SHAPE_FOOD);

    wrefresh(win);

}

 

TBool checkfood(struct TFood *pfood, struct TSnake *psnake)

{

    struct TSnakeNode *pnode = GetSnakeTail(psnake);

 

    int i = 0;

    for (; i < psnake->length; ++i, pnode = pnode->front)

        if (pfood->y == pnode->y && pfood->x == pnode->x)

            return False;

 

    return True;

}

 

WINDOW* newlogw()

{

    WINDOW *win = newwin(LOGWIN_YLEN, LOGWIN_XLEN, GAMEWIN_YLEN + 2, 3);

    box(win, 0, 0);

    mvwprintw(win, 0, 2, " LOG ");

    wrefresh(win);

     

    return win;

}

 

void runlog(WINDOW *win, char *str)

{

    static char logbuf[LOGBUF_NUM][LOGBUF_LEN] = {0};

    static int  index = 0;

     

    strcpy(logbuf[index], str);

     

    int i = 0;

    for (; i < LOGBUF_NUM; ++i) {

        cleanline(win, i+1, 1);

        mvwprintw(win, i+1, 1, logbuf[(index+i) % LOGBUF_NUM]);

        wrefresh(win);

    }

     

    index = (index + LOGBUF_NUM - 1) % LOGBUF_NUM;

}

 

void cleanline(WINDOW *win, int y, int x)

{

    char EMPTYLINE[LOGBUF_LEN] = {0};

    memset(EMPTYLINE, ' ', LOGBUF_LEN-1);

     

    mvwprintw(win, y, x, EMPTYLINE);

    wrefresh(win);

}


 

 我在ubuntu10.04下面测试过。

编译方法:

cc -o snake filename.c -lncurses 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值