极简贪吃蛇(C语言)

------- 基于对C语言的学习,我想通过一个小游戏来告一段落

1 .模块设计

控制台的贪吃蛇小游戏,首先我认为可以分成视图模块,控制模块(键盘控制方向),蛇的移动模块


2.设计步骤

1.第一步当然是创建贪吃蛇结构体然后初始化贪吃蛇了,贪吃蛇有身体、有食物、有边界

贪吃蛇结构体代码如下

typedef struct body {  //蛇体;
	int x;
	int y;
}BODY;

typedef struct snake {
	BODY list[WIDE * HIGH];
	int size;
	BODY FOOD;
	COORD coord;  //光标的位置
	int dx;      //蛇头方向
	int dy;      //蛇头方向
	int score;
	BODY tail;
}SNAKE;

COORD 位于windows.h文件中,是一个结构体,用于设置光标位置详情点击这个

1.边界通过尝试我姑且设计成

ihYO48.png
打印效果如下:

ihY7uo.png
实现函数如下

void init_wall()
{
	for (int i = 0; i <= HIGH; i++)
	{
		for (int j = 0; j <= WIDE; j++)
		{
			if (i == HIGH || j == WIDE)
			{
				printf("+");
			}
			else
			{
				printf(" ");
			}

		}
		printf("\n");
	}
}
2.食物初始化

食物随机生成但不能在蛇身上
ihq40C.png
关于srand详解

。。。。。。。

3.贪吃蛇整体初始化
void init_FOOD(SNAKE* snake) {  //初始化food
	srand(time(NULL));
	snake->FOOD.x = rand() % 60;
	snake->FOOD.y = rand() % 20;
	for (int i = 0; i < snake->size; i++) { //食物不能在蛇身上
		if (snake->FOOD.x == snake->list[i].x && snake->FOOD.y == snake->list[i].y)
			init_FOOD(snake);
	}
}

void init_SNAKE(SNAKE* snake) {  //初始化蛇
	snake->list[0].x = WIDE / 2;  //初始化蛇头蛇尾
	snake->list[0].y =  HIGH/ 2;
	snake->list[1].x = WIDE / 2-1;   //初始化蛇尾
	snake->list[1].y = HIGH / 2;
	snake->tail = snake->list[1];

	snake->size = 2;   //初始化大小
	init_FOOD(snake);      //初始化食物

	snake->dx = 1;  //初始化蛇头方向
	snake->dy = 0;

	snake->score = 0;  //初始化分数

	

}

3.第二步进行蛇的移动了

void move_snake(SNAKE *snake) {
	snake->tail.x = snake->list[snake->size - 1].x; //在移动之前记录之前的蛇尾坐标蛇尾,以便于将其设置为空格 
	snake->tail.y = snake->list[snake->size - 1].y;

		for (int i = snake->size-1; i > 0; i--) { //更新身体坐标,从后向前
			snake->list[i] = snake->list[i - 1];
		}
		snake->list[0].x += snake->dx;  //蛇头方向
		snake->list[0].y += snake->dy;  //蛇头方向
           
	
}

3.第三步进行蛇的显示了

通过COORD设置

void show_SNAKE(SNAKE *snake) {//展示贪吃蛇
	//每次显示蛇都要注意设置光标的位置
	for (int i = 0; i < snake->size; i++) {
		snake->coord.X = snake->list[i].x;
		snake->coord.Y = snake->list[i].y;
		SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), snake->coord);
		if (i == 0) printf("@");
		else printf("*");
	}

	//显示食物
	snake->coord.X = snake->FOOD.x;
	snake->coord.Y = snake->FOOD.y;
	SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), snake->coord);
	printf("#");
	
	
	snake->coord.X = snake->tail.x;//覆盖原来的蛇尾为空格
	snake->coord.Y = snake->tail.y;
	SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), snake->coord);
	printf(" ");
}

由于打印之前的蛇尾还在显示屏所以要记录原先的蛇尾坐标,在打印新蛇之后,使用空格抹去原来的蛇尾

