C语言实现贪吃蛇[内附详细步骤]
C语言贪吃蛇项目
今天给分享一下使用C语言写个贪吃蛇小游戏,主要包含以下10部分内容:
1、windows光标定位与隐藏
2、欢迎界面
3、打印围墙
4、产生食物
5、初始化蛇身
6、响应按键
7、蛇身运动
8、碰撞检测
9、结束界面
10、程序运行
- windows光标定位与隐藏
COORD 是window API中定义的一种结构体,表示一个字符在控制台屏幕上的坐标。定义为:
typedef struct_COORD{
SHORT X; 横坐标
SHORT Y; 纵坐标
}COORD;
定位函数gotoxy,gotoDelete
void gotoprint(int x, int y) { gotoxy(x, y); printf("■"); } // 删除蛇尾 void gotoDelete(int x, int y) { gotoxy(x, y); printf(" "); } |
2. 欢迎界面
使用gotoxy函数将光标定义到页面相应的位置输出欢迎信息,页面左上角为(0,0)坐标。
将用户输入的姓名信息保存下来以便后面使用。
用户输入姓名后清屏,进入游戏界面。
void welcome() { gotoxy(10, 5); printf("/**********************************************/"); gotoxy(14, 8); printf("WELCOME TO THE GAME OF RETRO SNAKE"); gotoxy(14, 12); printf("wasd控制蛇身上下左右运动,反向移动等同于吃到自己导致游戏结束,除了wasd任意键暂停"); gotoxy(10, 20); printf("/**********************************************/"); gotoxy(14, 16); printf("请输入姓名:"); scanf("%s",username); system("cls"); } |
3.打印围墙
贪吃蛇围墙只需要定位到相应位置输出"■"即可,本次游戏的围墙为57*27
坐标图如下图所示:
void creatgraph() { int i; // 横向围墙 58 / 2 == 29列 for (i = 0; i < 58; i += 2) { gotoprint(i, 0); gotoprint(i, 26); } // 竖向围墙 1-25中间有25行 + 头尾两行 27行 for (i = 1; i < 26; i++) { gotoprint(0, i); gotoprint(56, i); }
// 游戏信息 gotoxy(60,5); printf("hello,%s",username); gotoxy(60,15); printf("您当前的得分为:"); gotoxy(76,15); printf("%d",score); } |
打印完后显示一下游戏信息。
注意:
汉字宽度是字符宽度的两倍,高度相等。即一个汉字占两个字节,一个英文字母占一个字节。
因此,"■"输出一次占两个字节,纵向上占一个字节,底部自身携带一些空隙。
4.产生食物
1、构造食物
struct Food { int x; int y; }food; |
2、定位食物
保证食物必须在围墙内:
x坐标范围: [2,54] -- 并且只要偶数部分,不是偶数部分需要转化为接近的偶数
y坐标范围: [1,25]
保证食物和蛇身没有重合,如果重合需要再次生成新的位置。
3、输出食物
void creatfood() { // 随机产生一个食物的位置 int flag = 0; while(!flag) { srand((unsigned int)time(NULL)); food.y = rand() % 25 + 1; // [1,25] food.x = rand() % 53 + 2; // [2,54] -- 只要偶数部分 if(food.x % 2 != 0) { food.x = food.x+1; // 不是偶数部分转化为接近的偶数 } // 不能与蛇身重复 snake *p = head; while(p) { if(p->x == food.x && p->y == food.y) { // 重复 -- 重新生成坐标 break; } p = p->next; } flag = 1; } gotoxy(food.x, food.y); printf("吃"); } |
5.初始化蛇身
蛇身构造
typedef struct Snakes { int x; int y; struct Snakes* next; }snake; snake* head; // 声明蛇头指针 |
绘制初始化的蛇身
void initSnake() { head = (snake*)malloc(sizeof(snake)); snake* p = (snake*)malloc(sizeof(snake)); 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;
//绘制初始蛇身 gotoprint(16,15); gotoprint(16,16); gotoprint(16,17); } |
6.响应按键
getch()为输入字符函数,但是是阻塞的,如果用户不输入进步向下进行,不满足蛇身自动向前运动的需求,因此替换为_kbhit()进行非阻塞的输入监听,监听到键盘输入后,使用_getch从缓冲区中将输入的字符读出来放入全局变量ch中。
另外,当程序执行时,循环一次需要进行一次碰撞检测,没有碰撞时,还需要进行蛇身的移动。
int clickControl() { while(1) { // 检测是否碰撞边界 if(collisionDetect() == 1) return 0; // _kbhit监听键盘有输入-非阻塞 if(_kbhit()) { ch = _getch(); } // 移动身体 movingBody(); } return 1; } |
7.蛇身运动
蛇身运动即:消除蛇尾节点,根据按键方向确定好新节点坐标,将新节点添加到蛇头位置即可。
移动后可以加一些延迟,使用Sleep(xx); xx以ms为单位。
void movingBody() { // 坐标修改 int x = head->x; int y = head->y; switch(ch) { case UP: y-=1; break; case DOWN: y+=1; break; case LEFT: x-=2; break; case RIGHT: x+=2; break; default: ch = 0; break; } if(ch) { // 消除尾节点 snake *p = head; while(p->next->next != NULL) { p = p->next; } snake *q = p->next; gotoDelete(q->x,q->y); free(q); p->next = NULL; // 新坐标结点置为头结点 snake* newNode = (snake*)malloc(sizeof(snake)); newNode->x = x; newNode->y = y; newNode->next = head; head = newNode; // 绘制蛇头 gotoprint(x,y); // 延迟 Sleep(500); } } |
注意:如果用户输入的是除了 wasd以外的按键则暂停游戏。
8.碰撞检测
碰撞检测主要有三种:
- 蛇身和边界
- 蛇头和蛇身
- 蛇头碰到食物
重新生成一个食物
在蛇身后面添加一个尾巴,可以不给x,y,因为下次移动的时候会直接将它释放掉。
加分
在分值位置更新分数
int collisionDetect() { // 检测蛇头和边界 if(head->x == 0 || head->x == 56 || head->y == 0 || head->y == 26) { Finish(); return 1; } // 蛇头和蛇身 snake *p = head->next; while(p != NULL) { if(head->x == p->x && head->y == p->y) { // 碰撞-结束 Finish(); return 1; } p = p->next; } // 碰到食物 if(head->x == food.x && head->y == food.y) { creatfood(); // 添加一个尾巴 snake* newNode = (snake*)malloc(sizeof(snake)); newNode->next = NULL; snake *p = head; while(p->next != NULL) { p = p->next; } p->next = newNode; score += 10; gotoxy(76,15); printf("%d",score); } return 0; } |
9.结束界面
清屏
显示用户名和得分
void Finish() { system("cls"); gotoxy(10, 10); printf("/**********************************************/"); gotoxy(10, 20); printf("/**********************************************/"); gotoxy(15, 14); printf("GAME OVER o(* ̄▽ ̄*)o"); gotoxy(18, 16); printf("%s, 你的得分 %d ",username, score); gotoxy(15, 18); printf("还不错哦, 继续努力O(∩_∩)O"); gotoxy(0, 27); // 释放空间 snake* p = head, *q; while (p != NULL) { q = p->next; free(p); p = q; } system("pause"); } |
10.运行程序
int main() { welcome(); creatgraph(); creatfood(); initSnake(); clickControl(); return 0; } |