贪吃蛇(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("游戏结束!");
}

猜你喜欢

转载自blog.csdn.net/weixin_41944412/article/details/82830131
今日推荐