4.第四步通过键盘来控制方向

kbhit()函数用法 位于<conio.h> 文件

void control_snake(SNAKE* snake) {
	char key = 0;
	while (_kbhit()) { //判断是否按下建,没有则为零
		key = _getch();  //获取键值
	}
	switch (key) {
	case 'a':
		snake->dx = -1;
		snake->dy = 0;
		break;
	case 'd':
		snake->dx = 1;
		snake->dy = 0;
		break;
	case 'w':
		snake->dx = 0;
		snake->dy = -1;
		break;
	case 's':
		snake->dx = 0;
		snake->dy = 1;
		break;
	}
5.第五步开始游戏
void start_game(SNAKE* snake) {
	while(snake->list[0].x<60&&snake->list[0].x>=0
		&& snake->list[0].y < 20 && snake->list[0].x >= 0) {
		//控制蛇的方向
		control_snake(snake); 

		move_snake(snake);
		//system("cls");  用这个不好,会清理掉我的边界wall
		show_SNAKE(snake);

		//是否寄掉了
		snake_eat_body(snake);

		//是否吃到了食物
		snake_eat_food(snake);

		Sleep(200);
	}
	game_end(snake);
}
void game_end(SNAKE* snake) {
	//system("cls");  用这可不好,把我wall搞没了
	snake->coord.X = WIDE/2; //更新光标
	snake->coord.Y = HIGH/2;
	SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), snake->coord);
	printf("游戏结束%d分",snake->score);
	exit(0); //结束进程
}
void snake_eat_body(SNAKE* snake) {//自己撞到了自己要死
	for (int i = 1; i < snake->size; i++) {
		if (snake->list[0].x == snake->list[i].x && snake->list[0].y == snake->list[i].y)
			game_end(snake);
	}
}

void snake_eat_food(SNAKE* snake){ //吃食物边长
	if (snake->list[0].x == snake->FOOD.x && snake->list[0].y == snake->FOOD.y) {//蛇头吃到了食物
		snake->size++;  //不用重新给坐标,因为下一次show_SNAKE的时候新的[size]使用了旧的[size]坐标
	                    //蛇头按照方向改变坐标就行   
		//食物自动覆盖,消失了,只需要生成新食物
		init_FOOD(snake);
		snake->score += 10;
	}
}

最后全部代码如下:(第一个C语言项目,哎呦终于写完了,这学期过一半,终于可以学算法啦笑哭~~~)

#include <stdio.h>
#include<stdlib.h>
#include<windows.h>
#include<string.h>
#include <conio.h>  //含按键设置函数  
#define WIDE 60
#define HIGH 20

//初始化屏幕大小   OK
// 初始化蛇和食物,食物要求随机生成
//将蛇和食物显示在屏幕上

void init_ui(){   //初始化屏幕大小
	int i=0, j=0;
	for ( i = 0; i < HIGH; i++) {
		for ( j = 0; j < WIDE; j++) {
			printf("#");
		}
		printf("\n");
	}
}


typedef struct body {  //蛇体;
	int x;
	int y;
}BODY;


typedef struct snake {
	BODY list[WIDE * HIGH];
	int size;
	BODY FOOD;
	COORD coord;  //光标的位置
	int dx;
	int dy;
	int score;
	BODY tail;
}SNAKE;

void init_FOOD(SNAKE* snake) {  //初始化food
	srand(time(NULL));
	snake->FOOD.x = rand() % 60;
	snake->FOOD.y = rand() % 20;
	for (int i = 0; i < snake->size; i++) { //食物不能在蛇身上
		if (snake->FOOD.x == snake->list[i].x && snake->FOOD.y == snake->list[i].y)
			init_FOOD(snake);
	}
}

void init_SNAKE(SNAKE* snake) {  //初始化蛇
	snake->list[0].x = WIDE / 2;  //初始化蛇头蛇尾
	snake->list[0].y =  HIGH/ 2;
	snake->list[1].x = WIDE / 2-1;
	snake->list[1].y = HIGH / 2;
	snake->tail = snake->list[1];

	snake->size = 2;   //初始化大小
	init_FOOD(snake);      //初始化食物

	snake->dx = 1;  //初始化方向
	snake->dy = 0;

	snake->score = 0;  //初始化分数

	

}

