在游戏中,有各种各样特效,其中有一种特效是通过计算随机产生,而不是一张又一张的图片更换,通过模拟现实中的粒子物理规律得到有趣真实的效果,这种叫作粒子特效,它能大量的降低资源大小,咱们一起实现一个简单的跟随鼠标的粒子特效。

 

Silverlight C# 游戏开发:绚丽的粒子特效-颜色粒子(一)_第1张图片

在flash中我不清楚是否好做,但是在Silverlight中实现粒子特效非常容易,今天咱们一起来做一个简单的粒子特效。
现在需要将基本的粒子创建出来,先分析粒子最基本的运动方式和规律,粒子具备衰减的特性,然后就是移动行为,为了让运动不具备规律还要加入例如XY轴随机向量和重力,具体分析请看下图。
 

Silverlight C# 游戏开发:绚丽的粒子特效-颜色粒子(一)_第2张图片 Silverlight C# 游戏开发:绚丽的粒子特效-颜色粒子(一)_第3张图片

依据上面的分析建立全局参数,为了让粒子效果看起来更加真实和不确定,这些包含了随机、透明度、粒子数、大小范围等等,请参看下面的代码:
     
     
     
     
  1. public class GlobalValue  
  2. {  
  3. /// <summary> 
  4. /// 全局随机函数,从时间取得种子,保证每次都不一样  
  5. /// summary> 
  6. public static Random random = new Random((int)DateTime.Now.Ticks);  
  7. /// <summary> 
  8. /// 起始透明度  
  9. /// summary> 
  10. public const double OPACITY = 1;  
  11. /// <summary> 
  12. /// 每次添加多少个粒子  
  13. /// summary> 
  14. public const double FIREWORK_NUM = 2;  
  15. /// <summary> 
  16. /// 重力  
  17. /// summary> 
  18. public const double GRAVITY = 0.1;  
  19. /// <summary> 
  20. /// 偏移X  
  21. /// summary> 
  22. public const double X_VELOCITY = 5;  
  23. /// <summary> 
  24. /// 偏移Y  
  25. /// summary> 
  26. public const double Y_VELOCITY = 5;  
  27. /// <summary> 
  28. /// 最小的半径  
  29. /// summary> 
  30. public const int SIZE_MIN = 1;  
  31. /// <summary> 
  32. /// 最大的半径  
  33. /// summary> 
  34. public const int SIZE_MAX = 10;  
  35. /// <summary> 
  36. /// 透明度衰减值  
  37. /// summary> 
  38. public const double OpacityInc = -0.02;  
  39. }  
 
然后建立基本粒子,我这里偷懒了,简单的写了一个DOT类:
     
     
     
     
  1. public class Dot: Canvas  
  2. {   
  3. public double XVelocity = 1;  
  4. public double YVelocity = 1;  
  5. public double Gravity = 1;  
  6.  
  7. public Dot(byte red, byte green, byte blue, double size)  
  8. {   
  9. double opac = GlobalValue.OPACITY;  
  10. size = GlobalValue.random.Next(GlobalValue.SIZE_MIN,GlobalValue.SIZE_MAX);  
  11. //生成圆圈粒子  
  12. {  
  13. Ellipse ellipse = new Ellipse();  
  14. ellipse.Width = size;  
  15. ellipse.Height = size;   
  16. ellipse.Fill = new SolidColorBrush(Color.FromArgb(255, red, green, blue));  
  17. ellipse.Opacity = opac;   
  18. ellipse.SetValue(Canvas.LeftProperty, -ellipse.Width / 2);  
  19. ellipse.SetValue(Canvas.TopProperty, -ellipse.Height / 2);  
  20. this.Children.Add(ellipse);  
  21. }  
  22. }  
  23. public void RunFirework()  
  24. {  
  25. XX = X + XVelocity;  
  26. YY = Y + YVelocity;  
  27. this.Opacity += GlobalValue.OpacityInc;  
  28. YVelocity += Gravity;   
  29. }  
  30. //制作一个绑定属性  
  31. public double X  
  32. {  
  33. get { return (double)(GetValue(Canvas.LeftProperty)); }  
  34. set { SetValue(Canvas.LeftProperty, value); }  
  35. }  
  36. public double Y  
  37. {  
  38. get { return (double)(GetValue(Canvas.TopProperty)); }  
  39. set { SetValue(Canvas.TopProperty, value); }  
  40. }  
  41. }  
 
