“粒子渲染版”Hello World

前言

    “Hello World”是大多数初学者接触计算机编程的第一个程序,也是最简单的程序。但面对枯燥乏味的“黑框框”,大多数初学者学习兴趣并不强烈。因此,我开发出此"粒子渲染版"Hello World,感受计算机编程不一样的美。

完整代码及注释 

// 设置 Windows 版本和 API 版本
#define WINVER 0x0A00
#define _WIN32_WINNT 0x0A00

// 包含必要的头文件
#include<graphics.h>
#include<conio.h>
#include<ctime>
#include<random>
#include <ShellScalingApi.h>        // 引用头文件
#pragma comment(lib, "Shcore.lib")  // 链接库文件
using namespace std;

// 常量定义
const double PI = 3.1415926;

// 随机数生成器
default_random_engine e(time(0));
uniform_int_distribution<int> random_color(0, 255);

//初始化界面(1920*1080)
int xScreen = 1920;
int yScreen = 1080;

//初始化函数
void init()
{ // 获取图形窗口句柄
    HWND hwnd = initgraph(xScreen, yScreen);

    // 设置窗口样式,去除标题栏
    SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & (!WS_CAPTION));

    // 设置窗口位置和大小
    SetWindowPos(hwnd, HWND_TOP, 0, 0, xScreen, yScreen, SWP_SHOWWINDOW);

    // 开始图形绘制批处理
    BeginBatchDraw();
}

// 绘制矩形的函数
void rectangle(DWORD* pMem, int x1, int y1, int x2, int y2, COLORREF color)
{
    for (; y1 <= y2; ++y1)

        for (int i = y1 * xScreen + x1, x = x1; x <= x2; ++i, ++x)

            if (i > 0 && i < xScreen * yScreen)  pMem[i] = BGR(color);
}

// 粒子类
class Paticals {
public:

    // 构造函数
    Paticals(TCHAR* str, int X, int Y, int size);

    // 获取目标位置
    void get_destination();

    // 移动粒子
    void move();
private:

    // 成员变量
    int X, Y;
    int size;
    TCHAR* str;
    DWORD* ImageBuffer;

    // 存储粒子属性的向量
    vector<COLORREF> color;
    vector<double> dest_x;
    vector<double> dest_y;
    vector<double> origin_x;
    vector<double> origin_y;
    vector<double> v;
};

// 粒子类的构造函数
Paticals::Paticals(TCHAR* str, int X, int Y, int size) :
    str(str), X(X), Y(Y), size(size)
{    // 随机数分布
    uniform_int_distribution<int> random_x(0, xScreen - 1);
    uniform_int_distribution<int> random_y(0, yScreen - 1);
    uniform_real_distribution<double> random_v(0.5, 1);

    // 获取目标位置和粒子属性
    get_destination();

    // 遍历粒子属性向量,初始化粒子属性
    for (int i = 0; i < dest_x.size(); ++i)
    {   
        v.push_back(random_v(e));
        origin_x.push_back(random_x(e));
        origin_y.push_back(random_y(e));
        color.push_back(RGB(random_color(e), random_color(e), random_color(e)));
    }
}

