惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

有赞技术团队
有赞技术团队
MyScale Blog
MyScale Blog
The Hacker News
The Hacker News
Google DeepMind News
Google DeepMind News
The Cloudflare Blog
GbyAI
GbyAI
Vercel News
Vercel News
量子位
Apple Machine Learning Research
Apple Machine Learning Research
Recent Announcements
Recent Announcements
美团技术团队
D
DataBreaches.Net
H
Help Net Security
大猫的无限游戏
大猫的无限游戏
人人都是产品经理
人人都是产品经理
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
B
Blog RSS Feed
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Y
Y Combinator Blog
S
Secure Thoughts
S
SegmentFault 最新的问题
The Last Watchdog
The Last Watchdog
Jina AI
Jina AI
Security Archives - TechRepublic
Security Archives - TechRepublic
F
Fortinet All Blogs
C
Check Point Blog
小众软件
小众软件
阮一峰的网络日志
阮一峰的网络日志
Schneier on Security
Schneier on Security
MongoDB | Blog
MongoDB | Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Stack Overflow Blog
Stack Overflow Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Hacker News: Ask HN
Hacker News: Ask HN
博客园 - 【当耐特】
Simon Willison's Weblog
Simon Willison's Weblog
Scott Helme
Scott Helme
S
Security @ Cisco Blogs
SecWiki News
SecWiki News
Hugging Face - Blog
Hugging Face - Blog
博客园 - 叶小钗
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Google Online Security Blog
Google Online Security Blog
S
Securelist
L
LINUX DO - 最新话题
Forbes - Security
Forbes - Security
D
Darknet – Hacking Tools, Hacker News & Cyber Security
I
InfoQ
Engineering at Meta
Engineering at Meta

博客园 - AndyHai

谁动了我的构造函数? 一个PCM音频转换与混音的示例 关心则乱 让ASPX和ASMX脱离IIS运行的例子(ASP.NET宿主程序) SQL 中如何对纪录进行拆分 带有空值提示的TextBox NAT类型检测方法(转载) 在.NET中探测U盘的插入/拔出 用WebService实现中国移动的Provision反向接口 一个动态加载/卸载DLL的例子 用ASP.NET调用Tuxedo Tuxedo 搞定! 用Multi-Media Library实现的波形音频录制与播放 用Multi-Media Library制作流式音频播放器 研究如何用Multi-Media Library播放波形数据 又多一道面试题 面试 RTP协议
用C#实现的黑客帝国中的字符雨特效
AndyHai · 2008-09-28 · via 博客园 - AndyHai

在做一个WinForm登录框时,突然想到,如果有黑客帝国中字符雨的特效做背景,那应该蛮Cool的,所以就有了如下代码,随意写的,有点乱。

    public partial class CharacterRain : Component
    
{
        
/// <summary>
        
/// 必需的设计器变量。
        
/// </summary>

        private System.ComponentModel.IContainer components = null;

        
/// <summary> 
        
/// 清理所有正在使用的资源。
        
/// </summary>
        
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>

        protected override void Dispose(bool disposing)
        
{
            
if (RainThread != null && RainThread.IsAlive)
                Stop();

            
if (disposing && (components != null))
            
{
                components.Dispose();
            }

            
base.Dispose(disposing);
        }


        
组件设计器生成的代码

        
public CharacterRain()
        
{
            Initialize();

            InitializeComponent();
        }


        
public CharacterRain(IContainer container)
        
{
            Initialize();

            container.Add(
this);

            InitializeComponent();
        }


        
private object BMPLock = new object();
        
private Bitmap BMP;
        
private Graphics Graph;

        
private void Initialize()
        
{
            
this.DrawRainEvent = new EventHandler(CharacterRainPanel_DrawRainEvent);
            OnPaint 
= new PaintEventHandler(ShowWindow_Paint);
        }


        
private PaintEventHandler OnPaint;

        
private char[] CHARACTERS = '`''1''2''3''4''5''6''7''8''9''0''-''=''\\''q''w''e''r''t''y''u''i''o''p''['']''a''s''d''f''g''h''j''k''l'';''\'''z''x''c''v''b''n''m'',''.''/''~''!''@''#''$''%''^''&''*''('')''_''+''|''Q''W''E''R''T''Y''U''I''O''P''{''}''A''S''D''F''G''H''J''K''L'':''"', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?' };
        private static readonly Random Rand = new Random();

        
private Control _ShowWindow = null;
        
/// <summary>
        
/// 获取、设置用于显示字符雨的窗口(或控件)
        
/// </summary>

