中国IT动力,最新最全的IT技术教程
最新100篇 | 推荐100篇 | 专题100篇 | 排行榜 | 搜索 | 在线API文档
首 页 | 程序开发 | 操作系统 | 软件应用 | 图形图象 | 网络应用 | 精文荟萃 | 教育认证 | 硬件维护 | 未整理篇 | 站长教程
ASP JS PHP工程 ASP.NET 网站建设 UML J2EESUN .NET VC VB VFP 网络维护 数据库 DB2 SQL2000 Oracle Mysql
服务器 Win2000 Office C DreamWeaver FireWorks Flash PhotoShop 上网宝典 CorelDraw 协议大全 网络安全 微软认证
硬件维护  CPU  主板  硬盘  内存  显卡  显示器  键盘鼠标  声卡音箱  打印机  机箱电源  BIOS  网卡  C#  Java  Delphi  vs.net2005
  当前位置:> 程序开发 > 编程语言 > Visual C++ > 图形图像与多媒体
池塘夜降彩色雨
作者:未知 时间:2005-07-20 14:14 出处:VC知识库 责编:chinaitpower
              摘要:池塘夜降彩色雨

池塘夜降彩色雨
作者:中科大少年班 陈辉
作者主页:http://go2debug.yeah.net

下载本文示例源代码

程序运行效果图如下:


一、问题描述
本程序是利用MFC制作的微软基础类应用程序,目的是模拟彩色雨滴滴落到池塘的情景,达到彩色雨滴从天而降,入水有声(尽管不怎么好听),产生圈圈涟漪。

二、数据结构:
主要的数据类型有两个带头结点的双向循环链表,这两个链表与MFC应用程序自动生成的对象类型混合使用,如下:

typedef struct {   //单个雨滴
	COLORREF color;//雨滴颜色
	bool visibility;   //可见性
	float radius; //半径
	float x;//雨滴中心位置 x
	float y;//雨滴中心位置 y
	float xvelocity;//雨滴速率 vx
	float yvelocity;//雨滴速率 vy
} droplet;

struct dropletchain {//所有雨滴组成的链表
	struct dropletchain * pre;
	droplet * drop;
	struct dropletchain * next;
};


typedef struct {//单个涟漪
	COLORREF color;//颜色
	float xdrop;//涟漪中心 x
	float ydrop;//涟漪中心 y
	float radius;//涟漪半径
	int shown;//是否绘制涟漪(这个参数在判断是否需要重绘时用到)
}ripple;

struct ripplechain {//  所有涟漪组成的链表
	struct ripplechain * pre;
	ripple * aripple;
	struct ripplechain * next;
};
对链表的操作混杂在类CCrainDlg(mfc 的对话框类)中。

三、大致的程序流程:
a) 在程序的初始化阶段 定义了两个链表
struct dropletchain dc;
struct ripplechain rc;
这两个都是空的链表,且
dc.drop=NULL;
dc.pre=&dc;
dc.next=&dc;
rc.aripple=NULL;
rc.pre=&rc;
rc.next=&rc;
b) 当点击“rain please "按钮开始绘图时,抛出一个windows子线程,这个线程负责图形的绘制工作,而主程序线程负责参数的调节和显示,以及流程的转移(如关闭子线程)。

c) 子线程的主要部分是个无限循环(直到主线程发出退出信号:通过改变重载了的CCrainDlg类的endthread参数值)
while(!this->endthread )
{
	draw();	
	draw();
	drive();	
}
第一个draw函数将图形(包括雨滴和涟漪)绘制出,第二个draw函数重绘一边,由于设置绘图模式为xor
PaintWindDC->SetROP2(R2_XORPEN);
所以第二个draw将绘好的图形擦去,由于视觉暂留,形成动画。