DOT从Canvas继承,它只是一个非常简单的点,然后依照颜色生成,那么现在将点放入到一个循环体中,制作相关的逻辑,我们这次一次使用了游戏循环方式中的链条式循环,基础理论请参看这里: http://nowpaper.blog.51cto.com/3893223/712448
建立一个Colorful类也是从Canvas上继承下来,它就是所有粒子的容器。
     
     
     
     
  1. public class Colorful : Canvas  
  2. {  
  3. private List<Dot> _dotGroup = new List<Dot>();  
  4.  
  5. private DispatcherTimer _timer;  
  6. private static int IntervalTime = 20;   
  7. public Colorful()  
  8. {  
  9. this.Background = new SolidColorBrush(Colors.Gray);   
  10. List<Object> array = new List<Object>();  
  11. Object abc = new Object();  
  12. Start();  
  13. }  
  14. void loop_timer_Tick(object sender, EventArgs e)  
  15. {  
  16. moveDots();  
  17. }  
  18.  
  19. void moveDots()  
  20. {  
  21. for (int i = _dotGroup.Count - 1; i >= 0; i--)  
  22. {  
  23. Dot dot = _dotGroup[i];  
  24. dot.RunFirework();  
  25. if (dot.Opacity <= 0.1)  
  26. {  
  27. this.Children.Remove(dot);  
  28. _dotGroup.Remove(dot);  
  29. }  
  30. }  
  31. }  
  32.  
  33. public virtual void addDotToGroup(double x, double y)  
  34. {  
  35. int seed = (int)DateTime.Now.Ticks;  
  36.  
  37. for (int i = 0; i < GlobalValue.FIREWORK_NUM; i++)  
  38. {  
  39. double size = GlobalValue.SIZE_MIN + (GlobalValue.SIZE_MAX - GlobalValue.SIZE_MIN) * GlobalValue.random.NextDouble();  
  40. byte red = (byte)(128 + (128 * GlobalValue.random.NextDouble()));  
  41. byte green = (byte)(128 + (128 * GlobalValue.random.NextDouble()));  
  42. byte blue = (byte)(128 + (128 * GlobalValue.random.NextDouble()));  
  43.  
  44. double xVelocity = GlobalValue.X_VELOCITY - 2 * GlobalValue.X_VELOCITY * GlobalValue.random.NextDouble();  
  45. double yVelocity = -GlobalValue.Y_VELOCITY * GlobalValue.random.NextDouble();  
  46. Dot dot = new Dot(red, green, blue, size);  
  47. dot.X = x;  
  48. dot.Y = y;  
  49. dot.XVelocity = xVelocity;  
  50. dot.YVelocity = yVelocity;  
  51. dot.Gravity = GlobalValue.GRAVITY;  
  52. dot.RunFirework();  
  53. _dotGroup.Add(dot);  
  54.  
  55. this.Children.Add(dot);  
  56. }  
  57. }  
  58. public virtual void Start()  
  59. {  
  60. _timer = new DispatcherTimer();  
  61.  
  62. _timer.Interval = TimeSpan.FromMilliseconds(IntervalTime);  
  63. _timer.Tick += new EventHandler(loop_timer_Tick);  
  64. _timer.Start();  
  65. }  
  66. }  
  67.    
  68. 这是一个只有执行逻辑的容器,addDot用来增加粒子,moveDots是移动粒子并且检测是否消失,如果消失则从List和父结构中移除掉。  
  69. 生成逻辑通过面向对象的方式实现,建立一个Colorful_FollowMouse类:  
  70. public class Colorful_FollowMouse : Colorful  
  71. {  
  72. public Colorful_FollowMouse()  
  73. {  
  74. MouseMove += new MouseEventHandler(Colorful_FollowMouse_MouseMove);  
  75. }  
  76. void Colorful_FollowMouse_MouseMove(object sender, MouseEventArgs e)  
  77. {  
  78. addDotToGroup(e.GetPosition(this).X, e.GetPosition(this).Y);  
  79. }  
  80. }  
 
添加到MainPage中LayoutRoot.Children.Add( new Colorful_ FollowMouse ());
运行看看效果吧:)鼠标滑动一下看看
 
我在工程中加入了一个Colorful_ClickMouse类,是通过点击产生粒子的操作效果,可以更换看看点击的感觉如何:)
对于一个游戏而言,如果粒子系统作的好,能够为游戏增加很多视觉乐趣,就如今天的颜色点特效,能够应用到很多程序当中,并不只是游戏,而且这个类一旦写好,就可以作为通用的方法为其他开发所用上,这个颜色点很有趣吧,以后后面咱们逐步实现更佳“绚丽”的特效,例如火焰、爆炸等等:)