C语言贪吃蛇
1、思路
- 贪吃蛇需要游戏的方框,那么方框怎么在控制台上画出来呢?
其实控制台也是有坐标的,将光标移动到特定的位置就可以在特定的位置输出了,利用函数SetConsoleCursorPosition将光标设定到我们想要的地方就可以画出方框了。其实蛇与食物都是这样画出来的。 - 怎样移动蛇呢?
假设用int a[10]表示蛇的位置a[0] 为蛇的尾巴,a[9]为舌头,移动的时候只需要把a[1]—a[9] 复制给a[0]—-a[8],然后a[9]的值在移动方向上左响应的调整,例如蛇向右边移动,则y轴坐标不变,x轴坐标增加一个格子 - 和按动方向键转变蛇的移动方向呢?
其实这和2一样,两者都要一个标志,标志蛇移动的方向。当按动方向键时改变这个标志,然后移动的时候舌头就可以做相应的改变。
2、函数分析
/*光标移到指定位置*/
void gotoXY(HANDLE hOut, int x, int y);
/*设置文本的颜色*/
void setTextColor(int i);
/*游戏环境设置*/
void setFrame();
/*画方框*/
void drawFrame();
/*显示信息*/
void showInformation();
/*打印食物*/
void printFood();
/*判断撞墙*/
int collsionWall();
/*判断穿墙*/
void throughWall();
/*打印蛇*/
void printSnake();
/*光标移到指定位置*/
void initSnake();
/*吃食物*/
void eatFood();
/*移动蛇的坐标*/
void moveSnake();
//蛇头接触蛇身蛇死亡返回 1
int isDied();
/*游戏结束*/
int gameover();
主函数:
int main()
{
srand(time(NULL));
do{
setFrame();
drawFrame();
showInformation();
initSnake();
printFood();
while (1){
g_acc = 0;
showInformation();
if (_kbhit()){
if (keyPush()){
break;
}
}
moveSnake();
eatFood();
printSnake();
if (isDied()){
break;
}
if (g_acc == 0){
Sleep(g_snake.speed);
}
else{
Sleep(100);
}
}
} while (gameover());
return 0;
}
3、代码
#include <stdio.h>
#include <windows.h>
#include <conio.h>
#include <time.h>
#include <math.h>
#define LEFT 4
#define TOP 3
#define WIDTH 20
#define HEIGTH 20
#define LENGTH ((WIDTH * HEIGTH ))
#define TOUP 72
#define TODOWN 80
#define TOLEFT 75
#define TORIGHT 77
//食物的样子
const char* FOODSTYLE[] = { "※","㊣","つ","ヒ","む","ら","☆","★","□","@","\
&","#","∵","∴","∷","あ","ほ","Ю","\
¥","€","¢","£","①","③","④","Β","ǖ","ㄈ","氼","ひ","щ","╋","╳"};
const int FOODLENGTH = sizeof(FOODSTYLE)/sizeof(char*);
//蛇的样子
const char* SNAKESTYLE[] = { "○", "●", "◎", "⊙" };
const int SNAKEBODYCOUNT = sizeof(SNAKESTYLE) / sizeof(char*);
//蛇的结构
typedef struct {
int x[LENGTH];//x轴
int y[LENGTH];//y轴
int direction;//方向
int length;//蛇的长度
int count;//已经吃的食物的个数
int level;//游戏等级
int score;//游戏得分
int speed;//游戏速度
}Snake;
typedef struct {
int x, y;
}Pos;
HANDLE g_hOut;
Snake g_snake = {{0},{0},TORIGHT,3,0,1,0,500 };
Pos g_food = {0,0};
Pos g_snake_tail = { 0, 0 };
int g_acc = 0;
/*光标移到指定位置*/
void gotoXY(HANDLE hOut, int x, int y);
/*设置文本的颜色*/
void setTextColor(int i);
/*游戏环境设置*/
void setFrame();
/*画方框*/
void drawFrame();
/*显示信息*/
void showInformation();
/*打印食物*/
void printFood();
/*判断撞墙*/
int collsionWall();
/*判断穿墙*/
void throughWall();
/*打印蛇*/
void printSnake();
/*光标移到指定位置*/
void initSnake();
/*吃食物*/
void eatFood();
/*移动蛇的坐标*/
void moveSnake();
//蛇头接触蛇身蛇死亡返回 1
int isDied();
/*游戏结束*/
int gameover();
void gotoXY(HANDLE hOut, int x, int y)
{
COORD pos = { x, y };
SetConsoleCursorPosition(hOut, pos);
}
void setTextColor(int i)
{
//HANDLE Handle = GetStdHandle(STD_OUTPUT_HANDLE);
if (i == 0){
SetConsoleTextAttribute(g_hOut, BACKGROUND_GREEN | FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN);
}
else if (i == 1){
SetConsoleTextAttribute(g_hOut, BACKGROUND_GREEN | FOREGROUND_INTENSITY | FOREGROUND_RED );
}
}
void setFrame(){
system("cls");
system("color 2E");
g_hOut = GetStdHandle(STD_OUTPUT_HANDLE); //定义显示器句柄变量
COORD frame_size = { LEFT + 2 * WIDTH + WIDTH, TOP + HEIGTH + TOP };
SetConsoleScreenBufferSize(g_hOut, frame_size);
CONSOLE_CURSOR_INFO CursorInfo;
GetConsoleCursorInfo(g_hOut, &CursorInfo);//获取控制台光标信息
CursorInfo.bVisible = false; //隐藏控制台光标
SetConsoleCursorInfo(g_hOut, &CursorInfo);//设置控制台光标状态
SetConsoleTitleA("贪吃蛇");
gotoXY(g_hOut, (LEFT * 2 + WIDTH * 2)/2 - 4, TOP - 2);
printf("贪吃蛇游戏");
//CloseHandle(g_hOut);
}
void drawFrame(){
//setTextColor();
//g_hOut = GetStdHandle(STD_OUTPUT_HANDLE);
gotoXY(g_hOut, LEFT, TOP);
printf("╔");
gotoXY(g_hOut, LEFT, TOP + HEIGTH);
printf("╚");
gotoXY(g_hOut, LEFT + 2 * WIDTH, TOP);
printf("╗");
gotoXY(g_hOut, LEFT + 2 * WIDTH, TOP + HEIGTH);
printf("╝");
for (int i = 2; i < 2*WIDTH; i += 2){
gotoXY(g_hOut, LEFT + i, TOP);
printf("═");
}
for (int i = 2; i < 2 * WIDTH; i += 2){
gotoXY(g_hOut, LEFT + i, TOP + HEIGTH);
printf("═");
}
for (int i = 1; i < HEIGTH; i += 1){
gotoXY(g_hOut, LEFT, TOP+i);
printf("║");
}
for (int i = 1; i < HEIGTH; i += 1){
gotoXY(g_hOut, LEFT + 2 * WIDTH, TOP + i);
printf("║");
}
}
void showInformation(){
int inter = 10;
gotoXY(g_hOut, LEFT + 2 * WIDTH + inter, TOP + 1);
printf("游戏得分:%d", g_snake.score);
gotoXY(g_hOut, LEFT + 2 * WIDTH + inter, TOP + 3);
printf("游戏等级:%d", g_snake.level);
gotoXY(g_hOut, LEFT + 2 * WIDTH + inter, TOP + 5);
printf("食物个数:%d", g_snake.count);
gotoXY(g_hOut, LEFT + 2 * WIDTH + inter, TOP + 7);
printf("游戏速度:%d", g_snake.speed);
gotoXY(g_hOut, LEFT + 2 * WIDTH + inter, TOP + 9);
printf("Esc 退出游戏");
gotoXY(g_hOut, LEFT + 2 * WIDTH + inter, TOP + 11);
printf("长按方向键:加速");
gotoXY(g_hOut, LEFT + 2 * WIDTH + inter, TOP + 13);
printf("按s键停止,按任意键开始");
}
void printFood(){
while (1){
g_food.x = 2 * (rand() % (WIDTH - 1) + 1) + LEFT;
g_food.y = (rand() % (HEIGTH - 1) + 1) + TOP;
int i = 0;
for (; i < g_snake.length; ++i){
if (g_food.x == g_snake.x[i] &&
g_food.y == g_snake.y[i]){
break;
}
}
if (i == g_snake.length){
break;
}
}
gotoXY(g_hOut, g_food.x, g_food.y);
printf(FOODSTYLE[rand() % FOODLENGTH]);
//printf("☆");
}
int collsionWall(){
if (g_snake.y[g_snake.length - 1] <= TOP
|| g_snake.y[g_snake.length - 1] >= TOP + HEIGTH
|| g_snake.x[g_snake.length - 1] <= LEFT
|| g_snake.x[g_snake.length - 1] >= LEFT + 2 * WIDTH){
return 1;
}
return 0;
}
void throughWall(){
if (g_snake.direction == TOUP &&
g_snake.y[g_snake.length - 1] == TOP){
g_snake.y[g_snake.length - 1] = TOP + HEIGTH - 1;
}
if (g_snake.direction == TODOWN &&
g_snake.y[g_snake.length - 1] == TOP + HEIGTH){
g_snake.y[g_snake.length - 1] = TOP + 1;
}
if (g_snake.direction == TOLEFT &&
g_snake.x[g_snake.length - 1] == LEFT){
g_snake.x[g_snake.length - 1] = LEFT + 2*WIDTH - 2;
}
if (g_snake.direction == TORIGHT &&
g_snake.x[g_snake.length - 1] == LEFT + 2 * WIDTH){
g_snake.x[g_snake.length - 1] = LEFT + 2;
}
/*g_snake_tail.x = g_snake.x[0];
g_snake_tail.y = g_snake.y[0];*/
}
void eatFood(){
if ((g_snake.x[g_snake.length - 1] == g_food.x) &&
(g_snake.y[g_snake.length - 1] == g_food.y)){//吃到食物了
//蛇的长度增加1,并移动蛇的坐标
memmove_s((void*)&g_snake.x[1], g_snake.length * sizeof(int), (void*)g_snake.x, g_snake.length*sizeof(int));
memmove_s((void*)&g_snake.y[1], g_snake.length * sizeof(int), (void*)g_snake.y, g_snake.length*sizeof(int));
++g_snake.count;
++g_snake.length;
++g_snake.score;
g_snake.score = 1.4*g_snake.score;
g_snake.level = g_snake.count/5+1;
if (g_snake.speed > 100){
g_snake.speed -= 10;
}
g_snake.x[0] = g_snake_tail.x;
g_snake.y[0] = g_snake_tail.y;
printFood();
}
}
void initSnake(){
g_snake.x[0] = g_snake_tail.x = LEFT + 2;
g_snake.y[0] = g_snake_tail.y = TOP + (HEIGTH >> 1);
for (int i = 1; i < g_snake.length; ++i){
g_snake.x[i] = g_snake.x[i - 1] + 2;
g_snake.y[i] = g_snake.y[i - 1];
}
}
void printSnake(){
//setTextColor();
int i = 0;
gotoXY(g_hOut, g_snake.x[i], g_snake.y[i]);
printf(SNAKESTYLE[rand() % SNAKEBODYCOUNT]);
//putwchar(rand() % SNAKEBODYCOUNT);
for (++i; i < g_snake.length - 1; ++i){
gotoXY(g_hOut, g_snake.x[i], g_snake.y[i]);
//printf("◎");
printf(SNAKESTYLE[rand() % SNAKEBODYCOUNT]);
}
setTextColor(1);
gotoXY(g_hOut, g_snake.x[i], g_snake.y[i]);
printf("¤");
setTextColor(0);
}
void moveSnake(){
gotoXY(g_hOut, g_snake.x[0], g_snake.y[0]);
printf(" ");
g_snake_tail.x = g_snake.x[0];
g_snake_tail.y = g_snake.y[0];
memmove_s((void*)g_snake.x, (g_snake.length-1)*sizeof(int), (void*)&g_snake.x[1], (g_snake.length - 1)*sizeof(int));
memmove_s((void*)g_snake.y, (g_snake.length-1)*sizeof(int), (void*)&g_snake.y[1], (g_snake.length - 1)*sizeof(int));
switch (g_snake.direction){
case TOUP:
g_snake.y[g_snake.length - 1] -= 1;
break;
case TODOWN:
g_snake.y[g_snake.length - 1] += 1;
break;
case TOLEFT:
g_snake.x[g_snake.length - 1] -= 2;
break;
case TORIGHT:
g_snake.x[g_snake.length - 1] += 2;
break;
default:
break;
}
//throughWall();
}
int isDied(){
for (int i = g_snake.length - 2; i >= 0; --i){
if ((g_snake.x[i] == g_snake.x[g_snake.length - 1])
&& (g_snake.y[i] == g_snake.y[g_snake.length - 1])){
return 1;
}
}
return collsionWall();
}
int keyPush(){
char ch = _getch();
if (ch == 0x1B){
//fflush(stdin);
return 1;
}
if (ch == 's'){
//system("pause");
_getch();
}
if (ch == -32){
ch = _getch();
if ((ch == TOUP || ch == TODOWN || ch == TOLEFT || ch == TORIGHT)){
if (ch == TOUP && g_snake.direction == TODOWN){
return 0;
}
else if (ch == TODOWN && g_snake.direction == TOUP){
return 0;
}
else if (ch == TOLEFT && g_snake.direction == TORIGHT){
return 0;
}
else if (ch == TORIGHT && g_snake.direction == TOLEFT){
return 0;
}
g_snake.direction = ch;
Sleep(20);
g_acc = 1;
}
}
//fflush(stdin);
return 0;
}
int gameover(){
char ch = 0;
system("cls");
gotoXY(g_hOut, (LEFT * 2 + WIDTH * 2) / 2 - 4, TOP + HEIGTH / 2);
printf("GAME OVER");
Sleep(500);
system("cls");
gotoXY(g_hOut, (LEFT * 2 + WIDTH * 2) / 2 - 4, TOP + HEIGTH / 2);
printf("try again?(y/n):");
scanf_s("%c", &ch);
fflush(stdin);
if (ch == 'y' || ch == 'Y'){
//HANDLE g_hOut;
g_snake = { { 0 }, { 0 }, TORIGHT, 3, 0, 1, 0, 500 };
g_food = { 0, 0 };
g_snake_tail = { 0, 0 };
g_acc = 0;
return 1;
}
return 0;
//exit(1);
}
int main()
{
srand(time(NULL));
do{
setFrame();
drawFrame();
showInformation();
initSnake();
printFood();
while (1){
g_acc = 0;
showInformation();
if (_kbhit()){
if (keyPush()){
break;
}
}
moveSnake();
eatFood();
printSnake();
if (isDied()){
break;
}
if (g_acc == 0){
Sleep(g_snake.speed);
}
else{
Sleep(100);
}
}
} while (gameover());
return 0;
}