程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> C語言實現貪吃蛇

C語言實現貪吃蛇

編輯:關於C語言
/*****************************************************************************************************************************
貪吃蛇實現原理:                                                                                                                                                                                *
貪吃蛇游戲在理論上是可以無限的進行下去的(除了撞牆和咬到自己),那麼游戲主體就一定是個循環。                        *
蛇是如何動起來的?在這裡就是通過不斷改變蛇的坐標,然後根據蛇的坐標不斷刷新屏幕在視覺上形成蛇的移動效果。*
食物出現在隨機位置(當然不能出現在障礙物和蛇身上)。                                                                                                        *
蛇能吃到食物其實就是蛇頭的坐標與食物的坐標重合時。                                                                                                            *
當蛇咬到自己或者撞到牆的時候游戲結束(坐標判斷)                                                                                                                *
******************************************************************************************************************************/


#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <windows.h>
#include <time.h>


//72,80,75,77是方向鍵對應的鍵值
#define UP 72
#define DOWN 80
#define LEFT 75
#define RIGHT 77
#define SNAKE 1     //蛇的坐標標識
#define FOOD 2      //食物的坐標標識
#define BAR 3       //牆的坐標標識


//初始化地圖 17*17
char map[17][17] = {0};
//初始化蛇頭坐標
unsigned char snake[50] = {77};
//初始化食物坐標
unsigned char food = 68;
//蛇長
char len = 1;


//存儲坐標數字與x、y的轉換函數
void tran(unsigned char num,unsigned char * x,unsigned char * y);
//打印游戲
void print_game(void);
//獲取方向函數(注意當蛇身長度超過一節時不能回頭)
int get_dir(int old_dir);
//移動蛇身函數(游戲大部分內容在其中)
void move_snake(int dir);
//生產食物的函數
unsigned char generate_food(void);
//判斷蛇死活的函數(判斷了蛇是否撞到邊界或者自食)
int isalive(void);


int main(void){
    int dir = UP;   //初始方向默認向上,UP是我們定義的宏
    //按道理該游戲是可以無限繼續下去的,因此是個循環
    while(1){
        print_game();   //打印游戲
        dir = get_dir(dir);     //獲取方向(我們摁下的方向)
        move_snake(dir);    //移動蛇身
        if(!isalive()){     //判斷蛇的生命狀態
            break;
        }
    }


    printf("Game Over!\n");
    return 0;
}
//
void tran(unsigned char num,unsigned char * x,unsigned char * y){
    *x = num >> 4;
    *y = (unsigned char)(num << 4) >> 4;    //注意這裡要做個強制類型轉換
                                            //根據匯編,如果不做強制轉換,y的值與num的值相同
}


