小项目特供 贪吃蛇游戏(基于C语言)

时间:2023-03-09 05:29:07
小项目特供 贪吃蛇游戏(基于C语言)

  C语言写贪吃蛇本来是打算去年暑假写的,结果因为ACM集训给耽搁了,因此借寒假的两天功夫写了这个贪吃蛇小项目,顺带把C语言重温了一次。

  是发表博客的前一天开始写的,一共写了三个版本,第一天写了第一版,第二天写了第二版和第三版。

  相信C语言写个小游戏或小项目是大多数计算机相关专业的学生都做的事情,但是作为一个数学专业的学生,我们教研室的老师对C语言的要求也就比较低了,大一没有让我们做个小项目实践一次。至今为止用C/C++做过的三个小项目(大作业),一个是外校同学让我帮忙写的学生信息管理系统(天呐,这名字都被大学用烂了...),一个是本校计院的同学让我帮忙写的链表设计的大作业,实话说,真的很无聊...

  最后一个小项目就是贪吃蛇了,比前两个有意思多了,强烈建议大学老师让学生做些简单的界面程序而非黑框框下的所谓管理系统....让学生体会到乐趣才是真谛啊。


  附:源码及游戏程序下载地址:链接:贪吃蛇 密码:v55s

  


  

 第一版

  首先是第一版的源码奉上,因为没有学过MFC,这一版是借鉴了其他网站上的C语言贪吃蛇算法思路和图形写成的。

  我认为这里的贪吃蛇算法思路非常棒,虽然不知道这种算法的来由但是我对此算法创始人由衷敬佩...

    这里的算法思路其实是将图上每一个点的二维坐标转换成一维序列,然后通过一维序列映射地图上的每一个坐标

    最让我敬佩的地方就是在蛇头重绘的时候,这里的贪吃蛇移动地图上的二维坐标和原始地图的一维序列将随着蛇头的移动而不断发生交替改变,以适应贪吃蛇循环队列的算法要求。

  操作说明:WSAD控制方向。

  

 #include <stdio.h>
