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

小项目特供 贪吃蛇游戏(基于C语言)的更多相关文章

  1. 基于React的贪吃蛇游戏的设计与实现

    代码地址如下:http://www.demodashi.com/demo/11818.html 贪吃蛇小游戏(第二版) 一年半前层用react写过贪吃蛇小游戏https://github.com/ca ...

  2. 【C语言项目】贪吃蛇游戏(上)

    目录 00. 目录 01. 开发背景 02. 功能介绍 03. 欢迎界面设计 3.1 常用终端控制函数 3.2 设置文本颜色函数 3.3 设置光标位置函数 3.4 绘制字符画(蛇) 3.5 欢迎界面函 ...

  3. Android快乐贪吃蛇游戏实战项目开发教程-01项目概述与目录

    一.项目简介 贪吃蛇是一个很经典的游戏,也很适合用来学习.本教程将和大家一起做一个Android版的贪吃蛇游戏. 我已经将做好的案例上传到了应用宝,无病毒.无广告,大家可以放心下载下来把玩一下.应用宝 ...

  4. WebGL实现HTML5的3D贪吃蛇游戏

    js1k.com收集了小于1k的javascript小例子,里面有很多很炫很酷的游戏和特效,今年规则又增加了新花样,传统的classic类型基础上又增加了WebGL类型,以及允许增加到2K的++类型, ...

  5. 100行JS实现HTML5的3D贪吃蛇游戏

    js1k.com收集了小于1k的javascript小例子,里面有很多很炫很酷的游戏和特效,今年规则又增加了新花样,传统的classic类型基础上又增加了WebGL类型,以及允许增加到2K的++类型, ...

  6. 「JavaScript」手起刀落-一起来写经典的贪吃蛇游戏

    回味 小时候玩的经典贪吃蛇游戏我们印象仍然深刻,谋划了几天,小时候喜欢玩的游戏,长大了终于有能力把他做出来(从来都没有通关过,不知道自己写的程序,是不是能通关了...),好了,闲话不多谈,先来看一下效 ...

  7. Love2D游戏引擎制作贪吃蛇游戏

    代码地址如下:http://www.demodashi.com/demo/15051.html Love2D游戏引擎制作贪吃蛇游戏 内附有linux下的makefile,windows下的生成方法请查 ...

  8. AI贪吃蛇前瞻——基于Dijkstra算法的最短路径问题

    在贪吃蛇流程结构优化之后,我又不满足于亲自操刀控制这条蠢蠢的蛇,干脆就让它升级成AI,我来看程序自己玩,哈哈. 一.Dijkstra算法原理 作为一种广为人知的单源最短路径算法,Dijkstra用于求 ...

  9. Qt 学习之路 2(34):贪吃蛇游戏(4)

    Qt 学习之路 2(34):贪吃蛇游戏(4) 豆子 2012年12月30日 Qt 学习之路 2 73条评论 这将是我们这个稍大一些的示例程序的最后一部分.在本章中,我们将完成GameControlle ...

随机推荐

  1. 在CentOS上安装ZooKeeper集群

    一共准备3个CentOS虚拟机 172.16.9.194 172.16.9.195 172.16.9.196 上传zookeeper-3.3.6.tar.gz到服务器并解压,3台服务器的目录结构如下 ...

  2. LINUX 命令行编辑快捷键

    转自:http://www.cnblogs.com/edwardlost/archive/2012/07/27/2611536.html 删除 ctrl + d 删除光标所在位置上的字符相当于VIM里 ...

  3. PHP弹出提示框并跳转到新页面即重定向到新页面

    本文为大家介绍下使用PHP弹出提示框并跳转到新页面,也就是大家所认为的重定向,下面的示例大家可以参考下   这两天写一个demo,需要用到提示并跳转,主要页面要求不高,觉得没必要使用AJAX,JS等, ...

  4. XMAL语法系列之-(2)---WPF控件继承图

    WPF控件继承图 1 FrameworkElement 1.1 Panel(面板类元素) 1.1.1 Canvas 1.1.2 DockPanel 1.1.3 Grid 1.1.4 TabPanel ...

  5. 用Javascript获取页面元素的位置

    制作网页的过程中,你有时候需要知道某个元素在网页上的确切位置. 下面的教程总结了Javascript在网页定位方面的相关知识. 一.网页的大小和浏览器窗口的大小 首先,要明确两个基本概念. 一张网页的 ...

  6. STM32F103xx bxCAN(Basic Extended CAN) 滤波机制

    一.背景 最近一个项目需要使用STM32F103xx实现CAN通信,而CAN总线的消息滤波在各个MCU上有不同机制, 譬如,SJA1000为标识符位屏蔽滤波机制,NXP的LPC17xx系列为标识符列表 ...

  7. UI第二节——UIButton详解

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launc ...

  8. r8 - ASC 41(俄罗斯多校)

    1 今天干的俄罗斯的一场多校,被虐哭啊,就做出两题. 2 3 4 5 6 7 Gym 100496D Data Mining 8 题目讲得是给你一串数字,然后给你i,p,表示从第i开始,对这串数离散话 ...

  9. PHP array_multisort() 函数详解 及 二维数组排序(模拟数据表记录按字段排序)

    一.先看最简单的情况. 有两个数组: $arr1 = array(1, 9, 5); $arr2 = array(6, 2, 4); array_multisort($arr1, $arr2); pr ...

  10. jQuery的$.ajax示例

    $.ajax({ url: 'index.php?module=products&submod=product_experience_manage&method=ajaxGetSele ...