void show_SNAKE(SNAKE *snake) {//展示贪吃蛇
	//每次显示蛇都要注意设置光标的位置
	for (int i = 0; i < snake->size; i++) {
		snake->coord.X = snake->list[i].x;
		snake->coord.Y = snake->list[i].y;
		SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), snake->coord);
		if (i == 0) printf("@");
		else printf("*");
	}

	//显示食物
	snake->coord.X = snake->FOOD.x;
	snake->coord.Y = snake->FOOD.y;
	SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), snake->coord);
	printf("#");
	
	
	snake->coord.X = snake->tail.x;//覆盖原来的蛇尾为空格
	snake->coord.Y = snake->tail.y;
	SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), snake->coord);
	printf(" ");
}


void move_snake(SNAKE *snake) {
	snake->tail.x = snake->list[snake->size - 1].x; //在移动之前记录之前的蛇尾坐标蛇尾,以便于将其设置为空格 
	snake->tail.y = snake->list[snake->size - 1].y;

		for (int i = snake->size-1; i > 0; i--) { //更新身体坐标
			snake->list[i] = snake->list[i - 1];
		}
		snake->list[0].x += snake->dx;  
		snake->list[0].y += snake->dy;
           
	
}
void control_snake(SNAKE* snake) {
	char key = 0;
	while (_kbhit()) { //判断是否按下建,没有则为零
		key = _getch();
	}
	switch (key) {
	case 'a':
		snake->dx = -1;
		snake->dy = 0;
		break;
	case 'd':
		snake->dx = 1;
		snake->dy = 0;
		break;
	case 'w':
		snake->dx = 0;
		snake->dy = -1;
		break;
	case 's':
		snake->dx = 0;
		snake->dy = 1;
		break;
	}

}void game_end(SNAKE* snake) {
	//system("cls");  用这可不好,把我wall搞没了
	snake->coord.X = WIDE/2; //更新光标
	snake->coord.Y = HIGH/2;
	SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), snake->coord);
	printf("游戏结束%d分",snake->score);
	exit(0); //结束进程
}
void snake_eat_body(SNAKE* snake) {
	for (int i = 1; i < snake->size; i++) {
		if (snake->list[0].x == snake->list[i].x && snake->list[0].y == snake->list[i].y)
			game_end(snake);
	}
}

void snake_eat_food(SNAKE* snake){
	if (snake->list[0].x == snake->FOOD.x && snake->list[0].y == snake->FOOD.y) {//蛇头吃到了食物
		snake->size++;  //不用重新给坐标,因为下一次show_SNAKE的时候新的[size]使用了旧的[size]坐标
	                    蛇头按照方向改变坐标就行    
		//食物自动覆盖,消失了,只需要生成新食物
		init_FOOD(snake);
		snake->score += 10;
	}
}

void start_game(SNAKE* snake) {
	while(snake->list[0].x<60&&snake->list[0].x>=0
		&& snake->list[0].y < 20 && snake->list[0].x >= 0) {
		//控制蛇的方向
		control_snake(snake); 

		move_snake(snake);
		//system("cls");  用这个不好,会清理掉我的边界wall
		show_SNAKE(snake);

		//是否寄掉了
		snake_eat_body(snake);

		//是否吃到了食物
		snake_eat_food(snake);

		Sleep(200);
	}
	game_end(snake);
}

void init_wall()
{
	for (int i = 0; i <= HIGH; i++)
	{
		for (int j = 0; j <= WIDE; j++)
		{
			if (i == HIGH || j == WIDE)
			{
				printf("+");
			}
			else
			{
				printf(" ");
			}

		}
		printf("\n");
	}
}

