贪吃蛇游戏开发笔记(附代码C++)

目录

0前言

1.游戏初始化

2.实现蛇的移动

3.吃食物

4.完整代码

5.拓展(播放背景音乐)

6.改进


0前言

C入门小白一枚,为了更好地深入学习C++,跟随博主们撰写游戏编程代码。

本文是在小破站跟随一个博主写的代码。C语言必学项目:贪吃蛇!大一计算机专业巩固C语言基础常用项目,一个小时带你做出C语言入门级游戏!_哔哩哔哩_bilibili代码比较粗糙,属于入门级别。

1.游戏初始化

首先要初始化一个游戏界面大小,一条蛇的形状大小、移动速度、移动方向、蛇头蛇身坐标。

设置窗口大小用到 initgraph() 函数。

注意:设置蛇头蛇身时注意头身坐标。蛇的速度和蛇身(实心圆)的半径要形成关系,否则行走的位移大小不一样,蛇身会重合。

void GameInit()
{
	//init 初始化游戏窗口大小   graph 图形窗口大小为640*480
	initgraph(640, 480);
    
    //初始化蛇
	snake.size = 3;
	snake.speed = 10;// 蛇的速度和蛇身(实心圆)的半径要形成关系,否则行走的位移大小不一样,蛇身会重合
	snake.dir = RIGHT;
	for (int i = 0; i < snake.size; i++)
	{
		snake.coor[i].x = 40-10*i;//坐标:蛇尾20蛇身30蛇头40
		snake.coor[i].y = 10;
	}

}

//绘制图形
void GameDraw()
{
	//双缓冲绘图
	BeginBatchDraw();
	//设置窗口背景颜色
	setbkcolor(RGB(47,79,79));
	cleardevice();//清除原设备
	//绘制蛇
	/*setfillcolor(BLUE);*/  //设置蛇的颜色
	for (int i = 0; i < snake.size; i++)
	{
		solidcircle(snake.coor[i].x, snake.coor[i].y, 5);//绘制实心圆作为蛇的一节
	}

	EndBatchDraw();//结束缓冲
}

2.实现蛇的移动

蛇初始状态就应能够实现自主移动。蛇的移动是坐标的改变,这里注意头身的半径和每一次位移的步长。步长==蛇的直径

蛇的移动方向变换由键盘输入键值实现。通过kbhit()getch()函数实现(包含在头文件<conio.h>中)。同时要撰写枚举,定义UP、Down、Right、Left。

蛇向上走必不能向下掉头,向左走不能向右掉头。(否则就是把自己吃掉了)

3.吃食物

首先要随机生成食物。系统产生一个随机数,如果单纯的用rand函数 ,每次执行产生的结果都是一样的,这导致随机数并不随机。因此需要需要设置随机数种子srand()函数包含在头文件<stdlib.h>中。

// 数据的初始化
void GameInit()
{
	// 设置随机数种子
	srand(GetTickCount());//获取系统开机到现在所经过的毫秒数
    
	// 初始化食物
	food.x = rand() % HEIGHT;//求模
	food.y = rand() % LENGTH;
	// 设置随机数种子需要头文件stdlib.h	一般把时间作为随机数种子,因为时间是在不短变化的
	food.color = RGB(rand() % 256, rand() % 256, rand() % 256);
	food.r = rand() % 10 + 5;
	food.flag = true;

}

4.完整代码

#include<stdio.h>
#include<graphics.h>//绘图头文件
#include<conio.h>//获取按键信息头文件
#include<stdlib.h>//设置随机数种子需该头文件
#include<mmsystem.h>//定义的多媒体API 实现声音输出,在程序中加入背景音乐要包含该头文件
#pragma comment(lib,"winmm.lib")//告诉编译器,加载winmm.lib库文件(音乐)

/*
	贪吃蛇
	知识点:结构体、循环、函数、easyx,数组
	API接口输入
*/

//做一个界面,创建一个图形窗口
#define SNAKE_NUM 500	//宏的定义,蛇的最大节数
#define HEIGHT 480
#define LENGTH 640

/*enum 创建枚举类型;创建数据类型DIR,和 DIR 数据类型关联的命名整数常量被称为枚举量,DIR 数据类型的变量可能只是关联到这些枚举量的值之一
* enum Colors { red, orange, yellow = 9, green, blue };
* 在该示例中,命名常量 red 将被赋值为 0,orange 将为 1,yellow 将为 9,green 将为 10,blue 将为 11。
*/
enum DIR
{
	UP,
	DOWN,
	LEFT,
	RIGHT,
};

//蛇的结构
struct Snake
{
	int size;//蛇的节数
	int dir;//蛇的方向
	int speed;//蛇的速度
	POINT coor[SNAKE_NUM];//坐标,蛇的最大节数为500节
}snake;

// 食物的结构
struct Food
{
	int x;
	int y;
	int r;			// 食物半径大小
	bool flag;		// 食物是否被吃了
	DWORD color;	// 食物颜色		DWORD 表示Double Word双精度
}food;