d) drive是驱动函数,负责对每个"元素"(包括雨滴和涟漪)的状态进行分析以得到下个时刻的状态,并随机产生新的雨滴:
//这是处理雨点程序的主要部分
adropchain=dc.next;
while(adropchain!=&dc)
{
	adrop=adropchain->drop;
	adrop->x+=(adrop->xvelocity+xacce) ;//计算下个时刻的雨点位置
	adrop->y+=(adrop->yvelocity+yacce) ;
	if(adrop->x>aRect.right ||
		adrop->x<aRect.left ||
		adrop->y<aRect.top||
		adrop->y>aRect.bottom )//分析雨点是否越界,是则删去
		{
			adropchain->next->pre=adropchain->pre;
			adropchain=adropchain->next;
			delete adropchain->pre->next->drop ;
			delete adropchain->pre->next ;
			adropchain->pre->next=adropchain;
			this->m_dropnumber --;
			sprintf(s,"%d",m_dropnumber);
			this->SetDlgItemText(IDC_EDIT5,s);
		}
	else if(adrop->y>Rect1.top+40 && rand()%4==1)//雨点到达水面则删去此雨点并产生新涟漪
	{
		struct ripplechain * arc=new struct ripplechain;
		ripple * aripple=new ripple;
		arc->aripple =aripple;
		aripple->color=adrop->color ;//删去的雨点和新生的涟漪颜色相同
		aripple->radius =adrop->radius ;//初始半径也相同
		aripple->xdrop =adrop->x;//初位置传递下来
		aripple->ydrop =adrop->y;
		aripple->shown =0;
		arc->next=rc.next ;
		arc->pre =&rc;
		rc.next->pre =arc;
		rc.next=arc;
	
		adropchain->next->pre=adropchain->pre;
		adropchain=adropchain->next;
		delete adropchain->pre->next->drop ;
		delete adropchain->pre->next ;
		adropchain->pre->next=adropchain;
		this->m_dropnumber --;
		sprintf(s,"%d",m_dropnumber);
		this->SetDlgItemText(IDC_EDIT5,s);
	
		this->m_ripplenumber ++;
		sprintf(s,"%d",m_ripplenumber);
		this->SetDlgItemText(IDC_EDIT6,s);
		if(rand()%10==1 && soundon) 
				Beep(4000,1);                      //落水有声
	}	
	else//对下个雨点进行判断
	{
		adropchain=adropchain->next;
	} 
//下面是处理涟漪的程序的主要部分
aripplechain=rc.next;
while(aripplechain!=&rc)
{
	aripple=aripplechain ->aripple;
	if(aripple->radius>40 && aripple->shown ==0)//判断是否应删去此涟漪
	{
		aripplechain->next->pre=aripplechain->pre;
		aripplechain=aripplechain->next;
		delete aripplechain->pre->next->aripple  ;
		delete aripplechain->pre->next ;
		aripplechain->pre->next=aripplechain;
		this->m_ripplenumber --;
		sprintf(s,"%d",m_ripplenumber);
		this->SetDlgItemText(IDC_EDIT6,s);
	}
	else
	{
		aripple->radius +=1;//涟漪扩展
		aripplechain=aripplechain->next;//对下个涟漪进行判断
	}
}

e) 风的引入
这个程序对风进行即时的调节:
当鼠标在绘图区之外时无风;
当鼠标在绘图区之内时风矢量的起点在绘图区中心,终点在鼠标所指点,并且“风力”和“风向”参数在右侧显示出来。
风的实现是通过主线程改变CCrainDlg类的xacce和yacce的值来使绘图子线程得到相应的,因此这是即时的响应,不断改变鼠标位置可以使雨点曲线下落。

四、调试分析

a )数据类型很简单,对其的操作主要是遍历和插入以及删除,遍历的时间复杂度O(n)其它两个是O(1)

b )主要的难点在
线程控制,使程序达到参数即时可控,同时提高程序的健壮性
动画绘制,为了不产生抖动,尽可能不引入过多的函数,因为函数太多会带来系统栈操作的开销
windows图形处理,由于mfc绘制图形要很多“设备”所以比较麻烦,我曾没把将用过的CDC类型设备release掉而使计算机内存以每秒大约1兆的速率被吞噬掉,系统内存资源很快用光。

c )通过这个程序,较好地理解了前台处理与后台“结构”之间地关系,只要数据结构设计合理,关键在前台,但前台有时会制约后台(入为了提高速度以达到“即时响应“地目的)

d )通过这个程序,熟练了mfc的编程。

五、使用说明
点击"rain please"按钮即可进行绘图。鼠标的位置可以控制风的大小和方向.一些数据即时显示在右方.点击"hear rain"即可听到雨声。 点击"exit"退出。

作者简介:
中国科学技术大学少年班 陈辉 PB00004006
邮箱:go2debug@hotmail.com
主页:go2debug.yeah.net
作者近影:
关闭本页
 
首页 | 投资与合作 | 服务条款 | 隐私政策 | 收藏本站 | 设为首页 | 新用户注册 | 免责声明 | 使用帮助
Copyright ©2005-2008 chinaitpower.com All rights reserved. www.chinaitpower.com 版权所有