C++烟花实现思路及源码

这篇具有很好参考价值的文章主要介绍了C++烟花实现思路及源码。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一.程序展示

C++烟花实现思路及源码,c++,开源,经验分享,开发语言,Powered by 金山文档
C++烟花实现思路及源码,c++,开源,经验分享,开发语言,Powered by 金山文档
C++烟花实现思路及源码,c++,开源,经验分享,开发语言,Powered by 金山文档

二.程序简介

  1. 青春就像一场烟花,美得让人窒息,却短暂得让人流泪。

  1. 我们该如何用代码记录下现实中的烟花,让它成为永恒呢?

  1. 首先把烟花分成两个阶段:烟花弹升空烟花绽放

  1. 然后把烟花弹(jet)烟花(flower)各作为一个对象,再思考它们各自的属性

  1. 为了实现多个烟花的效果,创建烟花弹数组和烟花数组。

  1. 烟花弹和烟花各自的对象数组大小都为13(为了实现爱心烟花的操作才取13)

三.烟花弹升空

3.1烟花弹的属性

1.我们用initgraph()创建一个窗口,烟花弹要有一个升空,再绽放的动态变化

那么它应该具有int x,y,hy,t1,t2,dt这些代表着运动的属性,bool shoot这样的发射开关,

IMAGE jet_picture[2]这样储存图片的变量(为了达到闪烁的效果,我们准备一明一暗

两张烟花图片,交替变化,顺便引出byte n:1作为变化的枢纽)

C++烟花实现思路及源码,c++,开源,经验分享,开发语言,Powered by 金山文档

2.储存烟花弹的操作

IMAGE JET_PICTURE;
loadimage(&JET_PICTURE, "./jet.jpg", 200, 50);
SetWorkingImage(&JET_PICTURE);
int choice_jet = rand() % 5;
getimage(&jet_picture[0], choice_jet * 20, 0, 20, 50);
getimage(&jet_picture[1], (choice_jet + 5) * 20, 0, 20, 50);

3.2烟花弹发射的思路

1.烟花弹一个接一个地升空,一个接一个地绽放,仔细一想,

好像是一个烟花弹升空再绽放作为一个线程多个线程一起运行

2.再仔细一想,如果我们创建一个烟花弹对象数组,然后再来一个

循环遍历这个数组,如果这个烟花弹可发射(shoot==true),那就令(y-=5)

再加个(t2-t1>=dt)限制速度,到达最高点hy重置这个烟花弹,然后把此时的坐标x,y

传给烟花这个对象,让它开始绽放。再在这个循环外面套个循环,

每次都让可发射的烟花弹上升一点,这样整体看来就达到了并行的效果

3.还有两个关键问题:每次该让多少烟花弹发射呢,这些发射的烟花弹

是在同一高度,以同一速度上升,这样太僵硬了,因此,我们需要设计一种算法。

4.我们声明两个静态变量static int shoot_need = 0, shoot_reality = 0,

由上面的讲解,我们知道外部是有一个循环的,每次该循环遍历时,

shoot_need = rand() % 3 + 2,当 (shoot_reality < shoot_need)时,

声明一个局部变量int i = rand() % 13,然后随机访问一个烟花对象,

如果它原先没有发射,就令shoot=true,并把它输出在窗口上,然后shoot_reality++

直到与需要的烟花弹数量相等时退出循环

5.当然,烟花弹上升到最高点重置时shoot_reality--

shoot_need = rand() % 3 + 2;
        while (shoot_reality < shoot_need)
        {
            int i = rand() % 13;
            if (!jet[i].shoot)
            {
                jet[i].shoot = true;
                shoot_reality++;
                jet[i].t1 = GetTickCount();
                putimage(jet[i].x, jet[i].y, &jet[i].jet_picture[jet[i].n], SRCINVERT);
            }
        }

6.我们在初始化烟花发射(shoot=true)时,已经把烟花弹的图片输出到了窗口上,

