找回密码
 加入我们

QQ登录

只需一步,快速开始

搜索
查看: 6583|回复: 1

[开源] 桌面下雪的特效代码

[复制链接]

1214

主题

352

回帖

11

精华

管理员

菜鸟

积分
93755

贡献奖关注奖人气王精英奖乐于助人勋章

发表于 2011-8-6 08:30:59 | 显示全部楼层 |阅读模式

  1. program Snow;
  2. uses
  3.   Windows, Messages;
  4. const
  5.   SnowNumber = 500; // 雪点数量-1
  6. type
  7.   SnowNode = record
  8.     Point: TPoint; // 雪点位置
  9.     Color: Integer; // 先前颜色
  10.     Speed: Integer; // 下落速率
  11.     nMove: Integer; // 下落距离
  12.     Stick: Integer; // '粘连'度
  13.   end;

  14. var
  15.   SnowNodes: array[0..SnowNumber] of SnowNode; // 雪点数组
  16.   hTimer: Integer; // '随机风向'时钟句柄
  17.   CrWind: Integer; // 当前'风向' ( -1 ~ 1 )
  18.   CrStep: Integer; // 当前循环步数(用于限速)
  19.   ScreenWidth, ScreenHeight: Integer; // 屏幕尺寸


  20. // 取屏幕尺寸 -> ScreenWidth, ScreenHeight

  21. procedure GetScreenSize;
  22. begin
  23.   ScreenWidth := GetSystemMetrics(SM_CXSCREEN);
  24.   ScreenHeight := GetSystemMetrics(SM_CYSCREEN);
  25. end;

  26. // '随机风向'时钟

  27. procedure TimerProc(hWnd: HWND; uMsg: UINT; idEvent: UINT; dwTime: DWORD); stdcall;
  28. begin
  29.   SetTimer(0, hTimer, (Random(27) + 4) * 500, @TimerProc); // 重设下次风向改变时间
  30.   if (CrWind <> 0) then CrWind := 0 else CrWind := Random(3) - 1; // 修改风向
  31. end;

  32. // 初始化雪点数组

  33. procedure InitSnowNodes;
  34. var
  35.   hScreenDc, J: Integer;
  36. begin
  37.   hScreenDc := CreateDC(&#39; DISPLAY&#39; , nil, nil, nil);
  38.   for J := 0 to SnowNumber do
  39.   begin
  40.     SnowNodes[J].Point.X := Random(ScreenWidth);
  41.     SnowNodes[J].Point.Y := Random(ScreenHeight);
  42.     SnowNodes[J].Color := GetPixel(hScreenDc, SnowNodes[J].Point.X, SnowNodes[J].Point.Y);
  43.     SnowNodes[J].Speed := Random(5) + 1; // 几次循环作下落一次 (1~5)
  44.     SnowNodes[J].nMove := Random(SnowNodes[J].Speed) + 1; // 每次下落距离(1~5)
  45.     SnowNodes[J].Stick := 30 - Random(SnowNodes[J].Speed); // &#39;粘连&#39;度(几次循环作一次粘连判断)
  46.   end;
  47.   DeleteDC(hScreenDc);
  48. end;

  49. // 移动雪点 ..

  50. procedure MoveSnowNodes;
  51. var
  52.   hScreenDc, I, X, Y: Integer;
  53. begin
  54.   hScreenDc := CreateDC(&#39; DISPLAY&#39; , nil, nil, nil);
  55.   for I := 0 to SnowNumber do
  56.   begin
  57.   // 控制雪点下降速率
  58.     if (CrStep mod SnowNodes[I].Speed) <> 0 then Continue;
  59.   // 恢复上次被覆盖点
  60.     if GetPixel(hScreenDc, SnowNodes[I].Point.X, SnowNodes[I].Point.Y) = $FFFFFF then
  61.       SetPixel(hScreenDc, SnowNodes[I].Point.X, SnowNodes[I].Point.Y, SnowNodes[I].Color);
  62.   // 根据风向作随机飘落
  63.     X := SnowNodes[I].Point.X + Random(3) - 1 + CrWind;
  64.     Y := SnowNodes[I].Point.Y + SnowNodes[I].nMove;
  65.   // 积雪(停留)效果处理
  66.     if ((CrStep mod SnowNodes[I].Stick) = 0) // 降低积雪概率 ..
  67.       and (GetPixel(hScreenDc, X, Y) <> GetPixel(hScreenDc, X, Y + 1)) // &#39;边缘&#39;判断
  68.       and (GetPixel(hScreenDc, X - 1, Y) <> GetPixel(hScreenDc, X - 1, Y + 1))
  69.       and (GetPixel(hScreenDc, X + 1, Y) <> GetPixel(hScreenDc, X + 1, Y + 1)) then
  70.     begin
  71.    // 稍微调整坐标
  72.       if GetPixel(hScreenDc, X, Y - 1) = GetPixel(hScreenDc, X, Y - 2) then Dec(Y) // 上边缘
  73.       else if GetPixel(hScreenDc, X, Y + 1) = GetPixel(hScreenDc, X, Y + 2) then Inc(Y); // 下边缘
  74.       Inc(X, CrWind);
  75.    // 画三个点(雪花)
  76.       SetPixel(hScreenDc, X, Y, $FFFFFF);
  77.       SetPixel(hScreenDc, X + 1, Y + 1, $FFFFFF);
  78.       SetPixel(hScreenDc, X - 1, Y + 1, $FFFFFF);
  79.    // 重生雪点
  80.       SnowNodes[I].Point.Y := Random(10);
  81.       SnowNodes[I].Point.X := Random(ScreenWidth);
  82.       SnowNodes[I].Color := GetPixel(hScreenDc, SnowNodes[I].Point.X, SnowNodes[I].Point.Y);
  83.     end else
  84.     begin
  85.       if (X < 0) or (X > ScreenWidth) or (Y > ScreenHeight) then // 超出范围则重生雪点
  86.       begin
  87.         SnowNodes[I].Point.Y := Random(10);
  88.         SnowNodes[I].Point.X := Random(ScreenWidth);
  89.         SnowNodes[I].Color := GetPixel(hScreenDc, SnowNodes[I].Point.X, SnowNodes[I].Point.Y);
  90.       end else
  91.       begin
  92.     // 保存颜色并绘制雪点
  93.         SnowNodes[I].Color := GetPixel(hScreenDc, X, Y);
  94.         SetPixel(hScreenDc, X, Y, $FFFFFF);
  95.     // 此时保存新雪点位置
  96.         SnowNodes[I].Point.X := X;
  97.         SnowNodes[I].Point.Y := Y;
  98.       end;
  99.     end;
  100.   end;
  101.   DeleteDC(hScreenDc);
  102.   Inc(CrStep);
  103. end;

  104. var
  105.   ThreadMsg: TMsg; // 标准消息结构体
  106.   Frequency: Int64; // 高性能定时器频率
  107.   StartCt, EndCt: Int64; // 高性能定时器计数
  108.   ElapsedTime: Extended; // 时间间隔
  109. begin
  110.   Randomize; GetScreenSize; InitSnowNodes; // 初始化
  111.   QueryPerformanceFrequency(Frequency); // 高性能定时器频率
  112.   hTimer := SetTimer(0, 0, Random(5) * 500, @TimerProc); // 安装随机风向定时器
  113.   RegisterHotKey(0, 0, MOD_CONTROL, ORD(&#39; L&#39; )); // 注册退出热键 Ctrl+L
  114.   while TRUE do // 消息循环
  115.   begin
  116.     QueryPerformanceCounter(StartCt); // 执行运算前 计数值
  117.     if PeekMessage(ThreadMsg, 0, 0, 0, PM_REMOVE) then // 取到消息
  118.     begin
  119.       case ThreadMsg.message of
  120.         WM_TIMER:
  121.           TimerProc(0, 0, 0, 0); // 预设风向改变时间已到

  122.         WM_HOTKEY:
  123.           begin
  124.             KillTimer(0, hTimer); // 删除随机风向定时器
  125.             UnregisterHotKey(0, 0); // 删除退出热键 Ctrl+L
  126.             InvalidateRect(0, nil, TRUE); // 刷新屏幕
  127.             Break; // 跳出消息循环
  128.           end;

  129.         WM_DISPLAYCHANGE:
  130.           begin
  131.             GetScreenSize; // 重新取屏幕尺寸
  132.             InitSnowNodes; // 初始化雪点数组
  133.           end;
  134.       end;
  135.     end;
  136.     MoveSnowNodes; // 移动雪点
  137.     QueryPerformanceCounter(EndCt); // 执行运算后计数值
  138.     ElapsedTime := (EndCt - StartCt) / Frequency;
  139.     if (ElapsedTime < 0.0005) then Sleep(2) // 简单限速
  140.     else if (ElapsedTime < 0.0010) then Sleep(1)
  141.     else if (ElapsedTime < 0.0015) then Sleep(0);
  142.   end;
  143. end.
复制代码
【VB】QQ群:1422505加的请打上VB好友
【易语言】QQ群:9531809  或 177048
【FOXPRO】QQ群:6580324  或 33659603
【C/C++/VC】QQ群:3777552
【NiceBasic】QQ群:3703755

30

主题

693

回帖

0

精华

钻石会员

积分
2815
发表于 2015-3-20 10:10:08 | 显示全部楼层
嘿嘿 这个代码很不错
您需要登录后才可以回帖 登录 | 加入我们

本版积分规则

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