// 获取目标位置的函数
void Paticals::get_destination()
{
    // 获取图像缓冲区
    ImageBuffer = GetImageBuffer();

    // 设置文本样式
    settextstyle(size, 0, L"楷体");
    settextcolor(WHITE);

    // 在指定位置绘制文本
    outtextxy(X, Y, str);

    int i = 0;

    // 外层循环遍历2D网格的y坐标。
    for (int y = 0; y < yScreen; ++y)
    {
        // 计算一维数组'ImageBuffer'的索引。
        for (int x = 0; x < xScreen; ++x)
        {
            // 检查索引是否在范围内。
            int index = y * xScreen + x;

            // 检查'ImageBuffer'中当前像素是否非零。
            if (index > 0 && index < xScreen * yScreen)
            {
                if (ImageBuffer[index] != 0)
                {
                    int flag = 0; // 将标志变量初始化为0。

                    // 嵌套循环(2x2)检查当前像素周围的6x6区域。
                    for (int _y = y; _y < y + 6; ++_y)

                        for (int _x = x; _x < x + 6; ++_x)
                        {
                            index = _y * xScreen + _x;

                            // 检查索引是否在范围内。
                            if (index > 0 && index < xScreen * yScreen)

                                // 检查区域中的像素是否不是黑色。
                                if (ImageBuffer[index] != BGR(0, 0, 0))                                      ++flag;
                        }

                    // 检查区域中是否有超过25个像素不是黑色。
                    if (flag > 25)
                    {
                        // 记录区域的坐标。
                        dest_x.push_back(x);
                        dest_y.push_back(y);

                        // 将区域中的像素设置为黑色并跳到下一个区域。
                        for (int _y = y; _y < y + 6; ++_y)
                        {
                            for (int _x = x; _x < x + 6; ++_x)
                            {

                                int index = _y * xScreen + _x;

                                // 检查索引是否在范围内。
                                if (index > 0 && index < xScreen * yScreen)                                     ImageBuffer[index] = BLACK;
                            }
                        }

                        x += 5;
                    }
                }
            }
        }
    }
}

// 根据其目的地和速度移动粒子的方法。
void Paticals::move()
{
    for (int i = 0; i < dest_x.size() && i < origin_x.size(); ++i)
    {
        // 如果y坐标不等于目的地,则更新y坐标。
        if (int(origin_x[i]) != int(dest_x[i]))
            origin_x[i] > dest_x[i] ? origin_x[i] -= v[i] : origin_x[i] += v[i];

        // 如果y坐标不等于目的地,则更新y坐标。
        if (int(origin_y[i]) != int(dest_y[i]))
            origin_y[i] > dest_y[i] ? origin_y[i] -= v[i] : origin_y[i] += v[i];

        // 根据更新后的位置和颜色在'ImageBuffer'上绘制矩形。
        rectangle(ImageBuffer, origin_x[i], origin_y[i], origin_x[i] + 6 - 2, origin_y[i] + 6 - 2, color[i]);
    }
}

// 主函数
int main()
{
    // 设置进程的DPI感知,以适应高分辨率显示器
    SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE);

    // 初始化绘图环境等内容
    init();

    //输出的文字内容英语中文都可,可替换
    TCHAR str[] = _T("Hello World!");
    //60,320是输出文字的坐标(文字的左上角),300是字体大小
    //所有参数均可改
    Paticals characters(str, 60, 320, 300);

    // 主循环,直到键盘有输入
    while (!_kbhit())
    {
        // 清空绘图区域
        cleardevice();

        // 移动并绘制粒子效果,实现文字的动态效果
        characters.move();

        // 刷新绘图缓冲区
        FlushBatchDraw();
    }
    // 等待用户按下任意键
    _getch();

    // 关闭图形窗口
    closegraph();

    // 返回0表示程序正常结束
    return 0;
} 

步骤

  1. 图形初始化: 在 init 函数中,程序通过 initgraph 初始化图形窗口,设置窗口的样式并去除标题栏。然后通过 SetWindowPos 设置窗口的位置和大小。最后,通过 BeginBatchDraw 开始图形绘制批处理,这可以提高图形的绘制效率。

  2. 绘制矩形: 使用 rectangle 函数在图形窗口中绘制矩形。该函数接受左上角和右下角的坐标以及颜色,通过遍历坐标范围内的每个点,将相应位置的像素颜色设置为指定颜色。

  3. 粒子类: 定义了一个 Paticals 类来表示粒子。在构造函数中,通过传递粒子的初始位置、字符、大小等参数,生成具有随机属性的粒子群体。每个粒子有目标位置、当前位置、速度和颜色等属性。

  4. 目标位置计算: get_destination 函数根据粒子的数量和初始位置,计算出每个粒子的目标位置,使它们在一个圆形轨迹上均匀分布。

  5. 粒子移动: move 函数用于更新粒子的位置,并在图形窗口中绘制粒子。通过迭代每个粒子,根据其速度朝着目标位置移动,并绘制一个小矩形代表粒子。图形窗口被清空,然后绘制所有粒子,最后通过 putimage 函数将图形缓冲区中的内容显示到图形窗口上。