// 数据的初始化
void GameInit()
{
	// 播放背景音乐
	//mciSendString("open BGM.mp3 alias MYBGM",0,5,0);// 向多媒体设备发射一个字符串
	// alias BGM给该音乐取名为BGM
	//mciSendString("play MYBGM repeat",0,0,0);// repeat循环播放
    //这里需要添加一个.mp3纯文件到项目文件夹里。
    
	//init 初始化   graph 图形窗口大小为640*480		SHOWCONSOLE显示控制台
	initgraph(LENGTH, HEIGHT/*,SHOWCONSOLE*/);
	// 设置随机数种子
	srand(GetTickCount());//获取系统开机到现在所经过的毫秒数
	//初始化蛇
	snake.size = 3;
	snake.speed = 10;// 蛇的速度和蛇身(实心圆)的半径要形成关系,否则行走的位移大小不一样,蛇身会重合
	snake.dir = RIGHT;
	for (int i = 0; i < snake.size; i++)
	{
		snake.coor[i].x = 40-10*i;//坐标:蛇尾20蛇身30蛇头40
		snake.coor[i].y = 10;
	}
	// 初始化食物	rand():随机产生一个数,如果没有设置随机数种子,每次产生的都是固定的整数
	food.x = rand() % HEIGHT;
	food.y = rand() % LENGTH;
	// 设置随机数种子需要头文件stdlib.h	一般把时间作为随机数种子,因为时间是在不短变化的
	food.color = RGB(rand() % 256, rand() % 256, rand() % 256);
	food.r = rand() % 10 + 5;
	food.flag = true;

}

//绘制图形
void GameDraw()
{
	//双缓冲绘图
	BeginBatchDraw();
	//设置窗口背景颜色
	setbkcolor(RGB(47,79,79));
	cleardevice();//清除原设备
	//绘制蛇
	/*setfillcolor(BLUE);*/  //设置蛇的颜色
	for (int i = 0; i < snake.size; i++)
	{
		solidcircle(snake.coor[i].x, snake.coor[i].y, 5);//绘制实心圆作为蛇的一节
	}
	// 绘制食物
	if (food.flag)
	{
		solidcircle(food.x, food.y, food.r);
	}

	EndBatchDraw();//结束缓冲
}

//移动蛇
void snakeMove()
{
	// snake.coor[i].x++;
	// snake.coor[i].y++;
	// 让身体跟随头部移动
	for (int i = snake.size-1; i > 0 ; i--)
	{
		snake.coor[i] = snake.coor[i - 1];
	}
	// 移动是坐标发生改变
	switch (snake.dir)//判断移动方向,位置坐标发生相应改变
	{
	case UP:
		if (snake.coor[0].y <= 0)
		{
			snake.coor[0].y = HEIGHT;
		}
		snake.coor[0].y-=snake.speed;//蛇头向上移动
		break;
	case DOWN:
		if (snake.coor[0].y >= HEIGHT)
		{
			snake.coor[0].y = 0;
		}
		snake.coor[0].y+= snake.speed;//蛇头向下移动
		break;
	case LEFT:
		if (snake.coor[0].x <= 0)
		{
			snake.coor[0].x = LENGTH;
		}
		snake.coor[0].x-= snake.speed;//蛇头向左移动
		break;
	case RIGHT:
		if (snake.coor[0].x >= LENGTH)
		{
			snake.coor[0].x = 0;
		}
		snake.coor[0].x+= snake.speed;//蛇头向右移动
		break;
	}
}

// 通过按键改变蛇的移动方向,kbhit()和getch()需要使用一个头文件conio.h
void keyControl()
{
	//判断有无键值输入
	if (_kbhit())//_kbhit()检测是否有键值输入,若有按键输入则返回真1
	{
		//键值72 80 75 77分别表示上下左右键值
		switch (_getch())//识别获取按键方向使用getch()函数,_getch是一个阻塞函数,当把该函数放入main函数中时,按一下键盘它才动一次,所以要先判断有无键值输入
		{
		case 'w'://上
		case 'W':
		case '72'://数字键值用不了,为什么??????
			//改变方向
			if (snake.dir != DOWN)
			{
				snake.dir = UP;
			}
			break;
		case 's'://下
		case 'S':
		//case '80':
			if (snake.dir != UP)
			{
				snake.dir = DOWN;
			}
			break;
		case 'a'://左
		case 'A':
		case '75':
			if (snake.dir != RIGHT)
			{
				snake.dir = LEFT;
			}
			break;
		case 'd'://右
		case 'D':
		case '77':
			if (snake.dir != LEFT)
			{
				snake.dir = RIGHT;;
			}
			break;
		// 暂停游戏
		case ' ':
			while (1)// 输入空格,则进入死循环
			{
				if (_getch() == ' ')//若再键入空格,则返回主函数
				{
					return;
				}
			}
			break;
		}
	}
}
//吃食物
void EatFood()
{
	if (food.flag && snake.coor[0].x <= food.x + food.r && snake.coor[0].x >= food.x - food.r &&
		snake.coor[0].y <= food.y + food.r && snake.coor[0].y >= food.y - food.r)
	{
		food.flag = false;
		snake.size++;
	}
	// 食物被吃掉消失,重新生成一个食物
	if (!food.flag)
	{
		// 初始化食物
		food.x = rand() % HEIGHT;
		food.y = rand() % LENGTH;
		food.color = RGB(rand() % 256, rand() % 256, rand() % 256);
		food.r = rand() % 10 + 5;
		food.flag = true;
	}
}

int main()
{
	GameInit();
	// GameDraw();
	//snakeMove();
	while (1)//无限循环,把界面锁死,不闪屏
	{
		snakeMove();
		keyControl();
		GameDraw();
		EatFood();
		Sleep(100);//延迟50ms
	}
	return 0;
}

5.拓展(播放背景音乐)

mciSendString("open BGM.mp3 alias MYBGM",0,5,0);// 向多媒体设备发射一个字符串
// alias BGM给该音乐取名为BGM
mciSendString("play MYBGM repeat",0,0,0);// repeat循环播放

写该段代码前需添加一个.mp3纯文件到项目文件夹里。 

6.改进

该代码还存在一些bug和缺陷本文中还未解决。

bug1:游戏开始界面有概率不会出现食物。

bug2:游戏开始一半后有概率不会再出现食物。

缺陷1:每次只出现一个食物。

缺陷2:贪吃蛇的模样比较简约。

缺陷3:贪吃蛇不会撞墙死。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值