Skip to content

Commit f053447

Browse files
authored
Merge pull request #4 from Lelebees/main
Update SpriteCompositor to v2.1.0
2 parents e90ceef + f8143d1 commit f053447

9 files changed

Lines changed: 112 additions & 64 deletions

File tree

libraries/Lelebees.MdkScriptMixin.SpriteCompositor/Lelebees.MdkScriptMixin.SpriteCompositor/_releasenotes

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,8 @@
1515
Further reduced runtime memory allocation when rendering drawables by replacing Sprite groups with Composite Sprites.
1616
Moved Mirror functionality to the Sprites abstract class.
1717
Added Repeat- methods to Sprites class for Scale and Translate respectively.
18-
Break previous behaviour where you could edit a Sprite Group after it's instantiation.
18+
Break previous behaviour where you could edit a Sprite Group after it's instantiation.
19+
- 2.1.0
20+
Added transform functions to Sprites that replace lost Sprite Group functionality
21+
Fixed readme being instructions for an older version of the mixin.
22+
Fixed a floating point error accumulation bug when rotating sprites
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2.0.0
1+
2.1.0

libraries/Lelebees.MdkScriptMixin.SpriteCompositor/Lelebees.MdkScriptMixin.SpriteCompositor/readme.md

Lines changed: 49 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -9,56 +9,37 @@ An API wrapper that supports composing new sprites from multiple existing ones.
99
## Usage
1010

1111
You can instantiate regular sprites using the helper methods of the `Sprites` class. These return a builder (except for
12-
`Sprites.Group()`, which returns a group directly) that can be used to further configure the initial values of the
12+
`Sprites.Compose()`, which returns a composite sprite directly) that can be used to further configure the initial values
13+
of the
1314
sprite.
1415

