学习记录_C语言打砖块小游戏

第一次体验到了写代码一上午,修BUG修一天的感觉。但还有一个BUG始终不知道如何解决,那便是如果额外产生的小球触碰到礼盒砖块(会产生额外球),便会在左上角出现隐形球。无奈只好将礼盒砖块改为一个,并将存放小球信息的数组改为2。若有大佬给出建议,不胜感激。

玩法如下:

游戏有四种颜色砖块随机刷新在地图上:分别是深灰色(三血)、灰色(二血)、棕褐色(一血)、绿色(赠送额外小球);

使用鼠标控制球板移动,当所有砖块被击碎时胜利,否则失败。

1.效果展示:

2.编程思路:

构造二维数组来存储砖块,数组内容分别为0、1、2、3、4来表示不同种类的砖块。当小球进入砖块时触发碰撞检测,并对砖块生命值减一。同时用画墙函数根据当前数组中存储的内容来绘制砖块。

3.核心程序:

已知打砖块下游戏需要用小球实现对球板、砖块、窗口的碰撞。那么,程序的核心内容就是碰撞函数。由于知识有限,在写对砖块的碰撞函数时,先将一个砖块碰撞检测范围分为8部分,本别是四个顶角,以及上下左右两侧,当小球进入砖块时,便根据小球当前坐标在砖块内部范围进行检测。并根据检测内容给与小球不同方向的速度。

4.代码展示:

#define _CRT_SECUURE_NO_WARNINGS
#include <stdio.h>
#include <easyx.h>
#include <time.h>

/*碰撞思路:
首先定义一组二维数组表示,存放1表示砖块,0表示砖块被打碎
每个砖块都有自己的坐标x、y
进行碰撞检测时,若一个砖块对应的数组值为1,则触发检测
碰撞检测:
根据二维数组为砖块提高的x、y值,可以得打一块砖块的下、左、右三条边以及下方两个顶点
当小球碰到下边时,只需将y轴速度取反即可完成弹射效果
当小球碰到两侧时,只需将x轴速度取反即可完成弹射效果
但是
当小球碰到顶点时,需要将x轴与y轴速度均取反*/

#define block_w 85//砖块宽度
#define block_h 45//砖块高度
#define space 2//砖块间距
#define num_w 10//砖块横向数量
#define num_h 10//砖块纵向数量
/*在像素坐标中,以水平方向为x轴,铅垂方向为y轴,
但对应的数组中,以y表示行数,x表示列数*/
int num = 1;//当前小球数量
int flag = 0;//是否需要产生额外小球标志
int flag_1 = 0;//是否开始发射标志
int flag_2 = 0;//是否发生第一次弹射标志
int flag_3 = 0;//产生第n个额外小球标志
int tmpx = 0;
int tmpy = 0;
float decide = 4;//碰撞判定范围追加值
int arr[num_h][num_w];

enum speed//定义小球移动速度
{ 
	none,
	slowly = 2,
	medium,
	fastly  
};
typedef struct Ball//定义小球参数
{
	int x;
	int y;
	int r;
	int speedx;
	int speedy;	
}Ball;