        public Control ShowWindow
        
{
            
get return _ShowWindow; }
            
set
            
{
                
if (_ShowWindow != null)
                    _ShowWindow.Paint 
-= OnPaint;

                _ShowWindow 
= value;

                
if (_ShowWindow != null)
                    _ShowWindow.Paint 
+= OnPaint;
            }

        }


        
void ShowWindow_Paint(object sender, PaintEventArgs e)
        
{
            
//Paint();
            if (BMP != null)
            
{
                
lock (BMPLock)
                
{
                    
//e.Graphics.Clear(_ShowWindow.BackColor);
                    try
                    
{
                        e.Graphics.DrawImage(BMP, 
00);
                    }

                    
catch
                    
{
                    }

                }

            }

        }


        
private string _RainCharacters = "`1234567890-=\\qwertyuiop[]asdfghjkl;'zxcvbnm,./~!@#$%^&*()_+|QWERTYUIOP{}ASDFGHJKL:\"ZXCVBNM<>?";
        /// <summary>
        
/// 获取、设置字符雨中可能出现的字符
        
/// </summary>

        public string RainCharacters
        
{
            
get return _RainCharacters; }
            
set
            
{
                
if (string.IsNullOrEmpty(value))
                    value 
= "`1234567890-=\\qwertyuiop[]asdfghjkl;'zxcvbnm,./~!@#$%^&*()_+|QWERTYUIOP{}ASDFGHJKL:\"ZXCVBNM<>?";
                _RainCharacters = value;
                CHARACTERS 
= value.ToCharArray();
            }

        }


        
private Color _RainHeadColor = Color.Lime;
        
/// <summary>
        
/// 获取、设置字符雨头的颜色
        
/// </summary>

        public Color RainHeadColor
        
{
            
get return _RainHeadColor; }
            
set
            
{
                
if (!Running)
                    _RainHeadColor 
= value;
                
else
                    
throw new Exception("运行中不可以更改颜色。");
            }

        }



        
private Color _RainBodyColor = Color.Green;
        
/// <summary>
        
/// 获取、设置字符雨体的颜色
        
/// </summary>

        public Color RainBodyColor
        
{
            
get return _RainBodyColor; }
            
set
            
{
                
if (!Running)
                    _RainBodyColor 
= value;
                
else
                    
throw new Exception("运行中不可以更改颜色。");
            }

        }


        
private Color _RainTailColor = Color.DarkGreen;
        
/// <summary>
        
/// 获取、设置字符雨体的颜色
        
/// </summary>

        public Color RainTailColor
        
{
            
get return _RainTailColor; }
            
set
            
{
                
if (!Running)
                    _RainTailColor 
= value;
                
else
                    
throw new Exception("运行中不可以更改颜色。");
            }

        }



        
private Font _RainFont = new Font(new FontFamily("Consolas"), 12);
        
/// <summary>
        
/// 获取、设置字符雨的字体样式
        
/// </summary>

        public Font RainFont
        
{
            
get return _RainFont; }
            
set
            
{
                
if (!Running)
                    _RainFont 
= value;
                
else
                    
throw new Exception("运行中不可以更改字体。");
            }

        }


        
private int _StreamsCount = 100;
        
/// <summary>
        
/// 获取、设置字符雨的数量
        
/// </summary>

        public int StreamsCount
        
{
            
get return _StreamsCount; }
            
set
            
{
                
if (!Running)
                    _StreamsCount 
= value;
                
else
                    
throw new Exception("运行中不可以更改数量。");
            }

        }


        
private int _MaxLength = 50;
        
/// <summary>
        
/// 获取、设置每个雨滴的最大字符数
        
/// </summary>

        public int MaxLength
        
{
            
get return _MaxLength; }
            
set
            
{
                
if (!Running)
                
{
                    
if (value >= _MinLength)
                        _MaxLength 
= value;
                    
else
                        
throw new Exception("最大字符数不能小于最小字符数。");
                }

                
else
                    
throw new Exception("运行中不可以更改数量。");
            }

        }


        
private int _MinLength = 20;
        
/// <summary>
        
/// 获取、设置每个雨滴的最小字符数
        
/// </summary>

        public int MinLength
        
{
            
get return _MinLength; }
            
set
            
{
                
if (!Running)
                
{
                    
if (value <= _MaxLength)
                        _MinLength 
= value;
                    
else
                        
throw new Exception("最小字符数不能大于最大字符数。");
                }

                
else
                    
throw new Exception("运行中不可以更改数量。");
            }

        }


        
public bool Running
        
