Created
December 1, 2022 14:47
-
-
Save Mitscherlich/97759729b9ea15d59961b4cd899a6d1b to your computer and use it in GitHub Desktop.
snake in windows console
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <time.h> | |
#include <windows.h> | |
#include <stdlib.h> | |
#include <conio.h> | |
#pragma warning(disable : 4996) // 关闭警告 | |
#define U 1 | |
#define D 2 | |
#define L 3 | |
#define R 4 | |
void file_out(); | |
void tips(); | |
void printscore(); | |
void createfood(); | |
/*********************** | |
@func: 蛇的每个节点 | |
***********************/ | |
typedef struct snake | |
{ | |
int x; | |
int y; | |
struct snake *next; | |
} snake; | |
/*********************** | |
@func: 食物的位置信息 | |
***********************/ | |
typedef struct foodtype | |
{ | |
int x; | |
int y; | |
} foodtype; | |
int score = 0; // 总得分 | |
int add = 10; // 每次增加的分数 | |
int HighScore = 0; // 最高分 | |
int status = R; // 蛇前进的状态 | |
int sleeptime = 150; // 每次运行的时间间隔,控制速度 | |
snake *head; // 蛇头 | |
foodtype *food; // 食物 | |
snake *q; // 遍历蛇时使用的指针 | |
int gameover = 0; // 游戏结束的状态, 撞墙, 咬到自己,主动退出游戏 | |
HANDLE hOut; // 控制台句柄 | |
/* 黑色 0 深蓝 1 深绿 2 深蓝绿 3 深红 4 紫 5 暗绿 6 | |
白 7 灰 8 亮蓝 9 亮绿 10 亮蓝绿 11 红12 粉 13 | |
黄 14 亮白 15 | |
*/ | |
/******************* | |
@func:设置控制台的颜色 | |
@param bg: 背景色 | |
@param fg: 前景色 | |
*******************/ | |
void color(unsigned char bg, unsigned char fg) | |
{ | |
WORD wColor = ((bg & 0x0F) << 4 + (fg & 0x0F)); | |
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), wColor); | |
} | |
/************************ | |
@func: 设置文字颜色 | |
************************/ | |
void textcolor(char fg) | |
{ | |
// 恢复原有颜色 | |
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | | |
FOREGROUND_GREEN | | |
FOREGROUND_BLUE); | |
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), fg); | |
} | |
/******************* | |
@func:设置光标的位置 | |
@param x | |
@param y | |
*******************/ | |
void gotoxy(int x, int y) | |
{ | |
COORD c; | |
c.X = x; | |
c.Y = y; | |
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), c); | |
} | |
/******************* | |
@func:不显示控制台光标 | |
*******************/ | |
void close_cur() | |
{ | |
hOut = GetStdHandle(STD_OUTPUT_HANDLE); //获得输出句柄 | |
CONSOLE_CURSOR_INFO CursorInfo; | |
GetConsoleCursorInfo(hOut, &CursorInfo); //获取控制台光标信息 | |
CursorInfo.bVisible = 0; //隐藏控制台光标 | |
SetConsoleCursorInfo(hOut, &CursorInfo); //设置控制台光标状态 | |
} | |
/******************* | |
@func: 创建游戏地图 | |
0 2 56 (58 59) // 每个块的w: 2个字符,h: 一个字符 | |
1 | |
25 | |
(26) | |
*******************/ | |
void createmap() | |
{ | |
int i, j; | |
color(5, 0); // 深紫色边框 | |
gotoxy(0, 0); | |
for (i = 0; i < 60; i++) | |
printf(" "); //绘制上边框 | |
gotoxy(0, 26); | |
for (i = 0; i < 60; i++) | |
printf(" "); //绘制下边框 | |
for (i = 1; i < 26; i++) | |
{ //绘制左右边框 | |
gotoxy(0, i); | |
printf(" "); | |
gotoxy(58, i); | |
printf(" "); | |
} | |
color(3, 0); | |
for (i = 2; i < 57; i += 2) | |
{ // x : 2 4 6 ... 56 | |
for (j = 1; j < 26; j++) | |
{ // y : 1 2 3 ... 25 | |
gotoxy(i, j); | |
printf(" "); | |
} | |
} | |
tips(); | |
} | |
/************************** | |
@func: 游戏界面右侧的得分和小提示 | |
**************************/ | |
void tips() | |
{ | |
gotoxy(70, 4); | |
textcolor(11); | |
printf("最高记录: %d", HighScore); | |
textcolor(13); | |
gotoxy(75, 11); | |
printf("小提示"); | |
gotoxy(62, 13); | |
textcolor(6); | |
printf("++------------------------------++"); | |
gotoxy(62, 25); | |
printf("++------------------------------++"); | |
textcolor(3); | |
gotoxy(66, 14); | |
printf("每个食物的得分: %d分", add); | |
gotoxy(66, 16); | |
printf("不能撞墙,不能咬到自己"); | |
gotoxy(66, 18); | |
printf("用 ↑↓← →分别控制移动"); | |
gotoxy(66, 20); | |
printf("F1: 加速 F2: 减速"); | |
gotoxy(66, 22); | |
printf("space: 暂停游戏"); | |
gotoxy(66, 24); | |
printf("esc: 退出游戏"); | |
printscore(); | |
} | |
/******************* | |
@func: 绘制得分 | |
*******************/ | |
void printscore() | |
{ | |
gotoxy(72, 6); | |
textcolor(14); | |
printf("得分: %d", score); | |
} | |
/******************** | |
@func: 从save.txt中读取最高分 | |
********************/ | |
void file_out() | |
{ | |
FILE *fp; | |
fp = fopen("save.txt", "a+"); | |
fscanf(fp, "%d", &HighScore); | |
fclose(fp); | |
} | |
/**************************** | |
@func: 初始化蛇, 蛇的尾部坐标为: 24,5 | |
****************************/ | |
void initsnake() | |
{ | |
snake *tail; | |
int i; | |
tail = (snake *)malloc(sizeof(snake)); // 动态内存分配 | |
tail->x = 24; | |
tail->y = 5; | |
tail->next = NULL; | |
for (i = 1; i <= 4; i++) | |
{ | |
head = (snake *)malloc(sizeof(snake)); | |
head->next = tail; | |
head->x = 24 + 2 * i; | |
head->y = 5; | |
tail = head; | |
} | |
while (tail != NULL) | |
{ | |
gotoxy(tail->x, tail->y); | |
color(14, 0); | |
printf(" "); | |
tail = tail->next; | |
} | |
createfood(); | |
} | |
/*************** | |
@func: 随机出现食物 | |
1. 食物不能和蛇身重合 | |
2. 食物的x值坐标要为 偶数 | |
3. 食物要在边界内 | |
***************/ | |
void createfood() | |
{ | |
int ifok = 0, x = 0, y = 0; | |
while (!ifok) | |
{ | |
x = (rand() % 28 + 1) * 2; // 为偶数 | |
y = rand() % 25 + 1; | |
q = head; | |
while (q->next != NULL) | |
{ | |
if (q->x == x && q->y == y) | |
break; // 判断蛇身是否和食物重合 | |
q = q->next; | |
} | |
if (q->next == NULL) | |
ifok = 1; | |
} | |
gotoxy(x, y); | |
food->x = x; | |
food->y = y; | |
color(12, 0); | |
printf(" "); | |
} | |
/***************** | |
@func: 判断是否咬到自己 | |
蛇头的坐标值和蛇身上的任意坐标值重合 | |
*****************/ | |
int biteself() | |
{ | |
q = head->next; | |
while (q != NULL) | |
{ | |
if (q->x == head->x && q->y == head->y) | |
{ | |
return 1; | |
} | |
q = q->next; | |
} | |
return 0; | |
} | |
/********************** | |
@func: 撞墙的情况 | |
**********************/ | |
int cantcrosswall() | |
{ | |
if (head->x < 2 || head->x > 56 || head->y < 1 || head->y > 25) | |
{ | |
return 1; | |
} | |
return 0; | |
} | |
/************** | |
@func: 蛇加速前进 | |
两种情况蛇会加速前进: 蛇吃到食物 和按<F1>键 | |
加速时时 间间隔减少10 得分加2 | |
***************/ | |
void speedup() | |
{ | |
if (sleeptime >= 50) | |
{ | |
sleeptime = sleeptime - 10; | |
add = add + 2; | |
} | |
} | |
/***************** | |
@func: <F2> 蛇减速前进 | |
时间间隔 加 10 , 得分值 比之间减少 2分 | |
得分值 最少为 1 | |
*****************/ | |
void speeddown() | |
{ | |
if (sleeptime < 200) | |
{ | |
sleeptime += 10; | |
add -= 2; | |
if (add < 1) | |
add = 1; | |
} | |
} | |
/*********************** | |
@func: 吃到了食物,移动后最后一块不擦除 | |
***********************/ | |
void eatfood(snake *head) | |
{ | |
while (head != NULL) | |
{ | |
gotoxy(head->x, head->y); | |
color(14, 0); | |
printf(" "); | |
head = head->next; | |
} | |
score += add; | |
speedup(); | |
createfood(); | |
} | |
/************************** | |
@func: 没有吃到食物,移动后最后一块要擦除 | |
**************************/ | |
void donteatfood(snake *head) | |
{ | |
while (head->next->next != NULL) | |
{ | |
gotoxy(head->x, head->y); | |
color(14, 0); | |
printf(" "); | |
head = head->next; | |
} | |
//擦除最后一块 | |
gotoxy(head->next->x, head->next->y); | |
color(3, 0); | |
printf(" "); | |
free(head->next); // 释放原本最后一位的指针 | |
head->next = NULL; | |
} | |
/********************* | |
@func: 控制移动 | |
**********************/ | |
void snakemove() | |
{ | |
snake *nexthead; | |
nexthead = (snake *)malloc(sizeof(snake)); | |
nexthead->next = head; | |
if (status == U) | |
{ | |
nexthead->x = head->x; | |
nexthead->y = head->y - 1; | |
} | |
else if (status == D) | |
{ | |
nexthead->x = head->x; | |
nexthead->y = head->y + 1; | |
} | |
else if (status == R) | |
{ | |
nexthead->x = head->x + 2; | |
nexthead->y = head->y; | |
} | |
else if (status == L) | |
{ | |
nexthead->x = head->x - 2; | |
nexthead->y = head->y; | |
} | |
if (nexthead->x == food->x && nexthead->y == food->y) | |
{ // 下一个位置上有食物 | |
eatfood(nexthead); | |
printscore(); | |
} | |
else | |
{ | |
donteatfood(nexthead); | |
} | |
head = nexthead; | |
if (cantcrosswall()) | |
{ | |
gameover = 1; | |
} | |
if (biteself() == 1) | |
{ // 判断是否咬到自己 | |
gameover = 2; | |
} | |
} | |
/********************* | |
@func:键盘按键控制,蛇头不能转向与前进方向相反的方向 | |
*********************/ | |
void keyboardControl() | |
{ | |
while (!gameover) | |
{ | |
if (GetAsyncKeyState(VK_UP) & 0x8000 && status != D) | |
{ | |
status = U; | |
} | |
if (GetAsyncKeyState(VK_DOWN) & 0x8000 && status != U) | |
{ | |
status = D; | |
} | |
if (GetAsyncKeyState(VK_LEFT) & 0x8000 && status != R) | |
{ | |
status = L; | |
} | |
if (GetAsyncKeyState(VK_RIGHT) & 0x8000 && status != L) | |
{ | |
status = R; | |
} | |
if (GetAsyncKeyState(VK_SPACE) & 0x8000) | |
{ | |
while (1) | |
{ | |
Sleep(300); | |
if (GetAsyncKeyState(VK_SPACE) & 0x8000) | |
{ | |
break; | |
} | |
} | |
} | |
if (GetAsyncKeyState(VK_ESCAPE) & 0x8000) | |
{ | |
gameover = 3; | |
} | |
if (GetAsyncKeyState(VK_F1) & 0x8000) | |
{ | |
speedup(); | |
} | |
if (GetAsyncKeyState(VK_F2) & 0x8000) | |
{ | |
speeddown(); | |
} | |
Sleep(sleeptime); | |
snakemove(); | |
} | |
} | |
/****************** | |
@func: 存储最高分 | |
*******************/ | |
void file_in() | |
{ | |
FILE *fp; | |
fp = fopen("save.txt", "w+"); | |
fprintf(fp, "%d", score); | |
fclose(fp); | |
} | |
/********************** | |
@func: 游戏结束 | |
**********************/ | |
void endgame() | |
{ | |
int i, j; | |
textcolor(4); | |
system("cls"); | |
gotoxy(30, 5); | |
for (i = 0; i < 40; i++) | |
printf("+"); | |
gotoxy(30, 20); | |
for (i = 0; i < 40; i++) | |
printf("+"); | |
for (i = 6; i < 20; i++) | |
{ | |
gotoxy(30, i); | |
printf("+"); | |
gotoxy(69, i); | |
printf("+"); | |
} | |
textcolor(15); | |
gotoxy(45, 8); | |
printf("游戏结束!"); | |
if (gameover == 1) | |
{ | |
gotoxy(43, 10); | |
printf("您因撞墙而死!!"); | |
} | |
else | |
{ | |
gotoxy(41, 10); | |
printf("您因咬到自己而死!!"); | |
} | |
gotoxy(45, 12); | |
printf("得分: %d", score); | |
if (score > HighScore) | |
{ | |
gotoxy(42, 14); | |
printf("您已创新的记录!"); | |
file_in(); | |
} | |
else | |
{ | |
gotoxy(40, 14); | |
printf("您距离最高记录还差:%d分", HighScore - score); | |
} | |
} | |
int main() | |
{ | |
close_cur(); | |
srand((unsigned int)time(NULL)); | |
food = (foodtype *)malloc(sizeof(foodtype)); | |
system("mode con cols=98 lines=27"); | |
file_out(); | |
createmap(); | |
initsnake(); | |
keyboardControl(); | |
endgame(); | |
system("pause >nul"); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment