鱼C论坛

 找回密码
 立即注册
查看: 4121|回复: 42

[作品展示] 看烟花

[复制链接]
发表于 2023-1-30 02:20:50 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 额外减小 于 2023-1-30 21:16 编辑

前言

v并改变风格.jpg

最近几天烟花放的很狂啊...
天天看烟花
于是我想到了制作燃放烟花的程序
友情提示(预防针/心理准备)
没有GUI
就是黑框框
而且还一卡一卡的(因为坐标只能是整数)
但我保证了24帧/秒(楽)

设计意图

通过自主设计程序,实现放烟花的效果,不仅节约了放烟花的资金,还能在练习中提升自己的编程能力!

设计思路

1.依据简单的力学知识,计算烟花坐标随时间变化的函数
2.每帧都有其对应的时间,带入函数求出坐标,在该坐标按指定颜色打印出烟花点('*')即可
3.通过指针传递来初始化次级烟花数组。

可变因素

1.重力加速度(
2.每秒播放的帧数(默认24)
3.初始参数:起始点、初速度、发射角、颜色参数
4.每个烟花携带次级烟花数目
5.烟花爆炸前的飞行时间

源代码
#define _XOPEN_SOURCE
#define _GNU_SOURCE
#define _BSD_SOURCE
#define _USE_MATH_DEFINES

#include <math.h>
#include <stdio.h>
#include <windows.h>

#define G 9.8  //  重力加速度                                  /*可变*/
#define sleeptm 42  // 保持 24 帧每秒 (加上运行时间)             /*可变:每秒的帧数*/

typedef struct _FPOINT
{
        double x;
        double y;
} FPOINT;

typedef struct Firework
{
        FPOINT startp; //出发点 (正常坐标系,x=Pos_x,y=-Pos_y)
        double startv; //初速度
        double angle; //发射角 , RAD
        int color; //烟花颜色(1-15)
        int petal; //花瓣个数 
} FW;


void Pos(int x,int y);
void color(int type);
void getcoord(FPOINT *endp,FPOINT startp,double startv,double angle,int mstime);
int _round(double origin);
double mod(double a,double m,int *i);
 
FW * launchFATfirework(FW FATHER);
void launchSONfirework(int argc,FW * SONarray);


void Pos(int x,int y)
/*
设置光标位置
运行框左上方:(0,0)
从定位光标开始打印
若换行,变为从行首打印
*/
{
    COORD pos;
    pos.X=x;
    pos.Y=y;
    HANDLE hOutPut;
    hOutPut=GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleCursorPosition(hOutPut,pos);
}

void color(int type)
/*设置颜色*/
{
        if((type>=0)||(type<=15))
        {
                SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),type);
        }
        else
        {
                SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),7);
        }
}

int _round(double origin)
/*四舍五入函数
用于烟花位置打印
(精确度为1)*/
{
        double minus_origin=-origin;
        if(origin>=0)
        {
                if(origin-(int)origin>=0.5)
                {
                        return ((int)origin)+1;
                }
                else
                {
                        return (int)origin;
                }
        }
        else
        {
                if(minus_origin-(int)minus_origin>=0.5)
                {
                        return (int)origin-1;
                }
                else
                {
                        return (int)origin;
                }
        }
}

double mod(double a,double m,int *i)
//广义上取余数函数
//因为求余符号 % 只能用于整数 
{
        *i=0;
        if(m<=0)
        {
                return -1;
        }
        if(a>=0)
        {
                while((*i)*m<=a)
                {
                        (*i)++;
                }
                return a-(*i-1)*m;
        }
        else
        {
                while((*i)*m+a<0)
                {
                        (*i)++;
                }
                return a+(*i)*m;
        }
}

void getcoord(FPOINT *endp,FPOINT startp,double startv,double angle,int mstime)
//  获取烟花坐标(严格依据运动学定理) 
{
        endp->x=startp.x+startv*cos(angle)*mstime/1000;
        endp->y=startp.y+startv*sin(angle)*mstime/1000-G*mstime*mstime/2000000;
}

