mirror of
https://github.com/AlexMacocian/MonoGame.Extended.git
synced 2026-07-15 15:09:29 +00:00
High-Performance Particle System Rewrite (#990)
* Refactor particle system * Use correct alloc * Use original ParticleIterator imlementation for zero allications. * Move ParticleIterator to its own class instead of a nested class * Mark nullable * Add fallback mechanism for loading textures when it's an image file and not an xnb
This commit is contained in:
committed by
GitHub
parent
9fe1d3c619
commit
168d8fbc36
@@ -0,0 +1,20 @@
|
||||
// Copyright (c) Craftwork Games. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
// See LICENSE file in the project root for full license information.
|
||||
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Content;
|
||||
|
||||
namespace MonoGame.Extended.Tests;
|
||||
|
||||
public class MockContentManager : ContentManager
|
||||
{
|
||||
public MockContentManager() : base(new GameServiceContainer())
|
||||
{
|
||||
}
|
||||
|
||||
public override T Load<T>(string assetName)
|
||||
{
|
||||
return default(T);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,9 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="Sprites\**" />
|
||||
<EmbeddedResource Remove="Sprites\**" />
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,33 +1,35 @@
|
||||
using System;
|
||||
using Microsoft.Xna.Framework;
|
||||
using MonoGame.Extended.Particles.Profiles;
|
||||
using Xunit;
|
||||
|
||||
namespace MonoGame.Extended.Tests.Particles.Profiles
|
||||
{
|
||||
|
||||
public class PointProfileTests
|
||||
{
|
||||
[Fact]
|
||||
public void ReturnsZeroOffset()
|
||||
public unsafe void ReturnsZeroOffset()
|
||||
{
|
||||
var subject = new PointProfile();
|
||||
PointProfile subject = new PointProfile();
|
||||
|
||||
subject.GetOffsetAndHeading(out var offset, out _);
|
||||
Vector2 offset;
|
||||
Vector2 heading;
|
||||
subject.GetOffsetAndHeading(&offset, &heading);
|
||||
|
||||
Assert.Equal(0f, offset.X);
|
||||
Assert.Equal(0f, offset.Y);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReturnsHeadingAsUnitVector()
|
||||
public unsafe void ReturnsHeadingAsUnitVector()
|
||||
{
|
||||
var subject = new PointProfile();
|
||||
PointProfile subject = new PointProfile();
|
||||
|
||||
subject.GetOffsetAndHeading(out _, out var heading);
|
||||
Vector2 offset;
|
||||
Vector2 heading;
|
||||
subject.GetOffsetAndHeading(&offset, &heading);
|
||||
|
||||
var length = Math.Sqrt(heading.X * heading.X + heading.Y * heading.Y);
|
||||
double length = Math.Sqrt(heading.X * heading.X + heading.Y * heading.Y);
|
||||
Assert.Equal(1f, length, 6);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,38 +1,42 @@
|
||||
using System;
|
||||
using Microsoft.Xna.Framework;
|
||||
using MonoGame.Extended.Particles.Profiles;
|
||||
using Xunit;
|
||||
|
||||
namespace MonoGame.Extended.Tests.Particles.Profiles
|
||||
{
|
||||
public class RingProfileTests
|
||||
{
|
||||
[Fact]
|
||||
public void ReturnsOffsetEqualToRadius()
|
||||
public unsafe void ReturnsOffsetEqualToRadius()
|
||||
{
|
||||
var subject = new RingProfile
|
||||
RingProfile subject = new RingProfile
|
||||
{
|
||||
Radius = 10f
|
||||
};
|
||||
subject.GetOffsetAndHeading(out var offset, out _);
|
||||
|
||||
var length = Math.Sqrt(offset.X * offset.X + offset.Y * offset.Y);
|
||||
Assert.Equal(10f, length, 6);
|
||||
Vector2 offset;
|
||||
Vector2 heading;
|
||||
subject.GetOffsetAndHeading(&offset, &heading);
|
||||
|
||||
double length = Math.Sqrt(offset.X * offset.X + offset.Y * offset.Y);
|
||||
Assert.Equal(10.0f, length, precision: 5);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WhenRadiateIsTrue_HeadingIsEqualToNormalizedOffset()
|
||||
public unsafe void WhenRadiateIsTrue_HeadingIsEqualToNormalizedOffset()
|
||||
{
|
||||
var subject = new RingProfile
|
||||
RingProfile subject = new RingProfile
|
||||
{
|
||||
Radius = 10f,
|
||||
Radiate = Profile.CircleRadiation.Out
|
||||
Radiate = CircleRadiation.Out
|
||||
};
|
||||
subject.GetOffsetAndHeading(out var offset, out var heading);
|
||||
|
||||
Assert.Equal(heading.X, offset.X / 10, 6);
|
||||
Assert.Equal(heading.Y, offset.Y / 10, 6);
|
||||
Vector2 offset;
|
||||
Vector2 heading;
|
||||
subject.GetOffsetAndHeading(&offset, &heading);
|
||||
|
||||
Assert.Equal(heading.X, offset.X / 10, precision: 5);
|
||||
Assert.Equal(heading.Y, offset.Y / 10, precision: 5);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,221 @@
|
||||
// Copyright (c) Craftwork Games. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
// See LICENSE file in the project root for full license information.
|
||||
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
using Microsoft.Xna.Framework;
|
||||
using MonoGame.Extended.Serialization.Xml;
|
||||
|
||||
namespace MonoGame.Extended.Tests.Serialization.Xml;
|
||||
|
||||
public class XmlReaderExtensionsTests
|
||||
{
|
||||
private static XmlReader CreateXmlReader(string xml)
|
||||
{
|
||||
StringReader stringReader = new StringReader(xml);
|
||||
XmlReader xmlReader = XmlReader.Create(stringReader);
|
||||
xmlReader.MoveToContent();
|
||||
return xmlReader;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetAttributeInt_ValidValue_ReturnsCorrectInt()
|
||||
{
|
||||
int expected = 42;
|
||||
|
||||
string xml = $"<element testAttr=\"{expected}\" />";
|
||||
using XmlReader reader = CreateXmlReader(xml);
|
||||
int actual = reader.GetAttributeInt("testAttr");
|
||||
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetAttributeInt_MissingAttribute_ThrowsXmlException()
|
||||
{
|
||||
string xml = "<element />";
|
||||
using XmlReader reader = CreateXmlReader(xml);
|
||||
Assert.Throws<XmlException>(() => reader.GetAttributeInt("testAttr"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetAttributeInt_InvalidFormat_ThrowsXmlException()
|
||||
{
|
||||
string xml = "<element testAttr=\"not-a-number\" />";
|
||||
using XmlReader reader = CreateXmlReader(xml);
|
||||
Assert.Throws<XmlException>(() => reader.GetAttributeInt("testAttr"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetAttributeFloat_ValidValue_ReturnsCorrectFloat()
|
||||
{
|
||||
float expected = 3.14f;
|
||||
|
||||
string xml = $"<element testAttr=\"{expected}\" />";
|
||||
using XmlReader reader = CreateXmlReader(xml);
|
||||
float actual = reader.GetAttributeFloat("testAttr");
|
||||
|
||||
Assert.Equal(expected, actual, precision: 5);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetAttributeFloat_MissingAttribute_ThrowsXmlException()
|
||||
{
|
||||
string xml = "<element />";
|
||||
using XmlReader reader = CreateXmlReader(xml);
|
||||
Assert.Throws<XmlException>(() => reader.GetAttributeInt("testAttr"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetAttributeFloat_InvalidFormat_ThrowsXmlException()
|
||||
{
|
||||
string xml = "<element testAttr=\"not-a-float\" />";
|
||||
using XmlReader reader = CreateXmlReader(xml);
|
||||
Assert.Throws<XmlException>(() => reader.GetAttributeInt("testAttr"));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("true", true)]
|
||||
[InlineData("false", false)]
|
||||
[InlineData("True", true)]
|
||||
[InlineData("False", false)]
|
||||
public void GetAttributeBool_ValidValues_ReturnsCorrectBool(string value, bool expected)
|
||||
{
|
||||
string xml = $"<element testAttr=\"{value}\" />";
|
||||
using XmlReader reader = CreateXmlReader(xml);
|
||||
bool actual = reader.GetAttributeBool("testAttr");
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetAttributeBool_InvalidFormat_ThrowsXmlException()
|
||||
{
|
||||
string xml = "<element testAttr=\"maybe\" />";
|
||||
using XmlReader reader = CreateXmlReader(xml);
|
||||
Assert.Throws<XmlException>(() => reader.GetAttributeInt("testAttr"));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(nameof(PlayerIndex.One), PlayerIndex.One)]
|
||||
[InlineData(nameof(PlayerIndex.Two), PlayerIndex.Two)]
|
||||
[InlineData(nameof(PlayerIndex.Three), PlayerIndex.Three)]
|
||||
[InlineData(nameof(PlayerIndex.Four), PlayerIndex.Four)]
|
||||
public void GetAttributeEnum_ValidValues_ReturnsCorrectEnum(string value, PlayerIndex expected)
|
||||
{
|
||||
string xml = $"<element testAttr=\"{value}\" />";
|
||||
using XmlReader reader = CreateXmlReader(xml);
|
||||
PlayerIndex actual = reader.GetAttributeEnum<PlayerIndex>("testAttr");
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetAttributeEnum_MissingAttribute_ThrowsXmlException()
|
||||
{
|
||||
string xml = "<element />";
|
||||
using XmlReader reader = CreateXmlReader(xml);
|
||||
Assert.Throws<XmlException>(() => reader.GetAttributeInt("testAttr"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetAttributeEnum_InvalidValue_ThrowsXmlException()
|
||||
{
|
||||
string xml = "<element testAttr=\"InvalidEnumValue\" />";
|
||||
using XmlReader reader = CreateXmlReader(xml);
|
||||
Assert.Throws<XmlException>(() => reader.GetAttributeInt("testAttr"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetAttributeRectangle_ValidValue_ReturnsCorrectRectangle()
|
||||
{
|
||||
Rectangle expected = new Rectangle(1, 2, 3, 4);
|
||||
|
||||
string xml = $"<element testAttr=\"{expected.X},{expected.Y},{expected.Width},{expected.Height}\" />";
|
||||
using XmlReader reader = CreateXmlReader(xml);
|
||||
Rectangle actual = reader.GetAttributeRectangle("testAttr");
|
||||
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetAttributeRectangle_MissingAttribute_ThrowsXmlException()
|
||||
{
|
||||
string xml = "<element />";
|
||||
using XmlReader reader = CreateXmlReader(xml);
|
||||
Assert.Throws<XmlException>(() => reader.GetAttributeInt("testAttr"));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("1,2,3")]
|
||||
[InlineData("1,2,3,4,5")]
|
||||
[InlineData("a,b,c,d")]
|
||||
[InlineData("1.5,2,3,4")]
|
||||
public void GetAttributeRectangle_InvalidFormat_ThrowsXmlException(string value)
|
||||
{
|
||||
string xml = $"<element testAttr=\"{value}\" />";
|
||||
using XmlReader reader = CreateXmlReader(xml);
|
||||
Assert.Throws<XmlException>(() => reader.GetAttributeInt("testAttr"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetAttributeVector2_ValidValue_ReturnsCorrectVector2()
|
||||
{
|
||||
Vector2 expected = new Vector2(1.0f, 2.0f);
|
||||
|
||||
string xml = $"<element testAttr=\"{expected.X},{expected.Y}\" />";
|
||||
using XmlReader reader = CreateXmlReader(xml);
|
||||
Vector2 actual = reader.GetAttributeVector2("testAttr");
|
||||
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetAttributeVector2_MissingAttribute_ThrowsXmlException()
|
||||
{
|
||||
string xml = "<element />";
|
||||
using XmlReader reader = CreateXmlReader(xml);
|
||||
Assert.Throws<XmlException>(() => reader.GetAttributeInt("testAttr"));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("3.14")]
|
||||
[InlineData("1,2,3")]
|
||||
[InlineData("a,b")]
|
||||
public void GetAttributeVector2_InvalidFormat_ThrowsXmlException(string value)
|
||||
{
|
||||
string xml = $"<element testAttr=\"{value}\" />";
|
||||
using XmlReader reader = CreateXmlReader(xml);
|
||||
Assert.Throws<XmlException>(() => reader.GetAttributeInt("testAttr"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetAttributeVector3_ValidValue_ReturnsCorrectVector3()
|
||||
{
|
||||
Vector3 expected = new Vector3(1.0f, 2.0f, 3.0f);
|
||||
|
||||
string xml = $"<element testAttr=\"{expected.X},{expected.Y},{expected.Z}\" />";
|
||||
using XmlReader reader = CreateXmlReader(xml);
|
||||
Vector3 actual = reader.GetAttributeVector3("testAttr");
|
||||
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetAttributeVector3_MissingAttribute_ThrowsXmlException()
|
||||
{
|
||||
string xml = "<element />";
|
||||
using XmlReader reader = CreateXmlReader(xml);
|
||||
Assert.Throws<XmlException>(() => reader.GetAttributeInt("testAttr"));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("1.0,2.0")]
|
||||
[InlineData("1,2,3,4")]
|
||||
[InlineData("a,b,c")]
|
||||
public void GetAttributeVector3_InvalidFormat_ThrowsXmlException(string value)
|
||||
{
|
||||
string xml = $"<element testAttr=\"{value}\" />";
|
||||
using XmlReader reader = CreateXmlReader(xml);
|
||||
Assert.Throws<XmlException>(() => reader.GetAttributeInt("testAttr"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
// Copyright (c) Craftwork Games. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
// See LICENSE file in the project root for full license information.
|
||||
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using Microsoft.Xna.Framework;
|
||||
using MonoGame.Extended.Serialization.Xml;
|
||||
|
||||
namespace MonoGame.Extended.Tests.Serialization.Xml;
|
||||
|
||||
public class XmlWriterExtensionsTests
|
||||
{
|
||||
private static (XmlWriter writer, StringBuilder output) CreateXmlWriter()
|
||||
{
|
||||
StringBuilder output = new StringBuilder();
|
||||
|
||||
XmlWriterSettings settings = new XmlWriterSettings();
|
||||
settings.OmitXmlDeclaration = true;
|
||||
settings.Indent = true;
|
||||
|
||||
XmlWriter writer = XmlWriter.Create(output, settings);
|
||||
return (writer, output);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteAttributeInt_WritesCorrectAttribute()
|
||||
{
|
||||
(XmlWriter writer, StringBuilder output) = CreateXmlWriter();
|
||||
|
||||
writer.WriteStartElement("test");
|
||||
writer.WriteAttributeInt("value", 1);
|
||||
writer.WriteEndElement();
|
||||
writer.Flush();
|
||||
|
||||
Assert.Equal("<test value=\"1\" />", output.ToString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteAttributeFloat_WritesCorrectAttribute()
|
||||
{
|
||||
(XmlWriter writer, StringBuilder output) = CreateXmlWriter();
|
||||
|
||||
writer.WriteStartElement("test");
|
||||
writer.WriteAttributeFloat("value", 1.2f);
|
||||
writer.WriteEndElement();
|
||||
writer.Flush();
|
||||
|
||||
Assert.Equal("<test value=\"1.2\" />", output.ToString());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(true, "True")]
|
||||
[InlineData(false, "False")]
|
||||
public void WriteAttributeBool_WritesCorrectAttribute(bool value, string expected)
|
||||
{
|
||||
(XmlWriter writer, StringBuilder output) = CreateXmlWriter();
|
||||
|
||||
writer.WriteStartElement("test");
|
||||
writer.WriteAttributeBool("value", value);
|
||||
writer.WriteEndElement();
|
||||
writer.Flush();
|
||||
|
||||
Assert.Equal($"<test value=\"{expected}\" />", output.ToString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteAttributeRectangle_WritesCorrectAttribute()
|
||||
{
|
||||
(XmlWriter writer, StringBuilder output) = CreateXmlWriter();
|
||||
|
||||
Rectangle rectangle = new Rectangle(1, 2, 3, 4);
|
||||
|
||||
writer.WriteStartElement("test");
|
||||
writer.WriteAttributeRectangle("value", rectangle);
|
||||
writer.WriteEndElement();
|
||||
writer.Flush();
|
||||
|
||||
Assert.Equal($"<test value=\"{rectangle.X},{rectangle.Y},{rectangle.Width},{rectangle.Height}\" />", output.ToString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteAttributeVector2_WriteCorrectValue()
|
||||
{
|
||||
(XmlWriter writer, StringBuilder output) = CreateXmlWriter();
|
||||
|
||||
Vector2 vector = new Vector2(1.1f, 2.2f);
|
||||
|
||||
writer.WriteStartElement("test");
|
||||
writer.WriteAttributeVector2("value", vector);
|
||||
writer.WriteEndElement();
|
||||
writer.Flush();
|
||||
|
||||
Assert.Equal($"<test value=\"{vector.X},{vector.Y}\" />", output.ToString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteAttributeVector3_WriteCorrectValue()
|
||||
{
|
||||
(XmlWriter writer, StringBuilder output) = CreateXmlWriter();
|
||||
|
||||
Vector3 vector = new Vector3(1.1f, 2.2f, 3.3f);
|
||||
|
||||
writer.WriteStartElement("test");
|
||||
writer.WriteAttributeVector3("value", vector);
|
||||
writer.WriteEndElement();
|
||||
writer.Flush();
|
||||
|
||||
Assert.Equal($"<test value=\"{vector.X},{vector.Y},{vector.Z}\" />", output.ToString());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user