{
            
get return RainThread != null && RainThread.IsAlive; }
        }


        
private Thread RainThread;
        
private bool RUN;
        
private bool PAUSE;
        
private Brush BackBrush = null;

        
private Brush RainHeadBrush = null;
        
private Brush RainBodyBrush = null;
        
private Brush RainTailBrush = null;

        
/// <summary>
        
/// 开始显示字符雨
        
/// </summary>

        public void Start()
        
{
            
if (_ShowWindow == null)
                
throw new Exception("没有用于显示的窗口(或控件)");

            
if (!Running)
            
{
                RainThread 
= new Thread(new ParameterizedThreadStart(RainProcess));
                RUN 
= true;
                PAUSE 
= false;
                Ready();
                RainThread.Start();
            }

        }


        
private void Ready()
        
{
            Rain.RainFont 
= _RainFont;
            Rain.RainHeadColor 
= _RainHeadColor;
            Rain.RainBodyColor 
= _RainBodyColor;
            Rain.RainTailColor 
= _RainTailColor;
            Rain.BackColor 
= _ShowWindow.BackColor;

            
if (RainHeadBrush != null)
                RainHeadBrush.Dispose();
            
if (RainBodyBrush != null)
                RainBodyBrush.Dispose();
            
if (RainTailBrush != null)
                RainTailBrush.Dispose();
            
if (BackBrush != null)
                BackBrush.Dispose();

            RainHeadBrush 
= new SolidBrush(Rain.RainHeadColor);
            RainBodyBrush 
= new SolidBrush(Rain.RainBodyColor);
            RainTailBrush 
= new SolidBrush(Rain.RainTailColor);
            BackBrush 
= new SolidBrush(Rain.BackColor);

            
//RainItems.Clear();

            
using (Graphics g = _ShowWindow.CreateGraphics())
            
{
                g.Clear(Rain.BackColor);
            }

        }


        
private EventHandler DrawRainEvent;

        
void CharacterRainPanel_DrawRainEvent(object sender, EventArgs e)
        
{
            
//foreach (Rain.Item item in e.Items)
            
//{
            
//    _ShowWindow.Invalidate(new Rectangle(item.X, item.Y, item.Width, item.Height));
            
//    _ShowWindow.Update();
            
//}

            
using (Graphics g = _ShowWindow.CreateGraphics())
            
{
                g.DrawImage(BMP, 
00);
            }

            
//_ShowWindow.Invalidate(true);
            
//_ShowWindow.Refresh();
        }


        
//private List<Rain.Item> RainItems = new List<Rain.Item>();
        private object RainLOCK = new object();

        
private void RainProcess(object Param)
        
{
            
using (BMP = new Bitmap(_ShowWindow.Width, _ShowWindow.Height))
            
{
                
using (Graph = Graphics.FromImage(BMP))
                
{

                    List
<Rain> Rains = new List<Rain>();
                    
for (int i = 0; i < _StreamsCount; i++)
                        Rains.Add(
new Rain(_MinLength + Rand.Next(_MaxLength - _MinLength)));

                    
while (RUN)
                    
{
                        
if (PAUSE)
                        
{
                            Thread.Sleep(
300);
                            
continue;
                        }


                        DoRain(Rains);

                        Thread.Sleep(
50);
                    }


                    
foreach (Rain r in Rains)
                    
{
                        r.Uninit();
                    }

                }

            }

        }


        
private void DoRain(List<Rain> Rains)
        
