贪吃蛇(有穿墙+BGM功能)项目

一:首先下载一首音乐,这里我下载的是萧敬腾唱的斗罗大陆音乐,然后我把音乐格式转成了mp3,最后我把音乐名字改成了dldl.mp3。

二:BGM—dldl.mp3的存放位置:
在这里插入图片描述
在这里插入图片描述

三.
点击项目-属性
在这里插入图片描述
找到这个地方,把字符集改成“使用多字节字符集”:
在这里插入图片描述
源文件:Snake.cpp

#include<stdio.h>
#include<graphics.h>
#include<stdlib.h>
#include<time.h>
#include<conio.h>
#include<mmsystem.h>//多媒体设备的头文件,用来播放音乐
#pragma comment(lib,"winmm.lib")//多媒体设备的库文件,用来播放音乐

#define SNAKE_NUM 500//蛇的最大节数
int score = 0;//玩家得分一开始设置为0

//表示蛇的方向
enum DIR
{
	UP,
	DOWN,
	LEFT,
	RIGHT,
};

//对蛇各项属性的定义
struct Snake
{
	int size;//蛇的节数
	int dir;//蛇的方向
	int speed;//蛇的速度
	POINT coor[SNAKE_NUM];//蛇的坐标
}snake;

//对食物各项属性的定义
struct Food
{
	int x;			//食物的横坐标
	int y;			//食物的纵坐标
	int r;			//食物大小
	bool flag;		//食物是否被吃了
	DWORD color;	//食物颜色
}food;

//对蛇各项属性数据的初始化
void GameInit1()
{
	//播放背景音乐
	mciSendString("open ./res/dldl.mp3 alias BGM", 0, 0, 0);//用alias起一个别名叫BGM
	mciSendString("play BGM repeat",0,0,0);//用repeat循环播放BGM
	/*对蛇各项属性数据的初始化*/
	initgraph(640, 520/*SHOWCONSOL*/);//SHOWCONSOLE用于显示控制台,640是墙的宽,520是墙的高
	snake.size = 3;//初始化蛇的节数为3
	snake.speed = 10;//初始化蛇头的速度是10
	snake.dir = RIGHT;//初始化蛇的方向向右
	for (int i = 0; i < snake.size; i++)//0 1 2
	{
		snake.coor[i].x = 40 - 10 * i;//40 30 20
		snake.coor[i].y = 10;//10
	}
}

//对食物各项属性数据的初始化
void GameInit2()
{
	srand(timeGetTime());//函数以毫秒计的系统时间。该时间为从系统开启算起所经过的时间。
	food.x = rand() % 620 + 10;//对食物横坐标初始化且不让食物出现在边界上(故意写620给分数窗口留空间)
	food.y = rand() % 460 + 10;//对食物纵坐标初始化且不让食物出现在边界上(故意写460给分数窗口留空间)
	food.color = RGB(rand() % 256, rand() % 256, rand() % 256);//对食物颜色初始化
	food.r = rand() % 10 + 5;//对食物半径初始化
	food.flag = true;//对食物存在初始化,true代表是食物存在,false代表没食物不存在
}

