首页 > 其他 > 详细

贪吃蛇实现小结

时间:2020-04-11 20:04:55      阅读:79      评论:0      收藏:0      [点我收藏+]

前言

花了五个小时对着B站上的视频实现了贪吃蛇,很简陋版本的,只实现了基本步骤。5个小时里有最后两个小时都在debug,也算是在加深理解了...
当然了,虽然简陋但是核心基本都在,所以也算是略懂一二了,就想着趁热打铁总结一下顺带好好捋一下思路。
贪吃蛇这里游戏里有以下一些对象已经它们需要具备的功能,完成了这些,再借助一个主函数进行游戏运行就可以了。

对象分析

地图

一个限定的地图肯定是必不可少的,这里的地图其实要包含两个功能:

  1. 让玩家意识到这里是边界,即要显示出来;
  2. 不能让贪吃蛇越过这个边界。功能1通过输出特定符号即可,功能2就要发生与贪吃蛇交互了。

食物

分析同上:

  1. 显示;
  2. 被吃之后再次随机生成,且能让蛇长度++。

贪吃蛇

分析同上:

  1. 显示;
  2. 能移动;
  3. 能被控制;
  4. 能吃能长大;
  5. 会死亡。

主函数即其他相关函数分析

  1. 将三个对象的初始显示一起归并为初试化地图,并用一个函数来实现;
  2. 将贪吃蛇的移动已经操控用一个函数实现;
  3. 将贪吃蛇的死亡判定用一个函数实现;
  4. 将贪吃蛇吃食物长大以及食物被吃后随机再生成用一个函数实现;
  5. 主函数循环过程 移动 -》休眠 -》判定是否吃到食物 -》判定是否死亡 -》移动 即可。

准备工作

头文件及解释

#include<stdio.h>
	//标准输出输入头文件,写过c的都知道,没什么好说的
	//本代码中提供printf(); scanf();
#include<stdlib.h>
	//standard library标准库头文件
	//本代码中提供system();
#include<windows.h>
	//一个很重要的头文件,包含了其他Windows的头文件,在本程序中是提供
	//本代码中提供GetStdHandle(); sleep();
#include<time.h>
	//C/C++中的日期和时间头文件。用于需要时间方面的函数。
	//本代码中提供time();
#include<conio.h>
	//控制台输入输出的简写,定义了通过控制台进行数据输入输出的函数
	//本代码中提供getch();

相关函数

void srand(unsigned int);
	//使用无符号种子产生一系列伪随机数的起点
int rand(void);
	//从srand中指定的seed开始,返回一个[seed, RAND_MAX(0x7fff))的随机整数
	//在使用rand()前需要调用srand(),如果没有,则自动调用srand(1);
time_t time(time_t);
	//返回从1970s到现在的秒数并保存在形参中
	//用NULL做形参表示不保存在某个变量中,只返回值配合形成随机数使用,但是要强制类型转换
	//如何使用time函数算出当前时间?
int kbhit(void);
	//检查当前是都有键盘输入,有则返回非0值,否则返回0
int fflush(FILE*);
	//清除读写缓冲区,在需要立即把输出缓冲区的数据进行物理写入时
	//fflush(stdin); 为了不影响后面的数据读取
int getch(void);
	//当用户按下某个字符时,无需按回车,函数自动读取,但不显示在屏幕上
HANDLE GetStdHandle(STD_OUTPUT_HANDLE);
	//是一个window api,获取一个标准输出(实参)的句柄,用来标识Windows对象,个人理解是用来指定设备
void SetConsoleCursorPosition(HANDLE, COORD);
	//是一个window api,用于设置控制台(cmd)的光标位置
	//形参中handle指具体哪个句柄,coord指要设置的光标具体位置
Sleep(int);
	//用做延时,程序暂停若干时间,即形参中输入的整数,单位是毫秒
	//本代码中用来调节贪吃蛇移动速度,即移动一次中间间隔的时间
int system(char* command);
	//发出一个DOS指令,形参里面就是各种指令
	//system("pause"); 	冻结屏幕
	//system("CLS");	清屏

代码实现

#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
#include<time.h>
#include<conio.h>

//辅助宏定义
#define MAPHEIGHT 25
#define MAPWIDTH 60
#define SNAKESIZE 50
#define SNAKESPPED 100

//全局变量
int key = ‘w‘;					//初始化移动方向
int changeFlag = 0;				//蛇是否要变化,如果吃了食物则这个循环内先不变化
int score = 0;

//食物的结构体
struct {
	int x;
	int y;
}food;

//蛇的结构体
struct {
	//用数组是记录每一节蛇的坐标
	int x[SNAKESIZE];
	int y[SNAKESIZE];
	
	//蛇的长度
	int len;

	//蛇的移动速度
	int speed;
}snake;

//模块化设计(函数设计) --- 》》功能的划分 ---》》抽象到函数
void drawMap();		//画地图
void createFood();	//产生食物
void keyDown();		//按键操作
int snakeStatus();	//蛇的状态,判断是否结束游戏
void gotoxy(int x, int y);		//辅助函数:光标移动

