matlab五彩多图案3D烟花
来源:互联网 发布:nginx重定向域名不变 编辑:程序博客网 时间:2024/05/16 01:41
使用matlab制作漂亮的烟花,核心实现在于烟花图式的控制和关于如何控制多支烟花的同时释放。烟花样式的呈现需要经过复杂的数学表达式生成,升级到发射的角度和位移事变公式等,而多支烟花的同时释放难题源于matlab对多线程的不支持,幸运的是,matlab有Timer定时器,这样,我们可以实现单线程的非阻塞式烟花齐放。先上一张烟花爆炸的图形。
程序还支持在爆炸过程中即时随机改变烟花颜色,实现五彩缤纷的效果。
在程序中,我们可以通过滚动条调整RBG动态调整烟花颜色,可以改变烟花爆炸的速度和烟花爆炸后的颗粒数量,此外,还有下落的加速度。在上侧菜单中,我们可以选择不同的爆炸风格图案,背景图片,颜色等。这些都是通过回调函数的触发动态改变。
下面附上程序源码,大家有觉得写得不好的地方或不理解的地方都可以在下面评论讨论。
function yanhuamoban() clear all; %定义全局变量 global ah ;%坐标轴句柄 global styleNum ;%爆炸图案样式 global multiColor; %多颜色变换 global color;%烟花颜色 global v0;%烟花爆炸速度 global n; %粒子数量 global g;%粒子重力加速度 %变量初始化开始 multiColor = 0; styleNum = 3; color = [1 1 0]; v0 = 250; %烟花爆炸时的速度 n = 2000;%粒子shumu g=1000; %变量初始化结束 %GUI部分开始 fig = figure('units','normalized','position',[0.1 0.1 0.6 0.8],... 'menubar','none','numberTitle','off','Name','烟花欣赏','WindowButtonDownFcn',@yanhua... ); %菜单 file_menu = uimenu(fig,'Label','文件(&f)'); sub_file_menu1 = uimenu(file_menu,'Label','退出(&q)','CallBack',@file_menu_callback); style_menu = uimenu(fig,'Label','爆炸风格(&s)'); sub_style_menu1 = uimenu(style_menu,'Label','风格(&1)','CallBack',@style_menu_callback); sub_style_menu2 = uimenu(style_menu,'Label','风格(&2)','CallBack',@style_menu_callback); sub_style_menu3 = uimenu(style_menu,'Label','风格(&3)','CallBack',@style_menu_callback); sub_style_menu4 = uimenu(style_menu,'Label','风格(&4)','CallBack',@style_menu_callback); sub_style_menu5 = uimenu(style_menu,'Label','风格(&5)','CallBack',@style_menu_callback); sub_style_menu6 = uimenu(style_menu,'Label','风格(&6)','CallBack',@style_menu_callback); picture_menu = uimenu(fig,'Label','背景图片(&p)'); sub_picture_menu1 = uimenu(picture_menu,'Label','图片(&1)','CallBack',@picture_menu_callback); sub_picture_menu2 = uimenu(picture_menu,'Label','图片(&2)','CallBack',@picture_menu_callback); sub_picture_menu3 = uimenu(picture_menu,'Label','图片(&3)','CallBack',@picture_menu_callback); sub_picture_menu4 = uimenu(picture_menu,'Label','图片(&4)','CallBack',@picture_menu_callback); sub_picture_menu5 = uimenu(picture_menu,'Label','图片(&5)','CallBack',@picture_menu_callback); color_menu = uimenu(fig,'Label','烟花颜色(&c)'); sub_color_menu1 = uimenu(color_menu,'Label','黄色(&1)','CallBack',@color_menu_callback); sub_color_menu2 = uimenu(color_menu,'Label','紫红色(&2)','CallBack',@color_menu_callback); sub_color_menu3 = uimenu(color_menu,'Label','青色(&3)','CallBack',@color_menu_callback); sub_color_menu4 = uimenu(color_menu,'Label','红色(&4)','CallBack',@color_menu_callback); sub_color_menu5 = uimenu(color_menu,'Label','绿色(&5)','CallBack',@color_menu_callback); sub_color_menu6 = uimenu(color_menu,'Label','蓝色(&6)','CallBack',@color_menu_callback); sub_color_menu7 = uimenu(color_menu,'Label','白色(&7)','CallBack',@color_menu_callback); sub_color_menu8 = uimenu(color_menu,'Label','五彩变换(&8)','CallBack',@color_menu_callback); %按钮面板 color_button_group = uibuttongroup(fig,'Title','颜色调节面板','Position',[0.83,0.55,0.16,0.44]); speed_button_group = uibuttongroup(fig,'Title',regexprep('速度调节面板(num)','num',num2str(v0)),'Position',[0.83,0.36,0.16,0.185],'Tag','speed_panel'); number_button_group = uibuttongroup(fig,'Title',regexprep('数量调节面板(num)','num',num2str(n)),'Position',[0.83,0.005,0.16,0.35],'Tag','ammount_panel'); %颜色微调滑动条 red_slider = uicontrol(fig,'Style','slider','String','red','Position',[695,450,25,140],'Min',0,'Max',1,'Value',1,'backgroundColor',[1,0,0],'CallBack',@slider_callback); green_slider = uicontrol(fig,'Style','slider','String','green','Position',[735,450,25,140],'Min',0,'Max',1,'Value',1,'backgroundColor',[0,0,1],'CallBack',@slider_callback); blue_slider = uicontrol(fig,'Style','slider','String','blue','Position',[775,450,25,140],'Min',0,'Max',1,'Value',0,'backgroundColor',[0,1,0],'CallBack',@slider_callback); %颜色参数静态文本 color_text = uicontrol(fig,'Style','text','Position',[690,395,115,50],'Tag','color_text',... 'String',char('red=1','blue=1','green=0'),'backgroundColor',[1,0.95,0.87],'FontSize',10,'HorizontalAlignment','left'); %颜色演示面板 color_panel = uipanel(fig,'Title','颜色演示面板','BackgroundColor',color,'Units','pixels','Position',[690,345,115,40]); %修改速度按钮 fast_button = uicontrol(fig,'Style','pushbutton','Position',[700,280,100,40],'FontSize',10,'String','加快','CallBack',@button_callback); slow_button = uicontrol(fig,'Style','pushbutton','Position',[700,230,100,40],'FontSize',10,'String','减慢','CallBack',@button_callback); %修改数量按钮 increase_button = uicontrol(fig,'Style','pushbutton','Position',[700,160,100,40],'FontSize',10,'String','增多','CallBack',@button_callback); decrease_button = uicontrol(fig,'Style','pushbutton','Position',[700,110,100,40],'FontSize',10,'String','减少','CallBack',@button_callback); modNum_button = uicontrol(fig,'Style','pushbutton','Position',[700,60,100,40],'FontSize',10,'String','手动调整数量','CallBack',@button_callback); modG_button = uicontrol(fig,'Style','pushbutton','Position',[700,10,100,40],'FontSize',10,'String','手动调整加速度','CallBack',@button_callback); axes('DrawMode','fast','position',[0,0,0.8,1]); II=imread('back4.jpg'); image(II) ah = axes('DrawMode','fast','Color','none','position',[0,0,0.8,1]); axis([-200 420 1 410])%设置坐标轴的范围 grid off %GUI部分结束 hold on %烟花主控函数,每次点击鼠标按钮监听器都会调用此函数。 function yanhua(src,event) cp = get(ah,'CurrentPoint'); % 得到点击点的坐标 xt = cp(1,1);yt = cp(1,2); if(xt < 420)%若点击在按钮面板则不放烟花 launch(xt,yt)%烟花发射函数 end endend %主函数调用结束%colormap(hot)%烟花发射函数function launch(xt,yt) x=xt; y=0; H=plot(x,y,'w.'); %以白色,点来绘制图像。 set(H,'EraseMode','xor','MarkerSize',25)%擦除式绘图,通过在极短的时间里不断绘制新点坐标,擦出旧点坐标来实现烟花向上发射的运动效果 T = timer('TimerFcn',@timer_display1,'StopFcn',@stopFcn1,'TasksToExecute',50,'Period',0.005,'ExecutionMode','fixedSpacing');%非阻塞式定时器,以0.005秒为间隔调用TimerFcn,共调用50次。调用玩后会启动StopFcn函数,进行清尾工作,如清楚发射点图像,初始化烟花爆炸的定时器等。而烟花发射的运动,就是通过在这50次的重复调用中,不断更新点的坐标来实现的。 T.userData = {H,xt,yt,1};%定时器对象的属性。在定时函数里使用。定时器函数是不变的,但在重复调用中要实现点坐标的改变,就要通过改变定时器对象的对象属性才行。 %为什么要用对象属性而不是函数内定义的局部变量?因为局部变量在每次函数调用完毕就会被销毁,不能实现类似于静态变量的效果在下次重复调用中生效。那为什么不适用全局变量?因为全局变量是共用的,我的定时器A能用,定时器B也能用,A修改了这个变量,B中也生效了,这就有“线程安全性”问题了。 start(T);%启动定时器endfunction timer_display1(obj,event) userData = obj.userData;%获取对象数据 H = userData{1}; x = userData{2}; yt = userData{3}; i = userData{4}; y=i/50*yt;%执行50次,就到了鼠标点击位置,预备爆炸了。这个运动模型可以结合实际的物理模型做进一步优化,感兴趣的同学不妨试试。 set(H,'XData',x,'YData',y)%更新烟花坐标 drawnow;%重画页面,使烟花"H"出现在新位置 i=i+1;%这是控制烟花位移的关键 obj.userData = {H,x,yt,i};%更新对象数据,再下次重复调用时再取出使用endfunction stopFcn1(obj,event)%定时器1完成了它的50次调用使命,使烟花(点)到达爆炸处(鼠标位置),这个烟花(点)在这里被消除,然后开始了烟花爆炸的定时器初始化、启动工作 global n; global color; userData = obj.userData; H = userData{1} xt = userData{2}; yt = userData{3}; x=-20;y=-20; set(H,'XData',x,'YData',y); %上述程序使得烟花到达鼠标的位置后消失在视野内 %*************烟花的爆炸过程 x=zeros(n,1);%爆炸后的颗粒数为n y=zeros(n,1); h=plot(x,y,'.');%烟花爆炸后的形状 set(h,'Color',color); set(h,'erasemode','xor','MarkerSize',5) T = timer('TimerFcn',@timer_display2,'StopFcn',@stopFcn2,'TasksToExecute',40,'Period',0.05,'ExecutionMode','fixedSpacing'); T.userData = {h,xt,yt,0}; start(T);endfunction timer_display2(obj,event) global n v0 styleNum multiColor g; userData = obj.userData; h = userData{1}; x0 = userData{2}; y0 = userData{3}; t = userData{4}; theta=rand(n,1)*2*pi;%粒子的仰角 fy=rand(n,1)*2*pi;%粒子的方位角 theta1=round(12*rand(n,1))/6*pi; for i=1:n %绘制粒子下落过程, switch(styleNum)%图案判定,通过菜单修改全局变量控制 case 1 x(i)=2*v0*cos(fy(i))*cos(theta(i)+t*pi)*t+x0; y(i)=1.2*v0*cos(fy(i))*sin(theta(i)+i*pi)*t-g*t.^2+y0; case 2 if(mod(theta(i),0.4*pi)<=0.1*pi) x(i)=2*v0*cos(fy(i))*cos(theta(i)-4*t*pi)*t+x0; y(i)=1.2*v0*cos(fy(i))*sin(theta(i)-4*t*pi)*t-g*t.^2+y0; else x(i)=(mod(theta(i),0.4*pi)*2.5/pi+0.4)*2*v0*cos(fy(i))*cos(theta(i)-4*t*pi)*t+x0; y(i)=(mod(theta(i),0.4*pi)*2.5/pi+0.4)*1.2*v0*cos(fy(i))*sin(theta(i)-4*t*pi)*t-g*t.^2+y0; end case 3 x(i)=2*v0*cos(fy(i))*cos(theta(i)+i*t*pi)*t+x0; y(i)=1.2*v0*cos(fy(i))*sin(theta(i)+i*t*pi)*t-g*t.^2+y0; case 4 x(i)=0.8*fy(i)/pi*2*v0*cos(fy(i))*cos(theta(i)+i*pi)*t+x0; y(i)=0.8*fy(i)/pi*(1.2*v0*cos(fy(i))*sin(theta(i)+i*pi)*t-g*t.^2)+y0; case 5 x(i)=4*v0*cos(fy(i))*cos(theta1(i))*t+x0; y(i)=(4*v0*cos(fy(i))*sin(theta1(i)-cos(fy(i))*cos(theta1(i))*0.3*t*pi)*t-4*t.^2)+y0; case 6 x(i)=v0*cos(fy(i))*cos(theta1(i)+4*t*pi)*t+x0; y(i)=v0*cos(fy(i))*sin(theta1(i))*t-g*t.^2+y0; end end set(h,'xdata',x,'ydata',y); if(multiColor == 1) set(h,'Color',rand(1,3)); end drawnow; t = t + 0.01; obj.userData = {h,x0,y0,t};endfunction stopFcn2(obj,event) %下述程序使爆炸的烟花消失 global n; userData = obj.userData; h = userData{1}; x=zeros(n,1); y=zeros(n,1); set(h,'xdata',x,'ydata',y);end%hObject eventdata handles%按钮回调函数function button_callback(object,data,handles) global v0 n g; switch(object.String) case '加快' v0 = v0 + 50; speed_panel = findobj(gcf,'Tag','speed_panel'); speed_panel.Title = regexprep(speed_panel.Title,'\d*',num2str(v0));%正则表达式替换 case '减慢' v0 = v0 - 50; speed_panel = findobj(gcf,'Tag','speed_panel'); speed_panel.Title = regexprep(speed_panel.Title,'\d*',num2str(v0));%正则表达式替换 case '增多' n = n + 100; ammount_panel = findobj(gcf,'Tag','ammount_panel'); ammount_panel.Title = regexprep(ammount_panel.Title,'\d*',num2str(n));%正则表达式替换 case '减少' n = n - 100; ammount_panel = findobj(gcf,'Tag','ammount_panel'); ammount_panel.Title = regexprep(ammount_panel.Title,'\d*',num2str(n));%正则表达式替换 case '手动调整数量' ammount_input = inputdlg('请输入爆炸后烟花颗粒的数量','修改烟花数量',1); num=str2num(ammount_input{1}); if isempty(num) errordlg('必须输入有效数字','错误'); else n = num; ammount_panel = findobj(gcf,'Tag','ammount_panel'); ammount_panel.Title = regexprep(ammount_panel.Title,'\d*',num2str(n));%正则表达式替换 end case '手动调整加速度' ammount_input = inputdlg(strcat('请输入爆炸后烟花加速度值,当前值为:',num2str(g)),'修改加速度',1); num=str2num(ammount_input{1}); if isempty(num) errordlg('必须输入有效数字','错误'); else g = num; end endend%烟花样式改变菜单function style_menu_callback(object,data,handles) global styleNum; number = regexp(object.Label,'\d','match'); styleNum = str2num(number{1});endfunction file_menu_callback(object,data,handles) switch(object.Label) case '退出(&q)' close(gcf); endendfunction picture_menu_callback(object,data,handles) global ah; number = regexp(object.Label,'\d','match'); imageName = strcat(strcat('back',number),'.jpg'); axes('DrawMode','fast','position',[0,0,0.8,1]); II=imread(imageName{1}); image(II); ah = axes('DrawMode','fast','Color','none','position',[0,0,0.8,1]); axis([-200 420 1 410])%设置坐标轴的范围 grid off hold on;endfunction color_menu_callback(object,data,handles) global color multiColor; disp(object.Label); multiColor = 0;%初始化颜色状态 switch(object.Label) case '黄色(&1)' color = [1 1 0]; case '紫红色(&2)' color = [1 0 1]; case '青色(&3)' color = [0 1 1]; case '红色(&4)' color = [1 0 0]; case '绿色(&5)' color = [0 0 1]; case '蓝色(&6)' color = [0 1 0]; case '白色(&7)' color = [1 1 1]; case '五彩变换(&8)' color = [0 0 0]; multiColor = 1; end parseColor(color);endfunction slider_callback(obj,event) global color ; red_slider = findobj(gcf,'String','red'); blue_slider = findobj(gcf,'String','blue'); green_slider = findobj(gcf,'String','green'); color = [red_slider.Value,blue_slider.Value,green_slider.Value]; parseColor(color);endfunction[rbgStr] = parseColor(color) color_text = findobj(gcf,'Tag','color_text'); rbgStr = char(strcat('red=',num2str(color(1))),... strcat('blue=',num2str(color(2))),... strcat('green=',num2str(color(3)))); color_text.String = rbgStr; color_panel = findobj(gcf,'Title','颜色演示面板'); color_panel.BackgroundColor = color;end
可能大家还是不太明白,为什么有了定时器,即时没有多线程也能实现多支烟花同时爆炸呢?我们可以这样想,matlab永远只有一条主线程在跑,现在有3个烟花A,B,C要爆炸,只能让主线程在for循环中不断改变A的位移来控制A运动爆炸,然后再到B,但如果用定时器Ta,Tb来控制,我们可以让主线程控制Ta让烟花A移动一下,然后Ta睡眠0.0.5s,主线程控制Tb让烟花B移动,然后Tb睡眠,Ta调用…Ta,Tb调用间隔极短(短到人眼无法识别),看起来就是Ta,Tb一起让烟花A,B运动爆炸了。
1 0
- matlab五彩多图案3D烟花
- 貌似3D效果的JS烟花特效代码
- matlab 柱状图 填充图案
- matlab画心型图案
- C语言控制台打印3D爱心图案
- Matlab-3D画图
- matlab正余弦画心形图案
- 烟花
- 烟花
- 烟花
- 烟花
- 烟花
- 烟花
- 3D matlab 图像旋转
- matlab 绘制 3d 心
- Matlab 绘制3D半球
- matlab 3D绘图详解
- MATLAB 绘制3D Surf
- C# 计算标准偏差相当于Excel中的STDEV函数
- IDF-抓到一只苍蝇
- 字符串转换数字
- 编程小练习6
- 学霸的迷宫
- matlab五彩多图案3D烟花
- 学习hadoop之路 开始
- win8.1 Theano Anoconda Cuda
- 递归算法——约瑟夫问题
- 数组元素出现次数统计
- hdu4725The Shortest Path in Nya Graph---spfa求最短路
- HBase介绍
- 数据可视化---之---数据色彩化
- JAVA设计模式--观察者