#include <ctype.h>
#include <conio.h>
#include <time.h>
#include <windows.h> //背景宽-高
#define HEIGHT 20
#define WIDTH 20
//地图中心
#define XCENTER HEIGHT/2
#define YCENTER WIDTH/2
//最大蛇长
#define SNAKE_MAXLEN ((HEIGHT - 2) * (WIDTH - 2))
//坐标->编号
#define NUM(x,y) ((x-1)*(WIDTH-2)+(y-1)) //模型
struct Model{
char *ch;
int color;
char flag;
}
border = { "□", , },
background = { "█", , },
snakeHead = { "★", 0xE, },
snakeBody = { "■", 0xE, },
food = { "●", 0xC, }; int snakeLen = ; //贪吃蛇长度 //地图
struct Map {
int flag; //模型标识
int num; //坐标编号
}map[WIDTH][HEIGHT]; //坐标
//贪吃蛇移动范围(循环队列),分数位置
struct Coordinate{
int x, y;
}snake[SNAKE_MAXLEN], scorePos; int score; //分数
int header, tail; //蛇头蛇尾下标
HANDLE hConsole; void setCursor(int x, int y)
{
//参数x为行,y为列-与光标设置相反
COORD coord;
coord.X = *y; //宽字符决定占两列
coord.Y = x;
SetConsoleCursorPosition(hConsole, coord);
} void setColor(int color)
{
SetConsoleTextAttribute(hConsole, color);
} //随机生成食物
void createFood()
{
int num; //新食物对应的坐标编号
int range; //新食物所在范围
srand((unsigned)time(NULL)); //初始种子
range = SNAKE_MAXLEN - snakeLen; //食物生成范围
if (tail < header)
num = rand() % range + tail + ;
else {
num = rand() % range;
if (num >= header)
num += snakeLen;
}
//绘制食物
int tx = snake[num].x;
int ty = snake[num].y;
setCursor(tx, ty);
setColor(food.color);
printf("%s", food.ch);
map[tx][ty].flag = food.flag;
} //游戏结束
void gameOver()
{
setCursor(XCENTER, YCENTER - );
setColor(0xC); printf("Game Over!");
getch();
exit(); //结束程序
} void move(char direction)
{
//新蛇头
int tx = snake[header].x;
int ty = snake[header].y;
switch (direction)
{
case 'w':
tx--; break;
case 's':
tx++; break;
case 'a':
ty--; break;
case 'd':
ty++; break;
} //判断是否会出界或撞到自己
if (map[tx][ty].flag == border.flag || map[tx][ty].flag == snakeBody.flag)
gameOver(); //新蛇头绘制(此时未refresh模型标识)
setCursor(tx, ty);
setColor(snakeHead.color);
printf("%s", snakeHead.ch);
//原蛇头重绘制
setCursor(snake[header].x, snake[header].y);
printf("%s", snakeBody.ch); //小方块 //蛇头更新-队首移动
header = header == ? SNAKE_MAXLEN - : header - ;
//旧编号位置更正
int preNum = map[tx][ty].num; //蛇头位置旧编号
snake[preNum].x = snake[header].x;
snake[preNum].y = snake[header].y;
map[snake[preNum].x][snake[preNum].y].num = preNum;
//蛇头位置更正
snake[header].x = tx;
snake[header].y = ty;
map[tx][ty].num = header; //蛇头位置新编号 //判断是否吃到食物
if (map[tx][ty].flag == food.flag)
{
createFood(); //随机生成食物
snakeLen++; //蛇身加长
//更新-score
setCursor(scorePos.x, scorePos.y);
printf("%d", ++score);
}
else {
//删除蛇尾
setCursor(snake[tail].x, snake[tail].y);
map[snake[tail].x][snake[tail].y].flag = background.flag;
setColor(background.color);
printf("%s", background.ch);
tail = tail == ? SNAKE_MAXLEN - : tail - ;
} //更新-蛇头模型标识
map[tx][ty].flag = snakeBody.flag;
} //初始化界面
void init()
{
CONSOLE_CURSOR_INFO cci; //光标信息
header = ;
tail = snakeLen - ; //设置光标不可见
hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
GetConsoleCursorInfo(hConsole, &cci);
cci.bVisible = ;
SetConsoleCursorInfo(hConsole, &cci); //dos命令设置窗口大小
system("mode con:cols=100 lines=32"); //绘制背景
for (int x = ; x < HEIGHT; x++)
{
for (int y = ; y < WIDTH; y++)
{
if (x == || y == || x == HEIGHT - || y == WIDTH - )
{
map[x][y].flag = border.flag;
setColor(border.color);
printf("%s", border.ch);
}
else {
int num = NUM(x,y);
snake[num].x = x;
snake[num].y = y;
//背景设置
map[x][y].num = num;
map[x][y].flag = background.flag;
setColor(background.color);
printf("%s", background.ch);
}
}
printf("\n");
} //绘制初始贪吃蛇
setCursor(XCENTER, YCENTER - snakeLen / );
header = NUM(XCENTER, YCENTER - ); //蛇头位置
tail = header + snakeLen - ;
setColor(snakeBody.color);
for (int i = header; i <= tail; i++)
{
if (i == header) printf("%s", snakeHead.ch);
else printf("%s", snakeBody.ch);
map[snake[i].x][snake[i].y].flag = snakeBody.flag;
} //随机生成食物
createFood(); //其他信息
setCursor(XCENTER - , WIDTH + );
printf(" score: 0");
setCursor(XCENTER, WIDTH + );
printf(" Author: InkMark");
setCursor(XCENTER + , WIDTH + );
printf(" Blog: www.cnblogs.com/inkblots");
//分数位置
scorePos.x = XCENTER - ;
scorePos.y = WIDTH + ;
} int main()
{
//方向及其他初始化
char direction = 'a';
init(); char ch = tolower(getch());
if (ch == 'a' || ch == 'w' || ch == 's')
direction = ch; while () {
if (kbhit()) {
ch = tolower(getch());
if (ch == ' ')
ch = getch(); //实现空格-暂停
if(ch == 'a' || ch == 'd' || ch == 'w' || ch=='s')
if (ch + direction != && ch + direction != )
direction = ch; //不为反向时改变方向
}
move(direction);
Sleep();
} return ;
}

= 。=

  


第二版:

  第二版在第一版的算法基础上改进了图形界面和源码管理,新增了“加速”技能(比较方便实现)。

  控制方向也改为方向键了。

  第二版源码分为三个文件,运行源码需要链接一次。

  先是一个头文件,定义了要用到的库文件,常用常量和结构体,以及声明main中要用到的函数

  

 #ifndef CATALOG_H