接下来判断(t2-t1>=dt)若为真则调用putimage()擦除上个位置的烟花

t1=t2重置时间;然后再判断(y>hy)若还为真,则上升(y-=5),再调用

putimage()在下个位置显示烟花弹若为假,则把此时烟花弹的坐标传给

烟花,并重置烟花弹的属性。

四.烟花绽放

4.1烟花的属性

  1. 我们观察现实中的烟花,会发现它的绽放过程近似于以空间中的一点

作为圆心,半径从0开始不断变大,即以规则的圆形放大,直到最大半径,

然后缓慢消失。

  1. 那么它应该具有int x,y,r,cen_x,cen_y,max_r这些运动的属性,bool bloom

这样的开关, DWORD flower[240][240]这样储存烟花上的像素点数组。

(因为我们要把烟花上的像素点以圆形扩散的形式输出到窗口上,图片本身是有大小的

cen_x=cen_y=120,它们是图片中的圆心;xy作为窗口上烟花绽放的圆心

即烟花弹到最高点的坐标,另外max_r=120。)

3.当然你可以加入t1,t2,dt这些运动的属性来让烟花变速绽放

C++烟花实现思路及源码,c++,开源,经验分享,开发语言,Powered by 金山文档
  1. 储存烟花弹上的像素点的操作

IMAGE FLOWER, Flower;
loadimage(&FLOWER, "./flower.jpg", 3120, 240);
SetWorkingImage(&FLOWER);
static int choice_flower = 0;
getimage(&Flower, choice_flower * 240, 0, 240, 240);
choice_flower++;
SetWorkingImage(&Flower);
for (int y = 0; y < 240; y++)
    for (int x = 0; x < 240; x++)
          flower[y][x] = getpixel(y, x);

4.2烟花弹绽放的思路

  1. 我们声明一个指针存储绘图设备的显示缓冲区

DWORD* Drawing_window = GetImageBuffer();
  1. 然后我们可以通过它来向窗口上输出像素点

  1. 由上述讲解可知,在一个烟花弹上升到最高点消失再重置时,

它向一个烟花对象传来了它消失点的坐标,并且会让这个烟花对象的bloom为真,

我们就以这个坐标为烟花绽放的圆心

flower[i].x = jet[i].x;
flower[i].y = jet[i].y;
flower[i].bloom = true;
ResetJet(i);
  1. 我们需要一个循环遍历烟花对象数组如果r<max_r,并且bloom==true

就令r++

  1. 接下来是最关键的:将图片中的烟花的像素以圆形扩散的形式输出到窗口上

for (double a = 0; a <= 2 * PI; a += 0.01)
     {//图形上像素点的坐标
          int img_x= (int) (flower[i].cen_x + flower[i].r * cos(a));
          int img_y = (int)(flower[i].cen_y + flower[i].r * sin(a));
          if (img_x > 0 && img_x < 240 && img_y>0 && img_y < 240)
              {
                 //接近黑色的像素点不输出    
              int b = flower[i].flower[img_y][img_x] & 0xff;
              int g = (flower[i].flower[img_y][img_x] >> 8) & 0xff;
              int r = (flower[i].flower[img_y][img_x] >> 16);
              //窗口上像素点的坐标
              int win_x = (int)(flower[i].x + flower[i].r * cos(a));
              int win_y = (int)(flower[i].y + flower[i].r * sin(a));
              if (win_x > 0 && win_x < WIDTH && win_y>0 && win_y < HEIGHT && b>0x20 && g > 0x20 && r > 0x20)
                 Drawing_window[win_y * WIDTH + win_x] = BGR(flower[i].flower[img_y][img_x]);
                }
      }

6.我们声明两个局部变量img_x,img_y,借助圆的参数方程的知识,获取以cen_x,cen_y为圆心,

r为半径的圆在图片上的坐标,再加入一个判断防止它们越界。

