读万卷书,行万里路——木子成
/***********************************************
map数组:二维矩阵值-1为游戏墙
map数组:二维矩阵值1为蛇头
map数组:二维矩阵值2为蛇身
map数组:二维矩阵值3为食物
程序同一运行多次游戏时会暂停3秒
吃到一个食物,蛇移动速度加快,最快速度有阈值
方向键英文小写输入有效
屏幕最大化体验最佳
上:w、下:s、左:a、右:d
暂停:q、退出游戏
*************************************************/
main.c
#include<windows.h>
void pr_map(); //打印墙
void pr_startG(); //打印游戏开始界面
void deal_key(); //处理按键响应
void init_map(); //初始化游戏数据
void wait_start();
char Pause = 0; //游戏暂停开关
char GameStart = 0; //撞墙标识
void main()
{
init_game(); //初始化游戏数据
while (1)
if (!GameStart) //游戏未开始界面
{
pr_start(); //打印游戏开始界面
wait_start();
}
else //游戏开始界面
{
deal_key(); //响应按键
if (!Pause)
{
pr_game(); //打印游戏界面
update_snake();//更新地图
}
}
}
init.c
#include<time.h>
#include<stdlib.h>
#define up 'w'
#define down 's'
#define left 'a'
#define right 'd'
#define M 24
#define snake_size 3
int map[M][M];
extern char dir_key;
extern char down_key;
extern int speed;
extern int score;
void update_food();
typedef struct Snakes
{
int x;
int y;
struct Snakes* next;
}snake;
snake* head;
//初始化地图
void init_game()
{
snake* p = (snake*)malloc(sizeof(snake));
head = (snake*)malloc(sizeof(snake));
p = head;
srand((int)time(NULL)); //女娲在此播下随机种子
//蛇头位置
int i, j;
int x = rand() % (M / 2) + 3;
int y = rand() % (M / 2) + 3;
//循环进行游戏初始化
for (i = 0; i < M; i++)
for (j = 0; j < M; j++)
map[i][j] = 0;
speed = 200;
score = 0;
//食物总在蛇头右下方
update_food();
//随机贪食蛇位置、方向
if (x < y) //蛇身横向
{
for (i = 0; i < snake_size; i++)
if (i == 0)
{
map[x][y] = 1;
head->x = x;
head->y = y;
}
else
{
map[x - i][y] = 2;
snake* q = (snake*)malloc(sizeof(snake));
p->next = q;
q->x = x - i;
q->y = y;
p = q;
p->next = NULL;
}
dir_key = right; //初始化蛇移动方向
}
else //蛇身纵向
{
for (i = 0; i < snake_size; i++)
if (i == 0)
{
map[x][y] = 1;
head->x = x;
head->y = y;
}
else
{
map[x][y - i] = 2;
snake* q = (snake*)malloc(sizeof(snake));
p->next = q;
q->x = x;
q->y = y - i;
p = q;
p->next = NULL;
}
dir_key = down;
}
//标记游戏墙,数组外围一圈
for (i = 0; i < M; i++)
for (j = 0; j < M; j++)
if (i == 0 || i == M - 1 || j == 0 || j == M - 1)
map[i][j] = -1;
}
function.c
#include<stdlib.h>
#include<conio.h>
#include<windows.h>
#define up 'w'
#define down 's'
#define left 'a'
#define right 'd'
#define stop 'q'
#define out 'p'
#define M 24 //游戏地图尺寸
void pr_map();
void init_game();
typedef struct Snakes
{
int x;
int y;
struct Snakes* next;
}snake;
extern int map[M][M];
extern snake* head;
extern char GameStart;
extern char Pause;
char key[4] = { up, down, left, right }; //方便处理蛇移动是否反向,反向不响应,并且游戏正常
char dir_key;
char down_key;
int score = 0; //游戏得分
int speed = 200; //蛇移动速度
//移动光标
void gotoxy(int x, int y)
{
COORD pos;
HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
pos.X = x;
pos.Y = y;
SetConsoleCursorPosition(hOutput, pos);
// 隐藏光标
CONSOLE_CURSOR_INFO cursor;
cursor.bVisible = FALSE;
cursor.dwSize = sizeof(cursor);
SetConsoleCursorInfo(hOutput, &cursor);
}
//添加食物
void update_food()
{
int x, y;
while (1)
{
x = 1 + rand() % (M - 2);
y = 1 + rand() % (M - 2);
if (map[x][y] == 0)
{
map[x][y] = 3;
break;
}
}
}
//头部前进
void go_key()
{
snake* new_head = (snake*)malloc(sizeof(snake)); //分配存储空间
map[head->x][head->y] = 2; //头部变身体
switch (dir_key)
{
case up:
new_head->x = head->x;
new_head->y = head->y - 1; break;
case down:
new_head->x = head->x;
new_head->y = head->y + 1; break;
case left:
new_head->x = head->x - 1;
new_head->y = head->y; break;
case right:
new_head->x = head->x + 1;
new_head->y = head->y; break;
}
if (map[new_head->x][new_head->y] == 3) //吃掉食物
{
update_food();
score += 10;
speed = (speed < 100) ? speed + 0 : speed - 50; //加快速度
}
new_head->next = head;
head = new_head;
map[head->x][head->y] = 1; //标记头部
Sleep(speed);
}
//消除尾巴
void cat_tail()
{
snake* tail = (snake*)malloc(sizeof(snake));
tail = head;
while (tail->next->next != NULL) //下一节的下一节身体存在
tail = tail->next;
map[tail->next->x][tail->next->y] = 0; //消除尾巴(头部加一方式前进)
free(tail->next); //释放内存
tail->next = NULL; //尾部结构指向空,方便寻找
}
//更新蛇的位置
void update_snake()
{
switch (dir_key)
{
case up:
if (map[head->x][head->y - 1] == 0 || map[head->x][head->y - 1] == 3)
{
if (map[head->x][head->y - 1] == 0) //1----如果没有吃到食物将消除尾巴
cat_tail(); //1、2顺序勿换,head更新,cat_tail()易失效
go_key(); //2----头部前进
}
else if (map[head->x][head->y - 1] == -1 || map[head->x][head->y - 1] == 2)
{
GameStart = 0;
break;
}
break;
case down:
if (map[head->x][head->y + 1] == 0 || map[head->x][head->y + 1] == 3)
{
if (map[head->x][head->y + 1] == 0)
cat_tail();
go_key();
}
else if (map[head->x][head->y + 1] == -1 || map[head->x][head->y + 1] == 2)
{
GameStart = 0;
break;
}
break;
case left:
if (map[head->x - 1][head->y] == 0 || map[head->x - 1][head->y] == 3)
{
if (map[head->x - 1][head->y] == 0)
cat_tail();
go_key();
}
else if (map[head->x - 1][head->y] == -1 || map[head->x - 1][head->y] == 2)
{
GameStart = 0;
break;
}
break;
case right:
if (map[head->x + 1][head->y] == 0 || map[head->x + 1][head->y] == 3)
{
if (map[head->x + 1][head->y] == 0)
cat_tail();
go_key();
}
else if (map[head->x + 1][head->y] == -1 || map[head->x + 1][head->y] == 2)
{
GameStart = 0;
break;
}
break;
}
}
//处理按键
void deal_key()
{
if (_kbhit())
{
switch (down_key = _getch())
{
case up:
if (dir_key == key[1]) //反向移动指令不生效
break;
dir_key = down_key; //无论此指令是否意味着撞墙,交由update_snake()函数处理
break;
case down:
if (dir_key == key[0])
break;
dir_key = down_key;
break;
case left:
if (dir_key == key[3])
break;
dir_key = down_key;
break;
case right:
if (dir_key == key[2])
break;
dir_key = down_key;
break;
case out:
exit(0);
}
if (down_key == stop)
{
if (Pause == 0)
Pause = 1;
else
Pause = 0;
}
}
}
//等待用户按任意键开始游戏
void wait_start()
{
while (1) //等待用户按任意键开始游戏
if (_kbhit())
{
GameStart = 1; //游戏开始开关打开
break;
}
pr_map(); //打印地图
init_game(); //同一运行程序,游戏多次进行时初始化游戏数据
}
print.c
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
#include<windows.h>
#define M 24
extern map[M][M];
extern GameStart;
extern score;
void gotoxy(int x, int y);
//打印得分
void pr_score()
{
if(score / 100000000 >= 1) //多判断结构意在保证得分显示居中显示框
{
gotoxy(45 + 21, 4);
printf("%d", score);
}
else if (score/1000000>=1)
{
gotoxy(45 + 22, 4);
printf("%d", score);
}
else if (score / 10000 >= 1)
{
gotoxy(45 + 23, 4);
printf("%d", score);
}
else if (score / 100 >= 1)
{
gotoxy(45 + 23, 4);
printf("%d", score);
}
else
{
gotoxy(45 + 24, 4);
printf("\033[40;36m%d\033[0m", score);
}
system("color 0E"); //这里其实是一个bug,但是无意间发现此法可让蛇身、食物、得分显示闪烁
}
//打印地图
void pr_map()
{
system("cls"); //清除此时屏幕上显示的游戏提示
system("color 0E"); //设置屏幕颜色
for (int i = 0; i < M; i++)
for (int j = 0; j < M; j++)
{
if (map[i][j] == -1)
{
gotoxy(i * 2 + 45, j + 5);
printf("■");
}
}
gotoxy(45 + 16, 4);
printf("■");
gotoxy(45 + 32, 4);
printf("■");
gotoxy(45 + 16, 3);
printf("■■■■■■■■■");
}
//打印游戏界面
void pr_game()
{
for (int i = 0; i < M; i++)
for (int j = 0; j < M; j++)
{
if (map[i][j] == 0)
{
gotoxy(i * 2 + 45, j + 5);
printf(" ");
}
else if (map[i][j] == 1)
{
gotoxy(i * 2 + 45, j + 5);
printf("\033[40;33m●\033[0m");
}
else if (map[i][j] == 2)
{
gotoxy(i * 2 + 45, j + 5);
printf("○");
}
else if (map[i][j] == 3)
{
gotoxy(i * 2 + 45, j + 5);
printf("\033[40;31m⊙\033[0m");
}
}
pr_score();
}
//打印游戏未开始界面
void pr_start()
{
pr_map();
if(score!=0)
pr_score();
gotoxy(61, 11);
printf("▁▁▁▁▁▁▁▁");
gotoxy(61, 12);
printf("▏请切换最大屏 ▏");
gotoxy(61, 13);
printf("▔▔▔▔▔▔▔▔");
gotoxy(57, 14);
printf("▁▁▁▁▁▁▁▁▁▁▁▁");
gotoxy(57, 15);
printf("▏请切换英文小写输入法 ▏");
gotoxy(57, 16);
printf("▔▔▔▔▔▔▔▔▔▔▔▔");
gotoxy(53, 17);
printf("▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁");
gotoxy(53, 18);
printf("▏上: w ▏下: s ▏左: a ▏右: d ▏");
gotoxy(53, 19);
printf("▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔");
gotoxy(53, 20);
printf("▏暂停:q▏ ▏退出:p▏");
gotoxy(53, 21);
printf("▔▔▔▔ ▔▔▔▔");
gotoxy(58, 25);
printf("▁▁▁▁▁▁▁▁▁▁▁");
gotoxy(58, 26);
printf("▏请按任意键开始游戏 ▏");
gotoxy(58, 27);
printf("▔▔▔▔▔▔▔▔▔▔▔");
Sleep(3000); //防止蛇撞墙后,用户按任意键立马继续游戏
}