#define CATALOG_H #include<stdio.h>
#include<conio.h>
#include<time.h>
#include<windows.h> //背景上下伸展长度
#define TOP_EXTEND 3
#define BOTTOM_EXTEND 3
//背景宽-高
#define WIDTH 33
#define HEIGHT 20
//地图中心
#define XCENTER ((HEIGHT + 1)/2 + TOP_EXTEND)
#define YCENTER (WIDTH + 1)/2
//最大蛇长
#define SNAKE_MAXLEN ((HEIGHT - 2) * (WIDTH - 2))
//坐标->序号
#define ORDER(x,y) ((x - TOP_EXTEND - 1) * (WIDTH - 2) + (y - 1))
//点:在移动范围内
#define IN_RANGE(x,y) (x > TOP_EXTEND && x < HEIGHT + TOP_EXTEND - 1 && y > 0 && y < WIDTH - 1)
//默认暂停时间
#define PAUSE_TIME 500 /*全局变量*/
extern int snakeLen;
extern int direction;
extern int header, tail;
extern int score;
extern int skill;
extern int pauseTime;
extern HANDLE hConsole; //模型
typedef struct Model {
char *ch;
int color;
int flag;
}Model; //地图
typedef struct Map {
int flag; //模型标识
int order; //序号
}Map; //坐标
//贪吃蛇移动范围(循环队列),分数位置
typedef struct Coordinate {
int x, y;
}Coordinate; /******界面设定******/ void setCursor(int x, int y); void setColor(int color); void control(char ch); /******框架及功能******/ void init(); int move(char direction); void createFood(); #endif

catalog.h

  第二个是功能部分源码

 #include "catalog.h"

 Model    border = { NULL, 0x7,  },
