Client LuaCsForBarotrauma
ParticlePrefab.cs
1 using FarseerPhysics;
2 using Microsoft.Xna.Framework;
3 using System;
4 using System.Collections.Generic;
5 using System.Xml.Linq;
6 
7 namespace Barotrauma.Particles
8 {
10  {
12 
13  public enum DrawTargetType { Air = 1, Water = 2, Both = 3 }
14 
15  public readonly List<Sprite> Sprites;
16 
17  public override void Dispose()
18  {
19  GameMain.ParticleManager?.RemoveByPrefab(this);
20  foreach (Sprite spr in Sprites)
21  {
22  spr.Remove();
23  }
24  Sprites.Clear();
25  }
26 
27  public string Name => Identifier.Value;
28 
29  [Editable(0.0f, float.MaxValue), Serialize(5.0f, IsPropertySaveable.No, description: "How many seconds the particle remains alive.")]
30  public float LifeTime { get; private set; }
31 
32  [Editable(0.0f, float.MaxValue), Serialize(0.0f, IsPropertySaveable.No, description: "Will randomize lifetime value between lifetime and lifetimeMin. If left to 0 will use only lifetime value.")]
33  public float LifeTimeMin { get; private set; }
34 
35 
36  [Editable, Serialize(0.0f, IsPropertySaveable.No, description: "How long it takes for the particle to appear after spawning it.")]
37  public float StartDelayMin { get; private set; }
38  [Editable, Serialize(0.0f, IsPropertySaveable.No, description: "How long it takes for the particle to appear after spawning it.")]
39  public float StartDelayMax { get; private set; }
40  //movement -----------------------------------------
41 
42  private float angularVelocityMin;
43  public float AngularVelocityMinRad { get; private set; }
44 
46  public float AngularVelocityMin
47  {
48  get { return angularVelocityMin; }
49  private set
50  {
51  angularVelocityMin = value;
52  AngularVelocityMinRad = MathHelper.ToRadians(value);
53  }
54  }
55 
56  private float angularVelocityMax;
57  public float AngularVelocityMaxRad { get; private set; }
58 
60  public float AngularVelocityMax
61  {
62  get { return angularVelocityMax; }
63  private set
64  {
65  angularVelocityMax = value;
66  AngularVelocityMaxRad = MathHelper.ToRadians(value);
67  }
68  }
69 
70  private float startRotationMin;
71  public float StartRotationMinRad { get; private set; }
72 
73  [Editable, Serialize(0.0f, IsPropertySaveable.No, description: "The minimum initial rotation of the particle (in degrees).")]
74  public float StartRotationMin
75  {
76  get { return startRotationMin; }
77  private set
78  {
79  startRotationMin = value;
80  StartRotationMinRad = MathHelper.ToRadians(value);
81  }
82  }
83 
84  private float startRotationMax;
85  public float StartRotationMaxRad { get; private set; }
86 
87  [Editable, Serialize(0.0f, IsPropertySaveable.No, description: "The maximum initial rotation of the particle (in degrees).")]
88  public float StartRotationMax
89  {
90  get { return startRotationMax; }
91  private set
92  {
93  startRotationMax = value;
94  StartRotationMaxRad = MathHelper.ToRadians(value);
95  }
96  }
97 
98  [Editable, Serialize(false, IsPropertySaveable.No, description: "Should the particle face the direction it's moving towards.")]
99  public bool RotateToDirection { get; private set; }
100 
101  [Editable(0.0f, float.MaxValue, DecimalCount = 3), Serialize(0.0f, IsPropertySaveable.No, description: "Drag applied to the particle when it's moving through air.")]
102  public float Drag { get; private set; }
103 
104  [Editable(0.0f, float.MaxValue, DecimalCount = 3), Serialize(0.0f, IsPropertySaveable.No, description: "Drag applied to the particle when it's moving through water.")]
105  public float WaterDrag { get; private set; }
106 
107  private Vector2 velocityChange;
108  public Vector2 VelocityChangeDisplay { get; private set; }
109 
110  [Editable, Serialize("0.0,0.0", IsPropertySaveable.No, description: "How much the velocity of the particle changes per second.")]
111  public Vector2 VelocityChange
112  {
113  get { return velocityChange; }
114  private set
115  {
116  velocityChange = value;
117  VelocityChangeDisplay = ConvertUnits.ToDisplayUnits(value);
118  }
119  }
120 
121  private Vector2 velocityChangeWater;
122  public Vector2 VelocityChangeWaterDisplay { get; private set; }
123 
124  [Editable, Serialize("0.0,0.0", IsPropertySaveable.No, description: "How much the velocity of the particle changes per second when in water.")]
125  public Vector2 VelocityChangeWater
126  {
127  get { return velocityChangeWater; }
128  private set
129  {
130  velocityChangeWater = value;
131  VelocityChangeWaterDisplay = ConvertUnits.ToDisplayUnits(value);
132  }
133  }
134 
135  [Editable, Serialize(true, IsPropertySaveable.No, description: "Is the particle considered to be inside a submarine if it spawns at a position inside a hull (causing it to move with the sub)?")]
136  public bool CanEnterSubs { get; private set; }
137 
138  [Editable(0.0f, 10000.0f), Serialize(0.0f, IsPropertySaveable.No, description: "Radius of the particle's collider. Only has an effect if UseCollision is set to true.")]
139  public float CollisionRadius { get; private set; }
140 
141  [Editable, Serialize(false, IsPropertySaveable.No, description: "If enabled, the size (or changes in size) of the particle doesn't affect the size of the collider.")]
142  public bool InvariantCollisionSize { get; private set; }
143 
144  [Editable, Serialize(false, IsPropertySaveable.No, description: "Does the particle collide with the walls of the submarine and the level.")]
145  public bool UseCollision { get; private set; }
146 
147  [Editable, Serialize(false, IsPropertySaveable.No, description: "Does the particle disappear when it collides with something.")]
148  public bool DeleteOnCollision { get; private set; }
149 
150  [Editable(0.0f, 1.0f), Serialize(0.5f, IsPropertySaveable.No, description: "The friction coefficient of the particle, i.e. how much it slows down when it's sliding against a surface.")]
151  public float Friction { get; private set; }
152 
153  [Editable(0.0f, 1.0f)]
154  [Serialize(0.5f, IsPropertySaveable.No, description: "How much of the particle's velocity is conserved when it collides with something, i.e. the \"bounciness\" of the particle. (0.0 = the particle stops completely).")]
155  public float Restitution { get; private set; }
156 
157  //size -----------------------------------------
158 
159  [Editable(DecimalCount = 3), Serialize("1.0,1.0", IsPropertySaveable.No, description: "The minimum initial size of the particle.")]
160  public Vector2 StartSizeMin { get; private set; }
161 
162  [Editable(DecimalCount = 3), Serialize("1.0,1.0", IsPropertySaveable.No, description: "The maximum initial size of the particle.")]
163  public Vector2 StartSizeMax { get; private set; }
164 
165  [Editable, Serialize("0.0,0.0", IsPropertySaveable.No, description: "How much the size of the particle changes per second. The rate of growth for each particle is randomize between SizeChangeMin and SizeChangeMax.")]
166  public Vector2 SizeChangeMin { get; private set; }
167 
168  [Editable, Serialize("0.0,0.0", IsPropertySaveable.No, description: "How much the size of the particle changes per second. The rate of growth for each particle is randomize between SizeChangeMin and SizeChangeMax.")]
169  public Vector2 SizeChangeMax { get; private set; }
170 
171  [Editable(minValue: 0, maxValue: float.MaxValue, decimals: 2), Serialize(0.0f, IsPropertySaveable.No, description: "How many seconds it takes for the particle to grow to it's initial size.")]
172  public float GrowTime { get; private set; }
173 
174  //rendering -----------------------------------------
175 
176  [Editable, Serialize("1.0,1.0,1.0,1.0", IsPropertySaveable.No, description: "The initial color of the particle.")]
177  public Color StartColor { get; private set; }
178 
179  [Editable, Serialize("1.0,1.0,1.0,1.0", IsPropertySaveable.No, description: "The initial color of the particle.")]
180  public Color MiddleColor { get; private set; }
181 
182  [Editable, Serialize("1.0,1.0,1.0,1.0", IsPropertySaveable.No, description: "The color of the particle at the end of its lifetime.")]
183  public Color EndColor { get; private set; }
184 
185  [Editable, Serialize(false, IsPropertySaveable.No, description: "If true the color will go from StartColor to EndcColor and back to StartColor.")]
186  public bool UseMiddleColor { get; private set; }
187 
188  [Editable, Serialize(DrawTargetType.Air, IsPropertySaveable.No, description: "Should the particle be rendered in air, water or both.")]
189  public DrawTargetType DrawTarget { get; private set; }
190 
191  [Editable, Serialize(ParticleDrawOrder.Default, IsPropertySaveable.No, description: "Should the particle be always forced to render on top of entities or behind everything?")]
192  public ParticleDrawOrder DrawOrder { get; private set; }
193 
194  [Editable, Serialize(false, IsPropertySaveable.No, description: "Draw the particle even when it's calculated to be outside of view (the formula doesn't take scales into account). ")]
195  public bool DrawAlways { get; private set; }
196 
197  [Editable, Serialize(ParticleBlendState.AlphaBlend, IsPropertySaveable.No, description: "The type of blending to use when rendering the particle.")]
198  public ParticleBlendState BlendState { get; private set; }
199 
200  [Editable, Serialize(0, IsPropertySaveable.No, description: "Particles with a higher priority can replace lower-priority ones if the maximum number of active particles has been reached.")]
201  public int Priority { get; private set; }
202 
203  //animation -----------------------------------------
204 
205  [Editable(0.0f, float.MaxValue), Serialize(1.0f, IsPropertySaveable.No, description: "The duration of the particle's animation cycle (if it's animated).")]
206  public float AnimDuration { get; private set; }
207 
208  [Editable, Serialize(true, IsPropertySaveable.No, description: "Should the sprite animation be looped, or stay at the last frame when the animation finishes.")]
209  public bool LoopAnim { get; private set; }
210 
211  //----------------------------------------------------
212 
213  public readonly List<ParticleEmitterPrefab> SubEmitters = new List<ParticleEmitterPrefab>();
214 
215  public Dictionary<Identifier, SerializableProperty> SerializableProperties
216  {
217  get;
218  private set;
219  }
220 
221  //----------------------------------------------------
222 
223  public ParticlePrefab(ContentXElement element, ContentFile file) : base(file, element.NameAsIdentifier())
224  {
225  Sprites = new List<Sprite>();
226 
228 
229  //backwards compatibility
230  if (element.GetAttributeBool("drawontop", false))
231  {
232  DrawOrder = ParticleDrawOrder.Foreground;
233  }
234  if (BlendState == ParticleBlendState.Additive && DrawOrder == ParticleDrawOrder.Background)
235  {
236  DebugConsole.AddWarning($"Error in particle prefab {Identifier}: additive particles cannot be rendered in the background.");
237  }
238 
239  foreach (var subElement in element.Elements())
240  {
241  switch (subElement.Name.ToString().ToLowerInvariant())
242  {
243  case "sprite":
244  Sprites.Add(new Sprite(subElement));
245  break;
246  case "spritesheet":
247  case "animatedsprite":
248  Sprites.Add(new SpriteSheet(subElement));
249  break;
250  case "particleemitter":
251  case "emitter":
252  case "subemitter":
253  SubEmitters.Add(new ParticleEmitterPrefab(subElement));
254  break;
255  }
256  }
257 
258  if (Sprites.Count == 0)
259  {
260  DebugConsole.ThrowError($"Particle prefab \"{Name}\" in the file \"{file}\" has no sprites defined!",
261  contentPackage: element.ContentPackage);
262  }
263 
264  //if velocity change in water is not given, it defaults to the normal velocity change
265  if (element.GetAttribute("velocitychangewater") == null)
266  {
268  }
269 
270  if (element.GetAttribute("angularvelocity") != null)
271  {
272  AngularVelocityMin = element.GetAttributeFloat("angularvelocity", 0.0f);
274  }
275 
276  if (element.GetAttribute("startsize") != null)
277  {
278  StartSizeMin = element.GetAttributeVector2("startsize", Vector2.One);
280  }
281 
282  if (element.GetAttribute("sizechange") != null)
283  {
284  SizeChangeMin = element.GetAttributeVector2("sizechange", Vector2.Zero);
286  }
287 
288  if (element.GetAttribute("startrotation") != null)
289  {
290  StartRotationMin = element.GetAttributeFloat("startrotation", 0.0f);
292  }
293 
294  if (CollisionRadius <= 0.0f && UseCollision)
295  {
296  CollisionRadius = Sprites.Count > 0 ? Sprites[0].SourceRect.Width / 2.0f : 1;
297  }
298  }
299 
300  public Vector2 CalculateEndPosition(Vector2 startPosition, Vector2 velocity)
301  {
302  //endPos = x + vt + 1/2 * at^2
303  return startPosition + velocity * LifeTime + 0.5f * VelocityChangeDisplay * LifeTime * LifeTime;
304  }
305 
306  public Vector2 CalculateEndSize()
307  {
308  //endPos = x + vt + 1/2 * at^2
309  return StartSizeMax + 0.5f * SizeChangeMax * LifeTime * LifeTime;
310  }
311  }
312 }
Base class for content file types, which are loaded from filelist.xml via reflection....
Definition: ContentFile.cs:23
bool GetAttributeBool(string key, bool def)
static ParticleManager ParticleManager
Definition: GameMain.cs:101
Dictionary< Identifier, SerializableProperty > SerializableProperties
static readonly PrefabCollection< ParticlePrefab > Prefabs
ParticlePrefab(ContentXElement element, ContentFile file)
readonly List< ParticleEmitterPrefab > SubEmitters
readonly List< Sprite > Sprites
Vector2 CalculateEndPosition(Vector2 startPosition, Vector2 velocity)
readonly Identifier Identifier
Definition: Prefab.cs:34
static Dictionary< Identifier, SerializableProperty > DeserializeProperties(object obj, XElement element=null)