#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<Windows.h>
#include<conio.h>
#include<stdbool.h>
#define up 'w'
#define down 's'
#define left 'a'
#define right 'd'
void welcome(void); //欢迎界面的打印
void gotoxy(int x, int y); //光标跳转
void gotoprint(int x, int y); //光标跳转打印方格
void gotodelete(int x, int y); //光标跳转打印空格实现删除
void creatgraph(void); //地图的打印
void creatfood(void); //随机食物的打印
int clickcontrol(void); //循环主函数
void changebody(void); //用于移动变换蛇的位置
int judge(void); //判断游戏是否结束
void finish(void); //结束页面的打印
void eatfood(void); //吃到食物后的处理
typedef struct Snake { //蛇的节点声明
int x;
int y;
struct Snake* next;
}snake;
snake* head; //蛇头的全局变量
struct FOOD{
int x;
int y;
}food; //食物的结构定义
char name[20]; //用户名
int score = 0; //得分
char click = '1'; //输入储存
int main(void) //主函数负责函数调用
{
system("color 0B"); //system函数,没用过,这一步用来改变控制台字符颜色
welcome(); //先是欢迎界面
creatgraph(); //然后打印地图
creatfood(); //然后创造第一个食物
if (clickcontrol() == 0) //主要循环函数——一旦返回0就结束整个主函数
return 0;
return 0;
}
void welcome(void) //这个好说,直接跳转打印就行
{
gotoxy(10, 10);
printf("welcome to my game,注意反向即为自杀");
gotoxy(10, 12);
printf("Please enter your name:");
scanf_s("%s", name,20);
system("cls");
}
void gotoxy(int x, int y) //这个函数抄的,毕竟不会用window库
{
// 更新光标位置
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 gotoprint(int x, int y) //跳转打印方块
{
gotoxy(x, y);
printf("■");
}
void gotodelete(int x, int y) //跳转打印空格
{ //很关键的,空格要打印两个,这是因为方块实际上是一个长宽比为2:1的字符
gotoxy(x, y); //因而想要遮盖方块应该打印两个空格,不然就会得到一条弯曲不堪的蛇
printf(" ");
}
void creatgraph(void) //地图打印
{
for (int cnt = 0; cnt <= 56; cnt += 2) //x轴要留意,cnt每次+2,因为方块长度为2
{ //地图大小设置好
gotoprint(cnt, 0);
gotoprint(cnt, 26);
}
for (int cnt = 1; cnt <= 25; cnt++)
{
gotoprint(0, cnt);
gotoprint(56, cnt);
}
gotoxy(60, 10);
printf("score:%d", score);
gotoxy(60, 9);
printf("Hello %s", name);
snake* p, * q; //创建好原有蛇长
head = (snake*)malloc(sizeof(snake)); //并且分配好空间
p = (snake*)malloc(sizeof(snake));
q = (snake*)malloc(sizeof(snake));
head->x = 16;
head->y = 15;
p->x = 16;
p->y = 16;
q->x = 16;
q->y = 17;
head->next = p;
p->next = q;
q->next = NULL; //注意这个时候还不用打印蛇,打印蛇交给changebody函数
}
void creatfood(void)
{
srand((int)time(NULL)); //设置好随机数种子,用到时间函数
bool flag = false;
while (!flag) //创建食物的循环——考虑到食物创建失败
{
flag = true;
food.x = rand() % 53 + 2; //用上%来得到在的地图内的食物
food.y = rand() % 25 + 1;
if (food.x % 2 != 0)
{
food.x += 1; //若随机数x落到奇数要加1,因为方块都在偶数位上
}
snake* panduan = head; //遍历蛇身,判断食物没有直接落到蛇身上,若是,则重新创建食物
while (panduan != NULL)
{
if (food.x == panduan->x && food.y == panduan->y)
{
flag = false;
break;
}
panduan = panduan->next;
}
}
gotoxy(food.x, food.y); //循环结束,说明食物创建完成,则进行打印
printf("⊙");
}
int clickcontrol(void)
{
while (1) //循环主函数
{
if (judge() == 0) break; //每轮开始都先判断,若判断到结束,则退出循环,返回0,
if (_kbhit()) //在主函数就结束了整个函数
{ //window库里的,也是抄的,作用应该是获取缓冲区的输入
click = _getch();
}
changebody(); //调用函数
eatfood();
}
return 0;
}
void changebody(void)
{
int x = head->x;
int y = head->y;
snake* pi = head;
/*snake* new_head;
new_head = (snake*)malloc(sizeof(snake));*/ //这里注释掉的教训,不能一上来就直接分配空间,
while (pi->next->next != NULL) //不然如果出现输入不对,就会一直分配空间知道内存占满
{
pi = pi->next;
}
gotodelete(pi->next->x, pi->next->y); //遍历到蛇尾然后打印空格遮盖方块
//free(pi->next);
//pi->next = NULL;
switch (click) //switch-case函数分开情况
{
case up:
x = head->x;
y = head->y - 1;
break;
case down:
x = head->x;
y = head->y + 1;
break;
case left:
x = head->x - 2;
y = head->y;
break;
case right:
x = head->x + 2;
y = head->y;
break;
default:break;
}
if (x != head->x || y != head->y) //若蛇头坐标该表,则要创建一个新蛇头
{
snake* new_head;
new_head = (snake*)malloc(sizeof(snake)); //分配空间
new_head->next = head;
new_head->x = x;
new_head->y = y;
head = new_head; //注意把全局变量head重新定义,因为这个全局变量应该永远是蛇头
free(pi->next); //释放掉蛇尾的内存,并把蛇尾设置为NULL
pi->next = NULL;
}
gotoprint(head->x, head->y); //打印蛇头——注意这个蛇头是无论如何都要打印的,不能放进if块里面
Sleep(150); //不然会导致最开始的情况即没有任何输入的情况出错(方块被全部删完了)
} //这个Sleep函数用来调语句执行速度(延迟)
void eatfood(void)
{
if (head->x == food.x && head->y == food.y) //如果吃到了食物
{
creatfood(); //创建一个新食物
snake* pi = head;
snake* new_tail;
new_tail = (snake*)malloc(sizeof(snake)); //创建一个新尾巴
new_tail->next = NULL;
while (pi->next != NULL)
{
pi = pi->next;
}
pi->next = new_tail;
new_tail->x = 60; //把尾巴的坐标乱设一下,反正在changebody那里都会被删除然后释放的
new_tail->y = 0;
score += 10;
gotoxy(60, 10);
printf("score:%d", score);
}
}
int judge(void)
{
snake* pi = head;
if (head->x == 0 || head->x == 56 || head->y == 0 || head->y == 26) //撞墙判断
{
finish();
return 0;
}
while (pi->next != NULL)
{
pi = pi->next; //撞自己判断
if (head->x == pi->x && head->y == pi->y) //链表遍历
{
finish();
return 0;
}
}
return 1;
}
void finish(void)
{
system("cls"); //结束页面先清空页面
gotoxy(25, 13);
printf("game over");
snake* pi = head, * temp;
while (pi != NULL) //关键,释放整个链表的内存
{
temp = pi->next;
free(pi);
pi = temp;
}
system("pause"); //等待下一步输入
}
贪吃蛇小游戏(C语言实现)
最新推荐文章于 2024-05-26 21:23:04 发布