snakeHead = { "★", 0xE, },
snakeBody = { "■", 0xE, },
food = { "●", 0xC, }; Map map[HEIGHT][WIDTH]; Coordinate snake[SNAKE_MAXLEN], scorePos, skillPos; /************游戏界面设定************/ //隐藏光标
void hideCursor()
{
CONSOLE_CURSOR_INFO cci; //光标信息
hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
GetConsoleCursorInfo(hConsole, &cci);
cci.bVisible = ;
SetConsoleCursorInfo(hConsole, &cci);
} //设置光标位置
void setCursor(int x, int y)
{
//参数x为行,y为列-与光标设置相反
COORD coord;
coord.X = * y; //宽字符决定占两列
coord.Y = x;
SetConsoleCursorPosition(hConsole, coord);
} //设置文字颜色
void setColor(int color)
{
SetConsoleTextAttribute(hConsole, color);
} //绘制游戏窗口(包括dos环境初始窗口)
void createWindow()
{
//dos命令设置窗口大小
system("mode con:cols=72 lines=27"); //╔ ╗ ╝ ╚ ═ ║ ╠ ╣ ╦ ╩
setColor(0x7);
printf("╔════════════════╦════════════════╗\n"); //0~34
for (int i = ; i < TOP_EXTEND; i++)
printf("║ ║ ║\n");
printf("╠════════════════╩════════════════╣\n");
for (int i = ; i < HEIGHT - ; i++)
printf("║ ║\n");
printf("╠═════════════════════════════════╣\n");
for (int i = ; i < BOTTOM_EXTEND; i++)
printf("║ ║\n");
printf("╚═════════════════════════════════╝\n");
setCursor(HEIGHT + TOP_EXTEND, );
printf(" 操作指南:方向键控制,空格可暂停,5分后可获得技能.");
setCursor(HEIGHT + TOP_EXTEND + , );
printf(" Version : 2.0"); for (int x = TOP_EXTEND; x < HEIGHT + TOP_EXTEND; x++)
{
for (int y = ; y < WIDTH; y++)
if (IN_RANGE(x, y))
{
int order = ORDER(x, y);
snake[order].x = x;
snake[order].y = y;
//背景设置
map[x][y].order = order;
map[x][y].flag = ;
}
else map[x][y].flag = border.flag;
}
//其他信息
setColor(0x7);
setCursor(, );
printf(" 你的分数:0");
setCursor(, );
printf(" 技能:无");
setCursor(, YCENTER + );
printf(" Author: InkMark");
setCursor(, YCENTER + );
printf(" Blog: www.cnblogs.com/inkblots"); //分数位置
scorePos.x = ; scorePos.y = ;
skillPos.x = ; skillPos.y = ;
} //控制键
void control(char ch)
{
//本应取方向键高位再取低位,在此以简便为主
if (ch != -) return;
ch = getch();
//上72下80左75右77
if (ch == || ch == || ch == || ch == ) //低位相同
if (ch + direction != ) direction = ch; //不为反向时改变方向
} /************游戏信息输出************/ void getSkill()
{
setCursor(skillPos.x, skillPos.y);
printf("加速(S键)");
skill = ; //加速技能开启
} void alterScore(int addition)
{
score += addition;
if (score >= )
getSkill();
setCursor(scorePos.x, scorePos.y);
setColor(0x7);
printf("%d", score);
} void gameOver()
{
if (IDYES == MessageBox(NULL, "是否重新开始游戏?", "Snake_2.0", MB_YESNO))
{
system("CLS");
return;
} exit();
} /************游戏框架及功能************/ //变量初始化及界面初始化
void init()
{
pauseTime = PAUSE_TIME;
skill = ;
score = ;
snakeLen = ;
header = ;
tail = snakeLen - ; hideCursor();//隐藏光标
createWindow(); //绘制背景
} //贪吃蛇移动
//return:1为成功,0为失败
int move(char direction)
{
//新蛇头
int tx = snake[header].x;
int ty = snake[header].y;
//上72下80左75右77
switch (direction)
{
case : tx--; break;
case : tx++; break;
case : ty--; break;
case : ty++; break;
} //判断是否撞墙或撞到自己
if (map[tx][ty].flag == border.flag || map[tx][ty].flag == snakeBody.flag)
{
gameOver();
return ;
} //新蛇头绘制(此时未refresh模型标识)
setCursor(tx, ty);
setColor(snakeHead.color);
printf("%s", snakeHead.ch);
//原蛇头重绘制
setCursor(snake[header].x, snake[header].y);
printf("%s", snakeBody.ch); //蛇头更新-队首移动
header = header == ? SNAKE_MAXLEN - : header - ;
//旧编号位置更正
int preNum = map[tx][ty].order; //蛇头位置旧编号
snake[preNum].x = snake[header].x;
snake[preNum].y = snake[header].y;
map[snake[preNum].x][snake[preNum].y].order = preNum;
//蛇头位置更正
snake[header].x = tx;
snake[header].y = ty;
map[tx][ty].order = header; //蛇头位置新编号 //判断是否吃到食物
if (map[tx][ty].flag == food.flag)
{
snakeLen++; //蛇身加长
createFood(); //随机生成食物
//更新-score
alterScore();
}
else {
//删除蛇尾
setCursor(snake[tail].x, snake[tail].y);
map[snake[tail].x][snake[tail].y].flag = ;
printf(" ");
tail = tail == ? SNAKE_MAXLEN - : tail - ;
} //更新-蛇头模型标识
map[tx][ty].flag = snakeBody.flag; return ;
} //随机生成食物
void createFood()
{
int order; //新食物对应的坐标编号
int range; //新食物所在范围
srand((unsigned)time(NULL)); //初始种子
range = SNAKE_MAXLEN - snakeLen; //食物生成范围
if (tail < header)
order = rand() % range + tail + ;
else {
order = rand() % range;
if (order >= header)
order += snakeLen;
}
//绘制食物
int tx = snake[order].x;
int ty = snake[order].y;
setCursor(tx, ty);
setColor(food.color);
printf("%s", food.ch);
map[tx][ty].flag = food.flag;
}

Util.c

  第三个是主函数及初始化部分

 #include "catalog.h"

 int snakeLen;    //贪吃蛇长度
int direction; //贪吃蛇移动方向
int header, tail; //蛇头蛇尾下标
int score; //分数
int skill; //技能开关
int pauseTime; //暂停时间(Ms)
HANDLE hConsole; extern Model border, snakeHead, snakeBody, food;
extern Map map[HEIGHT][WIDTH];
extern Coordinate snake[SNAKE_MAXLEN], scorePos, skillPos; //初始化方案
void scheme()
{
//变量初始化及界面初始化
init(); //绘制初始贪吃蛇
setCursor(XCENTER, YCENTER - snakeLen / );
header = ORDER(XCENTER, YCENTER - snakeLen / ); //蛇头位置
tail = header + snakeLen - ;
setColor(snakeBody.color);
for (int i = header; i <= tail; i++)
{
if (i == header) printf("%s", snakeHead.ch);
else printf("%s", snakeBody.ch);
map[snake[i].x][snake[i].y].flag = snakeBody.flag;
} //随机生成食物
createFood(); //初始方向处理
direction = ;
char ch = getch();
control(ch);
} int main()
{
//初始方案
scheme(); while () {
if (kbhit()) {
char ch = getch();
if (ch == ' ') MessageBox(NULL, " 暂停中...\n 请单击确定继续游戏", "暂停游戏", MB_OK);
if (skill == && (ch == 's' || ch == 'S'))
pauseTime = pauseTime == PAUSE_TIME ? PAUSE_TIME / : PAUSE_TIME;
else control(ch); //控制方向
}
if (move(direction))
Sleep(pauseTime);
else scheme();
} return ;
}