7.我们再声明两个局部变量,win_x,win_y获取以x,y为圆心,r为半径的圆在窗口上的坐标,然后再加入一个判断防止它们越界。

8.最后我们利用 Drawing_window(存储了绘图设备的显示缓冲区),来实现烟花绽放。

9.Drawing_window里的参数是窗口上像素点的位置,BGR里的参数是图片中指定位置的像素点

五.爱心烟花

5.1爱心烟花的初始化

  1. 首先我们在指定数量个烟花弹升空绽放后停止烟花弹升空。

  1. 此时13的烟花弹的shoot都为false,我们将其作为爱心烟花出现的条件.

  1. 然后我们给每个烟花弹都初始化一个坐标,再让它们的速度一致,

以此来达到爱心烟花的效果。

    int x[13] = { 60,75,91,100,95,75,60,45,25,15,25,41,60 };
        int y[13] = { 65,53,40,22,5,4,20,4,5,22,40,53,65 };
        for (int i = 0; i < JET_NUM; i++)
        {//爱心坐标
            jet[i].x = x[i] * 10;
            jet[i].y = (y[i] + 75) * 10;
            jet[i].hy = y[i] * 10;
            jet[i].shoot = true;
            jet[i].t1 = GetTickCount();
            jet[i].dt = 10;
            putimage(jet[i].x, jet[i].y, &jet[i].jet_picture[jet[i].n], SRCINVERT);
        }

5.2爱心烟花的切换

  1. 爱心烟花的实现与前面正常烟花的实现在切换时有冲突,我们需要加入一些操作来调节

static int success_times = 0, reset_t1, reset_t2;
static bool change_jet_num = true;
static bool Love = true;
  1. 我们引入5个具有文件作用域的变量:success_times为成功绽放烟花的数量,我们通过让它达到指定值来引出爱心烟花;Love为了阻止爱心烟花一直运行(爱心烟花是同步上升的,13个烟花的shoot会同时重置为false,再一次满足了爱心烟花的条件);reset_t1获取爱心烟花开始时的时间,reset_t2获取当前的时间;我们声明一个局部变量count=0,当一个烟花的bloom=false和一个烟花弹的shoot=false时,count++,当它等于26时,并且已经过去6s,就重置回正常烟花;change_jet_num是为了更好地协调正常烟花和爱心烟花的切换而来的.

reset_t2 = GetTickCount();
int count = 0;
        for (int i = 0; i < FLOWER_NUM; i++)
            if (!flower[i].bloom)
                count++;
        for (int i = 0; i < JET_NUM; i++)
            if (!jet[i].shoot)
                count++;
        if ((count == 26) && (reset_t2 - reset_t1 > 6000))
        {//6秒后重置烟花
            success_times = 0;
            shoot_reality = 0;
            Love = true;
        }

六.源码展示

一些细节的地方没有说明,还有一些地方可以优化,大家可以照着源码再看看文章来源地址https://www.toymoban.com/news/detail-788404.html

#include<iostream>
#include<easyx.h>
#include<stdlib.h>

#define PI 3.1415826
#define WIDTH 1200
#define HEIGHT 700
#define JET_NUM 13
#define FLOWER_NUM 13
static int success_times = 0, reset_t1, reset_t2;
static bool change_jet_num = true;
static bool Love = true;

using namespace std;
inline void ResetJet(int);
inline void shoot();
inline void ResetFlower(int);
inline void bloom(DWORD*);
inline int love();

class JET
{
public:
    int x, y;
    int hy;
    DWORD t1, t2, dt;
    bool shoot;
    IMAGE jet_picture[2];
    byte n : 1;

