Skip to content

Instantly share code, notes, and snippets.

@Mitscherlich
Created December 1, 2022 14:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Mitscherlich/97759729b9ea15d59961b4cd899a6d1b to your computer and use it in GitHub Desktop.
Save Mitscherlich/97759729b9ea15d59961b4cd899a6d1b to your computer and use it in GitHub Desktop.
snake in windows console
#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