ParticleEffectWriterTests.cs 50 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097
  1. // Copyright (c) Craftwork Games. All rights reserved.
  2. // Licensed under the MIT license.
  3. // See LICENSE file in the project root for full license information.
  4. using System;
  5. using System.IO;
  6. using Microsoft.Xna.Framework;
  7. using MonoGame.Extended.Particles;
  8. using MonoGame.Extended.Particles.Modifiers;
  9. using MonoGame.Extended.Particles.Modifiers.Containers;
  10. using MonoGame.Extended.Particles.Modifiers.Interpolators;
  11. using MonoGame.Extended.Particles.Profiles;
  12. namespace MonoGame.Extended.Tests.Particles;
  13. public class ParticleEffectWriterTests
  14. {
  15. [Fact]
  16. public void WriteParticleEffect_NulLEffect_ThrowsArgumentNullException()
  17. {
  18. using MemoryStream stream = new MemoryStream();
  19. using ParticleEffectWriter writer = new ParticleEffectWriter(stream);
  20. Assert.Throws<ArgumentNullException>(() => writer.WriteParticleEffect(null));
  21. }
  22. [Fact]
  23. public void WriteParticleEffect_EmptyEffect_WritesMinimalXml()
  24. {
  25. ParticleEffect effect = new ParticleEffect("EmptyEffect");
  26. string expected =
  27. $"""
  28. <?xml version="1.0" encoding="utf-8"?>
  29. <ParticleEffect Name="EmptyEffect" Position="0,0" Rotation="0" Scale="1,1" AutoTrigger="True" AutoTriggerFrequency="1" />
  30. """;
  31. AssertParticleEffect(effect, expected);
  32. }
  33. [Fact]
  34. public void WriteParticleEffect_EmptyModifiers_WritesMinimalXml()
  35. {
  36. ParticleEffect effect = new ParticleEffect("TestEffect");
  37. ParticleEmitter emitter = new ParticleEmitter(1);
  38. emitter.Name = "EmptyModifiers";
  39. effect.Emitters.Add(emitter);
  40. string expected =
  41. $"""
  42. <?xml version="1.0" encoding="utf-8"?>
  43. <ParticleEffect Name="TestEffect" Position="0,0" Rotation="0" Scale="1,1" AutoTrigger="True" AutoTriggerFrequency="1">
  44. <Emitters>
  45. <ParticleEmitter Name="EmptyModifiers" LifeSpan="1" Offset="0,0" LayerDepth="0" ReclaimFrequency="60" Capacity="1" ModifierExecutionStrategy="Serial" RenderingOrder="FrontToBack">
  46. <Parameters>
  47. <Quantity Kind="Random" RandomMin="5" RandomMax="100" />
  48. <Speed Kind="Random" RandomMin="50" RandomMax="100" />
  49. <Color Kind="Constant" Constant="1,1,1" />
  50. <Opacity Kind="Random" RandomMin="0" RandomMax="1" />
  51. <Scale Kind="Random" RandomMin="0.5,0.5" RandomMax="1,1" />
  52. <Rotation Kind="Random" RandomMin="{-MathF.PI}" RandomMax="{MathF.PI}" />
  53. <Mass Kind="Constant" Constant="1" />
  54. </Parameters>
  55. <Profile Type="PointProfile" />
  56. </ParticleEmitter>
  57. </Emitters>
  58. </ParticleEffect>
  59. """;
  60. AssertParticleEffect(effect, expected);
  61. }
  62. [Fact]
  63. public void WriteParticleEffect_EmptyInterpolators_WritesMinimalXml()
  64. {
  65. ParticleEffect effect = new ParticleEffect("TestEffect");
  66. ParticleEmitter emitter = new ParticleEmitter(1);
  67. emitter.Name = "TestEmitter";
  68. effect.Emitters.Add(emitter);
  69. AgeModifier ageModifier = new AgeModifier();
  70. emitter.Modifiers.Add(ageModifier);
  71. string expected =
  72. $"""
  73. <?xml version="1.0" encoding="utf-8"?>
  74. <ParticleEffect Name="TestEffect" Position="0,0" Rotation="0" Scale="1,1" AutoTrigger="True" AutoTriggerFrequency="1">
  75. <Emitters>
  76. <ParticleEmitter Name="TestEmitter" LifeSpan="1" Offset="0,0" LayerDepth="0" ReclaimFrequency="60" Capacity="1" ModifierExecutionStrategy="Serial" RenderingOrder="FrontToBack">
  77. <Parameters>
  78. <Quantity Kind="Random" RandomMin="5" RandomMax="100" />
  79. <Speed Kind="Random" RandomMin="50" RandomMax="100" />
  80. <Color Kind="Constant" Constant="1,1,1" />
  81. <Opacity Kind="Random" RandomMin="0" RandomMax="1" />
  82. <Scale Kind="Random" RandomMin="0.5,0.5" RandomMax="1,1" />
  83. <Rotation Kind="Random" RandomMin="{-MathF.PI}" RandomMax="{MathF.PI}" />
  84. <Mass Kind="Constant" Constant="1" />
  85. </Parameters>
  86. <Profile Type="PointProfile" />
  87. <Modifiers>
  88. <Modifier Name="AgeModifier" Frequency="60" Type="AgeModifier" />
  89. </Modifiers>
  90. </ParticleEmitter>
  91. </Emitters>
  92. </ParticleEffect>
  93. """;
  94. AssertParticleEffect(effect, expected);
  95. }
  96. [Fact]
  97. public void WriteParticleEffect_BoxFillProfile_WritesExpected()
  98. {
  99. ParticleEffect effect = new ParticleEffect("TestEffect");
  100. ParticleEmitter emitter = new ParticleEmitter(1);
  101. emitter.Name = "TestEmitter";
  102. emitter.Profile = Profile.BoxFill(1.0f, 2.0f);
  103. effect.Emitters.Add(emitter);
  104. string expected =
  105. $"""
  106. <?xml version="1.0" encoding="utf-8"?>
  107. <ParticleEffect Name="TestEffect" Position="0,0" Rotation="0" Scale="1,1" AutoTrigger="True" AutoTriggerFrequency="1">
  108. <Emitters>
  109. <ParticleEmitter Name="TestEmitter" LifeSpan="1" Offset="0,0" LayerDepth="0" ReclaimFrequency="60" Capacity="1" ModifierExecutionStrategy="Serial" RenderingOrder="FrontToBack">
  110. <Parameters>
  111. <Quantity Kind="Random" RandomMin="5" RandomMax="100" />
  112. <Speed Kind="Random" RandomMin="50" RandomMax="100" />
  113. <Color Kind="Constant" Constant="1,1,1" />
  114. <Opacity Kind="Random" RandomMin="0" RandomMax="1" />
  115. <Scale Kind="Random" RandomMin="0.5,0.5" RandomMax="1,1" />
  116. <Rotation Kind="Random" RandomMin="{-MathF.PI}" RandomMax="{MathF.PI}" />
  117. <Mass Kind="Constant" Constant="1" />
  118. </Parameters>
  119. <Profile Type="BoxFillProfile" Width="1" Height="2" />
  120. </ParticleEmitter>
  121. </Emitters>
  122. </ParticleEffect>
  123. """;
  124. AssertParticleEffect(effect, expected);
  125. }
  126. [Fact]
  127. public void WriteParticleEffect_BoxProfile_WritesExpected()
  128. {
  129. ParticleEffect effect = new ParticleEffect("TestEffect");
  130. ParticleEmitter emitter = new ParticleEmitter(1);
  131. emitter.Name = "TestEmitter";
  132. emitter.Profile = Profile.Box(1.0f, 2.0f);
  133. effect.Emitters.Add(emitter);
  134. string expected =
  135. $"""
  136. <?xml version="1.0" encoding="utf-8"?>
  137. <ParticleEffect Name="TestEffect" Position="0,0" Rotation="0" Scale="1,1" AutoTrigger="True" AutoTriggerFrequency="1">
  138. <Emitters>
  139. <ParticleEmitter Name="TestEmitter" LifeSpan="1" Offset="0,0" LayerDepth="0" ReclaimFrequency="60" Capacity="1" ModifierExecutionStrategy="Serial" RenderingOrder="FrontToBack">
  140. <Parameters>
  141. <Quantity Kind="Random" RandomMin="5" RandomMax="100" />
  142. <Speed Kind="Random" RandomMin="50" RandomMax="100" />
  143. <Color Kind="Constant" Constant="1,1,1" />
  144. <Opacity Kind="Random" RandomMin="0" RandomMax="1" />
  145. <Scale Kind="Random" RandomMin="0.5,0.5" RandomMax="1,1" />
  146. <Rotation Kind="Random" RandomMin="{-MathF.PI}" RandomMax="{MathF.PI}" />
  147. <Mass Kind="Constant" Constant="1" />
  148. </Parameters>
  149. <Profile Type="BoxProfile" Width="1" Height="2" />
  150. </ParticleEmitter>
  151. </Emitters>
  152. </ParticleEffect>
  153. """;
  154. AssertParticleEffect(effect, expected);
  155. }
  156. [Fact]
  157. public void WriteParticleEffect_BoxUniformProfile_WritesExpected()
  158. {
  159. ParticleEffect effect = new ParticleEffect("TestEffect");
  160. ParticleEmitter emitter = new ParticleEmitter(1);
  161. emitter.Name = "TestEmitter";
  162. emitter.Profile = Profile.BoxUniform(1.0f, 2.0f);
  163. effect.Emitters.Add(emitter);
  164. string expected =
  165. $"""
  166. <?xml version="1.0" encoding="utf-8"?>
  167. <ParticleEffect Name="TestEffect" Position="0,0" Rotation="0" Scale="1,1" AutoTrigger="True" AutoTriggerFrequency="1">
  168. <Emitters>
  169. <ParticleEmitter Name="TestEmitter" LifeSpan="1" Offset="0,0" LayerDepth="0" ReclaimFrequency="60" Capacity="1" ModifierExecutionStrategy="Serial" RenderingOrder="FrontToBack">
  170. <Parameters>
  171. <Quantity Kind="Random" RandomMin="5" RandomMax="100" />
  172. <Speed Kind="Random" RandomMin="50" RandomMax="100" />
  173. <Color Kind="Constant" Constant="1,1,1" />
  174. <Opacity Kind="Random" RandomMin="0" RandomMax="1" />
  175. <Scale Kind="Random" RandomMin="0.5,0.5" RandomMax="1,1" />
  176. <Rotation Kind="Random" RandomMin="{-MathF.PI}" RandomMax="{MathF.PI}" />
  177. <Mass Kind="Constant" Constant="1" />
  178. </Parameters>
  179. <Profile Type="BoxUniformProfile" Width="1" Height="2" />
  180. </ParticleEmitter>
  181. </Emitters>
  182. </ParticleEffect>
  183. """;
  184. AssertParticleEffect(effect, expected);
  185. }
  186. [Fact]
  187. public void WriteParticleEffect_CircleProfile_WritesExpected()
  188. {
  189. ParticleEffect effect = new ParticleEffect("TestEffect");
  190. ParticleEmitter emitter = new ParticleEmitter(1);
  191. emitter.Name = "TestEmitter";
  192. emitter.Profile = Profile.Circle(1.0f, CircleRadiation.Out);
  193. effect.Emitters.Add(emitter);
  194. string expected =
  195. $"""
  196. <?xml version="1.0" encoding="utf-8"?>
  197. <ParticleEffect Name="TestEffect" Position="0,0" Rotation="0" Scale="1,1" AutoTrigger="True" AutoTriggerFrequency="1">
  198. <Emitters>
  199. <ParticleEmitter Name="TestEmitter" LifeSpan="1" Offset="0,0" LayerDepth="0" ReclaimFrequency="60" Capacity="1" ModifierExecutionStrategy="Serial" RenderingOrder="FrontToBack">
  200. <Parameters>
  201. <Quantity Kind="Random" RandomMin="5" RandomMax="100" />
  202. <Speed Kind="Random" RandomMin="50" RandomMax="100" />
  203. <Color Kind="Constant" Constant="1,1,1" />
  204. <Opacity Kind="Random" RandomMin="0" RandomMax="1" />
  205. <Scale Kind="Random" RandomMin="0.5,0.5" RandomMax="1,1" />
  206. <Rotation Kind="Random" RandomMin="{-MathF.PI}" RandomMax="{MathF.PI}" />
  207. <Mass Kind="Constant" Constant="1" />
  208. </Parameters>
  209. <Profile Type="CircleProfile" Radius="1" Radiate="Out" />
  210. </ParticleEmitter>
  211. </Emitters>
  212. </ParticleEffect>
  213. """;
  214. AssertParticleEffect(effect, expected);
  215. }
  216. [Fact]
  217. public void WriteParticleEffect_LineProfile_WritesExpected()
  218. {
  219. ParticleEffect effect = new ParticleEffect("TestEffect");
  220. ParticleEmitter emitter = new ParticleEmitter(1);
  221. emitter.Name = "TestEmitter";
  222. emitter.Profile = Profile.Line(Vector2.One, 1.0f);
  223. effect.Emitters.Add(emitter);
  224. string expected =
  225. $"""
  226. <?xml version="1.0" encoding="utf-8"?>
  227. <ParticleEffect Name="TestEffect" Position="0,0" Rotation="0" Scale="1,1" AutoTrigger="True" AutoTriggerFrequency="1">
  228. <Emitters>
  229. <ParticleEmitter Name="TestEmitter" LifeSpan="1" Offset="0,0" LayerDepth="0" ReclaimFrequency="60" Capacity="1" ModifierExecutionStrategy="Serial" RenderingOrder="FrontToBack">
  230. <Parameters>
  231. <Quantity Kind="Random" RandomMin="5" RandomMax="100" />
  232. <Speed Kind="Random" RandomMin="50" RandomMax="100" />
  233. <Color Kind="Constant" Constant="1,1,1" />
  234. <Opacity Kind="Random" RandomMin="0" RandomMax="1" />
  235. <Scale Kind="Random" RandomMin="0.5,0.5" RandomMax="1,1" />
  236. <Rotation Kind="Random" RandomMin="{-MathF.PI}" RandomMax="{MathF.PI}" />
  237. <Mass Kind="Constant" Constant="1" />
  238. </Parameters>
  239. <Profile Type="LineProfile" Axis="1,1" Length="1" />
  240. </ParticleEmitter>
  241. </Emitters>
  242. </ParticleEffect>
  243. """;
  244. AssertParticleEffect(effect, expected);
  245. }
  246. [Fact]
  247. public void WriteParticleEffect_PointProfile_WritesExpected()
  248. {
  249. ParticleEffect effect = new ParticleEffect("TestEffect");
  250. ParticleEmitter emitter = new ParticleEmitter(1);
  251. emitter.Name = "TestEmitter";
  252. emitter.Profile = Profile.Point();
  253. effect.Emitters.Add(emitter);
  254. string expected =
  255. $"""
  256. <?xml version="1.0" encoding="utf-8"?>
  257. <ParticleEffect Name="TestEffect" Position="0,0" Rotation="0" Scale="1,1" AutoTrigger="True" AutoTriggerFrequency="1">
  258. <Emitters>
  259. <ParticleEmitter Name="TestEmitter" LifeSpan="1" Offset="0,0" LayerDepth="0" ReclaimFrequency="60" Capacity="1" ModifierExecutionStrategy="Serial" RenderingOrder="FrontToBack">
  260. <Parameters>
  261. <Quantity Kind="Random" RandomMin="5" RandomMax="100" />
  262. <Speed Kind="Random" RandomMin="50" RandomMax="100" />
  263. <Color Kind="Constant" Constant="1,1,1" />
  264. <Opacity Kind="Random" RandomMin="0" RandomMax="1" />
  265. <Scale Kind="Random" RandomMin="0.5,0.5" RandomMax="1,1" />
  266. <Rotation Kind="Random" RandomMin="{-MathF.PI}" RandomMax="{MathF.PI}" />
  267. <Mass Kind="Constant" Constant="1" />
  268. </Parameters>
  269. <Profile Type="PointProfile" />
  270. </ParticleEmitter>
  271. </Emitters>
  272. </ParticleEffect>
  273. """;
  274. AssertParticleEffect(effect, expected);
  275. }
  276. [Fact]
  277. public void WriteParticleEffect_RingProfile_WritesExpected()
  278. {
  279. ParticleEffect effect = new ParticleEffect("TestEffect");
  280. ParticleEmitter emitter = new ParticleEmitter(1);
  281. emitter.Name = "TestEmitter";
  282. emitter.Profile = Profile.Ring(1.0f, CircleRadiation.In);
  283. effect.Emitters.Add(emitter);
  284. string expected =
  285. $"""
  286. <?xml version="1.0" encoding="utf-8"?>
  287. <ParticleEffect Name="TestEffect" Position="0,0" Rotation="0" Scale="1,1" AutoTrigger="True" AutoTriggerFrequency="1">
  288. <Emitters>
  289. <ParticleEmitter Name="TestEmitter" LifeSpan="1" Offset="0,0" LayerDepth="0" ReclaimFrequency="60" Capacity="1" ModifierExecutionStrategy="Serial" RenderingOrder="FrontToBack">
  290. <Parameters>
  291. <Quantity Kind="Random" RandomMin="5" RandomMax="100" />
  292. <Speed Kind="Random" RandomMin="50" RandomMax="100" />
  293. <Color Kind="Constant" Constant="1,1,1" />
  294. <Opacity Kind="Random" RandomMin="0" RandomMax="1" />
  295. <Scale Kind="Random" RandomMin="0.5,0.5" RandomMax="1,1" />
  296. <Rotation Kind="Random" RandomMin="{-MathF.PI}" RandomMax="{MathF.PI}" />
  297. <Mass Kind="Constant" Constant="1" />
  298. </Parameters>
  299. <Profile Type="RingProfile" Radius="1" Radiate="In" />
  300. </ParticleEmitter>
  301. </Emitters>
  302. </ParticleEffect>
  303. """;
  304. AssertParticleEffect(effect, expected);
  305. }
  306. [Fact]
  307. public void WriteParticleEffect_SprayProfile_WritesExpected()
  308. {
  309. ParticleEffect effect = new ParticleEffect("TestEffect");
  310. ParticleEmitter emitter = new ParticleEmitter(1);
  311. emitter.Name = "TestEmitter";
  312. emitter.Profile = Profile.Spray(Vector2.One, 1.0f);
  313. effect.Emitters.Add(emitter);
  314. string expected =
  315. $"""
  316. <?xml version="1.0" encoding="utf-8"?>
  317. <ParticleEffect Name="TestEffect" Position="0,0" Rotation="0" Scale="1,1" AutoTrigger="True" AutoTriggerFrequency="1">
  318. <Emitters>
  319. <ParticleEmitter Name="TestEmitter" LifeSpan="1" Offset="0,0" LayerDepth="0" ReclaimFrequency="60" Capacity="1" ModifierExecutionStrategy="Serial" RenderingOrder="FrontToBack">
  320. <Parameters>
  321. <Quantity Kind="Random" RandomMin="5" RandomMax="100" />
  322. <Speed Kind="Random" RandomMin="50" RandomMax="100" />
  323. <Color Kind="Constant" Constant="1,1,1" />
  324. <Opacity Kind="Random" RandomMin="0" RandomMax="1" />
  325. <Scale Kind="Random" RandomMin="0.5,0.5" RandomMax="1,1" />
  326. <Rotation Kind="Random" RandomMin="{-MathF.PI}" RandomMax="{MathF.PI}" />
  327. <Mass Kind="Constant" Constant="1" />
  328. </Parameters>
  329. <Profile Type="SprayProfile" Direction="1,1" Spread="1" />
  330. </ParticleEmitter>
  331. </Emitters>
  332. </ParticleEffect>
  333. """;
  334. AssertParticleEffect(effect, expected);
  335. }
  336. [Fact]
  337. public void WriteParticleEffect_AgeModifier_WritesExpected()
  338. {
  339. ParticleEffect effect = new ParticleEffect("TestEffect");
  340. ParticleEmitter emitter = new ParticleEmitter(1);
  341. emitter.Name = "TestEmitter";
  342. emitter.Profile = Profile.Point();
  343. AgeModifier modifier = new AgeModifier();
  344. emitter.Modifiers.Add(modifier);
  345. effect.Emitters.Add(emitter);
  346. string expected =
  347. $"""
  348. <?xml version="1.0" encoding="utf-8"?>
  349. <ParticleEffect Name="TestEffect" Position="0,0" Rotation="0" Scale="1,1" AutoTrigger="True" AutoTriggerFrequency="1">
  350. <Emitters>
  351. <ParticleEmitter Name="TestEmitter" LifeSpan="1" Offset="0,0" LayerDepth="0" ReclaimFrequency="60" Capacity="1" ModifierExecutionStrategy="Serial" RenderingOrder="FrontToBack">
  352. <Parameters>
  353. <Quantity Kind="Random" RandomMin="5" RandomMax="100" />
  354. <Speed Kind="Random" RandomMin="50" RandomMax="100" />
  355. <Color Kind="Constant" Constant="1,1,1" />
  356. <Opacity Kind="Random" RandomMin="0" RandomMax="1" />
  357. <Scale Kind="Random" RandomMin="0.5,0.5" RandomMax="1,1" />
  358. <Rotation Kind="Random" RandomMin="{-MathF.PI}" RandomMax="{MathF.PI}" />
  359. <Mass Kind="Constant" Constant="1" />
  360. </Parameters>
  361. <Profile Type="PointProfile" />
  362. <Modifiers>
  363. <Modifier Name="AgeModifier" Frequency="60" Type="AgeModifier" />
  364. </Modifiers>
  365. </ParticleEmitter>
  366. </Emitters>
  367. </ParticleEffect>
  368. """;
  369. AssertParticleEffect(effect, expected);
  370. }
  371. [Fact]
  372. public void WriteParticleEffect_CircleContainerModifier_WritesExpected()
  373. {
  374. ParticleEffect effect = new ParticleEffect("TestEffect");
  375. ParticleEmitter emitter = new ParticleEmitter(1);
  376. emitter.Name = "TestEmitter";
  377. emitter.Profile = Profile.Point();
  378. CircleContainerModifier modifier = new CircleContainerModifier();
  379. emitter.Modifiers.Add(modifier);
  380. effect.Emitters.Add(emitter);
  381. string expected =
  382. $"""
  383. <?xml version="1.0" encoding="utf-8"?>
  384. <ParticleEffect Name="TestEffect" Position="0,0" Rotation="0" Scale="1,1" AutoTrigger="True" AutoTriggerFrequency="1">
  385. <Emitters>
  386. <ParticleEmitter Name="TestEmitter" LifeSpan="1" Offset="0,0" LayerDepth="0" ReclaimFrequency="60" Capacity="1" ModifierExecutionStrategy="Serial" RenderingOrder="FrontToBack">
  387. <Parameters>
  388. <Quantity Kind="Random" RandomMin="5" RandomMax="100" />
  389. <Speed Kind="Random" RandomMin="50" RandomMax="100" />
  390. <Color Kind="Constant" Constant="1,1,1" />
  391. <Opacity Kind="Random" RandomMin="0" RandomMax="1" />
  392. <Scale Kind="Random" RandomMin="0.5,0.5" RandomMax="1,1" />
  393. <Rotation Kind="Random" RandomMin="{-MathF.PI}" RandomMax="{MathF.PI}" />
  394. <Mass Kind="Constant" Constant="1" />
  395. </Parameters>
  396. <Profile Type="PointProfile" />
  397. <Modifiers>
  398. <Modifier Name="CircleContainerModifier" Frequency="60" Type="CircleContainerModifier" Radius="0" Inside="True" RestitutionCoefficient="1" />
  399. </Modifiers>
  400. </ParticleEmitter>
  401. </Emitters>
  402. </ParticleEffect>
  403. """;
  404. AssertParticleEffect(effect, expected);
  405. }
  406. [Fact]
  407. public void WriteParticleEffect_DragModifier_WritesExpected()
  408. {
  409. ParticleEffect effect = new ParticleEffect("TestEffect");
  410. ParticleEmitter emitter = new ParticleEmitter(1);
  411. emitter.Name = "TestEmitter";
  412. emitter.Profile = Profile.Point();
  413. DragModifier modifier = new DragModifier();
  414. emitter.Modifiers.Add(modifier);
  415. effect.Emitters.Add(emitter);
  416. string expected =
  417. $"""
  418. <?xml version="1.0" encoding="utf-8"?>
  419. <ParticleEffect Name="TestEffect" Position="0,0" Rotation="0" Scale="1,1" AutoTrigger="True" AutoTriggerFrequency="1">
  420. <Emitters>
  421. <ParticleEmitter Name="TestEmitter" LifeSpan="1" Offset="0,0" LayerDepth="0" ReclaimFrequency="60" Capacity="1" ModifierExecutionStrategy="Serial" RenderingOrder="FrontToBack">
  422. <Parameters>
  423. <Quantity Kind="Random" RandomMin="5" RandomMax="100" />
  424. <Speed Kind="Random" RandomMin="50" RandomMax="100" />
  425. <Color Kind="Constant" Constant="1,1,1" />
  426. <Opacity Kind="Random" RandomMin="0" RandomMax="1" />
  427. <Scale Kind="Random" RandomMin="0.5,0.5" RandomMax="1,1" />
  428. <Rotation Kind="Random" RandomMin="{-MathF.PI}" RandomMax="{MathF.PI}" />
  429. <Mass Kind="Constant" Constant="1" />
  430. </Parameters>
  431. <Profile Type="PointProfile" />
  432. <Modifiers>
  433. <Modifier Name="DragModifier" Frequency="60" Type="DragModifier" DragCoefficient="0.47" Density="0.5" />
  434. </Modifiers>
  435. </ParticleEmitter>
  436. </Emitters>
  437. </ParticleEffect>
  438. """;
  439. AssertParticleEffect(effect, expected);
  440. }
  441. [Fact]
  442. public void WriteParticleEffect_LinearGravityModifier_WritesExpected()
  443. {
  444. ParticleEffect effect = new ParticleEffect("TestEffect");
  445. ParticleEmitter emitter = new ParticleEmitter(1);
  446. emitter.Name = "TestEmitter";
  447. emitter.Profile = Profile.Point();
  448. LinearGravityModifier modifier = new LinearGravityModifier();
  449. emitter.Modifiers.Add(modifier);
  450. effect.Emitters.Add(emitter);
  451. string expected =
  452. $"""
  453. <?xml version="1.0" encoding="utf-8"?>
  454. <ParticleEffect Name="TestEffect" Position="0,0" Rotation="0" Scale="1,1" AutoTrigger="True" AutoTriggerFrequency="1">
  455. <Emitters>
  456. <ParticleEmitter Name="TestEmitter" LifeSpan="1" Offset="0,0" LayerDepth="0" ReclaimFrequency="60" Capacity="1" ModifierExecutionStrategy="Serial" RenderingOrder="FrontToBack">
  457. <Parameters>
  458. <Quantity Kind="Random" RandomMin="5" RandomMax="100" />
  459. <Speed Kind="Random" RandomMin="50" RandomMax="100" />
  460. <Color Kind="Constant" Constant="1,1,1" />
  461. <Opacity Kind="Random" RandomMin="0" RandomMax="1" />
  462. <Scale Kind="Random" RandomMin="0.5,0.5" RandomMax="1,1" />
  463. <Rotation Kind="Random" RandomMin="{-MathF.PI}" RandomMax="{MathF.PI}" />
  464. <Mass Kind="Constant" Constant="1" />
  465. </Parameters>
  466. <Profile Type="PointProfile" />
  467. <Modifiers>
  468. <Modifier Name="LinearGravityModifier" Frequency="60" Type="LinearGravityModifier" Direction="0,0" Strength="0" />
  469. </Modifiers>
  470. </ParticleEmitter>
  471. </Emitters>
  472. </ParticleEffect>
  473. """;
  474. AssertParticleEffect(effect, expected);
  475. }
  476. [Fact]
  477. public void WriteParticleEffect_OpacityFastFadeModifier_WritesExpected()
  478. {
  479. ParticleEffect effect = new ParticleEffect("TestEffect");
  480. ParticleEmitter emitter = new ParticleEmitter(1);
  481. emitter.Name = "TestEmitter";
  482. emitter.Profile = Profile.Point();
  483. OpacityFastFadeModifier modifier = new OpacityFastFadeModifier();
  484. emitter.Modifiers.Add(modifier);
  485. effect.Emitters.Add(emitter);
  486. string expected =
  487. $"""
  488. <?xml version="1.0" encoding="utf-8"?>
  489. <ParticleEffect Name="TestEffect" Position="0,0" Rotation="0" Scale="1,1" AutoTrigger="True" AutoTriggerFrequency="1">
  490. <Emitters>
  491. <ParticleEmitter Name="TestEmitter" LifeSpan="1" Offset="0,0" LayerDepth="0" ReclaimFrequency="60" Capacity="1" ModifierExecutionStrategy="Serial" RenderingOrder="FrontToBack">
  492. <Parameters>
  493. <Quantity Kind="Random" RandomMin="5" RandomMax="100" />
  494. <Speed Kind="Random" RandomMin="50" RandomMax="100" />
  495. <Color Kind="Constant" Constant="1,1,1" />
  496. <Opacity Kind="Random" RandomMin="0" RandomMax="1" />
  497. <Scale Kind="Random" RandomMin="0.5,0.5" RandomMax="1,1" />
  498. <Rotation Kind="Random" RandomMin="{-MathF.PI}" RandomMax="{MathF.PI}" />
  499. <Mass Kind="Constant" Constant="1" />
  500. </Parameters>
  501. <Profile Type="PointProfile" />
  502. <Modifiers>
  503. <Modifier Name="OpacityFastFadeModifier" Frequency="60" Type="OpacityFastFadeModifier" />
  504. </Modifiers>
  505. </ParticleEmitter>
  506. </Emitters>
  507. </ParticleEffect>
  508. """;
  509. AssertParticleEffect(effect, expected);
  510. }
  511. [Fact]
  512. public void WriteParticleEffect_RectangleContainerModifier_WritesExpected()
  513. {
  514. ParticleEffect effect = new ParticleEffect("TestEffect");
  515. ParticleEmitter emitter = new ParticleEmitter(1);
  516. emitter.Name = "TestEmitter";
  517. emitter.Profile = Profile.Point();
  518. RectangleContainerModifier modifier = new RectangleContainerModifier();
  519. emitter.Modifiers.Add(modifier);
  520. effect.Emitters.Add(emitter);
  521. string expected =
  522. $"""
  523. <?xml version="1.0" encoding="utf-8"?>
  524. <ParticleEffect Name="TestEffect" Position="0,0" Rotation="0" Scale="1,1" AutoTrigger="True" AutoTriggerFrequency="1">
  525. <Emitters>
  526. <ParticleEmitter Name="TestEmitter" LifeSpan="1" Offset="0,0" LayerDepth="0" ReclaimFrequency="60" Capacity="1" ModifierExecutionStrategy="Serial" RenderingOrder="FrontToBack">
  527. <Parameters>
  528. <Quantity Kind="Random" RandomMin="5" RandomMax="100" />
  529. <Speed Kind="Random" RandomMin="50" RandomMax="100" />
  530. <Color Kind="Constant" Constant="1,1,1" />
  531. <Opacity Kind="Random" RandomMin="0" RandomMax="1" />
  532. <Scale Kind="Random" RandomMin="0.5,0.5" RandomMax="1,1" />
  533. <Rotation Kind="Random" RandomMin="{-MathF.PI}" RandomMax="{MathF.PI}" />
  534. <Mass Kind="Constant" Constant="1" />
  535. </Parameters>
  536. <Profile Type="PointProfile" />
  537. <Modifiers>
  538. <Modifier Name="RectangleContainerModifier" Frequency="60" Type="RectangleContainerModifier" Width="0" Height="0" RestitutionCoefficient="1" />
  539. </Modifiers>
  540. </ParticleEmitter>
  541. </Emitters>
  542. </ParticleEffect>
  543. """;
  544. AssertParticleEffect(effect, expected);
  545. }
  546. [Fact]
  547. public void WriteParticleEffect_RectangleLoopContainerModifier_WritesExpected()
  548. {
  549. ParticleEffect effect = new ParticleEffect("TestEffect");
  550. ParticleEmitter emitter = new ParticleEmitter(1);
  551. emitter.Name = "TestEmitter";
  552. emitter.Profile = Profile.Point();
  553. RectangleLoopContainerModifier modifier = new RectangleLoopContainerModifier();
  554. emitter.Modifiers.Add(modifier);
  555. effect.Emitters.Add(emitter);
  556. string expected =
  557. $"""
  558. <?xml version="1.0" encoding="utf-8"?>
  559. <ParticleEffect Name="TestEffect" Position="0,0" Rotation="0" Scale="1,1" AutoTrigger="True" AutoTriggerFrequency="1">
  560. <Emitters>
  561. <ParticleEmitter Name="TestEmitter" LifeSpan="1" Offset="0,0" LayerDepth="0" ReclaimFrequency="60" Capacity="1" ModifierExecutionStrategy="Serial" RenderingOrder="FrontToBack">
  562. <Parameters>
  563. <Quantity Kind="Random" RandomMin="5" RandomMax="100" />
  564. <Speed Kind="Random" RandomMin="50" RandomMax="100" />
  565. <Color Kind="Constant" Constant="1,1,1" />
  566. <Opacity Kind="Random" RandomMin="0" RandomMax="1" />
  567. <Scale Kind="Random" RandomMin="0.5,0.5" RandomMax="1,1" />
  568. <Rotation Kind="Random" RandomMin="{-MathF.PI}" RandomMax="{MathF.PI}" />
  569. <Mass Kind="Constant" Constant="1" />
  570. </Parameters>
  571. <Profile Type="PointProfile" />
  572. <Modifiers>
  573. <Modifier Name="RectangleLoopContainerModifier" Frequency="60" Type="RectangleLoopContainerModifier" Width="0" Height="0" />
  574. </Modifiers>
  575. </ParticleEmitter>
  576. </Emitters>
  577. </ParticleEffect>
  578. """;
  579. AssertParticleEffect(effect, expected);
  580. }
  581. [Fact]
  582. public void WriteParticleEffect_RotationModifier_WritesExpected()
  583. {
  584. ParticleEffect effect = new ParticleEffect("TestEffect");
  585. ParticleEmitter emitter = new ParticleEmitter(1);
  586. emitter.Name = "TestEmitter";
  587. emitter.Profile = Profile.Point();
  588. RotationModifier modifier = new RotationModifier();
  589. emitter.Modifiers.Add(modifier);
  590. effect.Emitters.Add(emitter);
  591. string expected =
  592. $"""
  593. <?xml version="1.0" encoding="utf-8"?>
  594. <ParticleEffect Name="TestEffect" Position="0,0" Rotation="0" Scale="1,1" AutoTrigger="True" AutoTriggerFrequency="1">
  595. <Emitters>
  596. <ParticleEmitter Name="TestEmitter" LifeSpan="1" Offset="0,0" LayerDepth="0" ReclaimFrequency="60" Capacity="1" ModifierExecutionStrategy="Serial" RenderingOrder="FrontToBack">
  597. <Parameters>
  598. <Quantity Kind="Random" RandomMin="5" RandomMax="100" />
  599. <Speed Kind="Random" RandomMin="50" RandomMax="100" />
  600. <Color Kind="Constant" Constant="1,1,1" />
  601. <Opacity Kind="Random" RandomMin="0" RandomMax="1" />
  602. <Scale Kind="Random" RandomMin="0.5,0.5" RandomMax="1,1" />
  603. <Rotation Kind="Random" RandomMin="{-MathF.PI}" RandomMax="{MathF.PI}" />
  604. <Mass Kind="Constant" Constant="1" />
  605. </Parameters>
  606. <Profile Type="PointProfile" />
  607. <Modifiers>
  608. <Modifier Name="RotationModifier" Frequency="60" Type="RotationModifier" RotationRate="0" />
  609. </Modifiers>
  610. </ParticleEmitter>
  611. </Emitters>
  612. </ParticleEffect>
  613. """;
  614. AssertParticleEffect(effect, expected);
  615. }
  616. [Fact]
  617. public void WriteParticleEffect_VelocityColorModifier_WritesExpected()
  618. {
  619. ParticleEffect effect = new ParticleEffect("TestEffect");
  620. ParticleEmitter emitter = new ParticleEmitter(1);
  621. emitter.Name = "TestEmitter";
  622. emitter.Profile = Profile.Point();
  623. VelocityColorModifier modifier = new VelocityColorModifier();
  624. emitter.Modifiers.Add(modifier);
  625. effect.Emitters.Add(emitter);
  626. string expected =
  627. $"""
  628. <?xml version="1.0" encoding="utf-8"?>
  629. <ParticleEffect Name="TestEffect" Position="0,0" Rotation="0" Scale="1,1" AutoTrigger="True" AutoTriggerFrequency="1">
  630. <Emitters>
  631. <ParticleEmitter Name="TestEmitter" LifeSpan="1" Offset="0,0" LayerDepth="0" ReclaimFrequency="60" Capacity="1" ModifierExecutionStrategy="Serial" RenderingOrder="FrontToBack">
  632. <Parameters>
  633. <Quantity Kind="Random" RandomMin="5" RandomMax="100" />
  634. <Speed Kind="Random" RandomMin="50" RandomMax="100" />
  635. <Color Kind="Constant" Constant="1,1,1" />
  636. <Opacity Kind="Random" RandomMin="0" RandomMax="1" />
  637. <Scale Kind="Random" RandomMin="0.5,0.5" RandomMax="1,1" />
  638. <Rotation Kind="Random" RandomMin="{-MathF.PI}" RandomMax="{MathF.PI}" />
  639. <Mass Kind="Constant" Constant="1" />
  640. </Parameters>
  641. <Profile Type="PointProfile" />
  642. <Modifiers>
  643. <Modifier Name="VelocityColorModifier" Frequency="60" Type="VelocityColorModifier" StationaryColor="0,0,0" VelocityColor="0,0,0" VelocityThreshold="0" />
  644. </Modifiers>
  645. </ParticleEmitter>
  646. </Emitters>
  647. </ParticleEffect>
  648. """;
  649. AssertParticleEffect(effect, expected);
  650. }
  651. [Fact]
  652. public void WriteParticleEffect_VelocityModifier_WritesExpected()
  653. {
  654. ParticleEffect effect = new ParticleEffect("TestEffect");
  655. ParticleEmitter emitter = new ParticleEmitter(1);
  656. emitter.Name = "TestEmitter";
  657. emitter.Profile = Profile.Point();
  658. VelocityModifier modifier = new VelocityModifier();
  659. emitter.Modifiers.Add(modifier);
  660. effect.Emitters.Add(emitter);
  661. string expected =
  662. $"""
  663. <?xml version="1.0" encoding="utf-8"?>
  664. <ParticleEffect Name="TestEffect" Position="0,0" Rotation="0" Scale="1,1" AutoTrigger="True" AutoTriggerFrequency="1">
  665. <Emitters>
  666. <ParticleEmitter Name="TestEmitter" LifeSpan="1" Offset="0,0" LayerDepth="0" ReclaimFrequency="60" Capacity="1" ModifierExecutionStrategy="Serial" RenderingOrder="FrontToBack">
  667. <Parameters>
  668. <Quantity Kind="Random" RandomMin="5" RandomMax="100" />
  669. <Speed Kind="Random" RandomMin="50" RandomMax="100" />
  670. <Color Kind="Constant" Constant="1,1,1" />
  671. <Opacity Kind="Random" RandomMin="0" RandomMax="1" />
  672. <Scale Kind="Random" RandomMin="0.5,0.5" RandomMax="1,1" />
  673. <Rotation Kind="Random" RandomMin="{-MathF.PI}" RandomMax="{MathF.PI}" />
  674. <Mass Kind="Constant" Constant="1" />
  675. </Parameters>
  676. <Profile Type="PointProfile" />
  677. <Modifiers>
  678. <Modifier Name="VelocityModifier" Frequency="60" Type="VelocityModifier" VelocityThreshold="0" />
  679. </Modifiers>
  680. </ParticleEmitter>
  681. </Emitters>
  682. </ParticleEffect>
  683. """;
  684. AssertParticleEffect(effect, expected);
  685. }
  686. [Fact]
  687. public void WriteParticleEffect_VortexModifier_WritesExpected()
  688. {
  689. ParticleEffect effect = new ParticleEffect("TestEffect");
  690. ParticleEmitter emitter = new ParticleEmitter(1);
  691. emitter.Name = "TestEmitter";
  692. emitter.Profile = Profile.Point();
  693. VortexModifier modifier = new VortexModifier();
  694. emitter.Modifiers.Add(modifier);
  695. effect.Emitters.Add(emitter);
  696. string expected =
  697. $"""
  698. <?xml version="1.0" encoding="utf-8"?>
  699. <ParticleEffect Name="TestEffect" Position="0,0" Rotation="0" Scale="1,1" AutoTrigger="True" AutoTriggerFrequency="1">
  700. <Emitters>
  701. <ParticleEmitter Name="TestEmitter" LifeSpan="1" Offset="0,0" LayerDepth="0" ReclaimFrequency="60" Capacity="1" ModifierExecutionStrategy="Serial" RenderingOrder="FrontToBack">
  702. <Parameters>
  703. <Quantity Kind="Random" RandomMin="5" RandomMax="100" />
  704. <Speed Kind="Random" RandomMin="50" RandomMax="100" />
  705. <Color Kind="Constant" Constant="1,1,1" />
  706. <Opacity Kind="Random" RandomMin="0" RandomMax="1" />
  707. <Scale Kind="Random" RandomMin="0.5,0.5" RandomMax="1,1" />
  708. <Rotation Kind="Random" RandomMin="{-MathF.PI}" RandomMax="{MathF.PI}" />
  709. <Mass Kind="Constant" Constant="1" />
  710. </Parameters>
  711. <Profile Type="PointProfile" />
  712. <Modifiers>
  713. <Modifier Name="VortexModifier" Frequency="60" Type="VortexModifier" Position="0,0" Strength="0" OuterRadius="0" InnerRadius="0" MaxVelocity="0" RotationAngle="0" />
  714. </Modifiers>
  715. </ParticleEmitter>
  716. </Emitters>
  717. </ParticleEffect>
  718. """;
  719. AssertParticleEffect(effect, expected);
  720. }
  721. [Fact]
  722. public void WriteParticleEffect_ColorInterpolator_WritesExpected()
  723. {
  724. ParticleEffect effect = new ParticleEffect("TestEffect");
  725. ParticleEmitter emitter = new ParticleEmitter(1);
  726. emitter.Name = "TestEmitter";
  727. emitter.Profile = Profile.Point();
  728. AgeModifier modifier = new AgeModifier();
  729. ColorInterpolator interpolator = new ColorInterpolator();
  730. modifier.Interpolators.Add(interpolator);
  731. emitter.Modifiers.Add(modifier);
  732. effect.Emitters.Add(emitter);
  733. string expected =
  734. $"""
  735. <?xml version="1.0" encoding="utf-8"?>
  736. <ParticleEffect Name="TestEffect" Position="0,0" Rotation="0" Scale="1,1" AutoTrigger="True" AutoTriggerFrequency="1">
  737. <Emitters>
  738. <ParticleEmitter Name="TestEmitter" LifeSpan="1" Offset="0,0" LayerDepth="0" ReclaimFrequency="60" Capacity="1" ModifierExecutionStrategy="Serial" RenderingOrder="FrontToBack">
  739. <Parameters>
  740. <Quantity Kind="Random" RandomMin="5" RandomMax="100" />
  741. <Speed Kind="Random" RandomMin="50" RandomMax="100" />
  742. <Color Kind="Constant" Constant="1,1,1" />
  743. <Opacity Kind="Random" RandomMin="0" RandomMax="1" />
  744. <Scale Kind="Random" RandomMin="0.5,0.5" RandomMax="1,1" />
  745. <Rotation Kind="Random" RandomMin="{-MathF.PI}" RandomMax="{MathF.PI}" />
  746. <Mass Kind="Constant" Constant="1" />
  747. </Parameters>
  748. <Profile Type="PointProfile" />
  749. <Modifiers>
  750. <Modifier Name="AgeModifier" Frequency="60" Type="AgeModifier">
  751. <Interpolators>
  752. <Interpolator Name="ColorInterpolator" Type="ColorInterpolator" StartValue="0,0,0" EndValue="0,0,0" />
  753. </Interpolators>
  754. </Modifier>
  755. </Modifiers>
  756. </ParticleEmitter>
  757. </Emitters>
  758. </ParticleEffect>
  759. """;
  760. AssertParticleEffect(effect, expected);
  761. }
  762. [Fact]
  763. public void WriteParticleEffect_HueInterpolator_WritesExpected()
  764. {
  765. ParticleEffect effect = new ParticleEffect("TestEffect");
  766. ParticleEmitter emitter = new ParticleEmitter(1);
  767. emitter.Name = "TestEmitter";
  768. emitter.Profile = Profile.Point();
  769. AgeModifier modifier = new AgeModifier();
  770. HueInterpolator interpolator = new HueInterpolator();
  771. modifier.Interpolators.Add(interpolator);
  772. emitter.Modifiers.Add(modifier);
  773. effect.Emitters.Add(emitter);
  774. string expected =
  775. $"""
  776. <?xml version="1.0" encoding="utf-8"?>
  777. <ParticleEffect Name="TestEffect" Position="0,0" Rotation="0" Scale="1,1" AutoTrigger="True" AutoTriggerFrequency="1">
  778. <Emitters>
  779. <ParticleEmitter Name="TestEmitter" LifeSpan="1" Offset="0,0" LayerDepth="0" ReclaimFrequency="60" Capacity="1" ModifierExecutionStrategy="Serial" RenderingOrder="FrontToBack">
  780. <Parameters>
  781. <Quantity Kind="Random" RandomMin="5" RandomMax="100" />
  782. <Speed Kind="Random" RandomMin="50" RandomMax="100" />
  783. <Color Kind="Constant" Constant="1,1,1" />
  784. <Opacity Kind="Random" RandomMin="0" RandomMax="1" />
  785. <Scale Kind="Random" RandomMin="0.5,0.5" RandomMax="1,1" />
  786. <Rotation Kind="Random" RandomMin="{-MathF.PI}" RandomMax="{MathF.PI}" />
  787. <Mass Kind="Constant" Constant="1" />
  788. </Parameters>
  789. <Profile Type="PointProfile" />
  790. <Modifiers>
  791. <Modifier Name="AgeModifier" Frequency="60" Type="AgeModifier">
  792. <Interpolators>
  793. <Interpolator Name="HueInterpolator" Type="HueInterpolator" StartValue="0" EndValue="0" />
  794. </Interpolators>
  795. </Modifier>
  796. </Modifiers>
  797. </ParticleEmitter>
  798. </Emitters>
  799. </ParticleEffect>
  800. """;
  801. AssertParticleEffect(effect, expected);
  802. }
  803. [Fact]
  804. public void WriteParticleEffect_OpacityInterpolator_WritesExpected()
  805. {
  806. ParticleEffect effect = new ParticleEffect("TestEffect");
  807. ParticleEmitter emitter = new ParticleEmitter(1);
  808. emitter.Name = "TestEmitter";
  809. emitter.Profile = Profile.Point();
  810. AgeModifier modifier = new AgeModifier();
  811. OpacityInterpolator interpolator = new OpacityInterpolator();
  812. modifier.Interpolators.Add(interpolator);
  813. emitter.Modifiers.Add(modifier);
  814. effect.Emitters.Add(emitter);
  815. string expected =
  816. $"""
  817. <?xml version="1.0" encoding="utf-8"?>
  818. <ParticleEffect Name="TestEffect" Position="0,0" Rotation="0" Scale="1,1" AutoTrigger="True" AutoTriggerFrequency="1">
  819. <Emitters>
  820. <ParticleEmitter Name="TestEmitter" LifeSpan="1" Offset="0,0" LayerDepth="0" ReclaimFrequency="60" Capacity="1" ModifierExecutionStrategy="Serial" RenderingOrder="FrontToBack">
  821. <Parameters>
  822. <Quantity Kind="Random" RandomMin="5" RandomMax="100" />
  823. <Speed Kind="Random" RandomMin="50" RandomMax="100" />
  824. <Color Kind="Constant" Constant="1,1,1" />
  825. <Opacity Kind="Random" RandomMin="0" RandomMax="1" />
  826. <Scale Kind="Random" RandomMin="0.5,0.5" RandomMax="1,1" />
  827. <Rotation Kind="Random" RandomMin="{-MathF.PI}" RandomMax="{MathF.PI}" />
  828. <Mass Kind="Constant" Constant="1" />
  829. </Parameters>
  830. <Profile Type="PointProfile" />
  831. <Modifiers>
  832. <Modifier Name="AgeModifier" Frequency="60" Type="AgeModifier">
  833. <Interpolators>
  834. <Interpolator Name="OpacityInterpolator" Type="OpacityInterpolator" StartValue="0" EndValue="0" />
  835. </Interpolators>
  836. </Modifier>
  837. </Modifiers>
  838. </ParticleEmitter>
  839. </Emitters>
  840. </ParticleEffect>
  841. """;
  842. AssertParticleEffect(effect, expected);
  843. }
  844. [Fact]
  845. public void WriteParticleEffect_RotationInterpolator_WritesExpected()
  846. {
  847. ParticleEffect effect = new ParticleEffect("TestEffect");
  848. ParticleEmitter emitter = new ParticleEmitter(1);
  849. emitter.Name = "TestEmitter";
  850. emitter.Profile = Profile.Point();
  851. AgeModifier modifier = new AgeModifier();
  852. RotationInterpolator interpolator = new RotationInterpolator();
  853. modifier.Interpolators.Add(interpolator);
  854. emitter.Modifiers.Add(modifier);
  855. effect.Emitters.Add(emitter);
  856. string expected =
  857. $"""
  858. <?xml version="1.0" encoding="utf-8"?>
  859. <ParticleEffect Name="TestEffect" Position="0,0" Rotation="0" Scale="1,1" AutoTrigger="True" AutoTriggerFrequency="1">
  860. <Emitters>
  861. <ParticleEmitter Name="TestEmitter" LifeSpan="1" Offset="0,0" LayerDepth="0" ReclaimFrequency="60" Capacity="1" ModifierExecutionStrategy="Serial" RenderingOrder="FrontToBack">
  862. <Parameters>
  863. <Quantity Kind="Random" RandomMin="5" RandomMax="100" />
  864. <Speed Kind="Random" RandomMin="50" RandomMax="100" />
  865. <Color Kind="Constant" Constant="1,1,1" />
  866. <Opacity Kind="Random" RandomMin="0" RandomMax="1" />
  867. <Scale Kind="Random" RandomMin="0.5,0.5" RandomMax="1,1" />
  868. <Rotation Kind="Random" RandomMin="{-MathF.PI}" RandomMax="{MathF.PI}" />
  869. <Mass Kind="Constant" Constant="1" />
  870. </Parameters>
  871. <Profile Type="PointProfile" />
  872. <Modifiers>
  873. <Modifier Name="AgeModifier" Frequency="60" Type="AgeModifier">
  874. <Interpolators>
  875. <Interpolator Name="RotationInterpolator" Type="RotationInterpolator" StartValue="0" EndValue="0" />
  876. </Interpolators>
  877. </Modifier>
  878. </Modifiers>
  879. </ParticleEmitter>
  880. </Emitters>
  881. </ParticleEffect>
  882. """;
  883. AssertParticleEffect(effect, expected);
  884. }
  885. [Fact]
  886. public void WriteParticleEffect_ScaleInterpolator_WritesExpected()
  887. {
  888. ParticleEffect effect = new ParticleEffect("TestEffect");
  889. ParticleEmitter emitter = new ParticleEmitter(1);
  890. emitter.Name = "TestEmitter";
  891. emitter.Profile = Profile.Point();
  892. AgeModifier modifier = new AgeModifier();
  893. ScaleInterpolator interpolator = new ScaleInterpolator();
  894. modifier.Interpolators.Add(interpolator);
  895. emitter.Modifiers.Add(modifier);
  896. effect.Emitters.Add(emitter);
  897. string expected =
  898. $"""
  899. <?xml version="1.0" encoding="utf-8"?>
  900. <ParticleEffect Name="TestEffect" Position="0,0" Rotation="0" Scale="1,1" AutoTrigger="True" AutoTriggerFrequency="1">
  901. <Emitters>
  902. <ParticleEmitter Name="TestEmitter" LifeSpan="1" Offset="0,0" LayerDepth="0" ReclaimFrequency="60" Capacity="1" ModifierExecutionStrategy="Serial" RenderingOrder="FrontToBack">
  903. <Parameters>
  904. <Quantity Kind="Random" RandomMin="5" RandomMax="100" />
  905. <Speed Kind="Random" RandomMin="50" RandomMax="100" />
  906. <Color Kind="Constant" Constant="1,1,1" />
  907. <Opacity Kind="Random" RandomMin="0" RandomMax="1" />
  908. <Scale Kind="Random" RandomMin="0.5,0.5" RandomMax="1,1" />
  909. <Rotation Kind="Random" RandomMin="{-MathF.PI}" RandomMax="{MathF.PI}" />
  910. <Mass Kind="Constant" Constant="1" />
  911. </Parameters>
  912. <Profile Type="PointProfile" />
  913. <Modifiers>
  914. <Modifier Name="AgeModifier" Frequency="60" Type="AgeModifier">
  915. <Interpolators>
  916. <Interpolator Name="ScaleInterpolator" Type="ScaleInterpolator" StartValue="0,0" EndValue="0,0" />
  917. </Interpolators>
  918. </Modifier>
  919. </Modifiers>
  920. </ParticleEmitter>
  921. </Emitters>
  922. </ParticleEffect>
  923. """;
  924. AssertParticleEffect(effect, expected);
  925. }
  926. [Fact]
  927. public void WriteParticleEffect_VelocityInterpolator_WritesExpected()
  928. {
  929. ParticleEffect effect = new ParticleEffect("TestEffect");
  930. ParticleEmitter emitter = new ParticleEmitter(1);
  931. emitter.Name = "TestEmitter";
  932. emitter.Profile = Profile.Point();
  933. AgeModifier modifier = new AgeModifier();
  934. VelocityInterpolator interpolator = new VelocityInterpolator();
  935. modifier.Interpolators.Add(interpolator);
  936. emitter.Modifiers.Add(modifier);
  937. effect.Emitters.Add(emitter);
  938. string expected =
  939. $"""
  940. <?xml version="1.0" encoding="utf-8"?>
  941. <ParticleEffect Name="TestEffect" Position="0,0" Rotation="0" Scale="1,1" AutoTrigger="True" AutoTriggerFrequency="1">
  942. <Emitters>
  943. <ParticleEmitter Name="TestEmitter" LifeSpan="1" Offset="0,0" LayerDepth="0" ReclaimFrequency="60" Capacity="1" ModifierExecutionStrategy="Serial" RenderingOrder="FrontToBack">
  944. <Parameters>
  945. <Quantity Kind="Random" RandomMin="5" RandomMax="100" />
  946. <Speed Kind="Random" RandomMin="50" RandomMax="100" />
  947. <Color Kind="Constant" Constant="1,1,1" />
  948. <Opacity Kind="Random" RandomMin="0" RandomMax="1" />
  949. <Scale Kind="Random" RandomMin="0.5,0.5" RandomMax="1,1" />
  950. <Rotation Kind="Random" RandomMin="{-MathF.PI}" RandomMax="{MathF.PI}" />
  951. <Mass Kind="Constant" Constant="1" />
  952. </Parameters>
  953. <Profile Type="PointProfile" />
  954. <Modifiers>
  955. <Modifier Name="AgeModifier" Frequency="60" Type="AgeModifier">
  956. <Interpolators>
  957. <Interpolator Name="VelocityInterpolator" Type="VelocityInterpolator" StartValue="0,0" EndValue="0,0" />
  958. </Interpolators>
  959. </Modifier>
  960. </Modifiers>
  961. </ParticleEmitter>
  962. </Emitters>
  963. </ParticleEffect>
  964. """;
  965. AssertParticleEffect(effect, expected);
  966. }
  967. private void AssertParticleEffect(ParticleEffect effect, string expected)
  968. {
  969. string actual = string.Empty;
  970. using (MemoryStream stream = new MemoryStream())
  971. {
  972. using (ParticleEffectWriter writer = new ParticleEffectWriter(stream))
  973. {
  974. writer.WriteParticleEffect(effect);
  975. stream.Position = 0;
  976. }
  977. using StreamReader reader = new StreamReader(stream);
  978. actual = reader.ReadToEnd();
  979. }
  980. Assert.Equal(expected, actual);
  981. }
  982. }