Client LuaCsForBarotrauma
ParticleManager.cs
1 using Microsoft.Xna.Framework;
2 using Microsoft.Xna.Framework.Graphics;
3 using System;
4 using System.Collections.Generic;
5 using System.Linq;
6 
7 namespace Barotrauma.Particles
8 {
10  {
11  AlphaBlend, Additive//, Distortion
12  }
13 
15  {
16  private const int MaxOutOfViewDist = 500;
17 
18  private int particleCount;
19  public int ParticleCount
20  {
21  get { return particleCount; }
22  }
23 
24  private int maxParticles;
25  public int MaxParticles
26  {
27  get { return maxParticles; }
28  set
29  {
30  if (maxParticles == value || value < 4) { return; }
31 
32  Particle[] newParticles = new Particle[value];
33  for (int i = 0; i < Math.Min(maxParticles, value); i++)
34  {
35  newParticles[i] = particles[i];
36  }
37 
38  particleCount = Math.Min(particleCount, value);
39  particles = newParticles;
40  maxParticles = value;
41 
42  var oldParticlesInCreationOrder = particlesInCreationOrder.ToList();
43  particlesInCreationOrder.Clear();
44  foreach (var particle in oldParticlesInCreationOrder)
45  {
46  if (particles.Contains(particle))
47  {
48  particlesInCreationOrder.AddLast(particle);
49  }
50  }
51  }
52  }
53  private Particle[] particles;
54 
60  private readonly LinkedList<Particle> particlesInCreationOrder = new LinkedList<Particle>();
61 
62  private Camera cam;
63 
64  public Camera Camera
65  {
66  get { return cam; }
67  set { cam = value; }
68  }
69 
70  public ParticleManager(Camera cam)
71  {
72  this.cam = cam;
73 
74  MaxParticles = GameSettings.CurrentConfig.Graphics.ParticleLimit;
75  }
76 
77  public Particle CreateParticle(string prefabName, Vector2 position, float angle, float speed, Hull hullGuess = null, float collisionIgnoreTimer = 0f, Tuple<Vector2, Vector2> tracerPoints = null)
78  {
79  return CreateParticle(prefabName, position, new Vector2((float)Math.Cos(angle), (float)-Math.Sin(angle)) * speed, angle, hullGuess, collisionIgnoreTimer, tracerPoints: tracerPoints);
80  }
81 
82  public Particle CreateParticle(string prefabName, Vector2 position, Vector2 velocity, float rotation = 0.0f, Hull hullGuess = null, float collisionIgnoreTimer = 0f, Tuple<Vector2, Vector2> tracerPoints = null)
83  {
84  ParticlePrefab prefab = FindPrefab(prefabName);
85 
86  if (prefab == null)
87  {
88  DebugConsole.ThrowError("Particle prefab \"" + prefabName + "\" not found!");
89  return null;
90  }
91  return CreateParticle(prefab, position, velocity, rotation, hullGuess, collisionIgnoreTimer: collisionIgnoreTimer, tracerPoints:tracerPoints);
92  }
93 
94  public Particle CreateParticle(ParticlePrefab prefab, Vector2 position, Vector2 velocity, float rotation = 0.0f, Hull hullGuess = null, bool drawOnTop = false, float collisionIgnoreTimer = 0f, float lifeTimeMultiplier = 1f, Tuple<Vector2, Vector2> tracerPoints = null)
95  {
96  if (prefab == null || prefab.Sprites.Count == 0) { return null; }
97  if (particleCount >= MaxParticles)
98  {
99  for (int i = 0; i < particleCount; i++)
100  {
101  if (particles[i].Prefab.Priority < prefab.Priority ||
102  (!particles[i].Prefab.DrawAlways && prefab.DrawAlways))
103  {
104  RemoveParticle(i);
105  break;
106  }
107  }
108  if (particleCount >= MaxParticles) { return null; }
109  }
110 
111  Vector2 particleEndPos = prefab.CalculateEndPosition(position, velocity);
112 
113  Vector2 minPos = new Vector2(Math.Min(position.X, particleEndPos.X), Math.Min(position.Y, particleEndPos.Y));
114  Vector2 maxPos = new Vector2(Math.Max(position.X, particleEndPos.X), Math.Max(position.Y, particleEndPos.Y));
115 
116  if (tracerPoints != null)
117  {
118  minPos = new Vector2(
119  Math.Min(Math.Min(minPos.X, tracerPoints.Item1.X), tracerPoints.Item2.X),
120  Math.Min(Math.Min(minPos.Y, tracerPoints.Item1.Y), tracerPoints.Item2.Y));
121  maxPos = new Vector2(
122  Math.Max(Math.Max(maxPos.X, tracerPoints.Item1.X), tracerPoints.Item2.X),
123  Math.Max(Math.Max(maxPos.Y, tracerPoints.Item1.Y), tracerPoints.Item2.Y));
124  }
125 
126  Rectangle expandedViewRect = MathUtils.ExpandRect(cam.WorldView, MaxOutOfViewDist);
127 
128  if (!prefab.DrawAlways)
129  {
130  if (minPos.X > expandedViewRect.Right || maxPos.X < expandedViewRect.X) { return null; }
131  if (minPos.Y > expandedViewRect.Y || maxPos.Y < expandedViewRect.Y - expandedViewRect.Height) { return null; }
132  }
133 
134  if (particles[particleCount] == null) { particles[particleCount] = new Particle(); }
135  Particle particle = particles[particleCount];
136 
137  particle.Init(prefab, position, velocity, rotation, hullGuess, drawOnTop, collisionIgnoreTimer, lifeTimeMultiplier, tracerPoints: tracerPoints);
138  particleCount++;
139  particlesInCreationOrder.AddFirst(particle);
140 
141  return particle;
142  }
143 
144  public static List<ParticlePrefab> GetPrefabList()
145  {
146  return ParticlePrefab.Prefabs.ToList();
147  }
148 
149  public static ParticlePrefab FindPrefab(string prefabName)
150  {
151  ParticlePrefab.Prefabs.TryGet(prefabName, out ParticlePrefab prefab);
152  return prefab;
153  }
154 
155  private void RemoveParticle(int index)
156  {
157  particlesInCreationOrder.Remove(particles[index]);
158  particleCount--;
159 
160  (particles[particleCount], particles[index]) = (particles[index], particles[particleCount]);
161  }
162 
163 
164  public void RemoveParticle(Particle particle)
165  {
166  for (int i = 0; i < particleCount; i++)
167  {
168  if (particles[i] == particle)
169  {
170  RemoveParticle(i);
171  return;
172  }
173  }
174  }
175 
176  public void Update(float deltaTime)
177  {
178  MaxParticles = GameSettings.CurrentConfig.Graphics.ParticleLimit;
179 
180  for (int i = 0; i < particleCount; i++)
181  {
182  bool remove;
183  try
184  {
185  remove = particles[i].Update(deltaTime) == Particle.UpdateResult.Delete;
186  }
187  catch (Exception e)
188  {
189  DebugConsole.ThrowError("Particle update failed", e);
190  remove = true;
191  }
192 
193  if (remove) { RemoveParticle(i); }
194  }
195  }
196 
197  public void UpdateTransforms()
198  {
199  for (int i = 0; i < particleCount; i++)
200  {
201  particles[i].UpdateDrawPos();
202  }
203  }
204 
205  public Dictionary<ParticlePrefab, int> CountActiveParticles()
206  {
207  Dictionary<ParticlePrefab, int> activeParticles = new Dictionary<ParticlePrefab, int>();
208  for (int i = 0; i < particleCount; i++)
209  {
210  if (!activeParticles.ContainsKey(particles[i].Prefab)) activeParticles[particles[i].Prefab] = 0;
211  activeParticles[particles[i].Prefab]++;
212  }
213  return activeParticles;
214  }
215 
216  public void Draw(SpriteBatch spriteBatch, bool inWater, bool? inSub, ParticleBlendState blendState)
217  {
219 
220  foreach (var particle in particlesInCreationOrder)
221  {
222  if (particle.BlendState != blendState) { continue; }
223  //equivalent to !particles[i].DrawTarget.HasFlag(drawTarget) but garbage free and faster
224  if ((particle.DrawTarget & drawTarget) == 0) { continue; }
225  if (inSub.HasValue)
226  {
227  bool isOutside = particle.CurrentHull == null;
228  if (!particle.DrawOnTop && isOutside == inSub.Value)
229  {
230  continue;
231  }
232  }
233 
234  particle.Draw(spriteBatch);
235  }
236  }
237 
238  public void ClearParticles()
239  {
240  particleCount = 0;
241  particlesInCreationOrder.Clear();
242  }
243 
244  public void RemoveByPrefab(ParticlePrefab prefab)
245  {
246  if (particles == null) { return; }
247  for (int i = particles.Length - 1; i >= 0; i--)
248  {
249  if (particles[i]?.Prefab == prefab)
250  {
251  if (i < particleCount) { particleCount--; }
252 
253  particlesInCreationOrder.Remove(particles[particleCount]);
254  Particle swap = particles[particleCount];
255  particles[particleCount] = null;
256  particles[i] = swap;
257  }
258  }
259  }
260 
261  }
262 }
Rectangle WorldView
Definition: Camera.cs:123
UpdateResult Update(float deltaTime)
Definition: Particle.cs:219
void Init(ParticlePrefab prefab, Vector2 position, Vector2 speed, float rotation, Hull hullGuess=null, bool drawOnTop=false, float collisionIgnoreTimer=0f, float lifeTimeMultiplier=1f, Tuple< Vector2, Vector2 > tracerPoints=null)
Definition: Particle.cs:113
Particle CreateParticle(string prefabName, Vector2 position, float angle, float speed, Hull hullGuess=null, float collisionIgnoreTimer=0f, Tuple< Vector2, Vector2 > tracerPoints=null)
void RemoveByPrefab(ParticlePrefab prefab)
Dictionary< ParticlePrefab, int > CountActiveParticles()
void RemoveParticle(Particle particle)
static List< ParticlePrefab > GetPrefabList()
Particle CreateParticle(ParticlePrefab prefab, Vector2 position, Vector2 velocity, float rotation=0.0f, Hull hullGuess=null, bool drawOnTop=false, float collisionIgnoreTimer=0f, float lifeTimeMultiplier=1f, Tuple< Vector2, Vector2 > tracerPoints=null)
Particle CreateParticle(string prefabName, Vector2 position, Vector2 velocity, float rotation=0.0f, Hull hullGuess=null, float collisionIgnoreTimer=0f, Tuple< Vector2, Vector2 > tracerPoints=null)
void Draw(SpriteBatch spriteBatch, bool inWater, bool? inSub, ParticleBlendState blendState)
static ParticlePrefab FindPrefab(string prefabName)
static readonly PrefabCollection< ParticlePrefab > Prefabs
readonly List< Sprite > Sprites
Vector2 CalculateEndPosition(Vector2 startPosition, Vector2 velocity)