void drawMap() {
	//☉:食物         ■:蛇身体
	srand((unsigned int)time(NULL));		//随机函数种子
	//1、圈地
			//1、1左右边框
	for (int i = 0; i <= MAPHEIGHT; i++) {
		gotoxy(0, i);
		printf("■");
		gotoxy(MAPWIDTH, i);
		printf("■");
	}
			//2、2上下边框
	for (int i = 0; i < MAPWIDTH; i += 2) {		//横向每个占用两个字符,所以是+=2
		gotoxy(i, 0);
		printf("■");
		gotoxy(i, MAPHEIGHT);
		printf("■");
	}
	//2、画蛇
			//2、1确定蛇的属性(长度、速度、坐标)
	snake.len = 3;
	snake.speed = SNAKESPPED;
					//开始蛇头在屏幕正中间
	snake.x[0] = MAPWIDTH / 2;		
	snake.y[0] = MAPHEIGHT / 2;
			//2、2画蛇
			//画蛇头
	gotoxy(snake.x[0], snake.y[0]);
	printf("■");
			//画蛇身
	for (int i = 1; i < snake.len; i++) {
		snake.x[i] = snake.x[i - 1] + 2;		//从蛇头开始,下一个身位是上一个身位的横坐标+2
		snake.y[i] = snake.y[i - 1];				//下一个身位与上一个身位的纵坐标是相同的,这表示蛇的初试状态是横着放的
		gotoxy(snake.x[i], snake.y[i]);		//开始到位置上逐个画蛇身
		printf("■");
	}
	//3、画食物
			//3、1确定坐标
	while (1) {
		food.x = rand() % (MAPWIDTH - 4) + 2;		//去掉边界,横向每个边界占2,所以都是以2为单位的
		food.y = rand() % (MAPHEIGHT - 2) + 1;		//去掉边界,纵向每个边界占1,所以都是以1为单位的
		if (food.x % 2 == 0)
			break;
	}
			//3、2画出食物
	gotoxy(food.x, food.y);
	printf("☉");
}

void createFood() {
	//蛇把食物吃了
	if (snake.x[0] == food.x && snake.y[0] == food.y) {
		score++;
		//随机产生新的食物
		srand((unsigned int)time(NULL));
		while (1) {
			int flag = 1;
			food.x = rand() % (MAPWIDTH - 4) + 2;
			food.y = rand() % (MAPHEIGHT - 2) + 1;
			//且产生的食物不能在蛇的身上
			for (int i = 0; i < snake.len; i++) {
				if (snake.x[i] == food.x && snake.y[i] == food.y) {		//利用循环判断新产生的食物是不是和蛇在一起
					flag = 0;		//表示食物不合适,重新产生
					break;
				}
			}
			if (flag && food.x % 2 == 0) {		//因为横坐标占两个字符,所以要横坐标要是偶数,显示完整
				break;
			}
		}
		gotoxy(food.x, food.y);
		printf("☉");
		snake.len++;
		changeFlag = 1;	//蛇的标记是1,表示蛇这一个循环中先不变化
	}
}

void keyDown() {
	//无按键的操作
	if (_kbhit()) {		//检测有无按键输入
		fflush(stdin);		//清空输入缓冲区,通常是为了确保不影响后面的数据读取,例如在读完一个字符串后紧接着又要读取一个字符
		key = _getch();
	}
	//擦除最后的位置
	if (!changeFlag) {			//如果吃了食物就不擦除,然后蛇长度+1,达到长度变长的目的
		gotoxy(snake.x[snake.len - 1], snake.y[snake.len - 1]);
		printf("  ");
	}
	//后面的蛇身
	for (int i = snake.len - 1; i > 0; i--) {
		snake.x[i] = snake.x[i - 1];			//后一个变成前一个的状态,所以在往前移
		snake.y[i] = snake.y[i - 1];			//不能用i--,因为会对i造成变成
	}
	//方向的处理以及对蛇头的处理
	switch (key) {
	case ‘W‘:
	case ‘w‘:
		snake.y[0]--;
		break;
	case ‘S‘:
	case ‘s‘:
		snake.y[0]++;
		break;
	case ‘A‘:
	case ‘a‘:
		snake.x[0] -= 2;
		break;
	case ‘D‘:
	case ‘d‘:
		snake.x[0] += 2;
		break;
	}
	gotoxy(snake.x[0], snake.y[0]);
	printf("■");
	changeFlag = 0;
	gotoxy(MAPHEIGHT + 2, 0);			//移动不能一直看着光标
}

int snakeStatus() {
	//不能撞墙
	if (snake.x[0] == 0 || snake.x[0] == MAPWIDTH - 2 || snake.y[0] == 0 || snake.y[0] == MAPHEIGHT - 1)     //有差异,要注意
		return 0;
	//不能撞自己
	for (int i = 1; i < snake.len; i++) {
		if (snake.x[0] == snake.x[i] && snake.y[0] == snake.y[i])
			return 0;
	}
	return 1;
}

void gotoxy(int x, int y) {
	//1、找到控制台的窗口
	HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);	
	//2、光标的结构体
	COORD coord;
	//3、设置光标坐标
	coord.X = x;	
	coord.Y = y;
	//4、同步到控制台SetConsoleCursorPosition
	SetConsoleCursorPosition(handle, coord);
}

int main() {
	char t;
	while (1) {
		system("cls");
		drawMap();
		score = 0;
		while (1) {
			createFood();
			Sleep(snake.speed);			//使计算机程序(进程,任务或线程)进入休眠,使其在一段时间内处于非活动状态,形参单位是毫秒,即休眠时间
			keyDown();
			if (!snakeStatus()) {
				break;
			}
		}
		//gotoxy(MAPWIDTH / 2, MAPHEIGHT / 2);
		printf("GameOver\t\n");
		printf("Your Score is %d\n", score);
		printf("Want Restart?(Y/N)\t");
		scanf_s ("%c", &t);
		if (t == ‘n‘)
			break;
	}
	gotoxy(MAPWIDTH / 2, MAPHEIGHT / 2);
	printf("EXIT");
	system("pause");
	return 0;
}

贪吃蛇实现小结

原文:https://www.cnblogs.com/Za-Ya-Hoo/p/12680401.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!