1516
All sprites and sprite groups implement the `Sprite` interface, which you can use to `Translate()`, `Rotate()`, or
1617
`Scale()` a sprite after instantiation, among other things. Individual Sprite types may have additional properties and
17-
methods available, like `TextureSprite`'s `Mirror()` functions.
18-
19-
See the [demo project](https://github.com/malforge/mdk2-packages/blob/main/libraries/Lelebees.MdkScriptMixin.SpriteCompositor/SpriteCompositor.Demo/Program.cs) for a detailed example.
20-
21-
### Grouping Sprites
22-
23-
You can group sprites by calling `Sprites.Group()` or creating a `new SimpleSpriteGroup()`.
24-
25-
If this implementation does
26-
not fit your needs, you can extend the `SpriteGroup` abstract class. If you do, you will be required to implement the
27-
`Clone()` and `GetChildren()` methods.
28-
29-
**Avoid creating a new list in `GetChildren()`**, as the function is invoked
30-
whenever a transformation is applied to the group. I recommend using the following example as a guide:
31-
32-
```csharp
33-
public class CustomSpriteGroup : SpriteGroup
34-
{
35-
private readonly List<Sprite> backingList;
36-
37-
public Sprite UnspecifiedSprite
38-
{
39-
get { return backingList[0]; }
40-
set { backingList[0] = value; }
41-
}
42-
43-
public TextureSprite SpecificSprite
44-
{
45-
get { return (TextureSprite) backingList[1]; }
46-
set { backingList[1] = value; }
47-
}
48-
49-
public CustomSpriteGroup(Sprite unspecifiedSprite, TextureSprite specificSprite)
50-
{
51-
this.backingList = new List<Sprite> { unspecifiedSprite, specificSprite };
52-
}
53-
54-
public override Sprite Clone() => new CustomSpriteGroup(backingList.Select(sprite => sprite.Clone()).ToList());
55-
56-
protected override List<Sprite> GetChildren() => backingList;
57-
}
58-
```
59-
60-
If, for some reason, the abstract `SpriteGroup` class also does not suit your needs, you can implement the `Sprite`
61-
interface directly, though if you feel the need to do so, there may be a structural problem with your program.
18+
methods available.
19+
20+
See
21+
the [demo project](https://github.com/malforge/mdk2-packages/blob/main/libraries/Lelebees.MdkScriptMixin.SpriteCompositor/SpriteCompositor.Demo/Program.cs)
22+
for a detailed example.
23+
24+
### Composing Sprites
25+
26+
You can compose a new sprite by calling `Sprites.Compose()` or creating a `new CompositeSprite()`. This Composite sprite
27+
will act just like a normal sprite, even though it is made up of multiple child sprites.
28+
29+
Once you have created a composite sprite, you cannot add or remove child sprites. If you need to perform operations on
30+
multiple sprites without creating a composite sprite, use the dedicated `Sprites` methods which are clarified below.
31+
32+
If these options do not
33+
not fit your needs, you can extend the `CompositeSprite` class, or implement the `Sprite` interface yourself.
34+
35+
You should avoid composing a sprite that has both `TextSprite` objects and `TextureSprite` objects as they behave
36+
differently and can cause unexpected behavior when grouped together.
37+
38+
### Performing Transformations On Groups
39+
40+
Sometimes you don't want to compose a sprite, but you do want to apply the same transformation to multiple sprites.
41+
In this case the `Sprites` abstract class has `Translate()`, `Scale()` and `Rotate()` functions available that can
42+
transform multiple sprites at once.
6243

6344
### Anchors
6445

@@ -69,22 +50,38 @@ an `Anchor` will also scale the distance to the anchor point.
6950

7051
### Displaying Sprites
7152

72-
In order to draw your composed sprites to an LCD screen, you'll need to call the `Sprite.AsRenderable()` method, which will
53+
In order to draw your composed sprites to an LCD screen, you'll need to call the `Sprite.AsRenderable()` method, which
54+
will
7355
return an array of `MySprite` objects that your sprite consists of. You can draw these to the screen in one go
7456
using the `MySpriteDrawFrame.AddRange()` method. `AsRenderable()` takes an optional `RectangleF viewport` as parameter.
7557
Supplying this will move the sprites so that (0,0) is the center of the viewport.
7658

7759
## Legal
60+
7861
`Copyright (c) 2026 Lelebees`
7962

80-
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
63+
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public
64+
License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
65+
version.
8166

82-
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
67+
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
68+
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
69+
details.
8370

84-
You should have received a copy of the GNU Lesser General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
71+
You should have received a copy of the GNU Lesser General Public License along with this program. If not,
72+
see <https://www.gnu.org/licenses/>.
8573

8674
### License
87-
You can find a copy of the [GNU General Public License](https://github.com/malforge/mdk2-packages/blob/main/libraries/Lelebees.MdkScriptMixin.SpriteCompositor/Lelebees.MdkScriptMixin.SpriteCompositor/COPYING) and [GNU Lesser General Public License](https://github.com/malforge/mdk2-packages/blob/main/libraries/Lelebees.MdkScriptMixin.SpriteCompositor/Lelebees.MdkScriptMixin.SpriteCompositor/COPYING.LESSER) next to this source code in COPYING and COPYING.LESSER respectively.
75+
76+
You can find a copy of
77+
the [GNU General Public License](https://github.com/malforge/mdk2-packages/blob/main/libraries/Lelebees.MdkScriptMixin.SpriteCompositor/Lelebees.MdkScriptMixin.SpriteCompositor/COPYING)
78+
and [GNU Lesser General Public License](https://github.com/malforge/mdk2-packages/blob/main/libraries/Lelebees.MdkScriptMixin.SpriteCompositor/Lelebees.MdkScriptMixin.SpriteCompositor/COPYING.LESSER)
79+
next to this source code in COPYING and COPYING.LESSER respectively.
8880

8981
### Reaching out
90-
You can reach me as @lelebees on Discord, or through the project's [Github Repository](https://github.com/Lelebees/mdk2-packages-sprite-compositor). Please note while reaching out on Discord that I generally do not accept random friend requests. @Mention me in the [programmable block channel](https://discord.com/channels/125011928711036928/216219467959500800) of the Keen Software House Discord Server to get a hold of me.
82+
83+
You can reach me as @lelebees on Discord, or through the
84+
project's [GitHub Repository](https://github.com/Lelebees/mdk2-packages-sprite-compositor). Please note while reaching
85+
out on Discord that I generally do not accept random friend requests. @Mention me in
86+
the [programmable block channel](https://discord.com/channels/125011928711036928/216219467959500800) of the Keen
87+
Software House Discord Server to get a hold of me.

libraries/Lelebees.MdkScriptMixin.SpriteCompositor/Lelebees.MdkScriptMixin.SpriteCompositor/src/sprite/Sprites.cs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,5 +170,54 @@ public static Sprite MirroredHorizontal(Sprite sprite, Anchor anchor = null)
170170
clone.Scale(new Vector2(-1, 1), anchor);
171171
return clone;
172172
}
173+
174+
/// <summary>
175+
/// Translate a group of sprites with the given vector
176+
/// </summary>
177+
/// <param name="vector">the offset to translate the sprites by</param>
178+
/// <param name="sprites">the sprites to translate</param>
179+
public static void Translate(Vector2 vector, params Sprite[] sprites)
180+
{
181+
foreach (var sprite in sprites) sprite.Translate(vector);
182+
}
183+
184+
/// <summary>
185+
/// Translate a group of sprites with the x and y offset
186+
/// </summary>
187+
/// <param name="x">the x-offset to translate the sprites by</param>
188+
/// <param name="y">the y-offset to translate the sprites by</param>
189+
/// <param name="sprites">the sprites to translate</param>
190+
public static void Translate(float x, float y, params Sprite[] sprites) => Translate(new Vector2(x, y), sprites);
191+
192+
/// <summary>
193+
/// Rotate a group of sprites with the given angle. Rotates in place unless an anchor is given.
194+
/// </summary>
195+
/// <param name="angle">The angle to rotate the sprites by</param>
196+
/// <param name="anchor">Optional anchor to rotate around</param>
197+
/// <param name="sprites">the sprites to rotate</param>
198+
public static void Rotate(Angle angle, Anchor anchor = null, params Sprite[] sprites)
199+
{
200+
foreach (var sprite in sprites) sprite.Rotate(angle, anchor);
201+
}
202+
203+
/// <summary>
204+
/// Scale a group of sprites with the given scalars. X and Y can scale separately. Scales in place unless an anchor is given.
205+
/// </summary>
206+
/// <param name="scalar">The amount to scale x and y by.</param>
207+
/// <param name="anchor">If passed, scales a sprite's distance to this point in addition to the sprite itself.</param>
208+
/// <param name="sprites">The sprites to scale</param>
209+
public static void Scale(Vector2 scalar, Anchor anchor = null, params Sprite[] sprites)
210+
{
211+
foreach (var sprite in sprites) sprite.Scale(scalar, anchor);
212+
}
213+
214+
/// <summary>
215+
/// Scale a group of sprites with the given scalar. Scales in place unless an anchor is given.
216+
/// </summary>
217+
/// <param name="scalar">the amount to scale the sprites by</param>
218+
/// <param name="anchor">If passed, scales a sprite's distance to this point in addition to the sprite itself.</param>
219+
/// <param name="sprites">The sprites to scale</param>
220+
public static void Scale(float scalar, Anchor anchor = null, params Sprite[] sprites) =>
221+
Scale(new Vector2(scalar, scalar), anchor, sprites);
173222
}
174223
}

libraries/Lelebees.MdkScriptMixin.SpriteCompositor/Lelebees.MdkScriptMixin.SpriteCompositor/src/sprite/atoms/TextureSprite.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
1111
You should have received a copy of the GNU Lesser General Public License along with Sprite Compositor.
1212
If not, see <https://www.gnu.org/licenses/>. */
1313

14+
using System;
1415
using VRage.Game.GUI.TextPanel;
1516
using VRageMath;
1617

@@ -51,12 +52,12 @@ public override void Scale(Vector2 scalar, Anchor anchor = null)
5152

5253
public override void Rotate(Angle angle, Anchor positionAnchor = null)
5354
{
54-
Sprite.RotationOrScale += (float)angle.Radians;
55+
Sprite.RotationOrScale = (float)((Sprite.RotationOrScale + angle.Radians) % (2 * Math.PI));
5556
base.Rotate(angle, positionAnchor);
5657
}
5758

5859
public override Sprite Clone() => new TextureSprite(Sprite);
59-
60+
6061

6162
public class TextureSpriteBuilder
6263
{

libraries/Lelebees.MdkScriptMixin.SpriteCompositor/Lelebees.MdkScriptMixin.SpriteCompositor/src/sprite/molecules/CompositeSprite.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ public virtual void Rotate(Angle angle, Anchor positionAnchor = null)
107107
{
108108
if (Children[index].Type != SpriteType.TEXT)
109109
{
110-
Children[index].RotationOrScale += (float)angle.Radians;
110+
Children[index].RotationOrScale =(float)((Children[index].RotationOrScale + angle.Radians) % (2 * Math.PI));
111111
}
112112

113113
if (anchor == Children[index].Position) continue;

libraries/Lelebees.MdkScriptMixin.SpriteCompositor/SpriteCompositor.Demo/Program.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,7 @@ This will therefore not create slanted text! */
7979
// You can also set an initial scale for text using the builder.
8080
// However, here we want to scale the distance the text has to the sun, so we supply the sun as the anchor for the scale operation.
8181
textLayer.Scale(1.5f, sunSprite);
82-
// Any new operations will be applied to the newly grouped sprites as well, but previous operations will not be applied.
83-
sunSprite.Scale(2f);
82+
sunSprite.Scale(2);
8483
// It's also possible to scale X and Y separately.
8584
}
8685

libraries/Lelebees.MdkScriptMixin.SpriteCompositor/SpriteCompositor.Demo/SpriteCompositor.Demo.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
<PrivateAssets>all</PrivateAssets>
1414
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
1515
</PackageReference>
16-
<PackageReference Include="Mal.Mdk2.PbPackager" Version="2.2.3">
16+
<PackageReference Include="Mal.Mdk2.PbPackager" Version="2.2.4">
1717
<PrivateAssets>all</PrivateAssets>
1818
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
1919
</PackageReference>

libraries/Lelebees.MdkScriptMixin.SpriteCompositor/SpriteCompositor.Test/src/sprite/atoms/TextureSpriteTest.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,8 @@ public void ArbitraryRotationsSetCorrectRotation(params double[] radians)
3434
{
3535
sprite.Rotate(angle);
3636
}
37-
38-
// Note here (and this is not obvious) that unlike the angle struct, a sprite's rotation value can grow indefinitely
39-
// This means that values above and below 2 * Math.PI are possible. The test keeps this in mind.
40-
var totalAngle = angles.Sum(angle => angle.Radians);
37+
38+
var totalAngle = angles.Sum(angle => angle.Radians) % (2 * Math.PI);
4139
Assert.That(sprite.Rotation, Is.EqualTo(totalAngle).Within(Precision));
4240
}
4341

0 commit comments

Comments
 (0)