FW * launchFATfirework(FW FATHER)  //  发射一级烟花 
{
        int mstime=0,explosion,i,count;
        if(mod(FATHER.angle,2*M_PI,&i)<M_PI)
        {
                explosion=(int)(1000*(FATHER.startv*sin(FATHER.angle)/G)); // 当烟花飞行至最高点时爆炸 
        }
        else
        {
                explosion=3000;                                  /*可变:一级烟花向下发射时的爆炸时间*/
        }
        FPOINT now;
        while(mstime<=explosion)
        {
                getcoord(&now,FATHER.startp,FATHER.startv,FATHER.angle,mstime);
                Pos(_round(now.x),-_round(now.y));
                color(FATHER.color);
                printf("*");
                Sleep(sleeptm);
                mstime+=sleeptm;
                system("cls");
        }
        
        FW *SONarray=(FW *)malloc(sizeof(FW)*FATHER.petal);
        FW *ptr=SONarray;
        
        for(count=0;count<FATHER.petal;count++,ptr++)
        {
                ptr->startp.x=now.x;
                ptr->startp.y=now.y;
                ptr->startv=15;                                                                   /*可变:二级烟花的初速度*/
                ptr->angle=0.5+2*M_PI/FATHER.petal*count; //  设置为均匀放射(相邻两初速度方向夹角相等) 
                ptr->color=FATHER.color;
                ptr->petal=0; //  每瓣二级烟花附带的三级烟花数量 (一般设为 0 ) 
        }
        
        return SONarray;
}

void launchSONfirework(int argc,FW * SONarray)
{
        int mstime=0,i,count;
        FPOINT p[argc];
        FW *ptr=SONarray;
        while(mstime<1000)//explosion                                       /*可变:二级烟花爆炸时间*/
        {
                for(count=0;count<argc;count++)
                {
                        getcoord(&p[count],SONarray[count].startp,SONarray[count].startv,SONarray[count].angle,mstime);
                        Pos(_round(p[count].x),-_round(p[count].y));
                        color(SONarray[count].color);
                        printf("*");
                }
                Sleep(sleeptm);
                mstime+=sleeptm;
                system("cls");
        }
}

int main()
{
        int c;
        FPOINT p={100,-50};                                     /*可变:一级烟花起始点坐标(正常坐标系,x轴向右,y轴向上)*/
        FW father=
        {
                p,
                25,                /*可变:初速度*/
                1.8,               /*可变:发射角(RAD)*/
                4,                 /*可变:颜色*/
                5                  /*可变:附带二级烟花数目*/
        };                                                                   /*结构体变量内容可修改*/
        
        FW* son=launchFATfirework(father);

        launchSONfirework(5,son);
        
        free(son);
        
        return 0;
}

效果

简述:较为朴素,没有尾迹,较为卡顿
建议全屏观看

改进

1.知道很多物理(竞?)大佬会说,欸,你看,这个烟花啊,他是要计算空气阻力的。
的确,二级烟花(其实是残渣)的质量较小,空气阻力理论上不可忽略
但是看看阻力的式子:f=kv2(k是多少忘记了,不重要,反正是一常量)
结合G=mg,我个人不觉得能够轻松愉快地解出位置随时间的变化函数。
看着这个微分方程都头大
物/数竞大佬可以帮忙解出关系式,并且对程序作出相应修改,如有完成者奖励1鱼币+1荣誉

2.一般的烟花都带有尾迹,很好看。但我目前没想到如何简便地为烟花添加尾迹。
如有完成者奖励2鱼币+1荣誉

3.提出让烟花更真实的建议并给出源代码的同学 奖励2鱼币+2荣誉(我不要gui谢谢哈,我只想知道用这种黑框框怎样会变得更逼真)

结语

本人系C语言新手,欢迎各位大佬对我的代码提出宝贵建议!

如果喜欢,别忘了评分
谢谢!

评分

参与人数 3荣誉 +8 鱼币 +10 贡献 +9 收起 理由
小甲鱼 + 2 + 3 + 3 鱼C有你更精彩^_^
liuhongrun2022 + 1 + 2 + 3
高山 + 5 + 5 + 3 很不错

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2023-1-30 02:33:02 | 显示全部楼层
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-1-30 02:35:59 | 显示全部楼层
本帖最后由 额外减小 于 2023-1-30 21:16 编辑

针对改进第一条

想到可以通过减小二级烟花对应重力加速度的值来近似它的有阻力运动。
例如
使用
        FW* son=launchFATfirework(father,G);
        
#undef G
#define G 0.05

        launchSONfirework(5,son,G);
        

