C语言贪吃蛇小黑窗
元灵石胎 人气:0思路:
1.利用整型二维数组保存显示数据,小蛇每移动一次清屏并便利数组做到动态效果。每次移动(清屏)的间隔时间控制了游戏难度,这个时间应不断缩减,直到游戏结束。
2.需要保存小蛇移动的方向,然后写一个函数通过小蛇的移动方向去处理二维数组中的数据,达到移动小蛇的目的。
3.小蛇的移动可分解为两个过程:头部像前方生长一格然后尾部消去一格。如果蛇头吃到食物,尾部无需消去,此时应立即随机生成一个新的食物。
4.游戏开始时小蛇应随机生成在地图某一位置,此时小蛇的默认移动方向也应该是随机的。
5每次移动前应接收玩家由键盘输入的移动方向,如果接收到后,判断合法后将其设为小蛇的默认移动方向,如果玩家未进行任何输入,小蛇应按照默认方向移动。
个人难点:
1.小蛇移动
该函数需要拿到蛇头当时所在的位置坐标和小蛇的移动方向。随后可由蛇头位置往移动方向往前生长一格,即将二维数组中目标移动位置的数据设置为小蛇的数据。消去蛇尾另写一个函数,调用前需先判断是否吃到食物,是否撞到墙壁或者是自身,然后决定是否削去尾部。消去蛇尾需获得蛇尾的位置,所以我们在该函数内加入递归搜索蛇尾的算法:进入函数后先判断此时的位置是否为蛇尾,若不是就将自身位置往后移动一格(将蛇身往后一格的坐标输入给DeleteTail函数,然后继续此过程),直到遇到蛇尾,然后将其消去(置零)。
具体代码实现如下:
int MoveSnake(int trend, int* px, int* py, int data[ROW][COL], int* t) { int ret = 1;//默认前进成功 //printf("trend=%d\n", trend); switch (trend) { case 1:*py -= 1; break;//向上 case 2:*px -= 1; break;//向左 case 3:*py += 1; break;//向下 case 4:*px += 1; break;//向右 }//找到即将前进的坐标 if (data[*py][*px] == 6) { data[*py][*px] = trend; CreatFood(data); *t *= 0.9; }//如果蛇头要前进的格子是食物,向前长一格,尾部不变; else if (data[*py][*px] == 0) { data[*py][*px] = trend;//向前长一格 DeleteTail(*px, *py, data);//消去最后的尾巴 } else { ret = 0; printf("前进失败\n"); }//前进失败 return ret; } int DeleteTail(int x, int y, int data[ROW][COL]) { //PrintTest(data); if (data[y][x] <= 4 && data[y][x] >= 1) { switch (data[y][x]) { case 1: if (DeleteTail(x, y + 1, data) == 0) { data[y][x] = 0; } break; case 2: if (DeleteTail(x + 1, y, data) == 0) { data[y][x] = 0; } break; case 3: if (DeleteTail(x, y - 1, data) == 0) { data[y][x] = 0; } break; case 4: if (DeleteTail(x - 1, y, data) == 0) { data[y][x] = 0; } break; } return 1; } else { return 0; } }
2.输入
在实际代码实现的过程中,我发现scanf函数无法实现需求,理由是程序执行到scanf语句时,会停留在该位置,直到scanf函数扫描到输入后,程序才会继续进行。经学习查阅,决定使用kbhit函数扫描此时键盘缓冲区中是否有数据:如果有就读取第一个数据,并将后面的数据清空,避免后面使用该数据,若没有数据,缓冲区不做任何处理,程序也应当继续执行。
使用kbhit函数前应“#include<conio.h>”。清理缓冲区运用的是getch()循环。代码如下:
int Input() { int trend = 0; if (kbhit()) { char trend_ = getch(); while (kbhit()) { getch(); }//清空缓冲区 //printf("已接收到%c ", trend_); switch (trend_) { case 'w':trend = 1; break; case 'a':trend = 2; break; case 's':trend = 3; break; case 'd':trend = 4; break; default:printf("请输入w,a,s,d以控制前进方向!!\n"); break; } } else { printf("请输入w,a,s,d以控制前进方向!!\n"); } return trend; }
完整源代码:
#pragma once #pragma warning(disable : 4996) #include<stdio.h> #include<time.h> #include<stdlib.h> #include<Windows.h> #include<conio.h> #define ROW 30 #define COL 30 #define TIME 300 int Game(); int Menu(); int Input(); int CreatHead(int* px, int* py, int data[ROW][COL]); void CreatFood(int data[ROW][COL]); int MoveSnake(int trend, int* px, int* py, int data[ROW][COL], int* t); int DeleteTail(int x, int y, int data[ROW][COL]); void PrintShow(int data[ROW][COL]); int GameOver(int score); void PrintTest(int data[ROW][COL]);
#include"main.h" int main() { int ret = 1; while (ret) { int choose = Menu(); int score = 0; switch (choose) { case 1: score = Game(); ret = GameOver(score); break; case 2: system("cls"); printf("==========================================================\n"); printf(" 游戏说明 \n"); printf(" 1.输入‘w'‘a'‘s'‘d'以控制小蛇的移动。\n"); printf(" 2.小蛇在固定时间内只移动一次,如一个时间段内输入多个方向\n则以第一次输入为准。\n"); printf(" 3.不能撞到墙壁或者是自身。\n"); printf(" 4.小蛇移动速度会在吃到食物后加快,直到游戏结束。\n"); printf(" 输入“1”继续...........\n"); printf("==========================================================\n"); int ok = 0; scanf("%d", &ok); if (ok) { system("cls"); break; } case 3: ret = 0; break; } } }
#include"main.h" int Game() { int data[ROW][COL] = { 0 }; int time_ = TIME; for (int i = 0; i < COL; i++) { for (int j = 0; j < ROW; j++) { if (i == 0 || i == COL - 1) { data[i][j] = 5;//边界墙 } if (j == 0 || j == ROW - 1) { data[i][j] = 5;//边界墙 } } }//初始化数据存储数组 //PrintShow(data); int x = 0, y = 0; int trend = CreatHead(&x, &y, data); //生成蛇头 CreatFood(data);//生成食物 int ret = 1; while (ret) { system("cls"); PrintShow(data); Sleep(time_); int trend_ = Input(); if (trend_ != 0) { trend = trend_; } ret = MoveSnake(trend, &x, &y, data, &time_); } int score = 0; for (int i = 0; i < ROW; i++) { for (int j = 0; j < COL; j++) { if (data[i][j] <= 4 && data[i][j] >= 1) { score++; } } } return score; } int Menu() { int choose = 0; while (1) { printf("==========================\n"); printf("===欢迎进入贪吃蛇游戏!===\n"); printf("=== 1、经典模式 ===\n"); printf("=== 2、游戏说明 ===\n"); printf("=== 3、退出游戏 ===\n"); printf("=== 请输入您的选项... ===\n"); printf("==========================\n"); scanf("%d", &choose); if (choose == 1 || choose == 2 || choose == 3) { break; } } return choose; } int MoveSnake(int trend, int* px, int* py, int data[ROW][COL], int* t) { int ret = 1;//默认前进成功 //printf("trend=%d\n", trend); switch (trend) { case 1:*py -= 1; break;//向上 case 2:*px -= 1; break;//向左 case 3:*py += 1; break;//向下 case 4:*px += 1; break;//向右 }//找到即将前进的坐标 if (data[*py][*px] == 6) { data[*py][*px] = trend; CreatFood(data); *t *= 0.9; }//如果蛇头要前进的格子是食物,向前长一格,尾部不变; else if (data[*py][*px] == 0) { data[*py][*px] = trend;//向前长一格 DeleteTail(*px, *py, data);//消去最后的尾巴 } else { ret = 0; printf("前进失败\n"); }//前进失败 return ret; } void CreatFood(int data[ROW][COL]) { srand(time(NULL)); while (1) { int x = rand() % (COL - 2) + 1; int y = rand() % (ROW - 2) + 1; if (data[y][x] == 0) { data[y][x] = 6; break; } } } int DeleteTail(int x, int y, int data[ROW][COL]) { //PrintTest(data); if (data[y][x] <= 4 && data[y][x] >= 1) { switch (data[y][x]) { case 1: if (DeleteTail(x, y + 1, data) == 0) { data[y][x] = 0; } break; case 2: if (DeleteTail(x + 1, y, data) == 0) { data[y][x] = 0; } break; case 3: if (DeleteTail(x, y - 1, data) == 0) { data[y][x] = 0; } break; case 4: if (DeleteTail(x - 1, y, data) == 0) { data[y][x] = 0; } break; } return 1; } else { return 0; } } int Input() { int trend = 0; if (kbhit()) { char trend_ = getch(); while (kbhit()) { getch(); }//清空缓冲区 //printf("已接收到%c ", trend_); switch (trend_) { case 'w':trend = 1; break; case 'a':trend = 2; break; case 's':trend = 3; break; case 'd':trend = 4; break; default:printf("请输入w,a,s,d以控制前进方向!!\n"); break; } } else { printf("请输入w,a,s,d以控制前进方向!!\n"); } return trend; } void PrintShow(int data[ROW][COL]) { for (int i = 0; i < ROW; i++) { for (int j = 0; j < COL; j++) { if (data[i][j] == 0) { printf(" "); } if (data[i][j] == 5) { printf("■"); } if (data[i][j] >= 1 && data[i][j] <= 4) { printf("□"); } if (data[i][j] == 6) { printf("●"); } } printf("\n"); } } int CreatHead(int* px, int* py, int data[ROW][COL]) { srand(time(NULL)); while (1) { *px = rand() % (COL - 8) + 4; *py = rand() % (ROW - 8) + 4; if (data[*py][*px] == 0) { break; } }//蛇头只能刷新在空格位置 //x,y始终为蛇头的坐标 int trend = rand() % 4 + 1;//1:上,2:左,3:下,4:右 data[*py][*px] = trend; switch (trend) { case 1:data[*py + 1][*px] = 1; data[*py + 2][*px] = 1; break; case 2:data[*py][*px + 1] = 2; data[*py][*px + 2] = 2; break; case 3:data[*py - 1][*px] = 3; data[*py - 2][*px] = 3; break; case 4:data[*py][*px - 1] = 4; data[*py][*px - 2] = 4; break; } return trend; } void PrintTest(int data[ROW][COL]) { printf("\n"); for (int i = 0; i < ROW; i++) { for (int j = 0; j < COL; j++) { printf("%d ", data[i][j]); } printf("\n"); } } int GameOver(int score) { system("cls"); printf("==============================================\n"); printf("游戏结束,您的小蛇最终长到了%d米长...\n", score); printf("输入1重新开始,输入其它退出游戏...\n"); int ret = 0; scanf("%d", &ret); if (ret == 1) { return 1; } else { return 0; } }
加载全部内容