    JET()
    {
        x = rand() % 1160 + 40;
        y = rand() % 100 + 600;
        hy = rand() % 350 + 50;
        if (rand() % 2)
            dt = rand() % 2 + 1;
        else
            dt = rand() % 10 + 15;
        shoot = false;
        t1 = t2 = 0;
        n = 0;
        IMAGE JET_PICTURE;
        loadimage(&JET_PICTURE, "./jet.jpg", 200, 50);
        SetWorkingImage(&JET_PICTURE);
        int choice_jet = rand() % 5;

        getimage(&jet_picture[0], choice_jet * 20, 0, 20, 50);
        getimage(&jet_picture[1], (choice_jet + 5) * 20, 0, 20, 50);
        //SetWorkingImage();
    }

}jet[JET_NUM];
class FLOWER
{
public:
    int x, y;
    int cen_x, cen_y;
    int r;
    int max_r;
    DWORD flower[240][240];
    bool bloom;

    FLOWER()
    {
        x = y = 0;
        cen_x = 120;
        cen_y = 120;
        max_r = 120;
        r = 0;
        bloom = false;
    
        IMAGE FLOWER, Flower;
        loadimage(&FLOWER, "./flower.jpg", 3120, 240);
        SetWorkingImage(&FLOWER);
        static int choice_flower = 0;
        getimage(&Flower, choice_flower * 240, 0, 240, 240);
        choice_flower++;
        SetWorkingImage(&Flower);
        for (int y = 0; y < 240; y++)
            for (int x = 0; x < 240; x++)
                flower[y][x] = getpixel(y, x);
    }

}flower[FLOWER_NUM];

int main()
{
    srand((unsigned)time(NULL));
    initgraph(WIDTH, HEIGHT);
    DWORD* Drawing_window = GetImageBuffer();
    BeginBatchDraw();
    while (1)
    {
        for (int i = 0; i < WIDTH; i++)
        {
            for (int k = 0; k < 4; k++)
            {
                int x = rand() % WIDTH;
                int y = rand() % HEIGHT;
                if (y < HEIGHT)            
                    Drawing_window[y * WIDTH + x] = BLACK;            
            }
        }
        shoot();
        bloom(Drawing_window);
        love();
        FlushBatchDraw();
    }
    EndBatchDraw();
}