void Wall()//墙体函数:根据每个砖块对应的二维数组的值来绘制不同颜色,若0值则不绘制砖块
{
	int x = 0, y = 0;
	for (y = 0; y < num_h; y++)
	{
		for (x = 0; x < num_w; x++)
		{
			if (arr[y][x])
			{
				if (arr[y][x] == 1)
				{
					setfillcolor(RGB(128, 128, 0));
				}
				else if (arr[y][x] == 2)
				{
					setfillcolor(RGB(128, 128, 128));
				}
				else if (arr[y][x] == 3)
				{
					setfillcolor(RGB(104, 104, 104));
				}
				else
				{
					setfillcolor(RGB(0, 128, 64));
				}
				solidrectangle(block_w * x, block_h * y, block_w * (x + 1) - space, block_h * (y + 1) - space);
			}		
		}
	}
}
void Extra(Ball ball[]);
void Check_crash(int* x, int* y, Ball* ball)//检测碰撞位置函数:进入一个砖块碰撞范围内,检测碰撞的位置
{
	if (arr[*y][*x] == 1)//撞到一血砖块直接撞碎
	{
		arr[*y][*x] = 0;
	}
	else if (arr[*y][*x] == 4)//撞到礼盒砖块得到一个额外球
	{
		arr[*y][*x] = 0;
		if (num < 3)
		{
			num++;
			flag_3++;
		}
		flag = 1;
		tmpx = ball->x;
		tmpy = ball->y;
		printf("%d\n", num);
		Extra(ball);
	}
	else
	{
		arr[*y][*x] -= 1;
	}
		//一个砖块的右边,截取宽度为两个像素,再去掉上边两个像素的矩形和下边两个像素的矩形,剩余的面积判定为右侧
	/*___|______________|___
	*    |              |右
	* ___|______________|侧_
		 |              |    */
	if (ball->x <= block_w * (*x + 1) - space && ball->x >= block_w * (*x + 1) - space - decide &&
		ball->y <= block_h * (*y + 1) - space - decide && ball->y >= block_h * (*y) + decide)//碰到砖块右侧
	{
		printf("右侧:%d\n", ball->speedx);
		ball->speedx = medium;
	}
	else if (ball->x>= block_w * (*x) && ball->x <= block_w * (*x) + decide &&
			 ball->y <= block_h * (*y + 1) - space - decide && ball->y >= block_h * (*y) + decide)//碰到砖块左侧
	{
		printf("左侧:%d\n", ball->speedx);
		ball->speedx = -medium;
	}
	else
	{
			//一个砖块的下边,截取宽度为两个像素,再去掉左边两个像素的矩形和右边两个像素的矩形,剩余的面积判定为下侧
			/*___|______________|___
			*    |              |
			* ___|______________|___
				 |     下 侧    |    */
		if (ball->y <= block_h * (*y + 1) - space && ball->y >= block_h * (*y + 1) - space - decide &&
			ball->x <= block_w * (*x + 1) - space - decide && ball->x >= block_w * (*x) + decide)//碰到砖块底边
		{
			ball->speedy = -fastly;
			printf("底边:%d\n", ball->speedy);
		}
		else if (ball->y >= block_h * (*y) && ball->y <= block_h * (*y) + decide &&
				 ball->x <= block_w * (*x + 1) - space - decide && ball->x >= block_w * (*x) + decide)//碰到砖块顶边
		{
			printf("顶边:%d\n", ball->speedy);
			ball->speedy = fastly;
		}
	}
	if (ball->x > block_w * (*x + 1) - space - decide && ball->x < block_w * (*x + 1) &&
		ball->y > block_h * (*y + 1) - space - decide && ball->y < block_h * (*y + 1))
	{
		printf("右下角:%d\t%d\n", ball->speedx, ball->speedy);
		ball->speedx = medium;
		ball->speedy = -fastly;
	}
	else if (ball->x > block_w * (*x) && ball->x < block_w * (*x) + decide &&
			 ball->y > block_h * (*y + 1) - space - decide && ball->y < block_h * (*y + 1))
	{
		printf("左下角:%d\t%d\n", ball->speedx, ball->speedy);
		ball->speedx = -medium;
		ball->speedy = -fastly;
	}
	else if (ball->x > block_w * (*x + 1) - space - decide && ball->x < block_w * (*x + 1) &&
			 ball->y > block_h * (*y) + decide && ball->y < block_h * (*y))
	{
		printf("右上角:%d\t%d\n", ball->speedx, ball->speedy);
		ball->speedx = -medium;
		ball->speedy = fastly;
	}
	else if (ball->speedx > block_w * (*x) && ball->speedx < block_w * (*x) + decide &&
			 ball->speedy > block_h * (*y) + decide && ball->speedy < block_h * (*y))
	{
		printf("左上角:%d\t%d\n", ball->speedx, ball->speedy);
		ball->speedx = medium;
		ball->speedy = fastly;
	}	
}
void Check_edge(Ball* ball)//窗口边缘碰撞检测
{
	if (ball->x <= ball->r)
	{
		ball->speedx = medium;
	}
	else if (ball->x >= block_w * 10 - ball->r)
	{
		ball->speedx = -medium;
	}
	else if (ball->y <= ball->r)
	{
		ball->speedy = -fastly;
	}
}
void Crash(Ball ball[])//碰撞函数
{
	int x = 0, y = 0, i = 0;
	for (y = 0; y < num_h; y++)
	{
		for (x = 0; x < num_w; x++)
		{
			for (i = 0; i < num; i++)
			{
				if (arr[y][x] >= 1 &&//遍历所有小球,检测各个小球是否进入砖块碰撞范围,若进入,则对该小球调用碰撞检测函数实现该小球的碰撞
					(ball[i].x <= block_w * (x + 1) - space &&
					 ball[i].x >= block_w * x &&
					 ball[i].y <= block_h * (y + 1) - space &&
				     ball[i].y >= block_h * y))
				{
					flag_2 = 1;
					Check_crash(&x, &y, &ball[i]);
				}
				else//若没有则检测是否与窗口碰撞
				{
					Check_edge(&ball[i]);
				}
			}
		}
	}
}
void Check_board(int* site, Ball* ball)//检测板子碰撞函数
{
	if (ball->x <= *site + 100 + ball->r && ball->x >= *site + 90 && ball->y >= block_h * num_h + 400 - ball->r)//碰到板子右角
	{
		ball->speedx = medium;
		ball->speedy = fastly;
	}
	else if (ball->x >= *site - ball->r && ball->x <= *site + 10 && ball->y >= block_h * num_h + 400 - ball->r)//碰到板子左角
	{
		ball->speedx = -medium;
		ball->speedy = fastly;
	}
	else
	{
		if (ball->y >= block_h * num_h + 400)//碰到板子顶边
		{
			ball->speedy = fastly;
		}
	}
}
void Board(ExMessage* msg, Ball ball[])//球板函数
{
	static int site = block_w * 5 + 10;
	if (peekmessage(msg, EM_MOUSE))
	{
		site = msg->x;//球板位置
		if (msg->lbutton)
		{
			flag_1 = 1;
		}
	}
	if (!flag_1)//若没有按下左键,则球的位置跟随球板位置
	{
		ball[0].x = site + 50;
		ball[0].y = block_h * num_h + 400;
	}
	setfillcolor(BLUE);
	fillrectangle(site, block_h * num_h + 400, site + 100, block_h * num_h + 410);
	for (int i = 0; i < num; i++)
	{
		if (ball[i].x <= site + 100 + ball[i].r && ball[i].x >= site - ball[i].r &&
			ball[i].y <= block_h * num_h + 410 && 
			ball[i].y >= block_h * num_h + 400 - ball[i].r && flag_2)
		{
			Check_board(&site, &ball[i]);
		}
	}
}
void Extra(Ball ball[])//产生额外小球
{
	if (flag_3 && flag)
	{
		ball[flag_3].x = tmpx;//额外小球初始位置和起始小球初始位置相同
		ball[flag_3].y = tmpy;
		ball[flag_3].r = ball[0].r;
		ball[flag_3].speedx = none;
		ball[flag_3].speedy = fastly;
		printf("最新的小球的x速度:%d和y速度%d位置为%d %d\n", ball[flag_3].speedx, ball[flag_3].speedy, ball[flag_3].x, ball[flag_3].y);
		flag = 0;
	}
}
void Ball_move(Ball ball[])//小球移动函数
{
	if (flag_1)
	{
		ball[0].y -= ball[0].speedy;
		ball[0].x += ball[0].speedx;		
	}
	if (flag_3)
	{
		for (int i = 0; i < flag_3; i++)
		{
			ball[i + 1].y -= ball[i + 1].speedy;
			ball[i + 1].x += ball[i + 1].speedx;
			setfillcolor(RGB(128, 128, 64));
			fillcircle(ball[i + 1].x, ball[i + 1].y - ball[i + 1].r, ball[i + 1].r);
			printf("球的位置x:%d,y:%d\n", ball[i + 1].x, ball[i + 1].y);
		}
	}
	setfillcolor(RGB(0, 128, 64));
	fillcircle(ball[0].x, ball[0].y - ball[0].r, ball[0].r);
	Sleep(1);
}
void Random()//对墙体砖块随机化,其中有4个礼盒砖块,15个三血砖块,30个二血砖块,20个空位,剩余的均为一血砖块
{
	int x = 0, y = 0;
	for (x = 0; x < num_w; x++)//先将砖块全部初始化为一血
	{
		for (y = 0; y < num_h; y++)
		{
			arr[y][x] = 1;
		}
	}
	int gift = 1;
	int empty = 20;
	int life_3 = 15;
	int life_2 = 30;
	while (life_2)
	{
		int i = rand() % num_w;
		int j = rand() % num_h;
		if (arr[j][i] == 1)
		{
			arr[j][i] = 2;
			life_2--;
		}
	}
	while (life_3)
	{
		int i = rand() % num_w;
		int j = rand() % num_h;
		if (arr[j][i] == 1)
		{
			arr[j][i] = 3;
			life_3--;
		}
	}
	while (gift)
	{
		int i = rand() % num_w;
		int j = rand() % num_h;
		if (arr[j][i] == 1)
		{
			arr[j][i] = 4;
			gift--;
		}
	}
	while (empty)
	{
		int i = rand() % num_w;
		int j = rand() % num_h;
		if (arr[j][i] == 1)
		{
			arr[j][i] = 0;
			empty--;
		}
	}
}
int Judge(Ball ball[])//判断小球是否都掉落,若全部掉落则游戏失败
{
	int count1 = 0;
	int count2 = 0;
	int x = 0, y = 0;
	for (x = 0; x < num_h; x++)
	{
		for (y = 0; y < num_w; y++)
		{
			if (arr[x][y] == 0)
			{
				count2++;
				if (count2 == num_w * num_h)
				{
					return 2;
				}
			}
		}
	}
	for (int i = 0; i < num; i++)
	{
		if (ball[i].y >= block_h * num_h + 500)
		{
			count1++;
		}
	}
	if (count1 == num)
	{
		return 0;
	}
	return 1;
}
int Menu(ExMessage* msg)//菜单函数
{
	BeginBatchDraw();
	setbkcolor(WHITE);
	cleardevice();
	char str[] = "按Enter开始游戏";
	settextcolor(RED);
	setbkmode(TRANSPARENT);
	settextstyle(100, 0, "楷体");
	int wid = textwidth(str);
	int hei = textheight(str);
	setfillcolor(BLUE);
	fillrectangle((block_w * num_w - wid) / 2, (block_h * num_h + 500 - hei) / 2, block_w * num_w - (block_w * num_w - wid) / 2, block_h * num_h + 500 - (block_h * num_h + 500 - hei) / 2);
	outtextxy((block_w * num_w - wid) / 2, (block_h * num_h + 500 - hei) / 2, str);
	FlushBatchDraw();
	if (peekmessage(msg, EM_KEY))//按键检测
	{
		if (msg->vkcode == 13)
		{
			return 0;
		}
	}
	return 1;
}
int main()
{
	int play = 1;
	int start = 1;
	int i = 0, j = 0;
	Ball ball[10] = { { 0, 450, 10, none, fastly   } ,{ 0, 0, 0, none, none }};
	ExMessage msg;
	srand((unsigned int)time(NULL));
	Random();
	initgraph(block_w * num_w, block_h * num_h + 500, EW_SHOWCONSOLE);
	while (start)
	{
		start = Menu(&msg);
	}
	while (play == 1)
	{
		BeginBatchDraw();
		setbkcolor(RGB(170, 170, 255));
		cleardevice();
		Wall();
		Board(&msg, ball);
		Crash(ball);
		Ball_move(ball);
		EndBatchDraw();
		play = Judge(ball);
	}
	while (1)
	{
		BeginBatchDraw();
		setbkcolor(WHITE);
		cleardevice();
		char str1[] = "菜逼快去学习";
		char str2[] = "666";
		settextcolor(RED);
		setbkmode(TRANSPARENT);
		settextstyle(50, 0, "楷体");
		int wid1 = textwidth(str1);
		int hei1 = textheight(str1);
		int wid2 = textwidth(str2);
		int hei2 = textheight(str2);
		if (play == 0)
		{
			outtextxy((block_w * num_w - wid1) / 2, (block_h * num_h + 500 - hei1) / 2, str1);
		}
		else
		{
			outtextxy((block_w * num_w - wid2) / 2, (block_h * num_h + 500 - hei2) / 2, str2);
		}
		FlushBatchDraw();
	}
	getchar();
	closegraph();
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值