linux下C語言編寫貪喫蛇遊戲

今天看了一下我之前關注過的一位大神的blog,看到他轉發的一篇貪喫蛇遊戲,感覺很有趣,於是將代碼放到linux系統下運行了一下,很不錯,mark一下!哈哈。

原文連接:點擊打開鏈接

/*********************************************************************************
 *      Copyright:  (C) 2017 zoulei
 *                  All rights reserved.
 *
 *       Filename:  snake.c
 *    Description:  This file
 *
 *        Version:  1.0.0(2017年09月09日)
 *         Author:  zoulei <[email protected]>
 *      ChangeLog:  1, Release initial version on "2017年09月09日 17時05分19秒"
 *
 ********************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <curses.h>
#include <signal.h>
#include <sys/time.h>
#define NUM 60

struct direct                //用來表示方向的
{
    int cx;
    int cy;
};
typedef struct node            //鏈表的結點
{
    int cx;
    int cy;
    struct node *back;
    struct node *next;
}node;

void initGame();            //初始化遊戲
int setTicker(int);            //設置計時器
void show();                //顯示整個畫面
void showInformation();        //顯示遊戲信息(前兩行)
void showSnake();            //顯示蛇的身體
void getOrder();            //從鍵盤中獲取命令
void over(int i);            //完成遊戲結束後的提示信息

void creatLink();                //(帶頭尾結點)雙向鏈表以及它的操作
void insertNode(int x, int y);
void deleteNode();
void deleteLink();

int ch;                                //輸入的命令
int hour, minute, second;            //時分秒
int length, tTime, level;            //(蛇的)長度,計時器,(遊戲)等級
struct direct dir, food;            //蛇的前進方向,食物的位置
node *head, *tail;                    //鏈表的頭尾結點

int main()
{
    initscr();
    initGame();
    signal(SIGALRM, show);
    getOrder();
    endwin();
    return 0;
}

void initGame()
{
    cbreak();                    //把終端的CBREAK模式打開
    noecho();                    //關閉回顯
    curs_set(0);                //把光標置爲不可見
    keypad(stdscr, true);        //使用用戶終端的鍵盤上的小鍵盤
    srand(time(0));                //設置隨機數種子
    //初始化各項數據
    hour = minute = second = tTime = 0;
    length = 1;
    dir.cx = 1;
    dir.cy = 0;
    ch = 'A';
    food.cx = rand() % COLS;
    food.cy = rand() % (LINES-2) + 2;
    creatLink();
    setTicker(20);
}

//設置計時器(這個函數是書本上的例子,有改動)
int setTicker(int 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;
    new_timeset.it_interval.tv_usec = n_usecs;
    n_msecs = 1;
    n_sec = n_msecs / 1000 ;
    n_usecs = ( n_msecs % 1000 ) * 1000L ;
    new_timeset.it_value.tv_sec     = n_sec  ;
    new_timeset.it_value.tv_usec    = n_usecs ;
    return setitimer(ITIMER_REAL, &new_timeset, NULL);
}

void showInformation()
{
    tTime++;
    if(tTime >= 1000000)                //
        tTime = 0;
    if(1 != tTime % 50)
        return;
    move(0, 3);
    //顯示時間
    printw("time: %d:%d:%d %c", hour, minute, second);
    second++;
    if(second > NUM)
    {
        second = 0;
        minute++;
    }
    if(minute > NUM)
    {
        minute = 0;
        hour++;
    }
    //顯示長度,等級
    move(1, 0);
    int i;
    for(i=0;i<COLS;i++)
        addstr("-");
    move(0, COLS/2-5);
    printw("length: %d", length);
    move(0, COLS-10);
    level = length / 3 + 1;
    printw("level: %d", level);
}

//蛇的表示是用一個帶頭尾結點的雙向鏈表來表示的,
//蛇的每一次前進,都是在鏈表的頭部增加一個節點,在尾部刪除一個節點
//如果蛇吃了一個食物,那就不用刪除節點了
void showSnake()
{
    if(1 != tTime % (30-level))
        return;
    //判斷蛇的長度有沒有改變
    bool lenChange = false;
    //顯示食物
    move(food.cy, food.cx);
    printw("@");
    //如果蛇碰到牆,則遊戲結束
    if((COLS-1==head->next->cx && 1==dir.cx)
        || (0==head->next->cx && -1==dir.cx)
        || (LINES-1==head->next->cy && 1==dir.cy)
        || (2==head->next->cy && -1==dir.cy))
    {
        over(1);
        return;
    }
    //如果蛇頭砬到自己的身體,則遊戲結束
    if('*' == mvinch(head->next->cy+dir.cy, head->next->cx+dir.cx) )
    {
        over(2);
        return;
    }
    insertNode(head->next->cx+dir.cx, head->next->cy+dir.cy);
    //蛇吃了一個“食物”
    if(head->next->cx==food.cx && head->next->cy==food.cy)
    {
        lenChange = true;
        length++;
        //恭喜你,通關了
        if(length >= 50)
        {
            over(3);
            return;
        }
        //重新設置食物的位置
        food.cx = rand() % COLS;
        food.cy = rand() % (LINES-2) + 2;
    }
    if(!lenChange)
    {
        move(tail->back->cy, tail->back->cx);
        printw(" ");
        deleteNode();
    }
    move(head->next->cy, head->next->cx);
    printw("*");
}

void show()
{
    signal(SIGALRM, show);        //設置中斷信號
    showInformation();
    showSnake();
    refresh();                    //刷新真實屏幕
}

void getOrder()
{
    //建立一個死循環,來讀取來自鍵盤的命令
    while(1)
    {
        ch = getch();
        if(KEY_LEFT == ch)
        {
            dir.cx = -1;
            dir.cy = 0;
        }
        else if(KEY_UP == ch)
        {
            dir.cx = 0;
            dir.cy = -1;
        }
        else if(KEY_RIGHT == ch)
        {
            dir.cx = 1;
            dir.cy = 0;
        }
        else if(KEY_DOWN == ch)
        {
            dir.cx = 0;
            dir.cy = 1;
        }
        setTicker(20);
    }
}

void over(int i)
{
    //顯示結束原因
    move(0, 0);
    int j;
    for(j=0;j<COLS;j++)
        addstr(" ");
    move(0, 2);
    if(1 == i)
        addstr("Crash the wall. Game over");
    else if(2 == i)
        addstr("Crash itself. Game over");
    else if(3 == i)
        addstr("Mission Complete");
    setTicker(0);                //關閉計時器
    deleteLink();                //釋放鏈表的空間
}

//創建一個雙向鏈表
void creatLink()
{
    node *temp = (node *)malloc( sizeof(node) );
    head = (node *)malloc( sizeof(node) );
    tail = (node *)malloc( sizeof(node) );
    temp->cx = 5;
    temp->cy = 10;
    head->back = tail->next = NULL;
    head->next = temp;
    temp->next = tail;
    tail->back = temp;
    temp->back = head;
}

//在鏈表的頭部(非頭結點)插入一個結點
void insertNode(int x, int y)
{
    node *temp = (node *)malloc( sizeof(node) );
    temp->cx = x;
    temp->cy = y;
    temp->next = head->next;
    head->next = temp;
    temp->back = head;
    temp->next->back = temp;
}

//刪除鏈表的(非尾結點的)最後一個結點
void deleteNode()
{
    node *temp = tail->back;
    node *bTemp = temp->back;
    bTemp->next = tail;
    tail->back = bTemp;
    temp->next = temp->back = NULL;
    free(temp);
    temp = NULL;
}

//刪除整個鏈表
void deleteLink()
{
    while(head->next != tail)
        deleteNode();
    head->next = tail->back = NULL;
    free(head);
    free(tail);
}

這裏主要依賴的是linux提供的libcurses庫。用gcc snake.c -o snake -lcurses命令進行編譯。


測試效果圖:



         通過基於這個庫我們還可以編寫坦克大戰,堆箱子等一些小遊戲,感覺蠻有意思的,萬萬沒想到小時候買的遊戲機裏面的遊戲也就這麼點代碼就能實現,小時候覺得特別神奇的玩意兒,沒想到自己也能夠編寫代碼去實現,哈哈,我相信以後程序員一定會是我特別喜歡熱愛的的一個職業,絕不僅僅是因爲工作!!!



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章