总体来说,这个程序通过粒子的目标位置和当前位置之间的差异,以及每个粒子的速度,模拟了一个简单的粒子系统,并通过图形库在窗口中实时展示粒子的运动。

运行效果

 开发环境:

    Visual Studio 2022 version 17.8.2Thank You for Downloading Visual Studio Community Edition (microsoft.com)

    EasyX_2023大暑版  EasyX Graphics Library for C++

结言

    欢迎各位初学者及此方面专家就此程序,进行讨论。

  • 8
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
好的,以下是一个简单的实现: HTML代码: ``` <div id="container"> <canvas id="firework"></canvas> <div id="text-container"> <div id="text-box"> <div id="text">Hello World</div> </div> </div> </div> ``` CSS代码: ``` body { margin: 0; padding: 0; text-align: center; } #container { position: relative; height: 100vh; } #firework { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } #text-container { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 300px; height: 200px; background-color: red; } #text-box { position: relative; top: 50%; transform: translateY(-50%); } #text { color: white; font-size: 36px; font-weight: bold; } ``` JavaScript代码: ``` var canvas = document.getElementById("firework"); var ctx = canvas.getContext("2d"); canvas.width = window.innerWidth; canvas.height = window.innerHeight; // 创建烟花粒子 function createParticle(x, y, color) { var particle = {}; particle.x = x; particle.y = y; particle.color = color; particle.vel = {}; particle.vel.x = Math.random() * 10 - 5; particle.vel.y = Math.random() * 10 - 5; particle.size = 5; return particle; } // 创建烟花 function createFirework(x, y) { var firework = {}; firework.x = x; firework.y = y; firework.particles = []; firework.color = "hsl(" + Math.random() * 360 + ", 100%, 50%)"; for (var i = 0; i < 50; i++) { var particle = createParticle(x, y, firework.color); firework.particles.push(particle); } return firework; } // 更新烟花粒子位置 function updateParticle(particle) { particle.x += particle.vel.x; particle.y += particle.vel.y; particle.vel.y += 0.1; particle.size -= 0.05; if (particle.size < 0) { particle.size = 0; } } // 更新烟花粒子数组 function updateParticles(particles) { for (var i = 0; i < particles.length; i++) { var particle = particles[i]; updateParticle(particle); } } // 渲染烟花粒子 function renderParticle(particle) { ctx.beginPath(); ctx.fillStyle = particle.color; ctx.arc(particle.x, particle.y, particle.size, 0, Math.PI * 2); ctx.fill(); } // 渲染烟花粒子数组 function renderParticles(particles) { for (var i = 0; i < particles.length; i++) { var particle = particles[i]; renderParticle(particle); } } // 更新烟花数组 function updateFireworks(fireworks) { for (var i = 0; i < fireworks.length; i++) { var firework = fireworks[i]; updateParticles(firework.particles); } } // 渲染烟花数组 function renderFireworks(fireworks) { for (var i = 0; i < fireworks.length; i++) { var firework = fireworks[i]; renderParticles(firework.particles); } } // 删除烟花 function removeFirework(fireworks, firework) { var index = fireworks.indexOf(firework); fireworks.splice(index, 1); } // 主循环 function loop(fireworks) { ctx.clearRect(0, 0, canvas.width, canvas.height); renderFireworks(fireworks); updateFireworks(fireworks); // 每秒钟创建一个烟花 if (Math.random() < 0.02) { var x = Math.random() * canvas.width; var y = Math.random() * canvas.height; var firework = createFirework(x, y); fireworks.push(firework); } // 删除已经烧完的烟花 for (var i = 0; i < fireworks.length; i++) { var firework = fireworks[i]; if (firework.particles.length === 0) { removeFirework(fireworks, firework); } } requestAnimationFrame(function() { loop(fireworks); }); } // 启动主循环 var fireworks = []; loop(fireworks); ``` 这个程序会在页面上创建一个带有“Hello World”文本的红色矩形,并在背景中播放烟花效果。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值