{

            
for (int i = 0; i < Rains.Count; i++)
            
{
                Rain rain 
= Rains[i];

                
if (!rain.Inited)
                
{
                    
if (!rain.Init(_ShowWindow.Width, Rand.Next(_ShowWindow.Height / 3)))
                        
continue;
                }


                Rain.Item item 
= rain.GetItem(CHARACTERS[Rand.Next(CHARACTERS.Length)]);
                Rain.Item prior 
= null;

                
if (item == null)
                    
continue;
                
else
                
{
                    
lock (BMPLock)
                    
{
                        
if (item.Y <= BMP.Height)
                        
{
                            
if (item.Type == Rain.Item.RainItemType.Head && rain.Prior.Type != Rain.Item.RainItemType.Tail)
                            
{
                                rain.Prior.Type 
= Rain.Item.RainItemType.Body;
                                prior 
= rain.Prior;
                            }


                            
if (item.Type == Rain.Item.RainItemType.Back)
                            
{
                                prior 
= rain.Prior;
                            }


                            
switch (item.Type)
                            
{
                                
case Rain.Item.RainItemType.Head:
                                    
{
                                        Graph.DrawString(
new string(item.CH, 1), _RainFont, RainHeadBrush, item.X, item.Y);
                                        
break;
                                    }

                                
case Rain.Item.RainItemType.Body:
                                    
{
                                        Graph.DrawString(
new string(item.CH, 1), _RainFont, RainBodyBrush, item.X, item.Y);
                                        
break;
                                    }

                                
case Rain.Item.RainItemType.Tail:
                                    
{
                                        Graph.DrawString(
new string(item.CH, 1), _RainFont, RainTailBrush, item.X, item.Y);
                                        
break;
                                    }

                                
case Rain.Item.RainItemType.Back:
                                    
{
                                        Graph.FillRectangle(BackBrush, item.X, item.Y, item.Width, item.Height);
                                        
break;
                                    }

                            }


                            
if (prior != null)
                            
{
                                
switch (prior.Type)
                                
{
                                    
case Rain.Item.RainItemType.Head:
                                        
{
                                            Graph.DrawString(
new string(prior.CH, 1), _RainFont, RainHeadBrush, prior.X, prior.Y);
                                            
break;
                                        }

                                    
case Rain.Item.RainItemType.Body:
                                        
{
                                            Graph.DrawString(
new string(prior.CH, 1), _RainFont, RainBodyBrush, prior.X, prior.Y);
                                            
break;
                                        }

                                    
case Rain.Item.RainItemType.Tail:
                                        
{
                                            Graph.DrawString(
new string(prior.CH, 1), _RainFont, RainTailBrush, prior.X, prior.Y);
                                            
break;
                                        }

                                    
case Rain.Item.RainItemType.Back:
                                        
{
                                            Graph.FillRectangle(BackBrush, prior.X, prior.Y, prior.Width, prior.Height);
                                            
break;
                                        }

                                }

                            }

                        }

                        
else
                        
{
                            item.Owner.Way 
= Rain.RainWay.Reverse;
                        }

                    }

                }

            }


            
try
            
{
                
if (!_ShowWindow.Disposing)
                    _ShowWindow.Invoke(DrawRainEvent, 
thisnew EventArgs());
            }

            
catch
            
{
            }

        }


        
/// <summary>
        
/// 停止显示字符雨
        
/// </summary>

        public void Stop()
        
{
            RUN 
= false;
        }


        
/// <summary>
        
/// 暂停显示
        
/// </summary>

        public void Pause()
        
{
            PAUSE 
= true;
        }


        
/// <summary>
        
/// 恢复暂停
        
/// </summary>

        public void Resume()
        
{
            PAUSE 
= false;
        }


        
//protected void Paint()
        
//{
        
//    lock (RainLOCK)
        
//    {
        
//        for (int i = RainItems.Count - 1; i >= 0; i--)
        
//        {
        
//            Rain.Item item = RainItems[i];

        
//            if (item.X < BMP.Width)
        
//            {
        
//                if (item.Y < BMP.Height)
        
//                {
        
//                    //if (e.ClipRectangle.X <= item.X && e.ClipRectangle.Y <= item.Y && e.ClipRectangle.Width >= item.Width && e.ClipRectangle.Height >= item.Height)
        
//                    {
        
//                        switch (item.Type)
        
//                        {
        
//                            case Rain.Item.RainItemType.Head:
        
//                                {
        
//                                    e.Graphics.DrawString(new string(item.CH, 1), _RainFont, RainHeadBrush, item.X, item.Y);
        
//                                    break;
        
//                                }
        
//                            case Rain.Item.RainItemType.Body:
        
//                                {
        
//                                    e.Graphics.DrawString(new string(item.CH, 1), _RainFont, RainBodyBrush, item.X, item.Y);
        
//                                    break;
        
//                                }
        
//                            case Rain.Item.RainItemType.Tail:
        
//                                {
        
//                                    e.Graphics.DrawString(new string(item.CH, 1), _RainFont, RainTailBrush, item.X, item.Y);
        
//                                    break;
        
//                                }
        
//                            case Rain.Item.RainItemType.Back:
        
//                                {
        
//                                    e.Graphics.FillRectangle(BackBrush, item.X, item.Y, item.Width, item.Height);
        
//                                    break;
        
//                                }
        
//                        }
        
//                    }
        
//                }
        
//                else
        
//                {
        
//                    item.Owner.Way = Rain.RainWay.Reverse;
        
//                }
        
//            }

        
//            if (item.Type == Rain.Item.RainItemType.Back)
        
//            {
        
//                RainItems.Remove(item);
        
//            }
        
//        }
        
//    }
        
