huidong

首页 | 会员登录 | 关于争取 2022 寒假做出汇东网 Ver3.0.0 !
搜索文章


旧版 http://huidong.xyz/?mode=2&id=439 

/////////////////////////////////////
//
//    图像切换动画效果(像素点位移)
//
//    Visual Studio 2022 | EasyX 20220610
//    
//    by huidong <mailhuid@163.com>
//    2022.7.28
//

#include "HiEasyX.h"
using std::vector;

int nWndWidth = 100;
int nWndHeight = 100;

#define SQR(x)    ((x)*(x))
#define DISTANCE(x1, y1, x2, y2)    sqrt(SQR(x2-x1)+SQR(y2-y1))

struct FloatPoint
{
    double x = 0, y = 0;
};

struct MovePoint
{
    FloatPoint pt = {};            // 原位置
    double vx = 0, vy = 0;        // 毫秒速度
    bool isRedundant = false;    // 该点是否多余(Src)
    bool isUsed = false;        // 是否已被作为目标点(Dst)

    HWND hwnd = NULL;
};

IMAGE imgSrc, imgDst;
vector<MovePoint> vecSrc, vecDst;
int nAnimateDuration = 2;    // 动画时长(秒)
int nFPS = 24;                // 帧率

int nDelayMS = (int)((1.0 / nFPS) * 1000);    // 每帧的延时(毫秒)

void Load(LPCTSTR src, LPCTSTR dst)
{
    loadimage(&imgSrc, src);
    loadimage(&imgDst, dst);
}

void Record()
{
    IMAGE* pImg[] = { &imgSrc,&imgDst };
    vector<MovePoint>* pVec[] = { &vecSrc,&vecDst };
    for (int i = 0; i < 2; i++)
    {
        SetWorkingImage(pImg[i]);
        for (int x = 0; x < getwidth(); x++)
        {
            for (int y = 0; y < getheight(); y++)
            {
                if (getpixel(x, y) == BLACK)
                {
                    MovePoint pt = { (double)x,(double)y };
                    pVec[i]->push_back(pt);
                }
            }
        }
    }
}

void Calc()
{
    // 平衡源点和目标点数量
    size_t sizeSrc = vecSrc.size();
    size_t sizeDst = vecDst.size();
    if (sizeSrc < sizeDst)
    {
        for (size_t i = 0; i < sizeDst - sizeSrc; i++)
        {
            vecSrc.push_back(vecSrc[rand() % sizeSrc]);
        }
    }
    else if (sizeSrc > sizeDst)
    {
        size_t sizeDiff = sizeSrc - sizeDst;
        for (size_t i = 0; i < sizeDiff; i++)
        {
            vecSrc[sizeSrc / sizeDiff * i].isRedundant = true;
        }
    }

    // 分配目标点,计算速度
    size_t sizeSrcNew = vecSrc.size();
    for (size_t i = 0; i < sizeSrcNew; i++)
    {
        FloatPoint ptBest = { -1,-1 };
        double dDistance = -1;
        int nBestIndex = -1;
        for (size_t j = 0; j < sizeDst; j++)
        {
            // 多余的点选哪个做目标都可以,但是其他点只能选择没用过的
            if (vecSrc[i].isRedundant || !vecDst[j].isUsed)
            {
                double dThis = DISTANCE(
                    vecSrc[i].pt.x, vecSrc[i].pt.y,
                    vecDst[j].pt.x, vecDst[j].pt.y);
                if (dThis < dDistance || dDistance == -1)
                {
                    ptBest = vecDst[j].pt;
                    dDistance = dThis;
                    nBestIndex = j;
                }
            }
        }

        if (nBestIndex == -1)
        {
            printf("\nError.\n");
            exit(-1);
        }

        if (!vecSrc[i].isRedundant)
        {
            vecDst[nBestIndex].isUsed = true;
        }
        vecSrc[i].vx = (ptBest.x - vecSrc[i].pt.x) / (double)nAnimateDuration / 1000;
        vecSrc[i].vy = (ptBest.y - vecSrc[i].pt.y) / (double)nAnimateDuration / 1000;
    }
}

void CreateWindowPixel()
{
    for (auto& pixel : vecSrc)
    {
        HiEasyX::PreSetWindowPos((int)pixel.pt.x * nWndWidth, (int)pixel.pt.y * nWndHeight);
        pixel.hwnd = HiEasyX::initgraph_win32(nWndWidth, nWndHeight);
        HiEasyX::SetWindowStyle(HiEasyX::GetWindowStyle() & ~WS_SIZEBOX);
        BEGIN_TASK();
        setbkcolor(WHITE);
        cleardevice();
        END_TASK();
        FLUSH_DRAW();
        Sleep (100);
    }
}

void Animate(bool reverse = false)
{
    int nDelayFrequency = nAnimateDuration * 1000 / nDelayMS;
    vector<MovePoint> vecPt = vecSrc;
    if (reverse)
    {
        for (size_t j = 0; j < vecSrc.size(); j++)
        {
            vecPt[j].pt.x += vecPt[j].vx * nAnimateDuration * 1000;
            vecPt[j].pt.y += vecPt[j].vy * nAnimateDuration * 1000;
            vecPt[j].vx = -vecPt[j].vx;
            vecPt[j].vy = -vecPt[j].vy;
            HiEasyX::MoveWindow(
                (int)vecPt[j].pt.x * nWndWidth,
                (int)vecPt[j].pt.y * nWndHeight,
                vecPt[j].hwnd
            );
        }
    }
    for (int i = 0; i < nDelayFrequency; i++)
    {
        for (size_t j = 0; j < vecSrc.size(); j++)
        {
            vecPt[j].pt.x += vecPt[j].vx * nDelayMS;
            vecPt[j].pt.y += vecPt[j].vy * nDelayMS;
            putpixel((int)vecPt[j].pt.x, (int)vecPt[j].pt.y, BLACK);
            HiEasyX::MoveWindow(
                (int)vecPt[j].pt.x * nWndWidth,
                (int)vecPt[j].pt.y * nWndHeight,
                vecPt[j].hwnd
            );
        }
        FlushBatchDraw();
        HpSleep(nDelayMS);
    }
}

int main()
{
    /*Load(L"点赞.bmp", L"投币.bmp");
    Record();
    Calc();
    CreateWindowPixel();
    Animate();
    Sleep (3000);
    closegraph();*/

    nWndWidth = 70;
    nWndHeight = 70;

    Load(L"投币.bmp", L"收藏.bmp");
    Record();
    Calc();
    CreateWindowPixel();
    Animate();
    Sleep (3000);
    closegraph();
    

    return 0;
}




返回首页


Copyright (C) 2018-2024 huidong