来使得二级烟花下落较缓
当然,拟合的不一定像

具体代码
#define _XOPEN_SOURCE
#define _GNU_SOURCE
#define _BSD_SOURCE
#define _USE_MATH_DEFINES

#include <math.h>
#include <stdio.h>
#include <windows.h>

#define G 9.8  //  重力加速度                                  /*可变*/
#define sleeptm 42  // 保持 24 帧每秒 (加上运行时间)             /*可变:每秒的帧数*/

typedef struct _FPOINT
{
        double x;
        double y;
} FPOINT;

typedef struct Firework
{
        FPOINT startp; //出发点 (正常坐标系,x=Pos_x,y=-Pos_y)
        double startv; //初速度
        double angle; //发射角 , RAD
        int color; //烟花颜色(1-15)
        int petal; //花瓣个数 
} FW;


void Pos(int x,int y);
void color(int type);
void getcoord(FPOINT *endp,FPOINT startp,double startv,double angle,double g,int mstime);
int _round(double origin);
double mod(double a,double m,int *i);
 
FW * launchFATfirework(FW FATHER,double g);
void launchSONfirework(int argc,FW * SONarray,double g);


void Pos(int x,int y)
/*
设置光标位置
运行框左上方:(0,0)
从定位光标开始打印
若换行,变为从行首打印
*/
{
    COORD pos;
    pos.X=x;
    pos.Y=y;
    HANDLE hOutPut;
    hOutPut=GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleCursorPosition(hOutPut,pos);
}

void color(int type)
/*设置颜色*/
{
        if((type>=0)||(type<=15))
        {
                SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),type);
        }
        else
        {
                SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),7);
        }
}

int _round(double origin)
/*四舍五入函数
用于烟花位置打印
(精确度为1)*/
{
        double minus_origin=-origin;
        if(origin>=0)
        {
                if(origin-(int)origin>=0.5)
                {
                        return ((int)origin)+1;
                }
                else
                {
                        return (int)origin;
                }
        }
        else
        {
                if(minus_origin-(int)minus_origin>=0.5)
                {
                        return (int)origin-1;
                }
                else
                {
                        return (int)origin;
                }
        }
}

double mod(double a,double m,int *i)
//广义上取余数函数
//因为求余符号 % 只能用于整数 
{
        *i=0;
        if(m<=0)
        {
                return -1;
        }
        if(a>=0)
        {
                while((*i)*m<=a)
                {
                        (*i)++;
                }
                return a-(*i-1)*m;
        }
        else
        {
                while((*i)*m+a<0)
                {
                        (*i)++;
                }
                return a+(*i)*m;
        }
}

void getcoord(FPOINT *endp,FPOINT startp,double startv,double angle,double g,int mstime)
//  获取烟花坐标(严格依据运动学定理) 
{
        endp->x=startp.x+startv*cos(angle)*mstime/1000;
        endp->y=startp.y+startv*sin(angle)*mstime/1000-g*mstime*mstime/2000000;
}

FW * launchFATfirework(FW FATHER,double g)  //  发射一级烟花 
{
        int mstime=0,explosion,i,count;
        if(mod(FATHER.angle,2*M_PI,&i)<M_PI)
        {
                explosion=(int)(1000*(FATHER.startv*sin(FATHER.angle)/g)); // 当烟花飞行至最高点时爆炸 
        }
        else
        {
                explosion=3000;                                  /*可变:一级烟花向下发射时的爆炸时间*/
        }
        FPOINT now;
        while(mstime<=explosion)
        {
                getcoord(&now,FATHER.startp,FATHER.startv,FATHER.angle,g,mstime);
                Pos(_round(now.x),-_round(now.y));
                color(FATHER.color);
                printf("*");
                Sleep(sleeptm);
                mstime+=sleeptm;
                system("cls");
        }
        
        FW *SONarray=(FW *)malloc(sizeof(FW)*FATHER.petal);
        FW *ptr=SONarray;
        
        for(count=0;count<FATHER.petal;count++,ptr++)
        {
                ptr->startp.x=now.x;
                ptr->startp.y=now.y;
                ptr->startv=15;                                                                   /*可变:二级烟花的初速度*/
                ptr->angle=0.5+2*M_PI/FATHER.petal*count; //  设置为均匀放射(相邻两初速度方向夹角相等) 
                ptr->color=FATHER.color;
                ptr->petal=0; //  每瓣二级烟花附带的三级烟花数量 (一般设为 0 ) 
        }
        
        return SONarray;
}

