C#实现黑客帝国字幕特效[转载]

看过电影《黑客帝国》得大概都会觉得里面那种黑底绿字的效果特别炫,闲来无事,就自己用C#写了个特效控件,并可以通过调整参数达到其他效果。
先看看《黑客帝国》经典的特效好了(图片经过压缩,可能不是很清楚):
           
再看看项目实现后的效果(参数设置的好的话,效果还是相当不错的):

       


实现方案:

实现并不是特别复杂,每条显示的字符串都作为一个WordInfo对象,该对象包含了速度、颜色、字体大小、字符个数等属性。在控件类WordRain中在该项目中,定义了两个Timer,一个是m_timer用来定时重绘控件,一个是m_newtimer用来定时创建新的WordInfo对象。在WordRain中还维持了两个ArrayList,一个是m_selectlist用来显示要绘制的字符(每次重绘控件的时候都会随机获取m_charlist中的一个字符用于显示),一个是m_charlist用来保存当前显示在控件中的WordInfo对象(超出控件范围的对象要及时删除)。


注意点和相关处理如下:

1. 字体较大字符串的必需在字体小的字符串之后画,避免字体小的字符串遮住字体大的字符串,影响效果。
    要达到这样的效果必须在每次重绘的时候,对m_charlist中的所有WordInfo对象按字体大小从小到大排序。实现如下:

[csharp]  view plain  copy
  1. public class WordInfoSorter : IComparer  
  2. {  
  3.     int IComparer.Compare(object x, object y)  
  4.     {  
  5.         if (((WordInfo)x).m_fontsize < ((WordInfo)y).m_fontsize) return -1;  
  6.         else if (((WordInfo)x).m_fontsize == ((WordInfo)y).m_fontsize) return 0;  
  7.         else return 1;  
  8.     }  
  9. }  
  10.   
  11. public partial class WordRain : UserControl  
  12. {  
  13.     //...  
  14.     private WordInfoSorter m_sorter;  
  15.     //...  
  16.     public WordRain()  
  17.     {  
  18.         //...  
  19.         m_sorter = new WordInfoSorter();  
  20.         //...  
  21.     }  
  22.     //...  
  23.     private void WordRain_Paint(object sender, PaintEventArgs e)  
  24.     {  
  25.         //...  
  26.         m_charlist.Sort(m_sorter);  
  27.         //...  
  28.     }  
  29.     //...  
  30. }  

2. 为了保证效果,字体较大的字符串颜色要接近前景色m_min_charcolor,字体较小的字符串颜色要更接近背景色m_max_charcolor。颜色根据字体的最大值和最小值来计算)。详见类WordInfo的SetFontAndColor()方法。

3. 同样为了保证效果,每个字符串有 m_count个字符,显示在最下面的字符颜色100%不透明,显示在最上面的字符颜色最接近透明。详见类WordInfo的GetColor()方法。


