貪喫蛇(C語言)

 

C語言實現簡易版貪喫蛇,通過移除蛇尾和打印新的蛇頭來實現移動效果,可以避免刷新整個蛇身的閃屏現象。

下面分別是頭文件和實現文件:

#ifndef SNAKE_H_INCLUDED
#define SNAKE_H_INCLUDED
/***************************************************
 * 文件名:snake.h
 * 描  述:定義遊戲的核心方法及相關結構
 * 創建人:777
 * 日  期:2018-01-01
 * 版  本:1.0
 *
 **************************************************/
#define MARGIN_X 25  //遊戲界面左邊距

#define up 'w'   //蛇的移動方向
#define down 's'
#define left 'a'
#define right 'd'
#define stop 'p'
/*
 *蛇身結構
 */
typedef struct _snake{
    int x;     //節點座標
    int y;
    struct _snake * next;
}SNAKE;
//聲明蛇頭蛇尾
SNAKE *head,*tail;
/*
 *食物結構
 */
struct Food
{
	int x;
	int y;
}food;
//聲明蛇的移動速度和蛇長變量
int speed;
/*
 *遊戲歡迎界面
 */
void welcome();
/*
 *顯示地圖
 */
void creatmap();
/*
 *生成蛇
 */
void showsnake();
/*
 *生成食物
 */
void creatfood();
/*
 *遊戲運行
 */
void playgame();
/*
 *打印蛇身,參數爲座標和背景顏色
 */
void gotoprint(int x, int y,int a, int b);
/*
 *清除一個點(蛇尾和食物)
 */
void gotodelete(int x, int y);
/*
 *移動蛇
 */
void MovingBody(char click);
/*
 *移動蛇身
 */
void ChangeBody(int a,int b);
/*
 *喫屎
 */
void Eating();
/*
 *結束判斷
 */
int Judge();
/*
 *結束遊戲
 */
void gameover();

#endif // SNAKE_H_INCLUDED
#ifndef SNAKELIB_H_INCLUDED
#define SNAKELIB_H_INCLUDED
/***************************************************
 * 文件名:GameLib.h
 * 描  述:定義遊戲中常用的控制檯操作
 * 創建人:777
 * 日  期:2018-01-01
 * 版  本:1.0
 *
 **************************************************/
/* 設置控制檯窗口標題 */
void SetTitle(char * title);
/* 設置控制檯窗口顏色 */
void SetColor(int, int);
/* 設置控制檯窗口尺寸 */
void SetConsoleWindowSize(int width, int height);
/* 設置光標的x、y座標-正常座標軸 */
void SetPosition(int x, int y);
/* 清屏 */
void Clear(int X, int Y);

#endif // SNAKELIB_H_INCLUDED
/***************************************************
 * 文件名:GameLib.c
 * 描  述:GameLib.h的實現文件
 * 創建人:777
 * 日  期:2018-01-01
 * 版  本:1.0
 *
 **************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <windows.h>
#include "snakeLib.h"
/*
 *設置窗口標題
 */
void SetTitle(char * title)
{
    SetConsoleTitle(title);
}
/*
 *設置窗口顏色
 */
void SetColor(int ForeColor, int BackGroundColor)
{
    HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);                    //獲取當前窗口句柄
    SetConsoleTextAttribute(handle, ForeColor + BackGroundColor * 0x10);//設置顏色
}
/*
 *設置窗口大小
 */
void SetConsoleWindowSize(int width, int height)
{
    HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
	//設置控制檯窗口的緩衝區大小
	COORD size = {width, height};
	SetConsoleScreenBufferSize(handle, size);
	//設置控制檯窗口大小,最大座標是緩衝區大小-1
	SMALL_RECT rect = {0, 0, width-1, height-1};
	SetConsoleWindowInfo(handle, 1, &rect);
}
/*
 *設置光標位置
 */
