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

  • 相关阅读:
    UVa 10118 记忆化搜索 Free Candies
    CodeForces 568B DP Symmetric and Transitive
    UVa 11695 树的直径 Flight Planning
    UVa 10934 DP Dropping water balloons
    CodeForces 543D 树形DP Road Improvement
    CodeForces 570E DP Pig and Palindromes
    HDU 5396 区间DP 数学 Expression
    HDU 5402 模拟 构造 Travelling Salesman Problem
    HDU 5399 数学 Too Simple
    CodeForces 567F DP Mausoleum
  • 原文地址:https://www.cnblogs.com/yy3b2007com/p/7414311.html
Copyright © 2011-2022 走看看