整个控件的代码如下:
[csharp]  view plain  copy
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.ComponentModel;  
  4. using System.Drawing;  
  5. using System.Drawing.Drawing2D;  
  6. using System.Data;  
  7. using System.Linq;  
  8. using System.Text;  
  9. using System.Windows.Forms;  
  10. using System.Collections;  
  11. using System.Runtime.InteropServices;  
  12.   
  13. namespace myControl  
  14. {  
  15.     public partial class WordRain : UserControl  
  16.     {  
  17.         private Timer m_timer;  //重绘定时器  
  18.         private Timer m_newtimer;   //新建字符定时器  
  19.         private Graphics m_g;     //画布  
  20.         private ArrayList m_charlist;     
  21.         private ArrayList m_selectlist;  
  22.         private WordInfoSorter m_sorter;  
  23.         private Random m_random;  
  24.   
  25.         public WordRain()  
  26.         {  
  27.             InitializeComponent();  
  28.             this.SetStyle(ControlStyles.UserPaint, true);  
  29.             this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);  
  30.             this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);  
  31.             this.SetStyle(ControlStyles.ResizeRedraw, true);  
  32.             this.SetStyle(ControlStyles.Selectable, true);  
  33.             this.BackColor = Color.Black;  
  34.               
  35.             m_charlist = new ArrayList();  
  36.             WordInfo wordinfo = new WordInfo();  
  37.             wordinfo.SetValue();  
  38.             m_charlist.Add(wordinfo);  
  39.             m_sorter = new WordInfoSorter();  
  40.             string[] arr = new string[] {"0","1","2","3","4","5","6","7","8","9"};  
  41.             m_selectlist = new ArrayList(arr);  
  42.             m_random = new Random();  
  43.             m_timer = new Timer();  
  44.             m_newtimer = new Timer();  
  45.             m_timer.Interval = 10;  
  46.             m_newtimer.Interval = 50;  
  47.             m_timer.Enabled = true;  
  48.             m_newtimer.Enabled = true;  
  49.             m_timer.Tick += new EventHandler(m_timer_Tick);  
  50.             m_newtimer.Tick += new EventHandler(m_newtimer_Tick);           
  51.         }  
  52.   
  53.         private string GetStringFromArrayList()  
  54.         {  
  55.             return (string)m_selectlist[m_random.Next(m_selectlist.Count)];  
  56.         }  
  57.   
  58.         void m_newtimer_Tick(object sender, EventArgs e)  
  59.         {  
  60.             WordInfo wordinfo = new WordInfo();  
  61.             wordinfo.SetValue();  
  62.             m_charlist.Add(wordinfo);  
  63.         }  
  64.   
  65.         void m_timer_Tick(object sender, EventArgs e)  
  66.         {  
  67.             this.Invalidate();  
  68.             ArrayList ObjToDel = new ArrayList();   
  69.             foreach (WordInfo temp in m_charlist)  
  70.             {  
  71.                 temp.m_posy += temp.m_runspeed;  
  72.                 if (temp.m_posy > this.Height + temp.m_fontsize * temp.m_count)  
  73.                     ObjToDel.Add(temp);  
  74.             }  
  75.             foreach (WordInfo temp in ObjToDel)  
  76.             {  
  77.                 m_charlist.Remove(temp);  
  78.             }  
  79.             ObjToDel.Clear();  
  80.         }  
  81.   
  82.         private void WordRain_Paint(object sender, PaintEventArgs e)  
  83.         {  
  84.             m_g = e.Graphics;  
  85.             m_charlist.Sort(m_sorter);  
  86.             SetXRange(this.Width);                     
  87.             foreach (WordInfo temp in m_charlist)  
  88.             {  
  89.                 using (Font font = new Font("Arial", temp.m_fontsize, GraphicsUnit.Pixel))  
  90.                 {  
  91.                     using(SolidBrush brush = new SolidBrush(temp.m_charcolor))                  
  92.                     {  
  93.                         for (int i = 0; i < temp.m_count; i++)  
  94.                         {  
  95.                             brush.Color = temp.GetColor(i);  
  96.                             m_g.DrawString(GetStringFromArrayList(), font, brush, temp.m_posx, temp.m_posy-temp.m_fontsize*i);    
  97.                         }  
  98.                     }  
  99.                 }  
  100.             }  
  101.   
  102.         }  
  103.   
  104.         //设置字体大小范围  
  105.         public void SetFontSizeRange(int minsize, int maxsize)  
  106.         {  
  107.             if (minsize > maxsize)  
  108.             {  
  109.                 throw new ArgumentException("参数minsize必须小于等于参数maxsize");  
  110.             }  
  111.             if (minsize < 1 || maxsize > 50)  
  112.             {  
  113.                 throw new ArgumentException("参数minsize和maxsize必须在区间[1,50]内");  
  114.             }  
  115.             WordInfo.m_min_fontsize = minsize;  
  116.             WordInfo.m_max_fontsize = maxsize;  
  117.         }  
  118.         //设置字体渐变颜色范围  
  119.         public void SetFontColorRange(Color firstColor, Color lastColor)  
  120.         {  
  121.             WordInfo.m_min_charcolor = firstColor;  
  122.             WordInfo.m_max_charcolor = lastColor;  
  123.         }  
  124.         //设置X轴所能到达的最大长度(即控件的宽度)  
  125.         public void SetXRange(int value)  
  126.         {  
  127.             WordInfo.m_max_xpos = value;  
  128.         }  
  129.         //设置速度  
  130.         public void SetSpeedRange(float minspeed, float maxspeed)  
  131.         {  
  132.             if (minspeed > maxspeed)  
  133.             {  
  134.                 throw new ArgumentException("参数minspeed必须小于等于参数maxspeed");  
  135.             }  
  136.             if (minspeed < 0.1 || maxspeed > 100.0)  
  137.             {  
  138.                 throw new ArgumentException("参数minspeed和maxspeed必须在区间[0.1,100.0]内");  
  139.             }  
  140.             WordInfo.m_min_runspeed = minspeed;  
  141.             WordInfo.m_min_runspeed = maxspeed;  
  142.         }  
  143.         //设置字符个数范围  
  144.         public void SetCountRange(int mincount, int maxcount)  
  145.         {  
  146.             if (mincount > maxcount)  
  147.             {  
  148.                 throw new ArgumentException("参数mincount必须小于等于参数maxcount");  
  149.             }  
  150.             if (mincount < 1 || maxcount > 100)  
  151.             {  
  152.                 throw new ArgumentException("参数mincount和maxcount必须在区间[1,100]内");  
  153.             }  
  154.             WordInfo.m_min_count = mincount;  
  155.             WordInfo.m_max_count = maxcount;  
  156.         }  
  157.         //设置字符列表  
  158.         public void SetArrayValue(ArrayList list)  
  159.         {  
  160.             if (list.Count == 0)  
  161.             {  
  162.                 throw new ArgumentException("参数list中的元素个数不能为0");  
  163.             }  
  164.             m_selectlist.Clear();  
  165.             m_selectlist = list;  
  166.         }  
  167.     }  
  168.   
  169.   
  170.     public class WordInfoSorter : IComparer  
  171.     {  
  172.         int IComparer.Compare(object x, object y)  
  173.         {  
  174.             if (((WordInfo)x).m_fontsize < ((WordInfo)y).m_fontsize) return -1;  
  175.             else if (((WordInfo)x).m_fontsize == ((WordInfo)y).m_fontsize) return 0;  
  176.             else return 1;  
  177.         }  
  178.     }  
  179.   
  180.     public class WordInfo  
  181.     {  
  182.         public int m_fontsize;      //字体大小  
  183.         public float m_runspeed;    //移动速度  
  184.         public Color m_charcolor;   //最下面的字的颜色,最上面的字的颜色为背景色  
  185.         public float m_posx;        //横坐标  
  186.         public float m_posy;        //纵坐标  
  187.         public int m_count;         //字符个数  
  188.         public ArrayList m_charList;  //要显示的字符列表  
  189.   
  190.         public static int m_max_xpos = 600;  
  191.         public static int m_min_count = 10;  
  192.         public static int m_max_count = 20;  
  193.         public static int m_min_fontsize = 4;  
  194.         public static int m_max_fontsize = 20;  
  195.         public static float m_min_runspeed = 0.6F;  
  196.         public static float m_max_runspeed = 4.2F;  
  197.         public static Color m_min_charcolor = Color.FromArgb(0, 255, 0);  
  198.         public static Color m_max_charcolor = Color.FromArgb(0, 55, 0);  
  199.         public static Random m_random = new Random();  
  200.   
  201.         public WordInfo()  
  202.         {  
  203.             this.m_count = 1;  
  204.             this.m_fontsize = 0;  
  205.             this.m_runspeed = 0;  
  206.             this.m_posx = 0;  
  207.             this.m_posy = 0;  
  208.             this.m_charcolor = Color.FromArgb(0, 255, 0);  
  209.         }  
  210.   
  211.   
  212.         //获取字体大小的随机值  
  213.         private int GetFontSize()  
  214.         {  
  215.             int i = m_random.Next();  
  216.             return i % (m_max_fontsize - m_min_fontsize) + m_min_fontsize;  
  217.         }  
  218.   
  219.         //获取速度的随机值  
  220.         private float GetSpeed()  
  221.         {  
  222.             int i = m_random.Next();  
  223.             int j = m_random.Next();  
  224.             return i % (m_max_runspeed - m_min_runspeed) + m_min_runspeed+ (j%10)/10.0F;  
  225.         }  
  226.   
  227.         //获取颜色的随机值  
  228.         private Color GetColor()  
  229.         {  
  230.             int min_r = m_min_charcolor.R;  
  231.             int min_g = m_min_charcolor.G;  
  232.             int min_b = m_min_charcolor.B;  
  233.             int max_r = m_max_charcolor.R;  
  234.             int max_g = m_max_charcolor.G;  
  235.             int max_b = m_max_charcolor.B;  
  236.             int r = m_random.Next((min_r > max_r ? max_r : min_r), (min_r < max_r ? max_r : min_r));  
  237.             int g = m_random.Next((min_g > max_g ? max_g : min_g), (min_g < max_g ? max_g : min_g));  
  238.             int b = m_random.Next((min_b > max_b ? max_b : min_b), (min_b < max_b ? max_b : min_b));  
  239.             return Color.FromArgb(r, g, b);  
  240.         }  
  241.   
  242.         //设置字体和颜色(字体越小,颜色越接近m_max_charcolor)  
  243.         private void SetFontAndColor()  
  244.         {  
  245.             int i = m_random.Next();  
  246.             int fontpart = i % (m_max_fontsize - m_min_fontsize);  
  247.             this.m_fontsize = m_min_fontsize + fontpart;  
  248.             float percent = ((float)fontpart) / ((float)(m_max_fontsize - m_min_fontsize));  
  249.             int min_r = m_min_charcolor.R;  
  250.             int min_g = m_min_charcolor.G;  
  251.             int min_b = m_min_charcolor.B;  
  252.             int max_r = m_max_charcolor.R;  
  253.             int max_g = m_max_charcolor.G;  
  254.             int max_b = m_max_charcolor.B;  
  255.             int rpart = (int)(Math.Abs(min_r - max_r) * percent);  
  256.             int gpart = (int)(Math.Abs(min_g - max_g) * percent);  
  257.             int bpart = (int)(Math.Abs(min_b - max_b) * percent);  
  258.             int r = min_r > max_r ? (max_r + rpart) : (max_r - rpart);  
  259.             int g = min_g > max_g ? (max_g + gpart) : (max_g - gpart);  
  260.             int b = min_b > max_b ? (max_b + bpart) : (max_b - bpart);  
  261.             this.m_charcolor = Color.FromArgb(r, g, b);  
  262.         }  
  263.   
  264.         //获取x轴坐标  
  265.         private float GetXPos()  
  266.         {  
  267.             int i = m_random.Next(m_max_xpos-1);  
  268.             return (float)(i + m_random.Next(10) / 10.0F);  
  269.   
  270.         }  
  271.   
  272.         //获取随机个数  
  273.         private int GetCount()  
  274.         {  
  275.             return m_random.Next(m_min_count, m_max_count);  
  276.         }  
  277.   
  278.         //设置相关值  
  279.         public void SetValue()  
  280.         {  
  281.             this.m_count = this.GetCount();  
  282.             this.SetFontAndColor();  
  283.             this.m_runspeed = this.GetSpeed();  
  284.             this.m_posy = m_count*m_fontsize*(-1.0F);  
  285.             this.m_posx = this.GetXPos();  
  286.         }  
  287.   
  288.         //获取颜色  
  289.         public Color GetColor(int index)  
  290.         {  
  291.             if (this.m_count == 1)  
  292.                 return this.m_charcolor;  
  293.             if (index == 0)  
  294.                 return this.m_charcolor;  
  295.             int rpart = (Math.Abs(m_charcolor.R - m_max_charcolor.R)) / m_count * index;  
  296.             int gpart = (Math.Abs(m_charcolor.G - m_max_charcolor.G)) / m_count * index;  
  297.             int bpart = (Math.Abs(m_charcolor.B - m_max_charcolor.B)) / m_count * index;  
  298.             int r = m_charcolor.R > m_max_charcolor.R ? (m_charcolor.R - rpart) : (m_charcolor.R + rpart);  
  299.             int g = m_charcolor.G > m_max_charcolor.G ? (m_charcolor.G - gpart) : (m_charcolor.G + gpart);  
  300.             int b = m_charcolor.B > m_max_charcolor.B ? (m_charcolor.B - bpart) : (m_charcolor.B + bpart);  
  301.             return Color.FromArgb(255-index*255/m_count, m_charcolor);  
  302.         }  
  303.     }  
  304. }  
  305. 转载来自:http://blog.csdn.net/Qian_F/article/details/19285075
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值