inline void ResetJet(int i)
{
    jet[i].x = rand() % 1120 + 40;
    for (int j = 0; j < JET_NUM; j++)
        if((jet[j].shoot) && ((jet[i].x - jet[j].x) <= 66))
            jet[i].x = rand() % 1120 + 40;
    jet[i].y = rand() % 30 + 600;
    jet[i].hy = rand() % 350 + 50;
    jet[i].shoot = false;
    jet[i].t1 = jet[i].t2 = 0;
    if (rand() % 2)
        jet[i].dt = rand() % 2 + 1;
    else
        jet[i].dt = rand() % 10 + 15;
}
inline void shoot()
{
    static int shoot_need = 1, shoot_reality = 0;
    if (!change_jet_num)
    {
        reset_t2 = GetTickCount();
        int count = 0;
        for (int i = 0; i < FLOWER_NUM; i++)
            if (!flower[i].bloom)
                count++;
        for (int i = 0; i < JET_NUM; i++)
            if (!jet[i].shoot)
                count++;
        if ((count == 26) && (reset_t2 - reset_t1 > 6000))
        {//6秒后重置烟花
            success_times = 0;
            shoot_reality = 0;
            Love = true;
        }
    }

    if (success_times <= 12)
        change_jet_num = true;
    else
        change_jet_num = false;

    if (change_jet_num)
    {
        shoot_need = rand() % 3 + 2;
        while (shoot_reality < shoot_need)
        {
            int i = rand() % 13;
            if (!jet[i].shoot)
            {
                jet[i].shoot = true;
                shoot_reality++;
                jet[i].t1 = GetTickCount();
                putimage(jet[i].x, jet[i].y, &jet[i].jet_picture[jet[i].n], SRCINVERT);//显示烟花弹
            }
        }
    }

    for (int i = 0; i < JET_NUM; i++)
    {
        jet[i].t2 = GetTickCount();
        if ((jet[i].shoot) && (jet[i].t2 - jet[i].t1 >= jet[i].dt))
        {
            putimage(jet[i].x, jet[i].y, &jet[i].jet_picture[jet[i].n], SRCINVERT);//擦除烟花弹
            if (jet[i].y > jet[i].hy)
            {
                jet[i].y -= 5;
                jet[i].n++;
                jet[i].t1 = jet[i].t2;
                putimage(jet[i].x, jet[i].y, &jet[i].jet_picture[jet[i].n], SRCINVERT);//显示烟花弹
            }
            else
            {
                if (change_jet_num)
                {
                    success_times++;
                    shoot_reality--;
                }
                flower[i].x = jet[i].x;
                flower[i].y = jet[i].y;
                flower[i].bloom = true;
                ResetJet(i);
            }
        }
    }
}
inline void ResetFlower(int i)
{
    flower[i].cen_x = 120;
    flower[i].cen_y = 120;
    flower[i].max_r = 120;
    flower[i].r = 0;
    flower[i].bloom = false;
}
inline void bloom(DWORD* Drawing_window)
{
    for (int i = 0; i < FLOWER_NUM; i++)
    {
        if ((flower[i].bloom)&&(flower[i].r < flower[i].max_r))
        {        
        flower[i].r++;
            for (double a = 0; a <= 2 * PI; a += 0.01)
            {//图形上像素点的坐标
                int img_x= (int) (flower[i].cen_x + flower[i].r * cos(a));
                int img_y = (int)(flower[i].cen_y + flower[i].r * sin(a));
                if (img_x > 0 && img_x < 240 && img_y>0 && img_y < 240)
                {
                    //接近黑色的像素点不输出    
                    int b = flower[i].flower[img_y][img_x] & 0xff;
                    int g = (flower[i].flower[img_y][img_x] >> 8) & 0xff;
                    int r = (flower[i].flower[img_y][img_x] >> 16);
                    //窗口上像素点的坐标
                    int win_x = (int)(flower[i].x + flower[i].r * cos(a));
                    int win_y = (int)(flower[i].y + flower[i].r * sin(a));
                    if (win_x > 0 && win_x < WIDTH && win_y>0 && win_y < HEIGHT && b>0x20 && g > 0x20 && r > 0x20)
                        Drawing_window[win_y * WIDTH + win_x] = BGR(flower[i].flower[img_y][img_x]);
                }
            }
        }
        if (flower[i].r >= flower[i].max_r)
            ResetFlower(i);
    }
}
inline int love()
{//爱心烟花
    int count = 0;
    for (int i = 0; i < JET_NUM; i++)
        if (!jet[i].shoot)
            count++;

    if ((!change_jet_num) && (!Love))
        return 0;

    if (count == 13)
    {
        reset_t1 = GetTickCount();
        Love = false;
        int x[13] = { 60,75,91,100,95,75,60,45,25,15,25,41,60 };
        int y[13] = { 65,53,40,22,5,4,20,4,5,22,40,53,65 };
        for (int i = 0; i < JET_NUM; i++)
        {//爱心坐标
            jet[i].x = x[i] * 10;
            jet[i].y = (y[i] + 75) * 10;
            jet[i].hy = y[i] * 10;
            jet[i].shoot = true;
            jet[i].t1 = GetTickCount();
            jet[i].dt = 10;
            putimage(jet[i].x, jet[i].y, &jet[i].jet_picture[jet[i].n], SRCINVERT);
        }
    }
    return 0;
}