void hide_cur()
{

	//隐藏控制台光标
	CONSOLE_CURSOR_INFO  cci;
	cci.dwSize = sizeof(cci);
	cci.bVisible = FALSE;
	SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cci);
}
int main(){
	hide_cur();//隐藏光标

	//分配结构体贪吃蛇
	SNAKE* snake = (SNAKE*)malloc(sizeof(SNAKE));
	//初始化贪吃蛇
	init_SNAKE(snake);
	
	//初始化边界
	init_wall();

	start_game(snake);
	
	
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是一个简单的贪吃蛇C语言代码,供参考: ```c #include <stdio.h> #include <stdlib.h> #include <conio.h> #include <windows.h> #define WIDTH 20 #define HEIGHT 20 #define MAX_LENGTH (WIDTH*HEIGHT) int snake[MAX_LENGTH][2]; int food[2]; int score; int length; int direction; int running; void init() { // 初始化贪吃蛇的位置 snake[0][0] = WIDTH / 2; snake[0][1] = HEIGHT / 2; snake[1][0] = WIDTH / 2 - 1; snake[1][1] = HEIGHT / 2; snake[2][0] = WIDTH / 2 - 2; snake[2][1] = HEIGHT / 2; length = 3; // 初始化食物的位置 food[0] = rand() % WIDTH; food[1] = rand() % HEIGHT; // 初始化分数 score = 0; // 初始化方向 direction = 'd'; // 初始化运行标志 running = 1; } void draw() { system("cls"); // 画出地图 for (int i = 0; i <= HEIGHT; i++) { for (int j = 0; j <= WIDTH; j++) { if (i == 0 || i == HEIGHT || j == 0 || j == WIDTH) { printf("#"); } else if (i == snake[0][1] && j == snake[0][0]) { printf("@"); } else if (i == food[1] && j == food[0]) { printf("*"); } else { int flag = 0; for (int k = 1; k < length; k++) { if (i == snake[k][1] && j == snake[k][0]) { printf("#"); flag = 1; break; } } if (!flag) { printf(" "); } } } printf("\n"); } // 显示分数 printf("Score: %d\n", score); } void update() { // 记录蛇尾位置 int tail[2]; tail[0] = snake[length - 1][0]; tail[1] = snake[length - 1][1]; // 移动蛇身 for (int i = length - 1; i > 0; i--) { snake[i][0] = snake[i - 1][0]; snake[i][1] = snake[i - 1][1]; } // 根据方向移动蛇头 switch (direction) { case 'w': snake[0][1]--; break; case 'a': snake[0][0]--; break; case 's': snake[0][1]++; break; case 'd': snake[0][0]++; break; } // 判断是否吃到食物 if (snake[0][0] == food[0] && snake[0][1] == food[1]) { // 食物位置随机生成 food[0] = rand() % WIDTH; food[1] = rand() % HEIGHT; // 分数加一 score++; // 蛇身长度加一 length++; } // 判断是否碰到墙壁或自己的身体 if (snake[0][0] == 0 || snake[0][0] == WIDTH || snake[0][1] == 0 || snake[0][1] == HEIGHT) { running = 0; } for (int i = 1; i < length; i++) { if (snake[0][0] == snake[i][0] && snake[0][1] == snake[i][1]) { running = 0; break; } } } void input() { // 获取键盘输入 if (_kbhit()) { char c = _getch(); if (c == 'w' || c == 'a' || c == 's' || c == 'd') { // 只有输入合法的方向键才会改变方向 if ((c == 'w' && direction != 's') || (c == 'a' && direction != 'd') || (c == 's' && direction != 'w') || (c == 'd' && direction != 'a')) { direction = c; } } } } int main() { init(); while (running) { draw(); update(); input(); Sleep(100); } printf("Game over\n"); printf("Your score: %d\n", score); return 0; } ``` 这个代码使用了Windows.h库中的一个函数`Sleep()`,该函数可以让程序暂停一段时间,单位是毫秒。在这个代码中,每100毫秒刷新一次屏幕,相当于一秒钟刷新10次。如果需要在其他平台上运行此代码,需要修改画图函数和暂停函数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值