//}

        
private class Rain
        
{
            
private static Font _RainFont;
            
public static Font RainFont
            
{
                
get return _RainFont; }
                
set
                
{
                    _RainFont 
= value;

                    _RainHeight 
= (int)(value.Size * value.FontFamily.GetLineSpacing(FontStyle.Regular) / value.FontFamily.GetEmHeight(FontStyle.Regular)) + 1;
                }

            }


            
public static Color BackColor;

            
public static Color RainBodyColor;

            
public static Color RainHeadColor;

            
public static Color RainTailColor;

            
private static int _RainHeight;
            
public static int RainHeight
            
{
                
get return _RainHeight; }
            }


            
private static object RangeLock = new object();
            
private static List<Rectangle> Ranges = new List<Rectangle>();

            Queue
<Item> Chars = new Queue<Item>();
            
private int _Length;
            
private int _BeginX;
            
private int _BeginY;

            
private RainWay _Way;

            
public RainWay Way
            
{
                
get return _Way; }
                
set { _Way = value; }
            }


            
private Rectangle Range;

            
public enum RainWay : byte
            
{
                
/// <summary>
                
/// 正向
                
/// </summary>

                Obverse = 0,

                
/// <summary>
                
/// 反向
                
/// </summary>

                Reverse = 1
            }


            
public bool Inited
            
{
                
get return Chars.Count > 0; }
            }


            
public bool Init(int Width, int Y)
            
{
                
bool Ret = true;

                Uninit();

                
if (Rand.Next(30< 10)
                    
return false;

                _BeginX 
= Rand.Next(Width);

                Size s 
= TextRenderer.MeasureText(" ", _RainFont);

                Range 
= new Rectangle(_BeginX, Y, s.Width, s.Height * _Length);

                
foreach (Rectangle r in Ranges)
                
{
                    
if (r.Contains(this.Range) || r.IntersectsWith(this.Range))
                    
{
                        Ret 
= false;
                        
break;
                    }

                }


                
if (Ret)
                    Ranges.Add(
this.Range);

                _BeginY 
= Y;
                _Way 
= RainWay.Obverse;
                _Prior 
= null;

                
return Ret;
            }


            
public void Uninit()
            
{
                
if (this.Range != null && Ranges.Contains(this.Range))
                    Ranges.Remove(
this.Range);
            }


            
item

            
public Rain(int Length)
            
{
                _Length 
= Length;
            }


            
public Item GetItem(char CH)
            
{
                Item Ret 
= null;
                
if (_Way == RainWay.Obverse)
                
{
                    Ret 
= Add(CH);
                    
if (Ret == null)
                        _Way 
= RainWay.Reverse;
                }

                
else
                
{
                    Ret 
= Remove();
                    
if (Ret == null)
                        _Way 
= RainWay.Obverse;
                }

                
return Ret;
            }


            
private Item _Prior = null;
            
public Item Prior
            
{
                
get
                
{
                    
return _Prior;
                }

            }


            
private Item Add(char CH)
            
{
                Item Ret 
= null;
                
if (Chars.Count < _Length)
                
{
                    Ret 
= new Item(this, CH, _BeginX, _BeginY + RainHeight * Chars.Count, Chars.Count == 0 ? Item.RainItemType.Tail : Item.RainItemType.Head);
                    
if (Ret.Type == Item.RainItemType.Head)
                        _Prior 
= Chars.Last();
                    Chars.Enqueue(Ret);
                }


                
return Ret;
            }


            
private Item Remove()
            
{
                Item Ret 
= null;
                
if (Chars.Count > 0)
                
{
                    Ret 
= Chars.Dequeue();
                    Ret.Type 
= Item.RainItemType.Back;

                    
if (Chars.Count > 0)
                    
{
                        _Prior 
= Chars.First();
                        _Prior.Type 
= Item.RainItemType.Tail;
                    }

                    
else
                        _Prior 
= null;
                }

                
return Ret;
            }

        }

    }

测试程序下载 

使用的时候,先设定ShowWindow,这个属性决定在哪个控件上显示字符雨,然后还可以设置如下属性:

MaxLength:每条字符雨的最大字符数量

MinLength:每条字符雨的最小字符数量

RainBodyColor:字符雨中间的颜色

RainCharacters:字符雨可以使用到的字符

FainFont:字体

RainHeadColor:最前面的字符的颜色

RainTailColor:最后面字符的颜色

StreamsCount:字符雨的数量

还有如下方法可供调用:

Start:开始显示

Stop:停止显示

Pause:暂停显示

Resume:恢复暂停