有趣之matlab-烟花

待整合1 2 3

  1. 动态

有趣编程之11

静态 逼真

3 .m文件路径下放back1.jpg back4.jpg…背景照片
点击screen 就会有小白点升起,爆炸

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
    end
end  %主函数调用结束
 
%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);%启动定时器
end
function 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};%更新对象数据,再下次重复调用时再取出使用
end
 
function 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);
end
function 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};
end
function 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
    end
end
%烟花样式改变菜单
function style_menu_callback(object,data,handles)
    global styleNum;
    number = regexp(object.Label,'\d','match');
    styleNum = str2num(number{1});
end
function file_menu_callback(object,data,handles)
    switch(object.Label)
        case '退出(&q)'
            close(gcf);
    end
end
function 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;
end
function 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);
end
 
function 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);
end
function[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

效果:
背景可自选,基于自己路径的图片,下图仅示例
在这里插入图片描述

参考博文

  • 11
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值