大家对WINDOWS的屏幕保护程序气泡一定不陌生,在此写一个简单的一个泡泡碰到四周会反弹的小程序,该程序所用到的所有函数,在上一遍日志C语言实现电子钟中都有提到,全部代码的话,在同名的资源中。在此只给出最关键的主函数。相信一目了然,注释也很丰富。
#include "clock_include.h"
#include "LCD_function.h"
#include "pxy_function.h"
#include "RTC_function.h"
#include "UART.h"
/**************************************************************************
***** 函数名: main()
***** 功能: 随机泡泡
***** 参数: 无
***** 返回值:
***** 创建者: 潘星宇
***** 创建时间: 2012-12-26
***** 最后更新:2013-1-5
****************************************************************************/
int main(void)
{
int random_value; //随机数存储变量
volatile static float angle; //角度值
float d; //画圆用1
U32 end_i;
U32 end_j;
volatile static U32 x0 = 250; //圆心坐标
volatile static U32 y0 = 100;
volatile static U32 x_register = 250; //储存上一次的圆心坐标
volatile static U32 y_register = 100;
static U32 radius = 30; //半径
int x; //画圆用2
int y; //画圆用3
volatile static U8 change_flag = 0; //碰到边框标志
volatile static U32 longth = 1; //长度计数用
const U32 enge_left = 50; //定义左边界
const U32 enge_right = 450; //定义右边界
const U32 enge_up = 20; //定义上边界
const U32 enge_down = 220; //定义下边界
LCD_Init(); //LCD初始化
Brush_Background(0xffff); //绘制背景
for (end_i=0; end_i<=400; end_i++) //绘制边框
{
PutPixel(50+end_i,20,0x0);
PutPixel(50+end_i,220,0x0);
}
for (end_j=0; end_j<=200; end_j++) //绘制边框
{
PutPixel(50,20+end_j,0x0);
PutPixel(450,20+end_j,0x0);
}
random_value = rand();
if (random_value < 0)
{
random_value = 0 - random_value;
}
random_value = random_value % 180; //对180求余
angle = (PI / 180)*random_value; //得到一随机角度
while (1)
{
while (1)
{
MidpointCircle (x_register, y_register, radius, 0xffff);
x=0;
y=radius;
d=5.0/4-radius;
while(x<=y)
{
PutPixel(x0+x,y0+y,0x0);
PutPixel(x0+x,y0-y,0x0);
PutPixel(x0-x,y0+y,0x0);
PutPixel(x0-x,y0-y,0x0);
PutPixel(x0+y,y0+x,0x0);
PutPixel(x0+y,y0-x,0x0);
PutPixel(x0-y,y0+x,0x0);
PutPixel(x0-y,y0-x,0x0);
if ((x0+x <= enge_left)||(x0-x <= enge_left)||(x0+y <= enge_left)||(x0-y <= enge_left)) //判断是否碰到了左边界
{
change_flag = 1;
}
else if ((x0+x >= enge_right)||(x0-x >= enge_right)||(x0+y >= enge_right)||(x0-y >= enge_right)|| //判断是否碰到了右边界
(y0+y >= enge_down) || (y0-y >= enge_down)||(y0+x >= enge_down)||(y0-x >= enge_down)) //判断是否碰到了下边界
{
change_flag = 2; //右与下边界反弹规律一致
}
else if ((y0+y <= enge_up)||(y0-y <= enge_up)||(y0+x <= enge_up)||(y0-x <= enge_up)) //判断是否碰到了上边界
{
change_flag = 3;
}
if(d<0)
{
d+=x*2.0+3;
}
else
{
d+=2.0*(x-y)+5;
y--;
}
x++;
}
for (end_i=0; end_i<=400; end_i++) //绘制边框
{
PutPixel(50+end_i,20,0x0);
PutPixel(50+end_i,220,0x0);
}
for (end_j=0; end_j<=200; end_j++) //绘制边框
{
PutPixel(50,20+end_j,0x0);
PutPixel(450,20+end_j,0x0);
}
delay (10000);
x_register = x0; //储存上一次的值
y_register = y0;
if (change_flag == 1) //碰到边框了
{
change_flag = 0;
if (angle > PI / 2.0)
{
angle = PI - angle;
}
else
{
angle = 2*PI - angle;
}
}
else if (change_flag == 2)
{
change_flag = 0;
if (angle > PI / 2.0)
{
angle = 2*PI - angle;
}
else
{
angle = PI - angle;
}
}
else if (change_flag == 3)
{
change_flag = 0;
angle = 2*PI - angle;
}
x0 = (U32)(x0 + longth*cos(angle) + 0.5); //圆心变化
y0 = (U32)(y0 - longth*sin(angle) + 0.5);
}
}
}
在此补充两点:
(1)一开始的随机函数是想让每次小球出现的位置不一致,后来发现实际上每次上电的位置都是一样的,推测应该是随机函数每次运行第一次结果是一样的,欢迎拍砖;
(2)随机泡泡反弹关键在于角度的确定和判断是否触边。
<1>角度不管反弹多少次,一定还是同一个角度(不过象限发生了变化),笔者没用这种方法
<2>按照数学上x正半轴为起点,逆时针旋转判断角度,分为上,下左右四个边界的方法,通过入射角来求反射角,笔者采用的是这种方法
(3)判断是否触边,笔者在这个程序里,用的是第一种八点画圆的方法,再每次画完八个点后,即进行判断,当然可以简化判断条件
(4)如果将边界拓展到物理屏以外,也就是虚拟屏大于物理屏的效果,就跟WINDOWS的气泡效果差不多了,不过WINDOWS的更为复杂,不仅有多个气泡的
碰撞效果,还有变色,阻尼效果等,感兴趣的朋友可以去搜别的文章,在此只是给大家提供个人的一个小小的思路,欢迎拍砖。