美文网首页
网易C++--书籍练习案例02--互动粒子

网易C++--书籍练习案例02--互动粒子

作者: heiqimingren | 来源:发表于2020-11-08 19:01 被阅读0次

    第一个版本:静止小球的初始化和显示

    #define WIDTH 1024         //屏幕的宽
    #define HEIGHT 768         //屏幕的高
    #define NUM_MOVERS 800     //小球的数量
    
    //定义小球结构
    struct Mover
    {
        COLORREF color;         //颜色
        float x, y;             //坐标
        float vx, vy;           //速度
        float radius;           //半径
    };
    
    //定义全局变量
    Mover movers[NUM_MOVERS];      //小球数组,每个数组元素都是一个结构体
    
    void startup()
    {
        //设置随机种子
        srand((unsigned int)time(NULL));
        //初始化小球数组
        for (int i = 0; i < NUM_MOVERS;i++)
        {
            movers[i].color = RGB(rand() % 256, rand() % 256, rand() % 256);
            movers[i].x = rand() % WIDTH;
            movers[i].y = rand() % HEIGHT;
            movers[i].vx = float(cos(float(i)))*(rand() % 34);       //这个速度变化不是线性变化哦,重点!
            movers[i].vy = float(sin(float(i)))*(rand() % 34);       //这个速度变化不是线性变化哦
            movers[i].radius = (rand() % 34) / 15.0;
        }
        initgraph(WIDTH, HEIGHT);
        BeginBatchDraw();
    }
    void show()
    {
        clearrectangle(0, 0, WIDTH - 1, HEIGHT - 1);   //清空画面中的全部矩形区域
        for (int i = 0; i < NUM_MOVERS;i++)
        {
            //画小球
            setcolor(movers[i].color);
            setfillstyle(movers[i].color);
            fillcircle(int(movers[i].x + 0.5), int(movers[i].y + 0.5), int(movers[i].radius + 0.5));    
        }
        FlushBatchDraw();
        Sleep(2);
    }
    void updateWithoutInput()
    {
    
    }
    void updateWithInput()
    {
    
    }
    void gameover()
    {
        EndBatchDraw();
        closegraph();
    }
    int main()
    {
        startup();
        while (1)
        {
            show();
            updateWithoutInput();
            updateWithInput();
        }
        gameover();
        return 0;
    }
    
    
    image.png

    ================================================================
    第二版本:小球的运动与反弹

    #include<stdio.h>
    #include<string.h>
    #include<stdlib.h>    //清屏命令在这里。
    #include <windows.h> //延时10毫秒-sleep,gotoxy函数
    #include <iostream>
    #include <conio.h>       //getch()----不用按回车,就可以输入字符。    
    #include <graphics.h>      //EasyX库,所使用的!
    #include <math.h>         //三角函数
    #include <algorithm>      //sort函数排序方法,https://blog.csdn.net/BIGKALA/article/details/81624691,这是方法适用的地址
    #include <time.h>
    
    
    using namespace std;
    
    
    
    #define WIDTH 1024         //屏幕的宽
    #define HEIGHT 768         //屏幕的高
    #define NUM_MOVERS 800     //小球的数量
    
    //定义小球结构
    struct Mover
    {
        COLORREF color;         //颜色
        float x, y;             //坐标
        float vx, vy;           //速度
        float radius;           //半径
    };
    
    //定义全局变量
    Mover movers[NUM_MOVERS];      //小球数组,每个数组元素都是一个结构体
    
    void startup()
    {
        //设置随机种子
        srand((unsigned int)time(NULL));
    
        //初始化小球数组
        for (int i = 0; i < NUM_MOVERS;i++)
        {
            movers[i].color = RGB(rand() % 256, rand() % 256, rand() % 256);
            movers[i].x = rand() % WIDTH;
            movers[i].y = rand() % HEIGHT;
            movers[i].vx = float(cos(float(i)))*(rand() % 34);       //这个速度变化不是线性变化哦,重点!
            movers[i].vy = float(sin(float(i)))*(rand() % 34);       //这个速度变化不是线性变化哦
            movers[i].radius = (rand() % 34) / 15.0;
        }
        initgraph(WIDTH, HEIGHT);
        BeginBatchDraw();
    }
    void show()
    {
        clearrectangle(0, 0, WIDTH - 1, HEIGHT - 1);   //清空画面中的全部矩形区域
        for (int i = 0; i < NUM_MOVERS;i++)
        {
            //画小球
            setcolor(movers[i].color);
            setfillstyle(movers[i].color);
            fillcircle(int(movers[i].x + 0.5), int(movers[i].y + 0.5), int(movers[i].radius + 0.5));
            
        }
        FlushBatchDraw();
        Sleep(2);
    
    }
    
    
    void updateWithoutInput()
    {
        for (int i = 0; i < NUM_MOVERS;i++)      //对所有小球进行遍历
        {
            float x = movers[i].x;      //当前小球的坐标
            float y = movers[i].y;
            float vx = movers[i].vx;     //当前小球的速度
            float vy = movers[i].vy;
    
            //根据 位置+速度,来更新小球的坐标
            float nextX = x + vx;
            float nextY = y + vy;
    
            //如果小球超过上下左右四个边界,就将位置设为边界处,速度反向
            if (nextX>WIDTH)  //右边边界
            {
                nextX = WIDTH;
                vx = -1 * vx;
            }
            else if (nextX<0 )  //左边边界
            {
                nextX = 0;
                vx = -1 * vx;
            }
            if (nextY>HEIGHT )   //下边边界
            {
                nextY = HEIGHT;
                vy = -1 * vy;
            }
            else if (nextY<0 )      //上边边界
            {
                nextY = 0;
                vy = -1 * vy;
            }
    
            //更新小球位置,速度的结构体数组
            movers[i].vx = vx;
            movers[i].vy = vy;
            movers[i].x = nextX;
            movers[i].y = nextY;
    
    
        }
    
        
    }
    void updateWithInput()
    {
    
    }
    void gameover()
    {
        EndBatchDraw();
        closegraph();
    }
    
    int main()
    {
        startup();
        while (1)
        {
            show();
            updateWithoutInput();
            updateWithInput();
        }
        gameover();
        return 0;
    }
    
    

    效果图片。注意图片里的小球都是动态的


    image.png

    ======================================================================

    第三版本:小球运动的规范化
    加入了阻尼运动

    #define WIDTH 1024         //屏幕的宽
    #define HEIGHT 768         //屏幕的高
    #define NUM_MOVERS 800     //小球的数量
    #define FRICTION 0.96f    //摩擦力,阻力系数
    
    
    
    //定义小球结构
    struct Mover
    {
        COLORREF color;         //颜色
        float x, y;             //坐标
        float vx, vy;           //速度
        float radius;           //半径
    };
    
    //定义全局变量
    Mover movers[NUM_MOVERS];      //小球数组,每个数组元素都是一个结构体
    
    void startup()
    {
        //设置随机种子
        srand((unsigned int)time(NULL));
    
        //初始化小球数组
        for (int i = 0; i < NUM_MOVERS;i++)
        {
            movers[i].color = RGB(rand() % 256, rand() % 256, rand() % 256);
            movers[i].x = rand() % WIDTH;
            movers[i].y = rand() % HEIGHT;
            movers[i].vx = float(cos(float(i)))*(rand() % 34);       //这个速度变化不是线性变化哦,重点!
            movers[i].vy = float(sin(float(i)))*(rand() % 34);       //这个速度变化不是线性变化哦
            movers[i].radius = (rand() % 34) / 15.0;
        }
        initgraph(WIDTH, HEIGHT);
        BeginBatchDraw();
    }
    void show()
    {
        clearrectangle(0, 0, WIDTH - 1, HEIGHT - 1);   //清空画面中的全部矩形区域
        for (int i = 0; i < NUM_MOVERS;i++)
        {
            //画小球
            setcolor(movers[i].color);
            setfillstyle(movers[i].color);
            fillcircle(int(movers[i].x + 0.5), int(movers[i].y + 0.5), int(movers[i].radius + 0.5));
            
        }
        FlushBatchDraw();
        Sleep(2);
    
    }
    
    
    void updateWithoutInput()
    {
        for (int i = 0; i < NUM_MOVERS;i++)      //对所有小球进行遍历
        {
            float x = movers[i].x;      //当前小球的坐标
            float y = movers[i].y;
            float vx = movers[i].vx;     //当前小球的速度
            float vy = movers[i].vy;
    
            //小球运动有一个阻尼,受到摩擦力限制,速度逐渐减小.每次循环,就减小一次
            vx = vx*FRICTION;
            vy = vy*FRICTION;
            //速度的绝对值
            float avgVX = abs(vx);
            float avgVY = abs(vy);
            //两个方向,速度的平均值
            float avgV = (avgVX + avgVY)*0.5f;
    
            //因为有上面阻尼的作用,如果速度过小,乘以一个0-3的随机数,会以比较大的概率让速度变大
            if (avgVX<0.1 )
            {
                vx = vx* float(rand()) / RAND_MAX * 3;
            }
            if ( avgVY<0.1)
            {
                vy = vy*float(rand()) / RAND_MAX * 3;
            }
            //小球的半径在0.4-3.5之间,速度越大,半径越大
            float sc = avgV*0.45f;
            sc = max(min(sc, 3.5f), 0.4f);
            movers[i].radius = sc;
    
            //根据 位置+速度,来更新小球的坐标
            float nextX = x + vx;
            float nextY = y + vy;
    
            //如果小球超过上下左右四个边界,就将位置设为边界处,速度反向
            if (nextX>WIDTH)  //右边边界
            {
                nextX = WIDTH;
                vx = -1 * vx;
            }
            else if (nextX<0 )  //左边边界
            {
                nextX = 0;
                vx = -1 * vx;
            }
            if (nextY>HEIGHT )   //下边边界
            {
                nextY = HEIGHT;
                vy = -1 * vy;
            }
            else if (nextY<0 )      //上边边界
            {
                nextY = 0;
                vy = -1 * vy;
            }
    
            //更新小球位置,速度的结构体数组
            movers[i].vx = vx;
            movers[i].vy = vy;
            movers[i].x = nextX;
            movers[i].y = nextY;
    
    
        }
    
        
    }
    void updateWithInput()
    {
    
    }
    void gameover()
    {
        EndBatchDraw();
        closegraph();
    }
    
    int main()
    {
        startup();
        while (1)
        {
            show();
            updateWithoutInput();
            updateWithInput();
        }
        gameover();
        return 0;
    }
    
    

    ===============================================
    第四版本:鼠标的吸引力

    
    #define WIDTH 1024         //屏幕的宽
    #define HEIGHT 768         //屏幕的高
    #define NUM_MOVERS 800     //小球的数量
    #define FRICTION 0.96f    //摩擦力,阻力系数
    
    
    
    //定义小球结构
    struct Mover
    {
        COLORREF color;         //颜色
        float x, y;             //坐标
        float vx, vy;           //速度
        float radius;           //半径
    };
    
    //定义全局变量
    Mover movers[NUM_MOVERS];      //小球数组,每个数组元素都是一个结构体
    int mouseX, mouseY;               //当前鼠标坐标
    
    
    void startup()
    {
        //设置随机种子
        srand((unsigned int)time(NULL));
    
        //初始化小球数组
        for (int i = 0; i < NUM_MOVERS;i++)
        {
            movers[i].color = RGB(rand() % 256, rand() % 256, rand() % 256);
            movers[i].x = rand() % WIDTH;
            movers[i].y = rand() % HEIGHT;
            movers[i].vx = float(cos(float(i)))*(rand() % 34);       //这个速度变化不是线性变化哦,重点!
            movers[i].vy = float(sin(float(i)))*(rand() % 34);       //这个速度变化不是线性变化哦
            movers[i].radius = (rand() % 34) / 15.0;
        }
    
        //初始化当前鼠标坐标在画布中心;
        mouseX = WIDTH / 2;
        mouseY = HEIGHT / 2;
    
        initgraph(WIDTH, HEIGHT);
        BeginBatchDraw();
    }
    void show()
    {
        clearrectangle(0, 0, WIDTH - 1, HEIGHT - 1);   //清空画面中的全部矩形区域
        for (int i = 0; i < NUM_MOVERS;i++)
        {
            //画小球
            setcolor(movers[i].color);
            setfillstyle(movers[i].color);
            fillcircle(int(movers[i].x + 0.5), int(movers[i].y + 0.5), int(movers[i].radius + 0.5));
            
        }
        FlushBatchDraw();
        Sleep(2);
    
    }
    
    void updateWithoutInput()
    {
        float toDist = WIDTH *0.86;         //吸引距离,如果小球与鼠标的距离在此范围内,就会被吸引
    
        for (int i = 0; i < NUM_MOVERS;i++)      //对所有小球进行遍历
        {
            float x = movers[i].x;      //当前小球的坐标
            float y = movers[i].y;
            float vx = movers[i].vx;     //当前小球的速度
            float vy = movers[i].vy;
    
            float dx = x - mouseX;   //计算当前小球和鼠标坐标的距离,可能是整数,也可能是负数
            float dy = y - mouseY;
            float d = sqrt(dx*dx + dy*dy);   //当前小球和鼠标位置的距离
            //下面将dx和dy,归一化,仅仅取其方向,和距离无关
            if (d!=0 )
            {
                dx = dx / d;
                dy = dy / d;
            }
            else
            {
                dx = 0;
                dy = 0;
            }
            //小球距离鼠标<toDist ,在此范围内小球会受到鼠标的吸引
            if (d<toDist )
            {
                //吸引力引起的加速度服务,小球距离鼠标越近引起的加速度越大           d越来越小--》toACC,越来越大。
                float toAcc = (1 - (d / toDist))*WIDTH*0.0014f;
                //由dx,dy归一化方向信息,加速度幅度值为toAcc,得到新的小球速度
                vx = vx - dx*toAcc;
                vy = vy - dy*toAcc;
            }
    
            //小球运动有一个阻尼,受到摩擦力限制,速度逐渐减小.每次循环,就减小一次
            vx = vx*FRICTION;
            vy = vy*FRICTION;
            //速度的绝对值
            float avgVX = abs(vx);
            float avgVY = abs(vy);
            //两个方向,速度的平均值
            float avgV = (avgVX + avgVY)*0.5f;
    
            //因为有上面阻尼的作用,如果速度过小,乘以一个0-3的随机数,会以比较大的概率让速度变大
            if (avgVX<0.1 )
            {
                vx = vx* float(rand()) / RAND_MAX * 3;
            }
            if ( avgVY<0.1)
            {
                vy = vy*float(rand()) / RAND_MAX * 3;
            }
            //小球的半径在0.4-3.5之间,速度越大,半径越大
            float sc = avgV*0.45f;
            sc = max(min(sc, 3.5f), 0.4f);
            movers[i].radius = sc;
    
            //根据 位置+速度,来更新小球的坐标
            float nextX = x + vx;
            float nextY = y + vy;
    
            //如果小球超过上下左右四个边界,就将位置设为边界处,速度反向
            if (nextX>WIDTH)  //右边边界
            {
                nextX = WIDTH;
                vx = -1 * vx;
            }
            else if (nextX<0 )  //左边边界
            {
                nextX = 0;
                vx = -1 * vx;
            }
            if (nextY>HEIGHT )   //下边边界
            {
                nextY = HEIGHT;
                vy = -1 * vy;
            }
            else if (nextY<0 )      //上边边界
            {
                nextY = 0;
                vy = -1 * vy;
            }
    
            //更新小球位置,速度的结构体数组
            movers[i].vx = vx;
            movers[i].vy = vy;
            movers[i].x = nextX;
            movers[i].y = nextY;
        }   
    }
    void updateWithInput()
    {
        MOUSEMSG m;      //定义鼠标消息
        while (MouseHit())      //检测当前是否有鼠标消息
        {
            m = GetMouseMsg();
            if (m.uMsg==WM_MOUSEMOVE )    //如果鼠标移动,更新当前鼠标坐标变量。
            {
                mouseX = m.x;
                mouseY = m.y;
            }
        }
    
    }
    void gameover()
    {
        EndBatchDraw();
        closegraph();
    }
    int main()
    {
        startup();
        while (1)
        {
            show();
            updateWithoutInput();
            updateWithInput();
        }
        gameover();
        return 0;
    }
    

    效果图:


    image.png

    ===========================================================================
    第五版本,鼠标的击打斥力

    #define WIDTH 1024         //屏幕的宽
    #define HEIGHT 768         //屏幕的高
    #define NUM_MOVERS 800     //小球的数量
    #define FRICTION 0.96f    //摩擦力,阻力系数
    
    
    
    //定义小球结构
    struct Mover
    {
        COLORREF color;         //颜色
        float x, y;             //坐标
        float vx, vy;           //速度
        float radius;           //半径
    };
    
    //定义全局变量
    Mover movers[NUM_MOVERS];      //小球数组,每个数组元素都是一个结构体
    int mouseX, mouseY;               //当前鼠标坐标
    int isMouseDown;                 //鼠标左键是否按下
    
    void startup()
    {
        //设置随机种子
        srand((unsigned int)time(NULL));
    
        //初始化小球数组
        for (int i = 0; i < NUM_MOVERS;i++)
        {
            movers[i].color = RGB(rand() % 256, rand() % 256, rand() % 256);
            movers[i].x = rand() % WIDTH;
            movers[i].y = rand() % HEIGHT;
            movers[i].vx = float(cos(float(i)))*(rand() % 34);       //这个速度变化不是线性变化哦,重点!
            movers[i].vy = float(sin(float(i)))*(rand() % 34);       //这个速度变化不是线性变化哦
            movers[i].radius = (rand() % 34) / 15.0;
        }
    
        //初始化当前鼠标坐标在画布中心;
        mouseX = WIDTH / 2;
        mouseY = HEIGHT / 2;
    
        isMouseDown = 0;      //初始鼠标未按下
    
        initgraph(WIDTH, HEIGHT);
        BeginBatchDraw();
    
    }
    void show()
    {
        clearrectangle(0, 0, WIDTH - 1, HEIGHT - 1);   //清空画面中的全部矩形区域
        for (int i = 0; i < NUM_MOVERS;i++)
        {
            //画小球
            setcolor(movers[i].color);
            setfillstyle(movers[i].color);
            fillcircle(int(movers[i].x + 0.5), int(movers[i].y + 0.5), int(movers[i].radius + 0.5));
            
        }
        FlushBatchDraw();
        Sleep(2);
    
    }
    
    
    void updateWithoutInput()
    {
        float toDist = WIDTH *0.86;         //吸引距离,如果小球与鼠标的距离在此范围内,就会被吸引
        float blowDist = WIDTH*0.5;         //击打距离,小球与鼠标的距离在此范围内,都会受到击打的斥力
    
    
    
        for (int i = 0; i < NUM_MOVERS;i++)      //对所有小球进行遍历
        {
            float x = movers[i].x;      //当前小球的坐标
            float y = movers[i].y;
            float vx = movers[i].vx;     //当前小球的速度
            float vy = movers[i].vy;
    
            float dx = x - mouseX;   //计算当前小球和鼠标坐标的距离,可能是整数,也可能是负数
            float dy = y - mouseY;
            float d = sqrt(dx*dx + dy*dy);   //当前小球和鼠标位置的距离
            //下面将dx和dy,归一化,仅仅取其方向,和距离无关
            if (d!=0 )
            {
                dx = dx / d;
                dy = dy / d;
            }
            else
            {
                dx = 0;
                dy = 0;
            }
            //小球距离鼠标<toDist ,在此范围内小球会受到鼠标的吸引
            if (d<toDist )
            {
                //吸引力引起的加速度服务,小球距离鼠标越近引起的加速度越大           d越来越小--》toACC,越来越大。
                float toAcc = (1 - (d / toDist))*WIDTH*0.0014f;
                //由dx,dy归一化方向信息,加速度幅度值为toAcc,得到新的小球速度
                vx = vx - dx*toAcc;
                vy = vy - dy*toAcc;
            }
            //当鼠标左键按下,并且小球距离鼠标<blowDist,在击打范围内时会受到向外的力。
            if (isMouseDown && d < blowDist)
            {
                //击打力引起的加速度幅度,这个公式表示小球距离鼠标越近击打斥力引起的加速度越大
                float blowAcc = (1 - (d / blowDist)) * 6;
                //0.5f - float(rand()) / RAND_MAX; --->产生-0.5到0.5的随机数,加入一些扰动
                //float(rand()) / RAND_MAX   --->产生0-1的随机数。
                //得到最新的小球速度。
    
                vx = vx + dx*blowAcc + 0.5f - float(rand()) / RAND_MAX;
                vy = vy + dy*blowAcc + 0.5f - float(rand()) / RAND_MAX;
    
    
    
            }
    
    
    
    
            //小球运动有一个阻尼,受到摩擦力限制,速度逐渐减小.每次循环,就减小一次
            vx = vx*FRICTION;
            vy = vy*FRICTION;
            //速度的绝对值
            float avgVX = abs(vx);
            float avgVY = abs(vy);
            //两个方向,速度的平均值
            float avgV = (avgVX + avgVY)*0.5f;
    
            //因为有上面阻尼的作用,如果速度过小,乘以一个0-3的随机数,会以比较大的概率让速度变大
            if (avgVX<0.1 )
            {
                vx = vx* float(rand()) / RAND_MAX * 3;
            }
            if ( avgVY<0.1)
            {
                vy = vy*float(rand()) / RAND_MAX * 3;
            }
            //小球的半径在0.4-3.5之间,速度越大,半径越大
            float sc = avgV*0.45f;
            sc = max(min(sc, 3.5f), 0.4f);
            movers[i].radius = sc;
    
            //根据 位置+速度,来更新小球的坐标
            float nextX = x + vx;
            float nextY = y + vy;
    
            //如果小球超过上下左右四个边界,就将位置设为边界处,速度反向
            if (nextX>WIDTH)  //右边边界
            {
                nextX = WIDTH;
                vx = -1 * vx;
            }
            else if (nextX<0 )  //左边边界
            {
                nextX = 0;
                vx = -1 * vx;
            }
            if (nextY>HEIGHT )   //下边边界
            {
                nextY = HEIGHT;
                vy = -1 * vy;
            }
            else if (nextY<0 )      //上边边界
            {
                nextY = 0;
                vy = -1 * vy;
            }
    
            //更新小球位置,速度的结构体数组
            movers[i].vx = vx;
            movers[i].vy = vy;
            movers[i].x = nextX;
            movers[i].y = nextY;
        }
    
        
    }
    void updateWithInput()
    {
        MOUSEMSG m;      //定义鼠标消息
        while (MouseHit())      //检测当前是否有鼠标消息
        {
            m = GetMouseMsg();
            if (m.uMsg==WM_MOUSEMOVE )    //如果鼠标移动,更新当前鼠标坐标变量。
            {
                mouseX = m.x;
                mouseY = m.y;
            }
            else if (m.uMsg ==WM_LBUTTONDOWN ) //左键按下
            {
                isMouseDown = 1;
            }
            else if (m.uMsg ==WM_LBUTTONUP )  //左键抬起
            {
                isMouseDown = 0;
            }
        }
    
    }
    void gameover()
    {
        EndBatchDraw();
        closegraph();
    }
    
    int main()
    {
        startup();
        while (1)
        {
            show();
            updateWithoutInput();
            updateWithInput();
        }
        gameover();
        return 0;
    }
    

    ===================================================
    第六版本:鼠标的干扰力。实现鼠标移动时对例子的扰动力,类似于在水面上拿树枝搅动,搅动的越快,扰动越大。

    #define WIDTH 1024         //屏幕的宽
    #define HEIGHT 768         //屏幕的高
    #define NUM_MOVERS 800     //小球的数量
    #define FRICTION 0.96f    //摩擦力,阻力系数
    
    
    
    //定义小球结构
    struct Mover
    {
        COLORREF color;         //颜色
        float x, y;             //坐标
        float vx, vy;           //速度
        float radius;           //半径
    };
    
    //定义全局变量
    Mover movers[NUM_MOVERS];      //小球数组,每个数组元素都是一个结构体
    int mouseX, mouseY;               //当前鼠标坐标
    int isMouseDown;                 //鼠标左键是否按下
    int prevMouseX, prevMouseY;      //上次鼠标位置
    int mouseVX, mouseVY;            //鼠标的速度, 
    
    void startup()
    {
        //设置随机种子
        srand((unsigned int)time(NULL));
    
        //初始化小球数组
        for (int i = 0; i < NUM_MOVERS;i++)
        {
            movers[i].color = RGB(rand() % 256, rand() % 256, rand() % 256);
            movers[i].x = rand() % WIDTH;
            movers[i].y = rand() % HEIGHT;
            movers[i].vx = float(cos(float(i)))*(rand() % 34);       //这个速度变化不是线性变化哦,重点!
            movers[i].vy = float(sin(float(i)))*(rand() % 34);       //这个速度变化不是线性变化哦
            movers[i].radius = (rand() % 34) / 15.0;
        }
    
        //初始化当前鼠标坐标在画布中心;
        mouseX = prevMouseX= WIDTH / 2;
        mouseY = prevMouseY= HEIGHT / 2;
    
        isMouseDown = 0;      //初始鼠标未按下
    
        initgraph(WIDTH, HEIGHT);
        BeginBatchDraw();
    
    }
    void show()
    {
        clearrectangle(0, 0, WIDTH - 1, HEIGHT - 1);   //清空画面中的全部矩形区域
        for (int i = 0; i < NUM_MOVERS;i++)
        {
            //画小球
            setcolor(movers[i].color);
            setfillstyle(movers[i].color);
            fillcircle(int(movers[i].x + 0.5), int(movers[i].y + 0.5), int(movers[i].radius + 0.5));
            
        }
        FlushBatchDraw();
        Sleep(2);
    
    }
    
    
    void updateWithoutInput()
    {
        float toDist = WIDTH *0.86;         //吸引距离,如果小球与鼠标的距离在此范围内,就会被吸引
        float blowDist = WIDTH*0.5;         //击打距离,小球与鼠标的距离在此范围内,都会受到击打的斥力
        float stirDist = WIDTH*0.125;       //扰动距离,小球与鼠标的距离在此范围内,都会受到鼠标的扰动
    
        //前后两次运行间鼠标移动的距离,即为鼠标的速度
        mouseVX = mouseX - prevMouseX;
        mouseVY = mouseY - prevMouseY;
        //为记录这次鼠标的坐标,更新上次鼠标坐标变量。
        prevMouseX = mouseX;
        prevMouseY = mouseY;
    
    
        for (int i = 0; i < NUM_MOVERS;i++)      //对所有小球进行遍历
        {
            float x = movers[i].x;      //当前小球的坐标
            float y = movers[i].y;
            float vx = movers[i].vx;     //当前小球的速度
            float vy = movers[i].vy;
    
            float dx = x - mouseX;   //计算当前小球和鼠标坐标的距离,可能是整数,也可能是负数
            float dy = y - mouseY;
            float d = sqrt(dx*dx + dy*dy);   //当前小球和鼠标位置的距离
            //下面将dx和dy,归一化,仅仅取其方向,和距离无关
            if (d!=0 )
            {
                dx = dx / d;
                dy = dy / d;
            }
            else
            {
                dx = 0;
                dy = 0;
            }
            //小球距离鼠标<toDist ,在此范围内小球会受到鼠标的吸引
            if (d<toDist )
            {
                //吸引力引起的加速度服务,小球距离鼠标越近引起的加速度越大           d越来越小--》toACC,越来越大。
                float toAcc = (1 - (d / toDist))*WIDTH*0.0014f;
                //由dx,dy归一化方向信息,加速度幅度值为toAcc,得到新的小球速度
                vx = vx - dx*toAcc;
                vy = vy - dy*toAcc;
            }
            //当鼠标左键按下,并且小球距离鼠标<blowDist,在击打范围内时会受到向外的力。
            if (isMouseDown && d < blowDist)
            {
                //击打力引起的加速度幅度,这个公式表示小球距离鼠标越近击打斥力引起的加速度越大
                float blowAcc = (1 - (d / blowDist)) * 6;
                //0.5f - float(rand()) / RAND_MAX; --->产生-0.5到0.5的随机数,加入一些扰动
                //float(rand()) / RAND_MAX   --->产生0-1的随机数。
                //得到最新的小球速度。
    
                vx = vx + dx*blowAcc + 0.5f - float(rand()) / RAND_MAX;
                vy = vy + dy*blowAcc + 0.5f - float(rand()) / RAND_MAX;
    
            }
    
            //若小球距离鼠标<stirDist,在此范围内小球会受到鼠标的扰动
            if (d<stirDist ) 
            {
                //扰动力引起的加速度幅度,小球距离鼠标越近引起的加速度越大,扰动力值更小。
                float mAcc = (1 - (d / stirDist))*WIDTH*0.00026f;
                //鼠标速度越快,引起的扰动力越大。
                vx = vx + mouseVX*mAcc;
                vy = vy + mouseVY*mAcc;
    
            }
    
            //小球运动有一个阻尼,受到摩擦力限制,速度逐渐减小.每次循环,就减小一次
            vx = vx*FRICTION;
            vy = vy*FRICTION;
            //速度的绝对值
            float avgVX = abs(vx);
            float avgVY = abs(vy);
            //两个方向,速度的平均值
            float avgV = (avgVX + avgVY)*0.5f;
    
            //因为有上面阻尼的作用,如果速度过小,乘以一个0-3的随机数,会以比较大的概率让速度变大
            if (avgVX<0.1 )
            {
                vx = vx* float(rand()) / RAND_MAX * 3;
            }
            if ( avgVY<0.1)
            {
                vy = vy*float(rand()) / RAND_MAX * 3;
            }
            //小球的半径在0.4-3.5之间,速度越大,半径越大
            float sc = avgV*0.45f;
            sc = max(min(sc, 3.5f), 0.4f);
            movers[i].radius = sc;
    
            //根据 位置+速度,来更新小球的坐标
            float nextX = x + vx;
            float nextY = y + vy;
    
            //如果小球超过上下左右四个边界,就将位置设为边界处,速度反向
            if (nextX>WIDTH)  //右边边界
            {
                nextX = WIDTH;
                vx = -1 * vx;
            }
            else if (nextX<0 )  //左边边界
            {
                nextX = 0;
                vx = -1 * vx;
            }
            if (nextY>HEIGHT )   //下边边界
            {
                nextY = HEIGHT;
                vy = -1 * vy;
            }
            else if (nextY<0 )      //上边边界
            {
                nextY = 0;
                vy = -1 * vy;
            }
    
            //更新小球位置,速度的结构体数组
            movers[i].vx = vx;
            movers[i].vy = vy;
            movers[i].x = nextX;
            movers[i].y = nextY;
        }
    
        
    }
    void updateWithInput()
    {
        MOUSEMSG m;      //定义鼠标消息
        while (MouseHit())      //检测当前是否有鼠标消息
        {
            m = GetMouseMsg();
            if (m.uMsg==WM_MOUSEMOVE )    //如果鼠标移动,更新当前鼠标坐标变量。
            {
                mouseX = m.x;
                mouseY = m.y;
            }
            else if (m.uMsg ==WM_LBUTTONDOWN ) //左键按下
            {
                isMouseDown = 1;
            }
            else if (m.uMsg ==WM_LBUTTONUP )  //左键抬起
            {
                isMouseDown = 0;
            }
        }
    
    }
    void gameover()
    {
        EndBatchDraw();
        closegraph();
    }
    
    int main()
    {
        startup();
        while (1)
        {
            show();
            updateWithoutInput();
            updateWithInput();
        }
        gameover();
        return 0;
    }
    
    

    相关文章

      网友评论

          本文标题:网易C++--书籍练习案例02--互动粒子

          本文链接:https://www.haomeiwen.com/subject/xibhbktx.html