参考视频:https://www.bilibili.com/video/av29580072/?p=1
GreedySnake.h
#ifndef GREEDYSNAKE_H_INCLUDED
#define GREEDYSNAKE_H_INCLUDED #define SNAKE_LENGTH 20 //蛇的长度最大为20
#define true 1
#define false 0
enum {UP = -, DOWN = , LEFT = -, RIGHT = }; typedef int bool; void FirstPage(); //设置起始游戏界面
void TestSpace(); //按空格开始游戏
void ShowBackground(); //展示游戏背景
void SetSnakeRandPos(); //为蛇产生一个随机的位置
void DrawSnake(); //画蛇
void SnakeMove(); //蛇动
void DestroySnake(); //销毁蛇
void ChangeDir(); //蛇随着方向键动起来
bool IsSnakeDie(); //判断蛇是否死亡
void ProduceFood(); //随机位置产生食物
void SnakeGrowUp(); //蛇变长
void PrintScore(); //打印分数 #endif // GREEDYSNAKE_H_INCLUDED
GreedySnake.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
#include <windows.h>
#include <time.h>
#include "GreedySnake.h" //把所有元素置为0
//snake[0][0]表示蛇头的行,snake[0][1]表示蛇头的列,snake[0][2]表示蛇头移动的方向
int g_arrSnake[SNAKE_LENGTH][] = { }; int g_iSnakeLength = ; //初始长度为3,但数组下标从0开始,故此处为2 char g_arrBackGround[][] =
{
"████████████████████████\n", //一个█占两个字节,占两个字符的位置
"█ █\n",
"█ █\n",
"█ █\n",
"█ █\n",
"█ █\n",
"█ █\n",
"█ █\n",
"█ █\n",
"█ █\n",
"█ █\n",
"█ █\n",
"█ █\n",
"█ █\n",
"█ █\n",
"█ █\n",
"█ █\n",
"█ █\n",
"█ █\n",
"████████████████████████\n"
}; int g_iSnakeDir = LEFT; //蛇的方向,默认向左
bool g_bIsProFood = true; //蛇产生食物的标记
int g_iRow; //食物的行坐标
int g_iCol; //食物的列坐标 int g_iScore = ; //分数 void FirstPage() //设置起始游戏界面
{
for (int i = ; i < ; ++i)
printf(" ");
for (int i = ; i < ; ++i)
printf("*");
printf("\n"); for (int j = ; j < ; ++j)
{
for (int i = ; i < ; ++i)
printf(" ");
printf("*");
for (int i = ; i < ; ++i)
printf(" ");
printf("*\n");
} for (int i = ; i < ; ++i)
printf(" ");
printf("*");
for (int i = ; i < ; ++i)
printf(" ");
printf("《 欢迎来到贪吃蛇的世界!》");
for (int i = ; i < ; ++i)
printf(" ");
printf("*\n"); for (int i = ; i < ; ++i)
printf(" ");
printf("*");
for (int i = ; i < ; ++i)
printf(" ");
printf("《 请按空格键开始游戏 》");
for (int i = ; i < ; ++i)
printf(" ");
printf("*\n"); for (int j = ; j < ; ++j)
{
for (int i = ; i < ; ++i)
printf(" ");
printf("*");
for (int i = ; i < ; ++i)
printf(" ");
printf("*\n");
} for (int i = ; i < ; ++i)
printf(" ");
for (int i = ; i < ; ++i)
printf("*");
for (int i = ; i < ; ++i)
printf("\n");
} void TestSpace() //按空格开始游戏
{
char c;
while ((c = getch()) != ' ') //getch()在头文件<conio>内
{ }
system("cls"); //清屏
} void ShowBackground() //展示游戏背景
{
for (int i = ; i < ; ++i)
printf(g_arrBackGround[i]);
} void SetSnakeRandPos() //设置蛇的初始位置,默认蛇的身子为三节,向左移动
{
int x, y;
srand((unsigned)time(NULL));
x = rand()% + ; //因为蛇的身子起始为三节,所以x的范围为1-20(蛇不能起始就撞墙)
y = rand()% + ; g_arrSnake[][] = y; //行 注意:x,y和初始背景中的行列刚好是反的
g_arrSnake[][] = x * ; //列 注意:一个█占两个字节,所以算其坐标时要乘以2
g_arrSnake[][] = LEFT; //方向 g_arrSnake[][] = y;
g_arrSnake[][] = x * + ;
g_arrSnake[][] = LEFT; g_arrSnake[][] = y;
g_arrSnake[][] = x * + ;
g_arrSnake[][] = LEFT; DrawSnake();
} void DrawSnake() //展示蛇
{
//因为一个█占两个字节,所以不能直接用strcpy(&arrBackGround[arrSnake[i][0]][arrSnake[i][1]],"█");否则会把\0拷贝进来,导致出错
//由于前面把arrSnake的所有元素都置为了0,所以当arrSnake[i][0]为0时,代表那个坐标处没有蛇的身子
for (int i = ; g_arrSnake[i][] != ; ++i)
strncpy(&g_arrBackGround[g_arrSnake[i][]][g_arrSnake[i][]], "█", ); //注意取地址符&不能漏掉!
} void DestroySnake() //销毁蛇
{
for (int i = ; g_arrSnake[i][] != ; ++i)
strncpy(&g_arrBackGround[g_arrSnake[i][]][g_arrSnake[i][]], " ", ); //注意取地址符&不能漏掉! } void SnakeMove() //蛇动
{
DestroySnake();
for(int i = SNAKE_LENGTH - ; i >= ; --i)
{
if(g_arrSnake[i][] != )
{
//把前一个节点的值,赋给当前节点
g_arrSnake[i][] = g_arrSnake[i-][];
g_arrSnake[i][] = g_arrSnake[i-][];
g_arrSnake[i][] = g_arrSnake[i-][];
}
} g_arrSnake[][] = g_iSnakeDir; //设置蛇头方向 //处理第一个节点(蛇头)
if(g_arrSnake[][] == LEFT || g_arrSnake[][] == RIGHT) //左右移动,列加减2
{
g_arrSnake[][] += g_arrSnake[][];
}
else
{
g_arrSnake[][] += g_arrSnake[][]; //上下移动,行加减1
} DrawSnake(); } void ChangeDir() //改变方向
{
//不能用getchar(), 会回显,并且要按回车之后才会开始读取
//不能用getch(), 同步检测 //异步检测
if(GetAsyncKeyState('W'))
{
if (g_arrSnake[][] != DOWN) //蛇不能回头
g_iSnakeDir = UP;
} if(GetAsyncKeyState('S'))
{
if (g_arrSnake[][] != UP)
g_iSnakeDir = DOWN;
} if(GetAsyncKeyState('A'))
{
if (g_arrSnake[][] != RIGHT)
g_iSnakeDir = LEFT;
} if(GetAsyncKeyState('D'))
{
if (g_arrSnake[][] != LEFT)
g_iSnakeDir = RIGHT;
}
} bool IsSnakeDie() //蛇死亡判断(包括撞墙和吃自己,两种情况)
{
if(g_arrSnake[][] == LEFT || g_arrSnake[][] == RIGHT) //如果蛇左右移动,则判断蛇头的左右是否是"█",如果是,则判定为蛇死亡
{
if(!strncmp(&g_arrBackGround[g_arrSnake[][]][g_arrSnake[][]+g_arrSnake[][]], "█", )) //注意取地址符&不能漏掉!
return true;
}
else //如果蛇上下移动,则判断蛇头的上下是否是"█"
{
if(!strncmp(&g_arrBackGround[g_arrSnake[][]+g_arrSnake[][]][g_arrSnake[][]], "█", ))
return true;
}
return false;
} void ProduceFood() //随机位置产生食物
{
//判断是否产生新的食物
if(g_bIsProFood == false)
return; bool bFlag = true;
srand((unsigned)time(NULL)); while() //产生合法的食物,即食物不与蛇的身子重合
{
g_iRow = rand()% + ; //行
g_iCol = rand()% + ; for (int i = ; g_arrSnake[i][] != ; i++) //遍历蛇
if (g_iRow == g_arrSnake[i][] && g_iCol == g_arrSnake[i][]) //如果在食物产生在蛇身上
{
bFlag = false;
break;
} if(bFlag == true)
break;
} strncpy(&g_arrBackGround[g_iRow][g_iCol*], "★", );
g_bIsProFood = false;
} void SnakeGrowUp() //蛇变长
{
if(g_iRow == g_arrSnake[][] && g_iCol* == g_arrSnake[][]) //注意:列要乘以2
{
if (UP == g_arrSnake[g_iSnakeLength][])
{
g_arrSnake[g_iSnakeLength+][] = g_arrSnake[g_iSnakeLength][]+;
g_arrSnake[g_iSnakeLength+][] = g_arrSnake[g_iSnakeLength][];
g_arrSnake[g_iSnakeLength+][] = g_arrSnake[g_iSnakeLength][];
}
else if (DOWN == g_arrSnake[g_iSnakeLength][])
{
g_arrSnake[g_iSnakeLength+][] = g_arrSnake[g_iSnakeLength][]-;
g_arrSnake[g_iSnakeLength+][] = g_arrSnake[g_iSnakeLength][];
g_arrSnake[g_iSnakeLength+][] = g_arrSnake[g_iSnakeLength][];
}
else if (LEFT == g_arrSnake[g_iSnakeLength][])
{
g_arrSnake[g_iSnakeLength+][] = g_arrSnake[g_iSnakeLength][];
g_arrSnake[g_iSnakeLength+][] = g_arrSnake[g_iSnakeLength][]+;
g_arrSnake[g_iSnakeLength+][] = g_arrSnake[g_iSnakeLength][];
}
else if (RIGHT == g_arrSnake[g_iSnakeLength][])
{
g_arrSnake[g_iSnakeLength+][] = g_arrSnake[g_iSnakeLength][];
g_arrSnake[g_iSnakeLength+][] = g_arrSnake[g_iSnakeLength][]-;
g_arrSnake[g_iSnakeLength+][] = g_arrSnake[g_iSnakeLength][];
}
g_iSnakeLength++;
g_bIsProFood = true;
g_iScore++;
} } void PrintScore() //打印分数
{
COORD rd;
//设置光标位置
rd.X = ;
rd.Y = ;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), rd);
printf("分数"); rd.X = ;
rd.Y = ;
//设置光标位置
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), rd);
//打印
printf ("%d", g_iScore);
}
main.c
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <windows.h>
#include <time.h>
#include "GreedySnake.h" int main()
{
FirstPage();
TestSpace();
system("cls");
SetSnakeRandPos();
ShowBackground(); while ()
{
system("cls");
ProduceFood();
SnakeGrowUp();
ChangeDir(); if(IsSnakeDie())
{
printf("snake die!\n");
break;
} SnakeMove();
ShowBackground();
PrintScore(); Sleep();
}
system("pause");
return ;
}