小项目特供 贪吃蛇游戏(基于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
小项目特供 贪吃蛇游戏(基于C语言)的更多相关文章
- 基于React的贪吃蛇游戏的设计与实现
代码地址如下:http://www.demodashi.com/demo/11818.html 贪吃蛇小游戏(第二版) 一年半前层用react写过贪吃蛇小游戏https://github.com/ca ...
- 【C语言项目】贪吃蛇游戏(上)
目录 00. 目录 01. 开发背景 02. 功能介绍 03. 欢迎界面设计 3.1 常用终端控制函数 3.2 设置文本颜色函数 3.3 设置光标位置函数 3.4 绘制字符画(蛇) 3.5 欢迎界面函 ...
- Android快乐贪吃蛇游戏实战项目开发教程-01项目概述与目录
一.项目简介 贪吃蛇是一个很经典的游戏,也很适合用来学习.本教程将和大家一起做一个Android版的贪吃蛇游戏. 我已经将做好的案例上传到了应用宝,无病毒.无广告,大家可以放心下载下来把玩一下.应用宝 ...
- WebGL实现HTML5的3D贪吃蛇游戏
js1k.com收集了小于1k的javascript小例子,里面有很多很炫很酷的游戏和特效,今年规则又增加了新花样,传统的classic类型基础上又增加了WebGL类型,以及允许增加到2K的++类型, ...
- 100行JS实现HTML5的3D贪吃蛇游戏
js1k.com收集了小于1k的javascript小例子,里面有很多很炫很酷的游戏和特效,今年规则又增加了新花样,传统的classic类型基础上又增加了WebGL类型,以及允许增加到2K的++类型, ...
- 「JavaScript」手起刀落-一起来写经典的贪吃蛇游戏
回味 小时候玩的经典贪吃蛇游戏我们印象仍然深刻,谋划了几天,小时候喜欢玩的游戏,长大了终于有能力把他做出来(从来都没有通关过,不知道自己写的程序,是不是能通关了...),好了,闲话不多谈,先来看一下效 ...
- Love2D游戏引擎制作贪吃蛇游戏
代码地址如下:http://www.demodashi.com/demo/15051.html Love2D游戏引擎制作贪吃蛇游戏 内附有linux下的makefile,windows下的生成方法请查 ...
- AI贪吃蛇前瞻——基于Dijkstra算法的最短路径问题
在贪吃蛇流程结构优化之后,我又不满足于亲自操刀控制这条蠢蠢的蛇,干脆就让它升级成AI,我来看程序自己玩,哈哈. 一.Dijkstra算法原理 作为一种广为人知的单源最短路径算法,Dijkstra用于求 ...
- Qt 学习之路 2(34):贪吃蛇游戏(4)
Qt 学习之路 2(34):贪吃蛇游戏(4) 豆子 2012年12月30日 Qt 学习之路 2 73条评论 这将是我们这个稍大一些的示例程序的最后一部分.在本章中,我们将完成GameControlle ...
随机推荐
- ng指令之 ng-repeat 篇
1>数据绑定 ng-repeat可以绑定数组和JSON对象数据.从下图可以看出控制器的scope()函数得到的对象与controller('ctrlName',['$scope',fun ...
- 几种常用的JS类定义方法(转)
// 方法1 对象直接量 var obj1 = { v1 : "", get_v1 : function() { return this.v1; }, set_v1 : funct ...
- 来自 Google 的 R 语言编码风格指南
来自 Google 的 R 语言编码风格指南R 语言是一门主要用于统计计算和绘图的高级编程语言. 这份 R 语言编码风格指南旨在让我们的 R 代码更容易阅读.分享和检查. 以下规则系与 Google ...
- 开源一个动态解析protobuf的工具
好久没写博客了,主要是这一年技术没啥长进都打杂了,还有就是生活琐事越来越多,人也越来越懒了…… 之前项目中用到了Protobuf,然后测试发现这玩意不好测,总不能每次定个协议或者改下都要编译Java代 ...
- myeclipse的项目导入到eclipse下,com.sun.org.apache.commons.beanutils.BeanUtils不能导入
com.sun.org.apache.commons.beanutils.BeanUtils这个包不能引入了怎么办自己下了个org.apache.commons的jar包了之后,改成import or ...
- 跨域攻击xss
要完全防止跨域攻击是很难的,对于有些站点是直接 拦截跨域的访问,在你从本站点跳转到其他站点时提醒,这算是一种手段吧. 而跨域攻击的发起就是在代码(包括html,css,js或是后台代码,数据库数据)里 ...
- LUXURY 7
A.Little Pony and Expected Maximum Time Limit:1000MS Memory Limit:262144KB 64bit IO Format:% ...
- cf.301.D. Bad Luck Island(dp + probabilities)
D. Bad Luck Island time limit per test 2 seconds memory limit per test 256 megabytes input standard ...
- (:: operator)作用域限定符的几种使用
一.(:: operator)解决局部变量与全局变量重名问题 ; int main() { ; cout<<var<<endl;//local variable cout< ...
- C\C++ sizeof 陷阱&&总结
今天使用动态数组,本来想通过sizeof 获取动态数据,结果出现了错误. 先对自己做个测试,能做出下面这个题目,并做出合理解释,可以不用往下看了. ][]; cout<< cout< ...