void SetPosition(int x, int y)
{
    COORD cursorPosition;   //光標的座標
    HANDLE handle;          //當前窗口句柄
    handle = GetStdHandle(STD_OUTPUT_HANDLE);
    cursorPosition.X = x;   //設置x、y座標
    cursorPosition.Y = y;
    SetConsoleCursorPosition(handle, cursorPosition);
}
/*
 *清屏函數,參數爲開始的行數和列數
 */
void Clear(int X, int Y)
{
    DWORD written;
    COORD start;    //開始座標
    HANDLE handle;  //當前窗口句柄
    handle = GetStdHandle(STD_OUTPUT_HANDLE);
    start.X = X;
    start.Y = Y;
    FillConsoleOutputAttribute(handle, 15, 120*35, start, &written);
    FillConsoleOutputCharacter(handle, ' ', 120*35, start, &written);
    SetConsoleCursorPosition(handle, start);
}

#include "snake.h"
#include "snakeLib.h"

int main()
{
    welcome();
    creatmap();
    creatfood();
    playgame();
    gameover();
    return 0;
}
/***************************************************
 * 文件名:snake.c
 * 描  述:實現遊戲的核心玩法
 * 創建人:777
 * 日  期:2018-01-01
 * 版  本:1.0
 *
 **************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <conio.h>
#include "snake.h"
#include "snakeLib.h"

/*
 *運行遊戲
 */
void playgame()
{
    char click;  //用戶按鍵
    while (1)
    {
        if (Judge()== 0) break;  //判斷遊戲是否結束
        //kbhit()函數,檢查當前是否有鍵盤輸入,若有則返回一個非0值,否則返回0。
        if (_kbhit()) click = _getch();
        MovingBody(click);
        Eating();
    }
}
/*
 *生成食物
 */
void creatfood()
{
    srand((int)time(NULL));
lable:
    food.y = rand() % 28 + 3;
    food.x = rand() % 52 + MARGIN_X + 7;
    if (food.x % 2 != 0)
    {
        food.x = food.x + 1;
    }
    SNAKE *judgement = head;
    while (1)  //遍歷排除蛇身重複
    {
        if (judgement->next == NULL) break;
        if (food.x == judgement->x && food.y == judgement->y)
        {
            goto lable;
        }
        judgement = judgement->next;
    }
    gotoprint(food.x, food.y,7,0);  //參數分別是X,Y座標和打印的背景顏色
}
/*
 *打印遊戲地圖
 */
void creatmap()
{
    int i;
    for (i = 0; i<58; i += 2)//打印上下邊框
    {
        gotoprint(i + MARGIN_X + 5, 2, 4,0);
        gotoprint(i + MARGIN_X + 5, 32, 4,0);
    }
    for (i = 1; i < 30; i++)
    {
        gotoprint(0 + MARGIN_X + 5, i + 2, 4,0);
        gotoprint(56 + MARGIN_X + 5, i + 2, 4,0);
    }
    //創建蛇頭
    head = (SNAKE*)malloc(sizeof(SNAKE));
    head->x = 15 + MARGIN_X + 10;
    head->y = 15;
    gotoprint(head->x, head->y,10, 0);
    //創建蛇尾
    tail = (SNAKE*)malloc(sizeof(SNAKE));
    //創建蛇身
    SNAKE *body = (SNAKE*)malloc(sizeof(SNAKE));
    body->x = 15 + MARGIN_X + 10;
    body->y = 16;
    head->next = body;
    body->next = tail;
    gotoprint(body->x, body->y,10, 0);

    //head->next = tail;
    tail->next = NULL;
    tail->x = 15 + MARGIN_X + 10;
    tail->y = 17;
    gotoprint(tail->x, tail->y,10, 0);
}
/*
 *遊戲歡迎界面實現
 */