SnakeMain.c


第三版:

  第三版加入了菜单,优化了部分界面,并将游戏分为两个基本模式。

  

  和第二版一样,分为三个文件

  头文件:

  

 #ifndef CATALOG_H
#define CATALOG_H #include<stdio.h>
#include<conio.h>
#include<time.h>
#include<windows.h> //背景上下伸展长度
#define TOP_EXTEND 3
#define BOTTOM_EXTEND 3
//背景宽-高
#define WIDTH 33
#define HEIGHT 20
//地图中心
#define XCENTER ((HEIGHT + 1)/2 + TOP_EXTEND)
#define YCENTER (WIDTH + 1)/2
//最大蛇长
#define SNAKE_MAXLEN ((HEIGHT - 2) * (WIDTH - 2))
//坐标->序号
#define ORDER(x,y) ((x - TOP_EXTEND - 1) * (WIDTH - 2) + (y - 1))
//点:在移动范围内
#define IN_RANGE(x,y) (x > TOP_EXTEND && x < HEIGHT + TOP_EXTEND - 1 && y > 0 && y < WIDTH - 1)
//默认暂停时间
#define PAUSE_TIME 500 /*全局变量*/
extern int snakeLen;
extern int direction;
extern int header, tail;
extern int score;
extern int skill;
extern int pauseTime;
extern int mode;
extern HANDLE hConsole; //模型
typedef struct Model {
char *ch;
int color;
int flag;
}Model; //地图
typedef struct Map {
int flag; //模型标识
int order; //序号
}Map; //坐标
//贪吃蛇移动范围(循环队列),分数位置
typedef struct Coordinate {
int x, y;
}Coordinate; /******界面设定******/ extern void setCursor(int x, int y); extern void setColor(int color); extern void control(char ch); /******框架及功能******/ extern void init(); extern int move(char direction); extern void createFood(); #endif

catalog.h

  功能文件:

 #include "catalog.h"

 Model    border = { NULL, 0x7,  },
