Jypeli  5
The simple game programming library
ParticleSystem.cs
Siirry tämän tiedoston dokumentaatioon.
1 using System;
2 using System.Collections.Generic;
3 using Microsoft.Xna.Framework;
4 using Microsoft.Xna.Framework.Graphics;
5 
6 namespace Jypeli.Effects
7 {
8  public enum BlendMode
9  {
10  Alpha,
11  Additive
12  }
13 
14 
18  public class ParticleSystem : GameObject
19  {
20  private Random random = new Random();
21 
22  // Lista efektin partikkeleille
23  private LinkedList<Particle> particles;
24 
25  // Jono efektin vapaille partikkeleille
26  private Queue<Particle> freeParticles;
27 
31  public Image ParticleImage { get; set; }
32 
36  public Image OuterParticleImage { get; set; }
37 
41  #region Subclass variables
42 
46  public double MinScale { get; set; }
50  public double MaxScale { get; set; }
51 
55  public double ScaleAmount { get; set; }
56 
60  public double MinVelocity { get; set; }
64  public double MaxVelocity { get; set; }
65 
69  public double MinLifetime { get; set; }
70 
74  public double MaxLifetime { get; set; }
75 
79  public double MinAcceleration { get; set; }
80 
84  public double MaxAcceleration { get; set; }
85 
89  public double MinRotationSpeed { get; set; }
90 
94  public double MaxRotationSpeed { get; set; }
95 
99  public double MinRotation { get; set; }
100 
104  public double MaxRotation { get; set; }
105 
109  public double AlphaAmount { get; set; }
110 
111  #endregion
112 
113  public BlendMode BlendMode { get; set; }
114 
118  public Boolean IgnoreWind { get; set; }
119 
120  private Boolean visible = true;
121  private Boolean fadeIn = false;
122  private Boolean fadeOut = false;
123  private double originalAlpha = 1.0;
124  private double fadeTime = 0.0;
125  private double fadeTimePassed = 0.0;
126 
131  public void FadeIn(double timeInSeconds)
132  {
133  if (!visible)
134  {
135  fadeTimePassed = 0.0;
136  fadeIn = true;
137  fadeTime = timeInSeconds;
138  }
139  }
140 
145  public void FadeOut(double TimeInSeconds)
146  {
147  if (visible)
148  {
149  originalAlpha = AlphaAmount;
150  fadeTimePassed = 0.0;
151  fadeOut = true;
152  fadeTime = TimeInSeconds;
153  }
154  }
160  public ParticleSystem(Image particleImage, int maxAmountOfParticles)
161  : base(0, 0)
162  {
163  this.ParticleImage = particleImage;
164  AlphaAmount = 1.0;
165  IgnoreWind = false;
166  BlendMode = BlendMode.Alpha;
167 
168  IsUpdated = true;
169  InitializeParticles();
170 
171  particles = new LinkedList<Particle>();
172  freeParticles = new Queue<Particle>(maxAmountOfParticles);
173  for (int i = 0; i < maxAmountOfParticles; i++)
174  {
175  freeParticles.Enqueue(new Particle());
176  }
177  }
178 
183  protected virtual void InitializeParticles()
184  {
185  }
186 
193  public void AddEffect(double x, double y, int numberOfParticles)
194  {
195  AddEffect(new Vector(x, y), numberOfParticles);
196  }
197 
198  public void AddEffect(Vector position, Angle angle, int numberOfParticles)
199  {
200  for (int i = 0; i < numberOfParticles && freeParticles.Count > 0; i++)
201  {
202  Particle p = freeParticles.Dequeue();
203  particles.AddLast(p);
204  InitializeParticle(p, position, angle);
205  }
206  }
207 
213  public void AddEffect(Vector position, int numberOfParticles)
214  {
215  for (int i = 0; i < numberOfParticles && freeParticles.Count > 0; i++)
216  {
217  Particle p = freeParticles.Dequeue();
218  particles.AddLast(p);
219  InitializeParticle(p, position);
220  }
221  }
222 
227  protected virtual Vector GiveRandomDirection()
228  {
229  double angle = random.NextDouble() * MathHelper.TwoPi;
230  return new Vector(Math.Cos(angle), Math.Sin(angle));
231  }
232 
238  protected virtual void InitializeParticle(Particle p, Vector position)
239  {
240  Vector direction = GiveRandomDirection();
241 
242  double scale = RandomGen.NextDouble(MinScale, MaxScale);
243  double rotation = RandomGen.NextDouble(MinRotation, MaxRotation);
244  double velocity = RandomGen.NextDouble(MinVelocity, MaxVelocity);
245  double lifetime = RandomGen.NextDouble(MinLifetime, MaxLifetime);
246  double acceleration = RandomGen.NextDouble(MinAcceleration, MaxAcceleration);
247  double rotationSpeed = RandomGen.NextDouble(MinRotationSpeed, MaxRotationSpeed);
248 
249  p.Initialize(position, scale, rotation, rotationSpeed, velocity * direction, acceleration * direction, lifetime);
250  }
251 
252  protected virtual void InitializeParticle(Particle p, Vector position, Angle angle)
253  {
254  Vector direction = GiveRandomDirection();
255 
256  double rotation = angle.Degrees;
257  double scale = RandomGen.NextDouble(MinScale, MaxScale);
258  double velocity = RandomGen.NextDouble(MinVelocity, MaxVelocity);
259  double lifetime = RandomGen.NextDouble(MinLifetime, MaxLifetime);
260  double acceleration = RandomGen.NextDouble(MinAcceleration, MaxAcceleration);
261  double rotationSpeed = RandomGen.NextDouble(MinRotationSpeed, MaxRotationSpeed);
262 
263  p.Initialize(position, scale, rotation, rotationSpeed, velocity * direction, acceleration * direction, lifetime);
264  }
265 
270  public override void Update(Time time)
271  {
272  double t = time.SinceLastUpdate.TotalSeconds;
273 
274  LinkedListNode<Particle> node = particles.First;
275  while (node != null)
276  {
277  Particle p = node.Value;
278  if (p.Alive)
279  {
280  p.Update(t);
281  node = node.Next;
282  }
283  else
284  {
285  freeParticles.Enqueue(p);
286  LinkedListNode<Particle> previous = node;
287  node = node.Next;
288  particles.Remove(previous);
289  }
290  }
291  if (fadeOut)
292  {
293  AlphaAmount = Math.Min(1 - fadeTimePassed / fadeTime, originalAlpha);
294  fadeTimePassed += t;
295  if (fadeTime <= fadeTimePassed)
296  {
297  AlphaAmount = 0.0;
298  fadeOut = false;
299  visible = false;
300  }
301  }
302  if (fadeIn)
303  {
304  AlphaAmount = Math.Min(fadeTimePassed / fadeTime, originalAlpha);
305  fadeTimePassed += t;
306  if (fadeTime <= fadeTimePassed)
307  {
308  AlphaAmount = originalAlpha;
309  fadeIn = false;
310  visible = true;
311  }
312  }
313 
314  base.Update(time);
315  }
316 
317 
318  static readonly Vector2 textureTopLeft = new Vector2(0.0f, 0.0f);
319  static readonly Vector2 textureBottomLeft = new Vector2(0.0f, 1.0f);
320  static readonly Vector2 textureTopRight = new Vector2(1.0f, 0.0f);
321  static readonly Vector2 textureBottomRight = new Vector2(1.0f, 1.0f);
322 
323  static readonly Vector3 topLeft = new Vector3(-0.5f, 0.5f, 0);
324  static readonly Vector3 bottomLeft = new Vector3(-0.5f, -0.5f, 0);
325  static readonly Vector3 topRight = new Vector3(0.5f, 0.5f, 0);
326  static readonly Vector3 bottomRight = new Vector3(0.5f, -0.5f, 0);
327 
328  static readonly VertexPositionTexture[] vertices =
329  {
330  // Triangle 1
331  new VertexPositionTexture(topLeft, textureTopLeft),
332  new VertexPositionTexture(bottomLeft, textureBottomLeft),
333  new VertexPositionTexture(topRight, textureTopRight),
334 
335  // Triangle 2
336  new VertexPositionTexture(bottomLeft, textureBottomLeft),
337  new VertexPositionTexture(bottomRight, textureBottomRight),
338  new VertexPositionTexture(topRight, textureTopRight),
339  };
340 
341  private static BlendState ToXnaBlendState(BlendMode mode)
342  {
343  switch (mode)
344  {
345  case BlendMode.Alpha:
346  return BlendState.AlphaBlend;
347  case BlendMode.Additive:
348  return BlendState.Additive;
349  default:
350  return BlendState.AlphaBlend;
351  }
352  }
353 
354  internal void Draw(Matrix worldMatrix)
355  {
356  var device = Game.GraphicsDevice;
357  var effect = Graphics.BasicTextureEffect;
358 
359  Texture2D texture = ParticleImage.XNATexture;
360 
361  device.RasterizerState = RasterizerState.CullClockwise;
362  device.SamplerStates[0] = SamplerState.LinearClamp;
363  device.BlendState = ToXnaBlendState(BlendMode);
364 
365  effect.Texture = texture;
366  effect.CurrentTechnique.Passes[0].Apply();
367 
368  if (OuterParticleImage == null)
369  {
370  foreach (Particle p in particles)
371  {
372  double nTime = p.Lifetime.TotalMilliseconds / p.MaxLifetime.TotalMilliseconds;
373  double alpha = 4 * nTime * (1 - nTime) * AlphaAmount;
374  float scale = (float)(p.Scale * (.75f + .25f * nTime * ScaleAmount));
375 
376  Matrix matrix =
377  Matrix.CreateScale(scale * texture.Width / texture.Height, scale, 1f)
378  * Matrix.CreateRotationZ((float)p.Rotation)
379  * Matrix.CreateTranslation((float)p.Position.X, (float)p.Position.Y, 0f)
380  * worldMatrix
381  ;
382 
383  effect.Alpha = (float)alpha;
384  effect.World = matrix;
385  effect.CurrentTechnique.Passes[0].Apply();
386 
387  device.DrawUserPrimitives<VertexPositionTexture>(PrimitiveType.TriangleList, vertices, 0, 2);
388  }
389  }
390  else
391  {
392  Texture2D outerTexture = OuterParticleImage.XNATexture;
393 
394  foreach (Particle p in particles)
395  {
396  double nTime = p.Lifetime.TotalMilliseconds / p.MaxLifetime.TotalMilliseconds;
397  double alpha = 4 * nTime * (1 - nTime) * AlphaAmount;
398  float scale = (float)(p.Scale * (.75f + .25f * nTime * ScaleAmount));
399 
400  Matrix matrix =
401  Matrix.CreateScale(scale, scale, 1f)
402  * Matrix.CreateRotationZ((float)p.Rotation)
403  * Matrix.CreateTranslation((float)p.Position.X, (float)p.Position.Y, 0f)
404  * worldMatrix
405  ;
406  Matrix matrix2 =
407  Matrix.CreateScale(0.65f, 0.65f, 1f)
408  * matrix;
409 
410  effect.Texture = texture;
411  effect.Alpha = (float)alpha;
412  effect.World = matrix;
413  effect.CurrentTechnique.Passes[0].Apply();
414 
415  device.DrawUserPrimitives<VertexPositionTexture>(PrimitiveType.TriangleList, vertices, 0, 2);
416 
417  effect.Texture = outerTexture;
418  effect.World = matrix2;
419  effect.CurrentTechnique.Passes[0].Apply();
420 
421  device.DrawUserPrimitives<VertexPositionTexture>(PrimitiveType.TriangleList, vertices, 0, 2);
422  }
423  }
424  }
425  }
426 }
double Rotation
Partikkelin kierto
Definition: Particle.cs:44
Vector Position
Partikkelin sijainti
Definition: Particle.cs:26
Järjestelmä partikkelien käsittelyyn
TimeSpan MaxLifetime
Partikkelin elinikä
Definition: Particle.cs:88
Suuntakulma (rajoitettu -180 ja 180 asteen välille) asteina ja radiaaneina. Tietoja kulmasta: http://...
Definition: Angle.cs:40
virtual void InitializeParticle(Particle p, Vector position)
Alustaa yhden partikkelin
Satunnaisgeneraattori. Luo satunnaisia arvoja, mm. lukuja, vektoreita sekä kulmia.
Definition: RandomGen.cs:39
static double NextDouble(double min, double max)
Palauttaa satunnaisen liukuluvun parametrien
Definition: RandomGen.cs:78
void Update(double time)
Päivittää partikkelin sijannin, nopeuden ja kierron
Definition: Particle.cs:132
virtual void InitializeParticle(Particle p, Vector position, Angle angle)
TimeSpan SinceLastUpdate
Aika joka on kulunut viime päivityksestä.
Definition: Time.cs:24
void AddEffect(double x, double y, int numberOfParticles)
Lisää efektin kentälle
Sisältää tiedon ajasta, joka on kulunut pelin alusta ja viime päivityksestä.
Definition: Time.cs:13
void FadeOut(double TimeInSeconds)
Efekti hiipuu näkyvistä tietyn sekuntimäärän aikana
Kuva.
Definition: Image.cs:24
virtual void InitializeParticles()
Metodi joka asettaa partikkeleille attribuutit Täytyy kutsua perityistä luokista
double Y
Definition: Vector.cs:275
Peliluokka reaaliaikaisille peleille.
Definition: DebugScreen.cs:10
double Degrees
Palauttaa tai asettaa kulman asteina.
Definition: Angle.cs:70
override void Update(Time time)
Kutsutaan kun luokka päivitetään
virtual Vector GiveRandomDirection()
Antaa satunnaisen suunnan
double X
Definition: Vector.cs:274
void AddEffect(Vector position, int numberOfParticles)
Lisää efektin kentälle
ParticleSystem(Image particleImage, int maxAmountOfParticles)
Muodostaja
static new GraphicsDevice GraphicsDevice
Definition: Game.cs:368
bool Alive
Onko partikkelin "elossa", eli päivitetäänkö ja piirretäänkö se
Definition: Particle.cs:80
double Scale
Partikkelin skaalaus
Definition: Particle.cs:35
void AddEffect(Vector position, Angle angle, int numberOfParticles)
void Initialize(Vector position, double scale, double rotation, double rotationSpeed, Vector velocity, Vector acceleration, double lifetime)
Alusta partikkeli
Definition: Particle.cs:113
2D-vektori.
Definition: Vector.cs:56
TimeSpan Lifetime
Partikkelin tämän hetkinen ikä
Definition: Particle.cs:97
Pelialueella liikkuva olio. Käytä fysiikkapeleissä PhysicsObject-olioita.
Definition: __GameObject.cs:54
void FadeIn(double timeInSeconds)
Efekti tulee näkyviin tietyn sekuntimäärän aikana