zoukankan      html  css  js  c++  java
  • 粒子算法:烟花、喷泉、爆炸

    参考:https://www.codeproject.com/articles/10003/a-basic-particles-system

    如果需要实现一个喷泉粒子系统:

    1)需要先定义每个粒子元素Particle类:它应包含有运动方向和速度,初始化位置(及运动一个生命值后的位置),生命值,粒子渲染的颜色,及一个生命值增加一个单位后对应的粒子属性变化。

    Vector.cs--存储粒子位置信息

      1 /// <summary>
      2     /// 向量
      3     /// </summary>
      4     public class Vector
      5     {
      6         #region Private members
      7         /// <summary>
      8         /// X Coorination of the vector
      9         /// </summary>
     10         private float m_Xcoord;
     11         /// <summary>
     12         /// Y Coorination of the vector
     13         /// </summary>
     14         private float m_Ycoord;
     15         /// <summary>
     16         /// Z Coorination of the vector
     17         /// </summary>
     18         private float m_Zcoord;
     19         #endregion
     20 
     21         #region Constructors
     22         /// <summary>
     23         /// Default constructor. Initiate vector at the (0,0,0) location
     24         /// </summary>
     25         public Vector()
     26         { }
     27 
     28         /// <summary>
     29         /// Initiate vector with given parameters
     30         /// </summary>
     31         /// <param name="inX">X coordination of vector</param>
     32         /// <param name="inY">Y coordination of vector</param>
     33         /// <param name="inZ">Z coordination of vector</param>
     34         public Vector(float inX, float inY, float inZ)
     35         {
     36             m_Xcoord = inX;
     37             m_Ycoord = inY;
     38             m_Zcoord = inZ;
     39         }
     40 
     41         /// <summary>
     42         /// Initiate vector with given parameters
     43         /// </summary>
     44         /// <param name="coordination">Vector's coordinations as an array</param>
     45         public Vector(float[] coordination)
     46         {
     47             m_Xcoord = coordination[0];
     48             m_Ycoord = coordination[1];
     49             m_Zcoord = coordination[2];
     50         }
     51 
     52         /// <summary>
     53         /// Initiate vector with same values as given Vector
     54         /// </summary>
     55         /// <param name="v">Vector to copy coordinations</param>
     56         public Vector(Vector vector)
     57         {
     58             m_Xcoord = vector.X;
     59             m_Ycoord = vector.Y;
     60             m_Zcoord = vector.Z;
     61         }
     62         #endregion
     63 
     64         #region Public properties
     65         /// <summary>
     66         /// X Coordination of vector
     67         /// </summary>
     68         public float X
     69         {
     70             get { return m_Xcoord; }
     71             set { m_Xcoord = value; }
     72         }
     73         /// <summary>
     74         /// Y Coordination of vector
     75         /// </summary>
     76         public float Y
     77         {
     78             get { return m_Ycoord; }
     79             set { m_Ycoord = value; }
     80         }
     81         /// <summary>
     82         /// Z Coordination of vector
     83         /// </summary>
     84         public float Z
     85         {
     86             get { return m_Zcoord; }
     87             set { m_Zcoord = value; }
     88         }
     89         #endregion
     90 
     91         #region Methods
     92 
     93         /// <summary>
     94         /// Add 2 vectors and create a new one.
     95         /// </summary>
     96         /// <param name="vector1">First vector</param>
     97         /// <param name="vector2">Second vector</param>
     98         /// <returns>New vector that is the sum of the 2 vectors</returns>
     99         public static Vector Add(Vector vector1, Vector vector2)
    100         {
    101             if (((Object)vector1 == null) || ((Object)vector2 == null))
    102                 return null;
    103             return new Vector(vector1.X + vector2.X, vector1.Y + vector2.Y, vector1.Z + vector2.Z);
    104         }
    105         /// <summary>
    106         /// Substract 2 vectors and create a new one.
    107         /// </summary>
    108         /// <param name="vector1">First vector</param>
    109         /// <param name="vector2">Second vector</param>
    110         /// <returns>New vector that is the difference of the 2 vectors</returns>
    111         public static Vector Subtract(Vector vector1, Vector vector2)
    112         {
    113             if (((Object)vector1 == null) || ((Object)vector2 == null))
    114                 return null;
    115             return new Vector(vector1.X - vector2.X, vector1.Y - vector2.Y, vector1.Z - vector2.Z);
    116         }
    117         /// <summary>
    118         /// Return a new vector with negative values.
    119         /// </summary>
    120         /// <param name="v">Original vector</param>
    121         /// <returns>New vector that is the inversion of the original vector</returns>
    122         public static Vector Neg(Vector vector)
    123         {
    124             if ((Object)vector == null)
    125                 return null;
    126             return new Vector(-vector.X, -vector.Y, -vector.Z);
    127         }
    128         /// <summary>
    129         /// Multiply a vector with a scalar
    130         /// </summary>
    131         /// <param name="vector">Vector to be multiplied</param>
    132         /// <param name="val">Scalar to multiply vector</param>
    133         /// <returns>New vector that is the multiplication of the vector with the scalar</returns>
    134         public static Vector Multiply(Vector vector, float val)
    135         {
    136             if ((Object)vector == null)
    137                 return null;
    138             return new Vector(vector.X * val, vector.Y * val, vector.Z * val);
    139         }
    140         #endregion
    141 
    142         #region Operators
    143 
    144         /// <summary>
    145         /// Check equality of two vectors
    146         /// </summary>
    147         /// <param name="vector1">First vector</param>
    148         /// <param name="vector2">Second vector</param>
    149         /// <returns>True - if he 2 vectors are equal.
    150         /// False - otherwise</returns>
    151         public static bool operator ==(Vector vector1, Vector vector2)
    152         {
    153             if (((Object)vector1 == null) || ((Object)vector2 == null))
    154                 return false;
    155             return ((vector1.X.Equals(vector2.X))
    156                 && (vector1.Y.Equals(vector2.Y))
    157                 && (vector1.Z.Equals(vector2.Z)));
    158         }
    159 
    160         /// <summary>
    161         /// Check inequality of two vectors
    162         /// </summary>
    163         /// <param name="vector1">First vector</param>
    164         /// <param name="vector2">Second vector</param>
    165         /// <returns>True - if he 2 vectors are not equal.
    166         /// False - otherwise</returns>
    167         public static bool operator !=(Vector vector1, Vector vector2)
    168         {
    169             if (((Object)vector1 == null) || ((Object)vector2 == null))
    170                 return false;
    171             return ((!vector1.X.Equals(vector2.X))
    172                 && (!vector1.Y.Equals(vector2.Y))
    173                 && (!vector1.Z.Equals(vector2.Z)));
    174         }
    175 
    176         /// <summary>
    177         /// Calculate the sum of 2 vectors.
    178         /// </summary>
    179         /// <param name="vector1">First vector</param>
    180         /// <param name="vector2">Second vector</param>
    181         /// <returns>New vector that is the sum of the 2 vectors</returns>
    182         public static Vector operator +(Vector vector1, Vector vector2)
    183         {
    184             if (((Object)vector1 == null) || ((Object)vector2 == null))
    185                 return null;
    186             return Vector.Add(vector1, vector2);
    187         }
    188         /// <summary>
    189         /// Calculate the substraction of 2 vectors
    190         /// </summary>
    191         /// <param name="vector1">First vector</param>
    192         /// <param name="vector2">Second vector</param>
    193         /// <returns>New vector that is the difference of the 2 vectors</returns>
    194         public static Vector operator -(Vector vector1, Vector vector2)
    195         {
    196             if (((Object)vector1 == null) || ((Object)vector2 == null))
    197                 return null;
    198             return Vector.Subtract(vector1, vector2);
    199         }
    200         /// <summary>
    201         /// Calculate the negative (inverted) vector
    202         /// </summary>
    203         /// <param name="v">Original vector</param>
    204         /// <returns>New vector that is the invertion of the original vector</returns>
    205         public static Vector operator -(Vector vector)
    206         {
    207             if ((Object)vector == null)
    208                 return null;
    209             return Vector.Neg(vector);
    210         }
    211         /// <summary>
    212         /// Calculate the multiplication of a vector with a scalar
    213         /// </summary>
    214         /// <param name="vector">Vector to be multiplied</param>
    215         /// <param name="val">Scalar to multiply vector</param>
    216         /// <returns>New vector that is the multiplication of the vector and the scalar</returns>
    217         public static Vector operator *(Vector vector, float val)
    218         {
    219             if ((Object)vector == null)
    220                 return null;
    221             return Vector.Multiply(vector, val);
    222         }
    223         /// <summary>
    224         /// Calculate the multiplication of a vector with a scalar
    225         /// </summary>
    226         /// <param name="val">Scalar to multiply vecto</param>
    227         /// <param name="vector">Vector to be multiplied</param>
    228         /// <returns>New vector that is the multiplication of the vector and the scalar</returns>
    229         public static Vector operator *(float val, Vector vector)
    230         {
    231             if ((Object)vector == null)
    232                 return null;
    233             return Vector.Multiply(vector, val);
    234         }
    235 
    236         #endregion
    237 
    238         #region Constants
    239         /// <summary>
    240         /// Standard (0,0,0) vector
    241         /// </summary>
    242         public static Vector Zero
    243         {
    244             get { return new Vector(0.0f, 0.0f, 0.0f); }
    245         }
    246         /// <summary>
    247         /// Standard (1,0,0) vector
    248         /// </summary>
    249         public static Vector XAxis
    250         {
    251             get { return new Vector(1.0f, 0.0f, 0.0f); }
    252         }
    253         /// <summary>
    254         /// Standard (0,1,0) vector
    255         /// </summary>
    256         public static Vector YAxis
    257         {
    258             get { return new Vector(0.0f, 1.0f, 0.0f); }
    259         }
    260         /// <summary>
    261         /// Standard (0,0,1) vector
    262         /// </summary>
    263         public static Vector ZAxis
    264         {
    265             get { return new Vector(0.0f, 0.0f, 1.0f); }
    266         }
    267         #endregion
    268 
    269         #region Overides
    270         public override bool Equals(object obj)
    271         {
    272             Vector vector = obj as Vector;
    273             if ((Object)vector != null)
    274                 return (m_Xcoord.Equals(vector.X))
    275                     && (m_Ycoord.Equals(vector.Y))
    276                     && (m_Zcoord.Equals(vector.Z));
    277             return false;
    278         }
    279 
    280         public override string ToString()
    281         {
    282             return string.Format(CultureInfo.InvariantCulture, "({0}, {1}, {2})", m_Xcoord, m_Ycoord, m_Zcoord);
    283         }
    284         public override int GetHashCode()
    285         {
    286             return m_Xcoord.GetHashCode() ^ m_Ycoord.GetHashCode() ^ m_Zcoord.GetHashCode();
    287         }
    288         #endregion
    289     }
    View Code

    Particle.cs---粒子属性类

     1     /// <summary>
     2     /// 粒子
     3     /// </summary>
     4     public class Particle
     5     {
     6         /// <summary>
     7         /// 当前粒子所在的位置信息
     8         /// </summary>
     9         private Vector position;
    10         /// <summary>
    11         /// 当前粒子运行的方向和速度
    12         /// </summary>
    13         private Vector velocity;
    14         /// <summary>
    15         /// 当前离子的生命值
    16         /// </summary>
    17         private int life;
    18         /// <summary>
    19         /// 当前离子渲染的颜色
    20         /// </summary>
    21         private Color color;
    22 
    23         public Particle() : this(Vector.Zero, Vector.Zero, Color.Black, 0) { }
    24 
    25         public Particle(Vector position, Vector velocity, Color color, int life)
    26         {
    27             this.position = position;
    28             this.velocity = velocity;
    29             this.color = color;
    30             if (life > 0)
    31             {
    32                 this.life = life;
    33             }
    34         }
    35 
    36         public virtual void Update()
    37         {
    38             // Update particle's movement according to environment
    39             this.velocity = this.velocity - NativeEnvironment.GetInstance().Gravity
    40                                     + NativeEnvironment.GetInstance().Wind;
    41             // Update particle's position according to movement
    42             this.position = this.position + this.velocity;
    43             // Update particle's age
    44             this.life++;
    45         }
    46 
    47         /// <summary>
    48         /// 获取 当前粒子的位置信息
    49         /// </summary>
    50         public Vector Position
    51         {
    52             get { return position; }
    53         }
    54 
    55         /// <summary>
    56         /// 获取 当前粒子的运行方向和速度
    57         /// </summary>
    58         public Vector Velocity
    59         {
    60             get { return velocity; }
    61         }
    62 
    63         /// <summary>
    64         /// 获取 当前粒子的生命值
    65         /// </summary>
    66         public int Life
    67         {
    68             get { return life; }
    69         }
    70 
    71         /// <summary>
    72         /// 获取 当前离子渲染的颜色
    73         /// </summary>
    74         public Color Color
    75         {
    76             get { return color; }
    77         }
    78     }

    2)需要考虑自然环境因素NativeEnvironment,并设定以下两个属性:重力、风速。

    NativeEnvironment.cs--自然环境因素

     1     /// <summary>
     2     /// 自然环境条件信息
     3     /// </summary>
     4     public class NativeEnvironment
     5     {
     6         /// <summary>
     7         /// 重力
     8         /// </summary>
     9         private Vector gravity = Vector.Zero;
    10         /// <summary>
    11         /// 风速
    12         /// </summary>
    13         private Vector wind = Vector.Zero;
    14 
    15         /// <summary>
    16         /// 单例实体对象
    17         /// </summary>
    18         private static NativeEnvironment instance = null;
    19 
    20         private NativeEnvironment() { }
    21 
    22         /// <summary>
    23         /// 获取 自然条件信息对象实例
    24         /// </summary>
    25         public static NativeEnvironment GetInstance()
    26         {
    27             if (instance == null)
    28             {
    29                 instance = new NativeEnvironment();
    30             }
    31             return instance;
    32         }
    33 
    34         /// <summary>
    35         /// 获取或设置 重力
    36         /// </summary>
    37         public Vector Gravity
    38         {
    39             get { return gravity; }
    40             set { gravity = value; }
    41         }
    42 
    43         /// <summary>
    44         /// 获取或设置 风速
    45         /// </summary>
    46         public Vector Wind
    47         {
    48             get { return wind; }
    49             set { wind = value; }
    50         }
    51     }

    3)定义一个喷泉粒子系统.类,它应该包含以下属性:存储当前粒子系统中所有粒子的集合容器、初始化系统时所有粒子的起始位置、最大生命值、粒子渲染的颜色、最大粒子个数,还应该包含以下几个方法:新增粒子,一个生命值单位变化后批量修改所有粒子的方法。

    Particles.cs --- 粒子系统抽象类

     1     /// <summary>
     2     /// 粒子系统
     3     /// </summary>
     4     public abstract class Particles
     5     {
     6         /// <summary>
     7         /// 当前粒子系统内所有的粒子元素存储集合
     8         /// </summary>
     9         protected List<Particle> particles = new List<Particle>();
    10         /// <summary>
    11         /// 粒子系统的中心位置
    12         /// </summary>
    13         protected Vector position;
    14         /// <summary>
    15         /// 默认粒子的最大生命值
    16         /// </summary>
    17         protected int maxLife = 150;
    18         /// <summary>
    19         /// 默认粒子的渲染颜色
    20         /// </summary>
    21         protected Color color;
    22 
    23         /// <summary>
    24         /// 生成(新增)粒子到粒子系统中
    25         /// </summary>
    26         /// <returns></returns>
    27         protected abstract Particle Create();
    28 
    29         /// <summary>
    30         /// 修改粒子系统中所有粒子的状态位置等信息
    31         /// </summary>
    32         /// <returns></returns>
    33         public abstract bool Update();
    34 
    35         public virtual void Draw(Graphics g)
    36         {
    37             Pen pen;
    38             int intense;
    39             Particle part;
    40 
    41             for (int i = 0; i < this.particles.Count; i++)
    42             {
    43                 part = this[i];
    44                 // Calculate particle intensity
    45                 intense = (int)((float)part.Life / this.MaxLife);
    46                 // Generate pen for the particle
    47                 pen = new Pen(Color.FromArgb(intense * this.color.R,
    48                                              intense * this.color.G,
    49                                              intense * this.color.B));
    50                 // Draw particle
    51                 g.DrawEllipse(pen, part.Position.X, part.Position.Y,
    52                     Math.Max(1, 4 * part.Life / this.MaxLife),
    53                     Math.Max(1, 4 * part.Life / this.MaxLife));
    54                 pen.Dispose();
    55             }
    56         }
    57 
    58         /// <summary>
    59         /// 根据index访问系统中某个粒子对象
    60         /// </summary>
    61         /// <param name="index"></param>
    62         /// <returns></returns>
    63         public Particle this[int index]
    64         {
    65             get { return (Particle)this.particles[index]; }
    66         }
    67 
    68         /// <summary>
    69         /// 返回系统中所有粒子个数
    70         /// </summary>
    71         public int Count
    72         {
    73             get { return this.particles.Count; }
    74         }
    75 
    76         /// <summary>
    77         /// 返回系统中粒子最大生命值
    78         /// </summary>
    79         public int MaxLife
    80         {
    81             get { return this.maxLife; }
    82         }
    83 
    84     }

    FountainParticlesSystem.cs---喷泉粒子系统定义

      1     public class FountainParticlesSystem : Particles
      2     {
      3         private static readonly int DEFAULT_NUM_PARTICLES = 500;
      4 
      5         // Random numbers generator
      6         private Random m_rand = new Random();
      7 
      8         /// <summary>
      9         /// Default constructor
     10         /// </summary>
     11         public FountainParticlesSystem()
     12             : this(Vector.Zero, Color.Black)
     13         { }
     14 
     15         /// <summary>
     16         /// Constructor
     17         /// </summary>
     18         /// <param name="pos">Starting position of system</param>
     19         public FountainParticlesSystem(Vector pos)
     20             : this(pos, Color.Black)
     21         { }
     22 
     23         /// <summary>
     24         /// Constructor
     25         /// </summary>
     26         /// <param name="pos">Starting position of system</param>
     27         /// <param name="col">Color of the particles in the system</param>
     28         public FountainParticlesSystem(Vector pos, Color col)
     29         {
     30             // Set system's position at given position
     31             this.position = pos;
     32             // Set system color to given color
     33             this.color = col;
     34             // Create ONLY 5 particles
     35             for (int i = 0; i < 5; i++)
     36             {
     37                 // Create particle, and add it to the list of particles
     38                 this.particles.Add(Create());
     39             }
     40         }
     41 
     42         /// <summary>
     43         /// Generate a single particle in the system.
     44         /// This function is used when particles are first created, and when they are regenerated
     45         /// </summary>
     46         /// <returns>New particle</returns>
     47         protected override Particle Create()
     48         {
     49             // 生成随机方向和速度的新粒子
     50             // 在一个喷泉,粒子移动几乎直
     51             float rndX = 2.0f * ((float)m_rand.NextDouble() - 0.4f);
     52             float rndY = -1.0f - 1 * (float)m_rand.NextDouble();
     53             float rndZ = 1.5f * ((float)m_rand.NextDouble() - 0.4f);
     54 
     55             // Create new particle at system's starting position
     56             Particle part = new Particle(this.position,
     57                 // With generated direction and speed
     58                 new Vector(rndX, rndY, rndZ), this.color,
     59                 // And a random starting life
     60                 m_rand.Next(50));
     61 
     62             // Return newly created particle
     63             return part;
     64         }
     65 
     66         /// <summary>
     67         /// Update all the particles in the system
     68         /// </summary>
     69         /// <returns>False - if there are no more particles in system
     70         /// True - otherwise</returns>
     71         public override bool Update()
     72         {
     73             Particle part;
     74             int count = this.Count;
     75 
     76             // For each particle
     77             for (int i = 0; i < count; i++)
     78             {
     79                 // Get particle from list
     80                 part = (Particle)this.particles[i];
     81                 // Update particle and check age
     82                 part.Update();
     83 
     84                 /*part.Life > this.maxLife && */
     85                 if (part.Position.Y >= this.position.Y)
     86                 {
     87                     // Remove old particles
     88                     this.particles.RemoveAt(i);
     89                     // Update counter and index
     90                     i--;
     91                     count = this.particles.Count;
     92                 }
     93             }
     94 
     95             // If there aren't enough particles
     96             if (this.particles.Count < DEFAULT_NUM_PARTICLES)
     97             {
     98                 // Add another particles
     99                 this.particles.Add(Create());
    100             }
    101 
    102             // Always return true, since system is regenerating
    103             return true;
    104         }
    105     }

    4)设定粒子一个生命值增长需要耗费的时间、一个用来渲染粒子系统当前生命时刻的画布。

     1     public partial class Main : Form
     2     {
     3         private static readonly Vector MIDDLE_OF_VIEW = new Vector(250, 250, 250);
     4         private Particles ps = null;
     5 
     6         public Main()
     7         {
     8             InitializeComponent();
     9 
    10             this.timer.Interval = 20;//ms
    11 
    12             NativeEnvironment.GetInstance().Gravity = new Vector(0.0f, -0.02f, 0.0f);
    13             NativeEnvironment.GetInstance().Wind = new Vector(0.0f, 0.0f, 0.0f);
    14 
    15             if (NativeEnvironment.GetInstance().Gravity == NativeEnvironment.GetInstance().Wind)
    16                 return;
    17         }
    18 
    19         private void btnStart_Click(object sender, EventArgs e)
    20         {
    21             ps = new FountainParticlesSystem(MIDDLE_OF_VIEW, Color.FromArgb(0, 0, 255));
    22             this.timer.Enabled = true;
    23         }
    24 
    25         private void timer_Tick(object sender, System.EventArgs e)
    26         {
    27             if (!ps.Update())
    28             {
    29                 picDisplay.Refresh();
    30                 ps = null;
    31                 this.timer.Enabled = false;
    32             }
    33             else
    34             {
    35                 picDisplay.Refresh();
    36             }
    37         }
    38 
    39         private void picDisplay_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
    40         {
    41             if (ps == null)
    42                 return;
    43             ps.Draw(e.Graphics);
    44         }
    45     }

    效果:

    代码下载位置:http://pan.baidu.com/s/1gfaODF1

  • 相关阅读:
    现代软件工程系列 学生的精彩文章 (5) 其实还是人的问题
    4层结构
    Spring Rich Client Project
    有关“理想”与“现实”的两篇文章
    TechEd归来
    Domain Model
    一次Java出错体验
    真心感谢热心帮助我的朋友
    Tapestry & Groovy
    采用 Domain Model 的架构设计的简单问答
  • 原文地址:https://www.cnblogs.com/yy3b2007com/p/7414311.html
Copyright © 2011-2022 走看看