void welcome()
{
    SetConsoleWindowSize(121, 36);  //設置窗口大小
    SetTitle("貪喫蛇1.0");   //設置標題
    SetPosition(MARGIN_X,10);
    /*歡迎界面    */
    printf("/***************************************************************/");
    SetPosition(MARGIN_X, 20);
    printf("/***************************************************************/");
    SetPosition(MARGIN_X + 18, 13);
    printf("歡迎來到貪喫蛇小遊戲");
    SetPosition(MARGIN_X, 16);
    printf("請在英文輸入法中操作,wasd控制蛇移動方向,反向移動等同於喫到自己,其他鍵暫停遊戲");
    SetPosition(MARGIN_X + 20, 18);
    printf("按任意鍵開始遊戲");
    _getch();
    Clear(0,0);
}
/*
 *打印蛇身
 */
void gotoprint(int x, int y, int a,int b)
{
    SetColor(a, b);
    SetPosition(x, y);
    printf("■");
}
/*
 *清除一個點(蛇尾和食物)
 */
void gotodelete(int x, int y)
{
    SetPosition(x, y);
    printf("  ");
}
/*
 *判斷遊戲是否結束
 */
int Judge()
{
    if (head->x == (MARGIN_X + 5)|| head->x == (MARGIN_X +61) || head->y == 2 || head->y == 32)
    {
        return 0;
    }
    SNAKE *p = head->next;
    while (1)
    {
        //通過遍歷蛇身座標,與蛇頭座標對比,判斷蛇頭是否撞到蛇身
        if (head->x == p->x && head->y == p->y)
        {
            return 0;
        }
        if (p->next == NULL) break; //遍歷完成退出循環
        p = p->next;
    }
    return 1;
}
/*
 *移動蛇,參數爲用戶按鍵
 */
void MovingBody(char click)
{
    int count = 0;  //記錄蛇長
    int a = head->x, b = head->y;  //記錄蛇頭座標
    SNAKE *p = head;
    //通過清除蛇尾實現動畫效果,注意在運動轉態才清除蛇尾,暫停時不清除
    if(click == up || click == down || click == right || click == left)
    {
        while (1)
        {
            count++;
            if (p->next == NULL)
            {
                gotodelete(p->x, p->y);
                break;
            }
            p = p->next;
        }
    }
    switch (click)
    {
    case up:
        head->y -= 1;
        ChangeBody(a,b);
        break;
    case down:
        head->y += 1;
        ChangeBody(a,b);
        break;
    case left:
        head->x -= 2;
        ChangeBody(a,b);
        break;
    case right:
        head->x += 2;
        ChangeBody(a,b);
        break;
    default:
        break;
    }
    //打印新的蛇頭
    p = head;
    gotoprint(p->x, p->y,10,0);
    if (count <= 10) speed = 150;
    else if (count > 10 && count <= 20) speed = 100;
    else if (count > 20 && count <= 40) speed = 50;
    else speed = 10;
    Sleep(speed);
}
/*
 *移動蛇身
 */
void ChangeBody(int a,int b)
{
    SNAKE *p = head->next;
    int mid1, mid2,_mid1,_mid2;
    mid1 = p->x;
    mid2 = p->y;
    while (1)
    {
        if (p->next == NULL) break;
        _mid1 = p->next->x;
        _mid2 = p->next->y;
        p->next->x = mid1;
        p->next->y = mid2;
        mid1 = _mid1;
        mid2 = _mid2;
        p = p->next;
    }
    p = head->next;
    p->x = a;
    p->y = b;
}
/*
 *喫屎
 */
void Eating()
{
    if (head->x == food.x && head->y == food.y)
    {
        creatfood();
        SNAKE * _new = (SNAKE*)malloc(sizeof(SNAKE));
        _new->next = NULL;
        SNAKE *p;
        p = head;
        while (1)
        {
            if (p->next == NULL) break;
            p = p->next;
        }
        p->next = _new;
    }
}
/*
 *結束
 */
void gameover()
{
    Clear(0,0);
    SetPosition(MARGIN_X + 10,15);
    SetColor(10,0);
    printf("遊戲結束!");
}

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