snakeHead = { "★", 0xE, },
snakeBody = { "■", 0xE, },
food = { "●", 0xC, }; Map map[HEIGHT][WIDTH]; Coordinate snake[SNAKE_MAXLEN], scorePos, skillPos, dotPos; #define UP 4 //向上偏移量
#define LEFT 6 //左移偏移量 /************游戏界面设定************/ //隐藏光标
void hideCursor()
{
CONSOLE_CURSOR_INFO cci; //光标信息
hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
GetConsoleCursorInfo(hConsole, &cci);
cci.bVisible = ;
SetConsoleCursorInfo(hConsole, &cci);
} //设置光标位置
void setCursor(int x, int y)
{
//参数x为行,y为列-与光标设置相反
COORD coord;
coord.X = * y; //宽字符决定占两列
coord.Y = x;
SetConsoleCursorPosition(hConsole, coord);
} //设置文字颜色
void setColor(int color)
{
SetConsoleTextAttribute(hConsole, color);
} //绘制游戏窗口(包括dos环境初始窗口)
void createWindow()
{
//dos命令设置窗口大小
system("mode con:cols=72 lines=28"); //╔ ╗ ╝ ╚ ═ ║ ╠ ╣ ╦ ╩
setColor(0x7);
printf("╔════════════════╦════════════════╗\n"); //0~34
for (int i = ; i < TOP_EXTEND; i++)
printf("║ ║ ║\n");
printf("╠════════════════╩════════════════╣\n");
for (int i = ; i < HEIGHT - ; i++)
printf("║ ║\n");
printf("╠═════════════════════════════════╣\n");
for (int i = ; i < BOTTOM_EXTEND; i++)
printf("║ ║\n");
printf("╚═════════════════════════════════╝\n");
setCursor(HEIGHT + TOP_EXTEND, );
printf(" 操作指南:上下键及回车键选择.");
setCursor(HEIGHT + TOP_EXTEND + , );
printf(" Version : 3.0"); for (int x = TOP_EXTEND; x < HEIGHT + TOP_EXTEND; x++)
{
for (int y = ; y < WIDTH; y++)
if (IN_RANGE(x, y))
{
int order = ORDER(x, y);
snake[order].x = x;
snake[order].y = y;
//背景设置
map[x][y].order = order;
map[x][y].flag = ;
}
else map[x][y].flag = border.flag;
}
//其他信息
setColor(0x7);
setCursor(, );
printf(" 你的分数:0");
setCursor(, );
printf(" 技能:无");
setCursor(, YCENTER + );
printf(" Author: InkMark");
setCursor(, YCENTER + );
printf(" Blog: www.cnblogs.com/inkblots"); //分数位置
scorePos.x = ; scorePos.y = ;
skillPos.x = ; skillPos.y = ;
} void menuButton(char ch)
{
int tx = dotPos.x;
int ty = dotPos.y;
if (ch == ) tx--;
else tx++; if (tx > XCENTER - UP && tx < XCENTER - UP + )
{
setCursor(dotPos.x, dotPos.y);
printf(" ");
setCursor(tx, ty);
printf("●");
dotPos.x = tx;
dotPos.y = ty;
}
} //绘制菜单并进行选择
void menu()
{
//╔ ╗ ╚ ╝ ═ ║ ╠ ╣ ╦ ╩
setCursor(XCENTER - UP, YCENTER - LEFT);
printf("╔═════════╗"); //
for (int i = ; i <= ; i++)
{
setCursor(XCENTER - UP + i, YCENTER - LEFT);
printf("║ ║");
}
setCursor(XCENTER - UP + , YCENTER - LEFT);
printf("╚═════════╝"); dotPos.x = XCENTER - UP + ;
dotPos.y = YCENTER - ;
setCursor(dotPos.x, dotPos.y);
printf("● 1.死亡模式");
setCursor(XCENTER - UP + , YCENTER - );
printf("2.技能模式");
setCursor(XCENTER - UP + , YCENTER - );
printf("3.退出游戏"); char ch;
while ((ch = getch()) != ) //确定键:13
{
if (ch != -) continue;
ch = getch();
if (ch == || ch == )
menuButton(ch);
} for (int i = ; i < ; i++)
{
setCursor(XCENTER - UP + i, YCENTER - LEFT);
printf(" ");
} mode = dotPos.x - XCENTER + UP;
if (mode == ) exit();
} //控制键
void control(char ch)
{
//本应取方向键高位再取低位,在此以简便为主
if (ch != -) return;
ch = getch();
//上72下80左75右77
if (ch == || ch == || ch == || ch == ) //低位相同
if (ch + direction != )
direction = ch; //不为反向时改变方向
} /************游戏信息输出************/ void getSkill()
{
setCursor(skillPos.x, skillPos.y);
printf("加速(S键)");
skill = ; //加速技能开启
} void alterScore(int addition)
{
score += addition;
if (mode == && score >= )
getSkill();
setCursor(scorePos.x, scorePos.y);
setColor(0x7);
printf("%d", score);
} void printInfo()
{
//╔ ╗ ╚ ╝ ═ ║ ╠ ╣ ╦ ╩
int col = ;
setCursor(HEIGHT + TOP_EXTEND - , col);
printf("╦");
setCursor(HEIGHT + TOP_EXTEND, col);
printf("║");
setCursor(HEIGHT + TOP_EXTEND + , col);
printf("║ 模 式");
if (mode == ) { setCursor(HEIGHT + TOP_EXTEND, );
printf(" 操作指南:方向键控制,空格可暂停.");
setCursor(HEIGHT + TOP_EXTEND, col + );
printf(" 无 尽");
}
else {
setCursor(HEIGHT + TOP_EXTEND, );
printf(" 操作指南:方向键控制,空格可暂停,8分后有惊喜.");
setCursor(HEIGHT + TOP_EXTEND, col + );
printf(" 技 能");
}
setCursor(HEIGHT + TOP_EXTEND + , col);
printf("╩");
} void gameOver()
{
if (IDYES == MessageBox(NULL, "是否重新开始游戏?", "Snake_2.0", MB_YESNO))
{
system("CLS");
return;
} exit();
} /************游戏框架及功能************/ //变量初始化及界面初始化
void init()
{
pauseTime = PAUSE_TIME;
skill = ;
score = ;
snakeLen = ;
header = ;
tail = snakeLen - ; hideCursor();//隐藏光标
createWindow(); //绘制背景 menu(); //菜单操作 printInfo();
} //贪吃蛇移动
//return:1为成功,0为失败
int move(char direction)
{
//新蛇头
int tx = snake[header].x;
int ty = snake[header].y;
//上72下80左75右77
switch (direction)
{
case : tx--; break;
case : tx++; break;
case : ty--; break;
case : ty++; break;
} //判断是否撞墙或撞到自己
if (map[tx][ty].flag == border.flag || map[tx][ty].flag == snakeBody.flag)
{
gameOver();
return ;
} //新蛇头绘制(此时未refresh模型标识)
setCursor(tx, ty);
setColor(snakeHead.color);
printf("%s", snakeHead.ch);
//原蛇头重绘制
setCursor(snake[header].x, snake[header].y);
printf("%s", snakeBody.ch); //蛇头更新-队首移动
header = header == ? SNAKE_MAXLEN - : header - ;
//旧编号位置更正
int preNum = map[tx][ty].order; //蛇头位置旧编号
snake[preNum].x = snake[header].x;
snake[preNum].y = snake[header].y;
map[snake[preNum].x][snake[preNum].y].order = preNum;
//蛇头位置更正
snake[header].x = tx;
snake[header].y = ty;
map[tx][ty].order = header; //蛇头位置新编号 //判断是否吃到食物
if (map[tx][ty].flag == food.flag)
{
snakeLen++; //蛇身加长
createFood(); //随机生成食物
//更新-score
if(pauseTime == PAUSE_TIME) alterScore();
else alterScore();
}
else {
//删除蛇尾
setCursor(snake[tail].x, snake[tail].y);
map[snake[tail].x][snake[tail].y].flag = ;
printf(" ");
tail = tail == ? SNAKE_MAXLEN - : tail - ;
} //更新-蛇头模型标识
map[tx][ty].flag = snakeBody.flag; return ;
} //随机生成食物
void createFood()
{
int order; //新食物对应的坐标编号
int range; //新食物所在范围
srand((unsigned)time(NULL)); //初始种子
range = SNAKE_MAXLEN - snakeLen; //食物生成范围
if (tail < header)
order = rand() % range + tail + ;
else {
order = rand() % range;
if (order >= header)
order += snakeLen;
}
//绘制食物
int tx = snake[order].x;
int ty = snake[order].y;
setCursor(tx, ty);
setColor(food.color);
printf("%s", food.ch);
map[tx][ty].flag = food.flag;
}