//绘制,显示蛇的形状
void GameDraw()
{
	BeginBatchDraw(); //双缓冲绘图开始,防止闪屏
	//设置窗口背景颜色
	setbkcolor(RGB(28, 115, 119));
	cleardevice();
	//绘制蛇
	setfillcolor(GREEN);//给蛇设置成绿色
	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()
{
	//假设蛇从右向左分别占了位置0、1、2,两次for循环,第一次for循环1和2都在位置2,0在位置1;
	//第二次for循环2在位置1,0和1在位置0
	for (int i = snake.size - 1; i > 0; i--)//i数值是2、1
	{
		snake.coor[i] = snake.coor[i - 1];//snake.coor[i]中x和y的坐标位置将变为snake.coor[i-1]中x和y的坐标位置
		//从而实现蛇身体的移动
	}
	//switch使蛇头移动
	switch (snake.dir)
	{
	case UP:
		snake.coor[0].y -= snake.speed;
		if (snake.coor[0].y <= 0)//如果蛇穿出了最上面的墙
		{
			snake.coor[0].y = 480;//那么就把蛇的初始位置放在最下面的墙,480是墙的高
		}
		break;
	case DOWN:
		snake.coor[0].y += snake.speed;
		if (snake.coor[0].y >= 480)//如果蛇穿出了最下面的墙
		{
			snake.coor[0].y = 0;//那么就把蛇的初始位置放在最上面的墙,480是墙的高
		}
		break;
	case LEFT:
		snake.coor[0].x -= snake.speed;
		if (snake.coor[0].x <= 0)//如果蛇穿出了最左面的墙
		{
			snake.coor[0].x = 640;//那么就把蛇的初始位置放在最右面的墙,640是墙的宽
		}
		break;
	case RIGHT:
		snake.coor[0].x += snake.speed;
		if (snake.coor[0].x >= 640)//如果蛇穿出了最右面的墙
		{
			snake.coor[0].x = 0;//那么就把蛇的初始位置放在最左面的墙,640是墙的宽
		}
		break;
	}
}

//通过按键改变蛇的移动方向及暂停蛇
void keyControl()
{
	//kbhit() 是一个C和C++函数,用于非阻塞地响应键盘输入事件
	//72 80 75 77 代表 上下左右键值
	if (_kbhit())
	{
		char t = _getch();
		if (t == -32) //用_getch()会产生双键值,第一个键值是-32,第二个才是上下左右键的实际键值
		{//所以要通过if来中和第一个键值。下面注释的代码可以测试你按下键值的双键值分别是多少
			t = _getch();
		}
		/*#include<cstdio>
		#include<conio.h>

		int main()
		{
			char c =NULL;
			while (c != 29)
			{
				if (c = _kbhit())
				{
					printf("kbhit:%d\n", c);
					c = _getch();
					printf("getch:%d\n", c);
				}
			}
		}*/
		switch (t)//_getch() 函数读入一个字符时 不用 enter 代码会继续跑
		{
		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死循环
			while (1)
			{
				if (_getch() == ' ')//再次输入空格,则执行return后退出keyControl()函数,死循环就不存在了
					//此时蛇就能正常跑
					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++;
		score += 10;// food.r
	}
	//如果食物被吃完了,则重新初始化食物
	if (!food.flag)
		GameInit2();
}

//玩家得分
void ComScore() //绘制得分窗口 
{
	setfillcolor(RGB(28, 115, 119));//填充得分矩形颜色为蓝绿色
	fillrectangle(0, 480, 639, 519);//得分矩形左部x坐标:0,矩形顶部y坐标:480,矩形右部x坐标:639,矩形底部y坐标:519
	settextcolor(BLACK);//设置指定DC中的文字颜色。
	char num[100];//定义字符串,存放得分 
	int t = score, k = 0; //t是临时变量,存放得分以便于计算得分,如果直接使用score会改变全局变量,k是字符数组下标 

	while (t) //把一个整型数的每一位转换成字符存放到字符数组中 
	{
		num[k++] = t % 10 + '0'; //把分数最后一位变成字符型,存放到数组中
		t /= 10; //把分数最后一位去掉以便于取得前面的数 
	}

	if (k == 0) //如果一开始得分就是0,那么就不会进入到上面的while循环里,所以需要再把0存到数组中 
		num[k++] = '0';


	outtextxy(13, 493, _T("得分:"));//在指定位置输出字符串
	for (int i = k - 1; i >= 0; i--)
	{
		outtextxy(60 + (k - i - 1) * 10, 493, num[i]);//在指定位置输出字符串
	}
	EndBatchDraw();//双缓冲绘图结束,防止闪屏
}

int main()
{
	GameInit1();//对蛇各项属性数据的初始化
	GameInit2();//对食物各项属性数据的初始化

	while (1)
	{
		GameDraw();//绘制,显示蛇的形状
		ComScore();//玩家得分
		keyControl();//通过按键改变蛇的移动方向及暂停蛇
		snakeMove();//移动蛇
		EatFood();//判断蛇吃食物
		Sleep(80);//延时0.08秒
	}
	return 0;
}

四.运行结果:
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值