到了这里,关于C++烟花实现思路及源码的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 抖音账号矩阵系统源码-开源部署开发者分享

    抖音账号矩阵系统,短视频账号矩阵系统源码, 短视频矩阵是一种常见的视频编码标准,它通过将视频分成多个小块并对每个小块进行压缩来实现高效的视频传输。短视频多账号矩阵系统,通过多账号一键授权管理的方式,为运营人员打造功能强大及全面的“矩阵式“管理平

    2024年02月15日
    浏览(63)
  • 抖音短视频矩阵系统源码开发搭建技术开源分享

    抖音短视频矩阵系统源码开发采用模块化设计,包括账号分析、营销活动、数据监控、自动化管理等功能。通过综合分析账号数据,快速发现账号的优势和不足,并提供全面的营销方案,以提高账号曝光率和粉丝数量。同时,系统还支持多账号管理和自动化操作,有效降低账

    2024年02月19日
    浏览(55)
  • 抖音seo短视频矩阵系统源码开发源代码分享--开源-可二开

    适用于抖音短视频seo矩阵系统,抖音矩阵系统源码,短视频seo矩阵系统源码,短视频矩阵源码开发,支持二次开发,开源定制,招商加盟SaaS研发等。 1. AI视频批量剪辑(文字转语音,自动配声,转场,视频背景等自定义配置) 2. 多平台账号一站式授权管理(支持抖音、快手

    2024年02月11日
    浏览(58)
  • 项目经验分享|openGauss 陈贤文:受益于开源,回馈于开源

    开源之夏 项目经验分享 2023 #08 #nbsp;关于 o penGauss nbsp;社区 openGauss是一款开源关系型数据库管理系统,采用木兰宽松许可证v2发行。openGauss内核深度融合华为在数据库领域多年的经验,结合企业级场景需求,持续构建竞争力特性。同时openGauss也是一个开源的数据库平台,鼓励社

    2024年02月08日
    浏览(41)
  • 一些实用Android的开源库,阿里架构师经验分享

    试想这么一个场景,在 A 页面打开 B 页面,然后 B 页面打开了 C 页面,C 页面又打开了 D 页面,而且还需要传递参数,在 D 页面修改了一些信息,然后这些信息更新之后,A、B、C 页面很可能都需要对应的进行数据更新,碰到这种需求该怎么处理? 有人说用 startActivityForResult

    2024年04月10日
    浏览(95)
  • Unity烟花特效实现(附源码)

    朋友过生,不知道送什么礼物,就想着用自己所学知识做个特效当礼物吧,嘿。 主要参考了 这位up的视频 ,感谢 https://github.com/hahahappyboy/UnityProjects/tree/main/%E7%83%9F%E8%8A%B1(%E7%B2%92%E5%AD%90%E7%B3%BB%E7%BB%9F) 主要就是1个主烟花粒子系统带3个子粒子系统,这三个小的粒子系统分别是拖

    2024年02月08日
    浏览(57)
  • 含源码,用Python实现浪漫烟花

    目录 前言 环境准备 代码编写 效果展示 Python实现浪漫的烟花特效 现在很多地方都不能放烟花了,既然看不到, 那作为程序猿的我们还不能自己用代码做一个吗? 今天就带大家用代码做一个烟花特效吧。 这里使用到的库有: pygame (用于游戏的编写)、random(用于产生随机

    2024年02月12日
    浏览(71)
  • 实战: 跨年烟花代码的实现(附源码)

    目录 前言 一、pandas是什么? 二、代码结构 1.介绍主html代码 2. js文件介绍 GameCanvas.js script.js 运行效果 本文章将介绍跨年烟花代码的实现以及源代码 提示:以下是本篇文章正文内容 示例:pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的。 代码如下:

    2024年01月22日
    浏览(43)
  • 开源网安受邀参加2023全球数字经济大会,分享软件安全落地实践经验

    近日, 2023全球数字经济大会数字安全生态建设专题论坛在京隆重举行 。作为2023全球数字经济大会的重要组成部分,本次论坛围绕“数字安全生态建设”这一主题,邀请政府主管部门、行业专家学者、关键信息基础设施运营主体、数字安全企业、数据要素流通等相关方参与交

    2024年02月12日
    浏览(57)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包