Util.c

  主文件:

 

 #include "catalog.h"

 int snakeLen;    //贪吃蛇长度
int direction; //贪吃蛇移动方向
int header, tail; //蛇头蛇尾下标
int score; //分数
int skill; //技能开关
int pauseTime; //暂停时间(Ms)
int mode;
HANDLE hConsole; extern Model border, snakeHead, snakeBody, food;
extern Map map[HEIGHT][WIDTH];
extern Coordinate snake[SNAKE_MAXLEN], scorePos, skillPos; //初始化方案
void scheme()
{
//变量初始化及界面初始化
init(); //绘制初始贪吃蛇
setCursor(XCENTER, YCENTER - snakeLen / );
header = ORDER(XCENTER, YCENTER - snakeLen / ); //蛇头位置
tail = header + snakeLen - ;
setColor(snakeBody.color);
for (int i = header; i <= tail; i++)
{
if (i == header) printf("%s", snakeHead.ch);
else printf("%s", snakeBody.ch);
map[snake[i].x][snake[i].y].flag = snakeBody.flag;
} //随机生成食物
createFood(); //初始方向处理
direction = ;
char ch = getch();
control(ch);
} int main()
{
//初始方案
scheme(); while () {
if (kbhit()) {
char ch = getch();
if (ch == ' ') MessageBox(NULL, " 暂停中...\n 请单击确定继续游戏", "暂停游戏", MB_OK);
if (mode == && skill == && (ch == 's' || ch == 'S'))
pauseTime = pauseTime == PAUSE_TIME ? PAUSE_TIME / : PAUSE_TIME;
else control(ch); //控制方向
}
if (move(direction))
Sleep(pauseTime);
else scheme();
} return ;
}

SnakeMain.c