void launchSONfirework(int argc,FW * SONarray,double g)
{
        int mstime=0,i,count;
        FPOINT p[argc];
        FW *ptr=SONarray;
        while(mstime<1000)//explosion                                       /*可变:二级烟花爆炸时间*/
        {
                for(count=0;count<argc;count++)
                {
                        getcoord(&p[count],SONarray[count].startp,SONarray[count].startv,SONarray[count].angle,g,mstime);
                        Pos(_round(p[count].x),-_round(p[count].y));
                        color(SONarray[count].color);
                        printf("*");
                }
                Sleep(sleeptm);
                mstime+=sleeptm;
                system("cls");
        }
}

int main()
{
        int c;
        FPOINT p={100,-50};                                     /*可变:一级烟花起始点坐标(正常坐标系,x轴向右,y轴向上)*/
        FW father=
        {
                p,
                25,                /*可变:初速度*/
                1.8,               /*可变:发射角(RAD)*/
                4,                 /*可变:颜色*/
                5                  /*可变:附带二级烟花数目*/
        };                                                                   /*结构体变量内容可修改*/
        
        FW* son=launchFATfirework(father,G);
        
#undef G
#define G 0.05

        launchSONfirework(5,son,G);
        
        free(son);
        
        return 0;
}
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

发表于 2023-1-30 09:30:59 From FishC Mobile | 显示全部楼层

回帖奖励 +1 鱼币

厉害厉害,加油
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

发表于 2023-1-30 10:52:54 | 显示全部楼层
你老家哪里啊,可以放烟花
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-1-30 10:58:01 | 显示全部楼层

回帖奖励 +1 鱼币

把你的windows.h去掉!!!!!!

评分

参与人数 1鱼币 +2 收起 理由
额外减小 + 2 鱼C有你更精彩^_^

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-1-30 12:23:00 | 显示全部楼层

回帖奖励 +1 鱼币

碰运气
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-1-30 13:02:18 | 显示全部楼层

回帖奖励 +1 鱼币

加油!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2023-1-30 13:17:23 | 显示全部楼层

回帖奖励 +1 鱼币

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2023-1-30 15:01:57 | 显示全部楼层

回帖奖励 +1 鱼币

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2023-1-30 15:38:32 | 显示全部楼层

回帖奖励 +1 鱼币

感谢鱼c!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-1-30 15:41:43 | 显示全部楼层

回帖奖励 +1 鱼币

加油!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2023-1-30 16:37:04 | 显示全部楼层
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2023-1-30 18:59:09 From FishC Mobile | 显示全部楼层

回帖奖励 +1 鱼币

厉害,学习中。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-1-30 21:02:18 | 显示全部楼层
Mike_python小 发表于 2023-1-30 10:58
把你的windows.h去掉!!!!!!

谢谢提醒
不过有必要发火吗()
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-1-30 21:04:10 | 显示全部楼层
Eschborn 发表于 2023-1-30 10:52
你老家哪里啊,可以放烟花

福州
话说不是很多地方都允许了吗?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-1-30 21:13:34 | 显示全部楼层
额外减小 发表于 2023-1-30 21:02
谢谢提醒
不过有必要发火吗()

不是 就调侃一句 我是Mac,所以看到很多好玩的程序(比如你这种,然后一看到“windows.h”就怒火攻心了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-1-30 21:14:14 | 显示全部楼层
额外减小 发表于 2023-1-30 21:02
谢谢提醒
不过有必要发火吗()

卧槽原来可以不用windows.h,我这就去试试
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-1-30 21:15:05 | 显示全部楼层
Mike_python小 发表于 2023-1-30 21:13
不是 就调侃一句 我是Mac,所以看到很多好玩的程序(比如你这种,然后一看到“windows.h”就怒火攻心了


那有休眠一定时间的功能函数吗?
就是在mac里面
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-1-30 21:15:10 | 显示全部楼层
额外减小 发表于 2023-1-30 21:02
谢谢提醒
不过有必要发火吗()

很好,我的编译器无法识别“COORD”,“HANDLE”和STD_OUTPUT_HANDLE
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-11-17 20:35

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表