void print_game(void){
    int i,j;
    //根據地圖上每點的情況繪制游戲( i 表示 x 軸,j 表示 y 軸),按行打印,j表示行,i表示列
    for(j = 0;j < 17;j ++){
        for(i = 0;i < 17;i ++){
            //空白地方
            if(map[i][j] == 0){
                putchar(' ');
            }
            //蛇身
            else if(map[i][j] == SNAKE){
                putchar('*');
            }
            //圍欄
            else if(map[i][j] == BAR){
                putchar('#');
            }
            //食物
            else if(map[i][j] == FOOD){
                putchar('$');
            }
        }
        putchar('\n');
    }
    Sleep(500);     //休眠函數 將進程掛起500ms,包含在window.h(在linux下用 sleep(),#include <unistd.h>)
    system("cls");  //清屏函數 配合下一次 print_game() 起到刷新作用,包含在stdlib.h中
}
int get_dir(int old_dir){


    int new_dir = old_dir;


    //用kbhit()與getch()組合實現鍵盤響應
    //kbhit() 檢查當前是否有鍵盤輸入,若有則返回一個非0值,否則返回0
    //getch() 用ch=_getch();會等待你按下任意鍵之後,把該鍵字符所對應的ASCII碼賦給ch,再執行下面的語句。
    if(_kbhit()){
        _getch();               //第一次輸出的方向鍵的擴展值,第二次是方向鍵的實際值,只有方向鍵上下左右這樣
        new_dir = _getch();     //getch()函數要使用兩次,原因是因為第一次返回的值指示該鍵擴展的字符,第二次調用才返回實際的鍵代碼


        //如果蛇身長度大於1,則不能回頭,如果摁回頭方向,則按原來方向走
        //abs(new_dir - old_dir) == 2 表示 |LEFT-RIGHT|
        //abs(new_dir - old_dir) == 8 表示 |UP-DOWN|
        if(len > 1 && (abs(new_dir - old_dir) == 2 || abs(new_dir - old_dir) == 8)){
            new_dir = old_dir;
        }
    }
    return new_dir;
}
void move_snake(int dir){
    int last = snake[0],current;    //last與current用於之後蛇坐標的更新
    int i,j;
    int grow=0;     //判斷是否要長身體
    unsigned char x, y,fx,fy;       //蛇坐標與食物坐標
    tran(food, &fx, &fy);   //食物坐標
    tran(snake[0], &x, &y); //蛇頭坐標
    switch (dir){           //更新蛇頭坐標(坐標原點是左上角)
        case UP:
            y--;
            break;
        case DOWN:
            y++;
            break;
        case LEFT:
            x--;
            break;
        case RIGHT:
            x++;
            break;
    }
    //按位抑或(妙!)
   //http://www.bianceng.cn
    snake[0] = ((x ^ 0) << 4) ^ y;      //將x,y換回一個數
//x與0抑或保留原值
       //將x與y重新合成一個值


    //蛇吃到了食物
    if (snake[0] == food) {
        grow = 1;
        food = generate_food();     //產生新食物
    }


/*******************************************************************************************************************************/
    for (i = 0; i<len; i++) {       //蛇移動的關鍵,通過將蛇頭原來的坐標賦給第二節,原來的第二節賦給第三節,依次下去,完成蛇坐標的更新
        if (i == 0)                //如果只有頭,跳過,因為前面已更新蛇頭坐標
            continue;
        current = snake[i];       //將當前操作的蛇節坐標存儲到current裡
        snake[i] = last;         //完成當前操作蛇節坐標的更新
        last = current;         //last記錄的是上一次操作蛇節的坐標,這次操作已經結束,故把current賦給last
}
/*******************************************************************************************************************************/
   
//如果蛇邊長了
    if (grow) {
        snake[len] = last;
        len++;
    }


    for (j = 0; j < 17; j ++){      //將邊界與食物加到地圖裡去(i,j 對應 x軸和y軸)
        for (i = 0; i < 17; i ++){
            if (i == 0 || i == 16 || j == 0 || j == 16){
                map[i][j] = BAR;
            }
            else if (i == fx&&j == fy){
                map[i][j] = FOOD;
            }
            else{
                map[i][j] = 0;
            }
        }


    for (i = 0; i < len; i++) {     //將蛇加到地圖裡去
        tran(snake[i], &x, &y);
        if (snake[i] > 0){
            map[x][y] = SNAKE;
        }
    }
}
}
unsigned char generate_food(void)
{
    unsigned char food_,fx,fy;
    int in_snake=0,i;
    //以當前時間為參數提供種子供rand()函數生成更為隨機的數
    srand((unsigned int)time(NULL));
    //循環產生在邊界內且不在蛇身上的食物
    do {
        food_ = rand() % 255;//產生一個0--255的隨機數
        tran(food_, &fx, &fy);
        for (i = 0; i < len; i++){
            if (food_ == snake[i]){
            //在不在蛇身上
                in_snake = 1;
            }
        }
    } while (fx == 0 || fx == 16 || fy == 0 || fy == 16 || in_snake);
    return food_;
}
int isalive(void)
{
    int self_eat = 0;
int i;
    unsigned char x, y;
    tran(snake[0], &x, &y);
    for (i = 1; i < len; i++){
        if (snake[0] == snake[i]){
            self_eat = 1;
        }
    }
    //蛇頭撞邊界或者吃到自己 ,則死掉
    return (x == 0 || x == 16 || y == 0 || y >= 16 || self_eat) ? 0 : 1;
}
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved