1
0
Fork 0
mirror of https://github.com/Ellpeck/MLEM.git synced 2024-11-25 14:08:34 +01:00

Compare commits

..

No commits in common. "1795acb30e99babdce01b51f81feed630c21e2ad" and "d0ece925502067eb5303854cc21101f53d92d3e8" have entirely different histories.

65 changed files with 589 additions and 588 deletions

View file

@ -21,10 +21,6 @@ Additions
Improvements
- Allow comparing Keybind and Combination based on the amount of modifiers they have
- Allow using multiple textures in a StaticSpriteBatch
- Added GenericInput support for Buttons.None
Removals
- Marked AStar.InfiniteCost as obsolete
### MLEM.Ui
Additions

View file

@ -8,6 +8,7 @@ using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using MLEM.Extensions;
using MLEM.Misc;
using static Android.Views.SystemUiFlags;
namespace Demos.Android {
[Activity(
@ -47,7 +48,7 @@ namespace Demos.Android {
base.OnWindowFocusChanged(hasFocus);
// hide the status bar
if (hasFocus)
this.Window.DecorView.SystemUiVisibility = (StatusBarVisibility) (SystemUiFlags.ImmersiveSticky | SystemUiFlags.LayoutStable | SystemUiFlags.LayoutHideNavigation | SystemUiFlags.LayoutFullscreen | SystemUiFlags.HideNavigation | SystemUiFlags.Fullscreen);
this.Window.DecorView.SystemUiVisibility = (StatusBarVisibility) (ImmersiveSticky | LayoutStable | LayoutHideNavigation | LayoutFullscreen | HideNavigation | Fullscreen);
}
}

View file

@ -27,7 +27,7 @@ namespace Demos {
// using it having wrong coordinates and/or sizes
// the regions that are part of the atlas are then referenced by region coordinates rather than texture coordinates
// (as seen below)
var atlas = new UniformTextureAtlas(Demo.LoadContent<Texture2D>("Textures/Anim"), 4, 4);
var atlas = new UniformTextureAtlas(LoadContent<Texture2D>("Textures/Anim"), 4, 4);
// create the four animations by supplying the time per frame, and the four regions used
// note that you don't need to use a texture atlas for this, you can also simply supply the texture and the regions manually here

View file

@ -20,7 +20,7 @@ namespace Demos {
public override void LoadContent() {
base.LoadContent();
// The layout of the texture is important for auto tiling to work correctly, and is explained in the XML docs for the methods used
this.texture = Demo.LoadContent<Texture2D>("Textures/AutoTiling");
this.texture = LoadContent<Texture2D>("Textures/AutoTiling");
// in this example, a simple string array is used for layout purposes. As the AutoTiling method allows any kind of
// comparison, the actual implementation can vary (for instance, based on a more in-depth tile map)
@ -59,12 +59,12 @@ namespace Demos {
}
// the texture region supplied to the AutoTiling method should only encompass the first filler tile's location and size
AutoTiling.DrawAutoTile(this.SpriteBatch, new Vector2(x + 1, y + 1) * AutoTilingDemo.TileSize, new TextureRegion(this.texture, 0, 0, AutoTilingDemo.TileSize, AutoTilingDemo.TileSize), ConnectsTo, Color.White);
AutoTiling.DrawAutoTile(this.SpriteBatch, new Vector2(x + 1, y + 1) * TileSize, new TextureRegion(this.texture, 0, 0, TileSize, TileSize), ConnectsTo, Color.White);
// when drawing extended auto-tiles, the same rules apply, but the source texture layout is different
var background = new TextureRegion(this.texture, 0, AutoTilingDemo.TileSize * 2, AutoTilingDemo.TileSize, AutoTilingDemo.TileSize);
var overlay = new TextureRegion(this.texture, background.Area.OffsetCopy(new Point(AutoTilingDemo.TileSize, 0)));
AutoTiling.DrawExtendedAutoTile(this.SpriteBatch, new Vector2(x + 8, y + 1) * AutoTilingDemo.TileSize, background, overlay, ConnectsTo, Color.White, Color.White);
var background = new TextureRegion(this.texture, 0, TileSize * 2, TileSize, TileSize);
var overlay = new TextureRegion(this.texture, background.Area.OffsetCopy(new Point(TileSize, 0)));
AutoTiling.DrawExtendedAutoTile(this.SpriteBatch, new Vector2(x + 8, y + 1) * TileSize, background, overlay, ConnectsTo, Color.White, Color.White);
}
}
this.SpriteBatch.End();

View file

@ -6,55 +6,55 @@ of the font in your game, and to change the characters which are available to dr
with.
-->
<XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics">
<Asset Type="Graphics:FontDescription">
<!--
Modify this string to change the font that will be imported.
-->
<FontName>JetBrainsMono-Regular.ttf</FontName>
<!--
Size is a float value, measured in points. Modify this value to change
the size of the font.
-->
<Size>32</Size>
<!--
Spacing is a float value, measured in pixels. Modify this value to change
the amount of spacing in between characters.
-->
<Spacing>0</Spacing>
<!--
UseKerning controls the layout of the font. If this value is true, kerning information
will be used when placing characters.
-->
<UseKerning>true</UseKerning>
<!--
Style controls the style of the font. Valid entries are "Regular", "Bold", "Italic",
and "Bold, Italic", and are case sensitive.
-->
<Style>Regular</Style>
<!--
If you uncomment this line, the default character will be substituted if you draw
or measure text that contains characters which were not included in the font.
-->
<DefaultCharacter>*</DefaultCharacter>
<!--
CharacterRegions control what letters are available in the font. Every
character from Start to End will be built and made available for drawing. The
default range is from 32, (ASCII space), to 126, ('~'), covering the basic Latin
character set. The characters are ordered according to the Unicode standard.
See the documentation for more information.
-->
<CharacterRegions>
<CharacterRegion>
<Start>&#32;</Start>
<End>&#591;</End>
</CharacterRegion>
</CharacterRegions>
</Asset>
<Asset Type="Graphics:FontDescription">
<!--
Modify this string to change the font that will be imported.
-->
<FontName>JetBrainsMono-Regular.ttf</FontName>
<!--
Size is a float value, measured in points. Modify this value to change
the size of the font.
-->
<Size>32</Size>
<!--
Spacing is a float value, measured in pixels. Modify this value to change
the amount of spacing in between characters.
-->
<Spacing>0</Spacing>
<!--
UseKerning controls the layout of the font. If this value is true, kerning information
will be used when placing characters.
-->
<UseKerning>true</UseKerning>
<!--
Style controls the style of the font. Valid entries are "Regular", "Bold", "Italic",
and "Bold, Italic", and are case sensitive.
-->
<Style>Regular</Style>
<!--
If you uncomment this line, the default character will be substituted if you draw
or measure text that contains characters which were not included in the font.
-->
<DefaultCharacter>*</DefaultCharacter>
<!--
CharacterRegions control what letters are available in the font. Every
character from Start to End will be built and made available for drawing. The
default range is from 32, (ASCII space), to 126, ('~'), covering the basic Latin
character set. The characters are ordered according to the Unicode standard.
See the documentation for more information.
-->
<CharacterRegions>
<CharacterRegion>
<Start>&#32;</Start>
<End>&#591;</End>
</CharacterRegion>
</CharacterRegions>
</Asset>
</XnaContent>

View file

@ -6,55 +6,55 @@ of the font in your game, and to change the characters which are available to dr
with.
-->
<XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics">
<Asset Type="Graphics:FontDescription">
<!--
Modify this string to change the font that will be imported.
-->
<FontName>CAYETANO.ttf</FontName>
<!--
Size is a float value, measured in points. Modify this value to change
the size of the font.
-->
<Size>32</Size>
<!--
Spacing is a float value, measured in pixels. Modify this value to change
the amount of spacing in between characters.
-->
<Spacing>0</Spacing>
<!--
UseKerning controls the layout of the font. If this value is true, kerning information
will be used when placing characters.
-->
<UseKerning>true</UseKerning>
<!--
Style controls the style of the font. Valid entries are "Regular", "Bold", "Italic",
and "Bold, Italic", and are case sensitive.
-->
<Style>Regular</Style>
<!--
If you uncomment this line, the default character will be substituted if you draw
or measure text that contains characters which were not included in the font.
-->
<DefaultCharacter>*</DefaultCharacter>
<!--
CharacterRegions control what letters are available in the font. Every
character from Start to End will be built and made available for drawing. The
default range is from 32, (ASCII space), to 126, ('~'), covering the basic Latin
character set. The characters are ordered according to the Unicode standard.
See the documentation for more information.
-->
<CharacterRegions>
<CharacterRegion>
<Start>&#32;</Start>
<End>&#591;</End>
</CharacterRegion>
</CharacterRegions>
</Asset>
<Asset Type="Graphics:FontDescription">
<!--
Modify this string to change the font that will be imported.
-->
<FontName>CAYETANO.ttf</FontName>
<!--
Size is a float value, measured in points. Modify this value to change
the size of the font.
-->
<Size>32</Size>
<!--
Spacing is a float value, measured in pixels. Modify this value to change
the amount of spacing in between characters.
-->
<Spacing>0</Spacing>
<!--
UseKerning controls the layout of the font. If this value is true, kerning information
will be used when placing characters.
-->
<UseKerning>true</UseKerning>
<!--
Style controls the style of the font. Valid entries are "Regular", "Bold", "Italic",
and "Bold, Italic", and are case sensitive.
-->
<Style>Regular</Style>
<!--
If you uncomment this line, the default character will be substituted if you draw
or measure text that contains characters which were not included in the font.
-->
<DefaultCharacter>*</DefaultCharacter>
<!--
CharacterRegions control what letters are available in the font. Every
character from Start to End will be built and made available for drawing. The
default range is from 32, (ASCII space), to 126, ('~'), covering the basic Latin
character set. The characters are ordered according to the Unicode standard.
See the documentation for more information.
-->
<CharacterRegions>
<CharacterRegion>
<Start>&#32;</Start>
<End>&#591;</End>
</CharacterRegion>
</CharacterRegions>
</Asset>
</XnaContent>

View file

@ -6,55 +6,55 @@ of the font in your game, and to change the characters which are available to dr
with.
-->
<XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics">
<Asset Type="Graphics:FontDescription">
<!--
Modify this string to change the font that will be imported.
-->
<FontName>CAYTANOB</FontName>
<!--
Size is a float value, measured in points. Modify this value to change
the size of the font.
-->
<Size>32</Size>
<!--
Spacing is a float value, measured in pixels. Modify this value to change
the amount of spacing in between characters.
-->
<Spacing>0</Spacing>
<!--
UseKerning controls the layout of the font. If this value is true, kerning information
will be used when placing characters.
-->
<UseKerning>true</UseKerning>
<!--
Style controls the style of the font. Valid entries are "Regular", "Bold", "Italic",
and "Bold, Italic", and are case sensitive.
-->
<Style>Regular</Style>
<!--
If you uncomment this line, the default character will be substituted if you draw
or measure text that contains characters which were not included in the font.
-->
<DefaultCharacter>*</DefaultCharacter>
<!--
CharacterRegions control what letters are available in the font. Every
character from Start to End will be built and made available for drawing. The
default range is from 32, (ASCII space), to 126, ('~'), covering the basic Latin
character set. The characters are ordered according to the Unicode standard.
See the documentation for more information.
-->
<CharacterRegions>
<CharacterRegion>
<Start>&#32;</Start>
<End>&#591;</End>
</CharacterRegion>
</CharacterRegions>
</Asset>
<Asset Type="Graphics:FontDescription">
<!--
Modify this string to change the font that will be imported.
-->
<FontName>CAYTANOB</FontName>
<!--
Size is a float value, measured in points. Modify this value to change
the size of the font.
-->
<Size>32</Size>
<!--
Spacing is a float value, measured in pixels. Modify this value to change
the amount of spacing in between characters.
-->
<Spacing>0</Spacing>
<!--
UseKerning controls the layout of the font. If this value is true, kerning information
will be used when placing characters.
-->
<UseKerning>true</UseKerning>
<!--
Style controls the style of the font. Valid entries are "Regular", "Bold", "Italic",
and "Bold, Italic", and are case sensitive.
-->
<Style>Regular</Style>
<!--
If you uncomment this line, the default character will be substituted if you draw
or measure text that contains characters which were not included in the font.
-->
<DefaultCharacter>*</DefaultCharacter>
<!--
CharacterRegions control what letters are available in the font. Every
character from Start to End will be built and made available for drawing. The
default range is from 32, (ASCII space), to 126, ('~'), covering the basic Latin
character set. The characters are ordered according to the Unicode standard.
See the documentation for more information.
-->
<CharacterRegions>
<CharacterRegion>
<Start>&#32;</Start>
<End>&#591;</End>
</CharacterRegion>
</CharacterRegions>
</Asset>
</XnaContent>

View file

@ -6,55 +6,55 @@ of the font in your game, and to change the characters which are available to dr
with.
-->
<XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics">
<Asset Type="Graphics:FontDescription">
<!--
Modify this string to change the font that will be imported.
-->
<FontName>CAYETANI</FontName>
<!--
Size is a float value, measured in points. Modify this value to change
the size of the font.
-->
<Size>32</Size>
<!--
Spacing is a float value, measured in pixels. Modify this value to change
the amount of spacing in between characters.
-->
<Spacing>0</Spacing>
<!--
UseKerning controls the layout of the font. If this value is true, kerning information
will be used when placing characters.
-->
<UseKerning>true</UseKerning>
<!--
Style controls the style of the font. Valid entries are "Regular", "Bold", "Italic",
and "Bold, Italic", and are case sensitive.
-->
<Style>Regular</Style>
<!--
If you uncomment this line, the default character will be substituted if you draw
or measure text that contains characters which were not included in the font.
-->
<DefaultCharacter>*</DefaultCharacter>
<!--
CharacterRegions control what letters are available in the font. Every
character from Start to End will be built and made available for drawing. The
default range is from 32, (ASCII space), to 126, ('~'), covering the basic Latin
character set. The characters are ordered according to the Unicode standard.
See the documentation for more information.
-->
<CharacterRegions>
<CharacterRegion>
<Start>&#32;</Start>
<End>&#591;</End>
</CharacterRegion>
</CharacterRegions>
</Asset>
<Asset Type="Graphics:FontDescription">
<!--
Modify this string to change the font that will be imported.
-->
<FontName>CAYETANI</FontName>
<!--
Size is a float value, measured in points. Modify this value to change
the size of the font.
-->
<Size>32</Size>
<!--
Spacing is a float value, measured in pixels. Modify this value to change
the amount of spacing in between characters.
-->
<Spacing>0</Spacing>
<!--
UseKerning controls the layout of the font. If this value is true, kerning information
will be used when placing characters.
-->
<UseKerning>true</UseKerning>
<!--
Style controls the style of the font. Valid entries are "Regular", "Bold", "Italic",
and "Bold, Italic", and are case sensitive.
-->
<Style>Regular</Style>
<!--
If you uncomment this line, the default character will be substituted if you draw
or measure text that contains characters which were not included in the font.
-->
<DefaultCharacter>*</DefaultCharacter>
<!--
CharacterRegions control what letters are available in the font. Every
character from Start to End will be built and made available for drawing. The
default range is from 32, (ASCII space), to 126, ('~'), covering the basic Latin
character set. The characters are ordered according to the Unicode standard.
See the documentation for more information.
-->
<CharacterRegions>
<CharacterRegion>
<Start>&#32;</Start>
<End>&#591;</End>
</CharacterRegion>
</CharacterRegions>
</Asset>
</XnaContent>

View file

@ -13,7 +13,7 @@ namespace Demos {
private static readonly FieldInfo[] EasingFields = typeof(Easings)
.GetFields(BindingFlags.Public | BindingFlags.Static).ToArray();
private static readonly Easings.Easing[] Easings = EasingsDemo.EasingFields
private static readonly Easings.Easing[] Easings = EasingFields
.Select(f => (Easings.Easing) f.GetValue(null)).ToArray();
private Group group;
private int current;
@ -27,11 +27,11 @@ namespace Demos {
this.group = new Group(Anchor.TopCenter, Vector2.One) {CanBeMoused = false};
this.group.AddChild(new Button(Anchor.AutoCenter, new Vector2(30, 10), "Next") {
OnPressed = e => {
this.current = (this.current + 1) % EasingsDemo.Easings.Length;
this.current = (this.current + 1) % Easings.Length;
this.progress = 0;
}
});
this.group.AddChild(new Paragraph(Anchor.AutoCenter, 1, p => EasingsDemo.EasingFields[this.current].Name, true));
this.group.AddChild(new Paragraph(Anchor.AutoCenter, 1, p => EasingFields[this.current].Name, true));
this.UiRoot.AddChild(this.group);
}
@ -47,7 +47,7 @@ namespace Demos {
var view = this.GraphicsDevice.Viewport;
// graph the easing function
var graphEase = EasingsDemo.Easings[this.current].ScaleInput(0, view.Width).ScaleOutput(-view.Height / 3, view.Height / 3);
var graphEase = Easings[this.current].ScaleInput(0, view.Width).ScaleOutput(-view.Height / 3, view.Height / 3);
for (var x = 0; x < view.Width; x++) {
var area = new RectangleF(x - 2, view.Height / 2 - graphEase(x) - 2, 4, 4);
this.SpriteBatch.Draw(this.SpriteBatch.GetBlankTexture(), area, Color.Green);
@ -55,7 +55,7 @@ namespace Demos {
// draw a little dot to show what it would look like
this.progress = (this.progress + (float) time.ElapsedGameTime.TotalSeconds / 2) % 1;
var dotEase = EasingsDemo.Easings[this.current].AndReverse().ScaleOutput(0, view.Height / 4);
var dotEase = Easings[this.current].AndReverse().ScaleOutput(0, view.Height / 4);
var pos = new RectangleF(view.Width / 2 - 4, view.Height - 20 - dotEase(this.progress), 8, 8);
this.SpriteBatch.Draw(this.SpriteBatch.GetBlankTexture(), pos, Color.Red);

View file

@ -23,11 +23,11 @@ namespace Demos {
private TimeSpan secondCounter;
static GameImpl() {
GameImpl.Demos.Add("Ui", ("An in-depth demonstration of the MLEM.Ui package and its abilities", game => new UiDemo(game)));
GameImpl.Demos.Add("Easings", ("An example of MLEM's Easings class, an adaptation of easings.net", game => new EasingsDemo(game)));
GameImpl.Demos.Add("Pathfinding", ("An example of MLEM's A* pathfinding implementation in 2D", game => new PathfindingDemo(game)));
GameImpl.Demos.Add("Animation and Texture Atlas", ("An example of UniformTextureAtlases, SpriteAnimations and SpriteAnimationGroups", game => new AnimationDemo(game)));
GameImpl.Demos.Add("Auto Tiling", ("A demonstration of the AutoTiling class that MLEM provides", game => new AutoTilingDemo(game)));
Demos.Add("Ui", ("An in-depth demonstration of the MLEM.Ui package and its abilities", game => new UiDemo(game)));
Demos.Add("Easings", ("An example of MLEM's Easings class, an adaptation of easings.net", game => new EasingsDemo(game)));
Demos.Add("Pathfinding", ("An example of MLEM's A* pathfinding implementation in 2D", game => new PathfindingDemo(game)));
Demos.Add("Animation and Texture Atlas", ("An example of UniformTextureAtlases, SpriteAnimations and SpriteAnimationGroups", game => new AnimationDemo(game)));
Demos.Add("Auto Tiling", ("A demonstration of the AutoTiling class that MLEM provides", game => new AutoTilingDemo(game)));
}
public GameImpl() {
@ -74,7 +74,7 @@ namespace Demos {
selection.AddChild(new Paragraph(Anchor.AutoLeft, 1, "Select the demo you want to see below using your mouse, touch input, your keyboard or a controller. Check the demos' <l https://github.com/Ellpeck/MLEM/tree/main/Demos>source code</l> for more in-depth explanations of their functionality or the <l https://mlem.ellpeck.de/>website</l> for tutorials and API documentation."));
selection.AddChild(new VerticalSpace(5));
foreach (var demo in GameImpl.Demos) {
foreach (var demo in Demos) {
selection.AddChild(new Button(Anchor.AutoCenter, new Vector2(1, 10), demo.Key, demo.Value.Item1) {
OnPressed = e => {
selection.IsHidden = true;
@ -92,9 +92,9 @@ namespace Demos {
}
protected override UiStyle InitializeDefaultUiStyle(SpriteBatch batch) {
var tex = MlemGame.LoadContent<Texture2D>("Textures/Test");
var tex = LoadContent<Texture2D>("Textures/Test");
return new UntexturedStyle(this.SpriteBatch) {
Font = new GenericSpriteFont(MlemGame.LoadContent<SpriteFont>("Fonts/TestFont")),
Font = new GenericSpriteFont(LoadContent<SpriteFont>("Fonts/TestFont")),
TextScale = 0.1F,
PanelTexture = new NinePatch(new TextureRegion(tex, 0, 8, 24, 24), 8),
ButtonTexture = new NinePatch(new TextureRegion(tex, 24, 8, 16, 16), 4),

View file

@ -41,8 +41,8 @@ namespace Demos {
// pathfinder's constructor
float Cost(Point pos, Point nextPos) {
if (nextPos.X < 0 || nextPos.Y < 0 || nextPos.X >= 50 || nextPos.Y >= 50)
return float.PositiveInfinity;
return this.world[nextPos.X, nextPos.Y] ? 1 : float.PositiveInfinity;
return AStar2.InfiniteCost;
return this.world[nextPos.X, nextPos.Y] ? 1 : AStar2.InfiniteCost;
}
// Actually initialize the pathfinder with the cost function, as well as specify if moving diagonally between tiles should be

View file

@ -28,7 +28,7 @@ namespace Demos {
public UiDemo(MlemGame game) : base(game) {}
public override void LoadContent() {
this.testTexture = Demo.LoadContent<Texture2D>("Textures/Test");
this.testTexture = LoadContent<Texture2D>("Textures/Test");
this.testPatch = new NinePatch(new TextureRegion(this.testTexture, 0, 8, 24, 24), 8);
base.LoadContent();
@ -38,10 +38,7 @@ namespace Demos {
// when using a SpriteFont, use GenericSpriteFont. When using a MonoGame.Extended BitmapFont, use GenericBitmapFont.
// Wrapping fonts like this allows for both types to be usable within MLEM.Ui easily
// Supplying a bold and an italic version is optional
Font = new GenericSpriteFont(
Demo.LoadContent<SpriteFont>("Fonts/TestFont"),
Demo.LoadContent<SpriteFont>("Fonts/TestFontBold"),
Demo.LoadContent<SpriteFont>("Fonts/TestFontItalic")),
Font = new GenericSpriteFont(LoadContent<SpriteFont>("Fonts/TestFont"), LoadContent<SpriteFont>("Fonts/TestFontBold"), LoadContent<SpriteFont>("Fonts/TestFontItalic")),
TextScale = 0.1F,
PanelTexture = this.testPatch,
ButtonTexture = new NinePatch(new TextureRegion(this.testTexture, 24, 8, 16, 16), 4),
@ -52,7 +49,7 @@ namespace Demos {
CheckboxCheckmark = new TextureRegion(this.testTexture, 24, 0, 8, 8),
RadioTexture = new NinePatch(new TextureRegion(this.testTexture, 16, 0, 8, 8), 3),
RadioCheckmark = new TextureRegion(this.testTexture, 32, 0, 8, 8),
AdditionalFonts = {{"Monospaced", new GenericSpriteFont(Demo.LoadContent<SpriteFont>("Fonts/MonospacedFont"))}},
AdditionalFonts = {{"Monospaced", new GenericSpriteFont(LoadContent<SpriteFont>("Fonts/MonospacedFont"))}},
LinkColor = Color.CornflowerBlue
};
var untexturedStyle = new UntexturedStyle(this.SpriteBatch) {
@ -161,7 +158,7 @@ namespace Demos {
// Check the WobbleButton method for an explanation of how this button works
this.root.AddChild(new Button(Anchor.AutoCenter, new Vector2(0.5F, 10), "Wobble Me", "This button wobbles around visually when clicked, but this doesn't affect its actual size and positioning") {
OnPressed = element => CoroutineHandler.Start(UiDemo.WobbleButton(element)),
OnPressed = element => CoroutineHandler.Start(WobbleButton(element)),
PositionOffset = new Vector2(0, 1)
});
// Another button that shows animations!
@ -194,13 +191,13 @@ namespace Demos {
this.root.AddChild(new VerticalSpace(3));
this.root.AddChild(new Paragraph(Anchor.AutoLeft, 1, "Progress bars!"));
var bar1 = this.root.AddChild(new ProgressBar(Anchor.AutoLeft, new Vector2(1, 8), Direction2.Right, 10) {PositionOffset = new Vector2(0, 1)});
CoroutineHandler.Start(UiDemo.WobbleProgressBar(bar1));
CoroutineHandler.Start(WobbleProgressBar(bar1));
var bar2 = this.root.AddChild(new ProgressBar(Anchor.AutoLeft, new Vector2(1, 8), Direction2.Left, 10) {PositionOffset = new Vector2(0, 1)});
CoroutineHandler.Start(UiDemo.WobbleProgressBar(bar2));
CoroutineHandler.Start(WobbleProgressBar(bar2));
var bar3 = this.root.AddChild(new ProgressBar(Anchor.AutoLeft, new Vector2(8, 30), Direction2.Down, 10) {PositionOffset = new Vector2(0, 1)});
CoroutineHandler.Start(UiDemo.WobbleProgressBar(bar3));
CoroutineHandler.Start(WobbleProgressBar(bar3));
var bar4 = this.root.AddChild(new ProgressBar(Anchor.AutoInline, new Vector2(8, 30), Direction2.Up, 10) {PositionOffset = new Vector2(1, 0)});
CoroutineHandler.Start(UiDemo.WobbleProgressBar(bar4));
CoroutineHandler.Start(WobbleProgressBar(bar4));
this.root.AddChild(new VerticalSpace(3));
var dropdown = this.root.AddChild(new Dropdown(Anchor.AutoLeft, new Vector2(1, 10), "Dropdown Menu"));

View file

@ -56,9 +56,9 @@ namespace MLEM.Data.Content {
private T Read<T>(string assetName, T existing) {
var triedFiles = new List<string>();
if (RawContentManager.readers == null)
RawContentManager.readers = RawContentManager.CollectContentReaders();
foreach (var reader in RawContentManager.readers) {
if (readers == null)
readers = CollectContentReaders();
foreach (var reader in readers) {
if (!reader.CanRead(typeof(T)))
continue;
foreach (var ext in reader.GetFileExtensions()) {

View file

@ -21,7 +21,7 @@ namespace MLEM.Data {
/// <param name="content">The content manager to add the json serializer to</param>
/// <param name="serializer">The json serializer to add</param>
public static void SetJsonSerializer(this ContentManager content, JsonSerializer serializer) {
ContentExtensions.Serializers[content] = serializer;
Serializers[content] = serializer;
}
/// <summary>
@ -31,7 +31,7 @@ namespace MLEM.Data {
/// <param name="content">The content manager whose serializer to get</param>
/// <returns>The content manager's serializer</returns>
public static JsonSerializer GetJsonSerializer(this ContentManager content) {
if (!ContentExtensions.Serializers.TryGetValue(content, out var serializer)) {
if (!Serializers.TryGetValue(content, out var serializer)) {
serializer = JsonConverters.AddAll(new JsonSerializer());
content.SetJsonSerializer(serializer);
}
@ -44,7 +44,7 @@ namespace MLEM.Data {
/// <param name="content">The content manager to add the converter to</param>
/// <param name="converter">The converter to add</param>
public static void AddJsonConverter(this ContentManager content, JsonConverter converter) {
var serializer = content.GetJsonSerializer();
var serializer = GetJsonSerializer(content);
serializer.Converters.Add(converter);
}
@ -60,7 +60,7 @@ namespace MLEM.Data {
public static T LoadJson<T>(this ContentManager content, string name, string[] extensions = null, JsonSerializer serializer = null) {
var triedFiles = new List<string>();
var serializerToUse = serializer ?? content.GetJsonSerializer();
foreach (var extension in extensions ?? ContentExtensions.JsonExtensions) {
foreach (var extension in extensions ?? JsonExtensions) {
var file = Path.Combine(content.RootDirectory, name + extension);
triedFiles.Add(file);
try {

View file

@ -23,8 +23,8 @@ namespace MLEM.Data {
/// <typeparam name="T">The type of the object to copy</typeparam>
/// <returns>A shallow copy of the object</returns>
[Obsolete("CopyExtensions has major flaws and insufficient speed compared to other libraries specifically designed for copying objects.")]
public static T Copy<T>(this T obj, BindingFlags flags = CopyExtensions.DefaultFlags, Predicate<FieldInfo> fieldInclusion = null) {
var copy = (T) CopyExtensions.Construct(typeof(T), flags);
public static T Copy<T>(this T obj, BindingFlags flags = DefaultFlags, Predicate<FieldInfo> fieldInclusion = null) {
var copy = (T) Construct(typeof(T), flags);
obj.CopyInto(copy, flags, fieldInclusion);
return copy;
}
@ -39,8 +39,8 @@ namespace MLEM.Data {
/// <typeparam name="T">The type of the object to copy</typeparam>
/// <returns>A deep copy of the object</returns>
[Obsolete("CopyExtensions has major flaws and insufficient speed compared to other libraries specifically designed for copying objects.")]
public static T DeepCopy<T>(this T obj, BindingFlags flags = CopyExtensions.DefaultFlags, Predicate<FieldInfo> fieldInclusion = null) {
var copy = (T) CopyExtensions.Construct(typeof(T), flags);
public static T DeepCopy<T>(this T obj, BindingFlags flags = DefaultFlags, Predicate<FieldInfo> fieldInclusion = null) {
var copy = (T) Construct(typeof(T), flags);
obj.DeepCopyInto(copy, flags, fieldInclusion);
return copy;
}
@ -54,7 +54,7 @@ namespace MLEM.Data {
/// <param name="fieldInclusion">A predicate that determines whether or not the given field should be copied. If null, all fields will be copied.</param>
/// <typeparam name="T">The type of the object to copy</typeparam>
[Obsolete("CopyExtensions has major flaws and insufficient speed compared to other libraries specifically designed for copying objects.")]
public static void CopyInto<T>(this T obj, T otherObj, BindingFlags flags = CopyExtensions.DefaultFlags, Predicate<FieldInfo> fieldInclusion = null) {
public static void CopyInto<T>(this T obj, T otherObj, BindingFlags flags = DefaultFlags, Predicate<FieldInfo> fieldInclusion = null) {
foreach (var field in typeof(T).GetFields(flags)) {
if (fieldInclusion == null || fieldInclusion(field))
field.SetValue(otherObj, field.GetValue(obj));
@ -71,7 +71,7 @@ namespace MLEM.Data {
/// <param name="fieldInclusion">A predicate that determines whether or not the given field should be copied. If null, all fields will be copied.</param>
/// <typeparam name="T">The type of the object to copy</typeparam>
[Obsolete("CopyExtensions has major flaws and insufficient speed compared to other libraries specifically designed for copying objects.")]
public static void DeepCopyInto<T>(this T obj, T otherObj, BindingFlags flags = CopyExtensions.DefaultFlags, Predicate<FieldInfo> fieldInclusion = null) {
public static void DeepCopyInto<T>(this T obj, T otherObj, BindingFlags flags = DefaultFlags, Predicate<FieldInfo> fieldInclusion = null) {
foreach (var field in obj.GetType().GetFields(flags)) {
if (fieldInclusion != null && !fieldInclusion(field))
continue;
@ -83,7 +83,7 @@ namespace MLEM.Data {
var otherVal = field.GetValue(otherObj);
// if the object we want to copy into doesn't have a value yet, we create one
if (otherVal == null) {
otherVal = CopyExtensions.Construct(field.FieldType, flags);
otherVal = Construct(field.FieldType, flags);
field.SetValue(otherObj, otherVal);
}
val.DeepCopyInto(otherVal, flags);
@ -92,7 +92,7 @@ namespace MLEM.Data {
}
private static object Construct(Type t, BindingFlags flags) {
if (!CopyExtensions.ConstructorCache.TryGetValue(t, out var constructor)) {
if (!ConstructorCache.TryGetValue(t, out var constructor)) {
var constructors = t.GetConstructors(flags);
// find a contructor with the correct attribute
constructor = constructors.FirstOrDefault(c => c.GetCustomAttribute<CopyConstructorAttribute>() != null);
@ -104,7 +104,7 @@ namespace MLEM.Data {
constructor = constructors.FirstOrDefault();
if (constructor == null)
throw new NullReferenceException($"Type {t} does not have a constructor with the required visibility");
CopyExtensions.ConstructorCache.Add(t, constructor);
ConstructorCache.Add(t, constructor);
}
return constructor.Invoke(new object[constructor.GetParameters().Length]);
}

View file

@ -60,7 +60,7 @@ namespace MLEM.Data {
if (this.allFlagsCache == null)
this.allFlagsCache = new Dictionary<DynamicEnum, bool>();
if (!this.allFlagsCache.TryGetValue(flags, out var ret)) {
ret = (DynamicEnum.GetValue(this) & DynamicEnum.GetValue(flags)) == DynamicEnum.GetValue(flags);
ret = (GetValue(this) & GetValue(flags)) == GetValue(flags);
this.allFlagsCache.Add(flags, ret);
}
return ret;
@ -76,7 +76,7 @@ namespace MLEM.Data {
if (this.anyFlagsCache == null)
this.anyFlagsCache = new Dictionary<DynamicEnum, bool>();
if (!this.anyFlagsCache.TryGetValue(flags, out var ret)) {
ret = (DynamicEnum.GetValue(this) & DynamicEnum.GetValue(flags)) != 0;
ret = (GetValue(this) & GetValue(flags)) != 0;
this.anyFlagsCache.Add(flags, ret);
}
return ret;
@ -87,13 +87,13 @@ namespace MLEM.Data {
public override string ToString() {
if (this.name == null) {
var included = new List<DynamicEnum>();
if (DynamicEnum.GetValue(this) != 0) {
foreach (var v in DynamicEnum.GetValues(this.GetType())) {
if (this.HasFlag(v) && DynamicEnum.GetValue(v) != 0)
if (GetValue(this) != 0) {
foreach (var v in GetValues(this.GetType())) {
if (this.HasFlag(v) && GetValue(v) != 0)
included.Add(v);
}
}
this.name = included.Count > 0 ? string.Join(" | ", included) : DynamicEnum.GetValue(this).ToString();
this.name = included.Count > 0 ? string.Join(" | ", included) : GetValue(this).ToString();
}
return this.name;
}
@ -107,7 +107,7 @@ namespace MLEM.Data {
/// <returns>The newly created enum value</returns>
/// <exception cref="ArgumentException">Thrown if the name or value passed are already present</exception>
public static T Add<T>(string name, BigInteger value) where T : DynamicEnum {
var storage = DynamicEnum.GetStorage(typeof(T));
var storage = GetStorage(typeof(T));
// cached parsed values and names might be incomplete with new values
storage.ClearCaches();
@ -119,7 +119,7 @@ namespace MLEM.Data {
throw new ArgumentException($"Duplicate name {name}", nameof(name));
}
var ret = DynamicEnum.Construct(typeof(T), name, value);
var ret = Construct(typeof(T), name, value);
storage.Values.Add(value, ret);
return (T) ret;
}
@ -134,9 +134,9 @@ namespace MLEM.Data {
/// <returns>The newly created enum value</returns>
public static T AddValue<T>(string name) where T : DynamicEnum {
BigInteger value = 0;
while (DynamicEnum.GetStorage(typeof(T)).Values.ContainsKey(value))
while (GetStorage(typeof(T)).Values.ContainsKey(value))
value++;
return DynamicEnum.Add<T>(name, value);
return Add<T>(name, value);
}
/// <summary>
@ -149,9 +149,9 @@ namespace MLEM.Data {
/// <returns>The newly created enum value</returns>
public static T AddFlag<T>(string name) where T : DynamicEnum {
BigInteger value = 1;
while (DynamicEnum.GetStorage(typeof(T)).Values.ContainsKey(value))
while (GetStorage(typeof(T)).Values.ContainsKey(value))
value <<= 1;
return DynamicEnum.Add<T>(name, value);
return Add<T>(name, value);
}
/// <summary>
@ -161,7 +161,7 @@ namespace MLEM.Data {
/// <typeparam name="T">The type whose values to get</typeparam>
/// <returns>The defined values for the given type</returns>
public static IEnumerable<T> GetValues<T>() where T : DynamicEnum {
return DynamicEnum.GetValues(typeof(T)).Cast<T>();
return GetValues(typeof(T)).Cast<T>();
}
/// <summary>
@ -171,7 +171,7 @@ namespace MLEM.Data {
/// <param name="type">The type whose values to get</param>
/// <returns>The defined values for the given type</returns>
public static IEnumerable<DynamicEnum> GetValues(Type type) {
return DynamicEnum.GetStorage(type).Values.Values;
return GetStorage(type).Values.Values;
}
/// <summary>
@ -182,9 +182,9 @@ namespace MLEM.Data {
/// <typeparam name="T">The type of the values</typeparam>
/// <returns>The bitwise OR (|) combination</returns>
public static T Or<T>(T left, T right) where T : DynamicEnum {
var cache = DynamicEnum.GetStorage(typeof(T)).OrCache;
var cache = GetStorage(typeof(T)).OrCache;
if (!cache.TryGetValue((left, right), out var ret)) {
ret = DynamicEnum.GetEnumValue<T>(DynamicEnum.GetValue(left) | DynamicEnum.GetValue(right));
ret = GetEnumValue<T>(GetValue(left) | GetValue(right));
cache.Add((left, right), ret);
}
return (T) ret;
@ -198,9 +198,9 @@ namespace MLEM.Data {
/// <typeparam name="T">The type of the values</typeparam>
/// <returns>The bitwise AND (&amp;) combination</returns>
public static T And<T>(T left, T right) where T : DynamicEnum {
var cache = DynamicEnum.GetStorage(typeof(T)).AndCache;
var cache = GetStorage(typeof(T)).AndCache;
if (!cache.TryGetValue((left, right), out var ret)) {
ret = DynamicEnum.GetEnumValue<T>(DynamicEnum.GetValue(left) & DynamicEnum.GetValue(right));
ret = GetEnumValue<T>(GetValue(left) & GetValue(right));
cache.Add((left, right), ret);
}
return (T) ret;
@ -214,9 +214,9 @@ namespace MLEM.Data {
/// <typeparam name="T">The type of the values</typeparam>
/// <returns>The bitwise XOR (^) combination</returns>
public static T Xor<T>(T left, T right) where T : DynamicEnum {
var cache = DynamicEnum.GetStorage(typeof(T)).XorCache;
var cache = GetStorage(typeof(T)).XorCache;
if (!cache.TryGetValue((left, right), out var ret)) {
ret = DynamicEnum.GetEnumValue<T>(DynamicEnum.GetValue(left) ^ DynamicEnum.GetValue(right));
ret = GetEnumValue<T>(GetValue(left) ^ GetValue(right));
cache.Add((left, right), ret);
}
return (T) ret;
@ -229,9 +229,9 @@ namespace MLEM.Data {
/// <typeparam name="T">The type of the values</typeparam>
/// <returns>The bitwise NEG (~) value</returns>
public static T Neg<T>(T value) where T : DynamicEnum {
var cache = DynamicEnum.GetStorage(typeof(T)).NegCache;
var cache = GetStorage(typeof(T)).NegCache;
if (!cache.TryGetValue(value, out var ret)) {
ret = DynamicEnum.GetEnumValue<T>(~DynamicEnum.GetValue(value));
ret = GetEnumValue<T>(~GetValue(value));
cache.Add(value, ret);
}
return (T) ret;
@ -253,7 +253,7 @@ namespace MLEM.Data {
/// <typeparam name="T">The type that the returned dynamic enum should have</typeparam>
/// <returns>The defined or combined dynamic enum value</returns>
public static T GetEnumValue<T>(BigInteger value) where T : DynamicEnum {
return (T) DynamicEnum.GetEnumValue(typeof(T), value);
return (T) GetEnumValue(typeof(T), value);
}
/// <summary>
@ -263,7 +263,7 @@ namespace MLEM.Data {
/// <param name="value">The value whose dynamic enum value to get</param>
/// <returns>The defined or combined dynamic enum value</returns>
public static DynamicEnum GetEnumValue(Type type, BigInteger value) {
var storage = DynamicEnum.GetStorage(type);
var storage = GetStorage(type);
// get the defined value if it exists
if (storage.Values.TryGetValue(value, out var defined))
@ -271,7 +271,7 @@ namespace MLEM.Data {
// otherwise, cache the combined value
if (!storage.FlagCache.TryGetValue(value, out var combined)) {
combined = DynamicEnum.Construct(type, null, value);
combined = Construct(type, null, value);
storage.FlagCache.Add(value, combined);
}
return combined;
@ -286,7 +286,7 @@ namespace MLEM.Data {
/// <typeparam name="T">The type of the dynamic enum value to parse</typeparam>
/// <returns>The parsed enum value, or null if parsing fails</returns>
public static T Parse<T>(string strg) where T : DynamicEnum {
return (T) DynamicEnum.Parse(typeof(T), strg);
return (T) Parse(typeof(T), strg);
}
/// <summary>
@ -297,28 +297,28 @@ namespace MLEM.Data {
/// <param name="strg">The string to parse into a dynamic enum value</param>
/// <returns>The parsed enum value, or null if parsing fails</returns>
public static DynamicEnum Parse(Type type, string strg) {
var cache = DynamicEnum.GetStorage(type).ParseCache;
var cache = GetStorage(type).ParseCache;
if (!cache.TryGetValue(strg, out var cached)) {
BigInteger? accum = null;
foreach (var val in strg.Split('|')) {
foreach (var defined in DynamicEnum.GetValues(type)) {
foreach (var defined in GetValues(type)) {
if (defined.name == val.Trim()) {
accum = (accum ?? 0) | DynamicEnum.GetValue(defined);
accum = (accum ?? 0) | GetValue(defined);
break;
}
}
}
if (accum != null)
cached = DynamicEnum.GetEnumValue(type, accum.Value);
cached = GetEnumValue(type, accum.Value);
cache.Add(strg, cached);
}
return cached;
}
private static Storage GetStorage(Type type) {
if (!DynamicEnum.Storages.TryGetValue(type, out var storage)) {
if (!Storages.TryGetValue(type, out var storage)) {
storage = new Storage();
DynamicEnum.Storages.Add(type, storage);
Storages.Add(type, storage);
}
return storage;
}

View file

@ -21,7 +21,7 @@ namespace MLEM.Data.Json {
/// <param name="serializer">The serializer to add the converters to</param>
/// <returns>The given serializer, for chaining</returns>
public static JsonSerializer AddAll(JsonSerializer serializer) {
foreach (var converter in JsonConverters.Converters)
foreach (var converter in Converters)
serializer.Converters.Add(converter);
return serializer;
}

View file

@ -29,7 +29,7 @@ namespace MLEM.Data.Json {
/// </summary>
/// <param name="type">The type that the dictionary is declared in</param>
/// <param name="memberName">The name of the dictionary itself</param>
public StaticJsonConverter(Type type, string memberName) : this(StaticJsonConverter<T>.GetEntries(type, memberName)) {}
public StaticJsonConverter(Type type, string memberName) : this(GetEntries(type, memberName)) {}
/// <summary>Writes the JSON representation of the object.</summary>
/// <param name="writer">The <see cref="T:Newtonsoft.Json.JsonWriter" /> to write to.</param>

View file

@ -81,7 +81,7 @@ namespace MLEM.Data {
var region = atlas[pos];
if (ignoreTransparent) {
if (this.IsTransparent(region))
if (IsTransparent(region))
continue;
}
@ -180,8 +180,8 @@ namespace MLEM.Data {
var width = this.alreadyPackedTextures.Max(t => t.PackedArea.Right);
var height = this.alreadyPackedTextures.Max(t => t.PackedArea.Bottom);
if (this.forcePowerOfTwo) {
width = RuntimeTexturePacker.ToPowerOfTwo(width);
height = RuntimeTexturePacker.ToPowerOfTwo(height);
width = ToPowerOfTwo(width);
height = ToPowerOfTwo(height);
}
if (this.forceSquare)
width = height = Math.Max(width, height);

View file

@ -116,7 +116,7 @@ namespace MLEM.Extended.Tiled {
/// <param name="frustum">The area that is visible, in pixel space.</param>
/// <param name="drawFunction">The draw function to use, or null to use <see cref="DefaultDraw"/></param>
public void DrawLayer(SpriteBatch batch, int layerIndex, RectangleF? frustum = null, DrawDelegate drawFunction = null) {
var draw = drawFunction ?? IndividualTiledMapRenderer.DefaultDraw;
var draw = drawFunction ?? DefaultDraw;
var (minX, minY, maxX, maxY) = this.GetFrustum(frustum);
for (var x = minX; x < maxX; x++) {
for (var y = minY; y < maxY; y++) {
@ -136,7 +136,7 @@ namespace MLEM.Extended.Tiled {
/// <param name="frustum">The area that is visible, in pixel space.</param>
/// <param name="addFunction">The add function to use, or null to use <see cref="DefaultAdd"/>.</param>
public void AddLayer(StaticSpriteBatch batch, int layerIndex, RectangleF? frustum = null, AddDelegate addFunction = null) {
var add = addFunction ?? IndividualTiledMapRenderer.DefaultAdd;
var add = addFunction ?? DefaultAdd;
var (minX, minY, maxX, maxY) = this.GetFrustum(frustum);
for (var x = minX; x < maxX; x++) {
for (var y = minY; y < maxY; y++) {

View file

@ -54,8 +54,8 @@ namespace MLEM.Extended.Tiled {
/// <returns>A 32-bit signed integer that is the hash code for this instance.</returns>
public override int GetHashCode() {
var hashCode = this.Layer.GetHashCode();
hashCode = hashCode * 397 ^ this.X;
hashCode = hashCode * 397 ^ this.Y;
hashCode = (hashCode * 397) ^ this.X;
hashCode = (hashCode * 397) ^ this.Y;
return hashCode;
}
@ -105,7 +105,7 @@ namespace MLEM.Extended.Tiled {
/// <param name="right">The right position.</param>
/// <returns>The sum of the positions.</returns>
public static LayerPosition operator +(LayerPosition left, LayerPosition right) {
return LayerPosition.Add(left, right);
return Add(left, right);
}
/// <summary>
@ -115,7 +115,7 @@ namespace MLEM.Extended.Tiled {
/// <param name="right">The right position.</param>
/// <returns>The difference of the positions.</returns>
public static LayerPosition operator -(LayerPosition left, LayerPosition right) {
return LayerPosition.Add(left, -right);
return Add(left, -right);
}
/// <summary>

View file

@ -54,8 +54,8 @@ namespace MLEM.Extended.Tiled {
/// <returns>A 32-bit signed integer that is the hash code for this instance.</returns>
public override int GetHashCode() {
var hashCode = this.Layer.GetHashCode();
hashCode = hashCode * 397 ^ this.X.GetHashCode();
hashCode = hashCode * 397 ^ this.Y.GetHashCode();
hashCode = (hashCode * 397) ^ this.X.GetHashCode();
hashCode = (hashCode * 397) ^ this.Y.GetHashCode();
return hashCode;
}
@ -105,7 +105,7 @@ namespace MLEM.Extended.Tiled {
/// <param name="right">The right position.</param>
/// <returns>The sum of the positions.</returns>
public static LayerPositionF operator +(LayerPositionF left, LayerPositionF right) {
return LayerPositionF.Add(left, right);
return Add(left, right);
}
/// <summary>
@ -115,7 +115,7 @@ namespace MLEM.Extended.Tiled {
/// <param name="right">The right position.</param>
/// <returns>The difference of the positions.</returns>
public static LayerPositionF operator -(LayerPositionF left, LayerPositionF right) {
return LayerPositionF.Add(left, -right);
return Add(left, -right);
}
/// <summary>

View file

@ -5,6 +5,7 @@ using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using MonoGame.Extended;
using MonoGame.Extended.Tiled;
using static MonoGame.Extended.Tiled.TiledMapTileFlipFlags;
using ColorHelper = MLEM.Extensions.ColorHelper;
namespace MLEM.Extended.Tiled {
@ -143,9 +144,9 @@ namespace MLEM.Extended.Tiled {
public static TiledMapTilesetTile GetTilesetTile(this TiledMapTileset tileset, int localId, bool createStub = true) {
var tilesetTile = tileset.Tiles.FirstOrDefault(t => t.LocalTileIdentifier == localId);
if (tilesetTile == null && createStub) {
if (!TiledExtensions.StubTilesetTiles.TryGetValue(localId, out tilesetTile)) {
if (!StubTilesetTiles.TryGetValue(localId, out tilesetTile)) {
tilesetTile = new TiledMapTilesetTile(localId);
TiledExtensions.StubTilesetTiles.Add(localId, tilesetTile);
StubTilesetTiles.Add(localId, tilesetTile);
}
}
return tilesetTile;
@ -270,12 +271,12 @@ namespace MLEM.Extended.Tiled {
/// <param name="position">The position to add to the object's position</param>
/// <param name="flipFlags">The flipping of the tile that this object belongs to. If set, the returned area will be "flipped" in the tile's space so that it matches the flip flags.</param>
/// <returns>The area that the tile covers</returns>
public static RectangleF GetArea(this TiledMapObject obj, TiledMap map, Vector2? position = null, TiledMapTileFlipFlags flipFlags = TiledMapTileFlipFlags.None) {
public static RectangleF GetArea(this TiledMapObject obj, TiledMap map, Vector2? position = null, TiledMapTileFlipFlags flipFlags = None) {
var tileSize = map.GetTileSize();
var area = new RectangleF(obj.Position / tileSize, obj.Size / tileSize);
if (flipFlags.HasFlag(TiledMapTileFlipFlags.FlipHorizontally))
if (flipFlags.HasFlag(FlipHorizontally))
area.X = 1 - area.X - area.Width;
if (flipFlags.HasFlag(TiledMapTileFlipFlags.FlipVertically))
if (flipFlags.HasFlag(FlipVertically))
area.Y = 1 - area.Y - area.Height;
if (position != null)
area.Offset(position.Value);

View file

@ -36,7 +36,7 @@ namespace MLEM.Extended.Tiled {
/// <param name="collisionFunction">The function used to collect the collision info of a tile, or null to use <see cref="DefaultCollectCollisions"/></param>
public void SetMap(TiledMap map, CollectCollisions collisionFunction = null) {
this.map = map;
this.collisionFunction = collisionFunction ?? TiledMapCollisions.DefaultCollectCollisions;
this.collisionFunction = collisionFunction ?? DefaultCollectCollisions;
this.collisionInfos = new TileCollisionInfo[map.Layers.Count, map.Width, map.Height];
for (var i = 0; i < map.TileLayers.Count; i++) {
for (var x = 0; x < map.Width; x++) {

View file

@ -18,7 +18,7 @@ namespace MLEM.Startup {
/// <summary>
/// The static game instance's input handler
/// </summary>
public static InputHandler Input => MlemGame.instance.InputHandler;
public static InputHandler Input => instance.InputHandler;
/// <summary>
/// This game's graphics device manager, initialized in the constructor
@ -64,7 +64,7 @@ namespace MLEM.Startup {
/// <param name="windowWidth">The default window width</param>
/// <param name="windowHeight">The default window height</param>
public MlemGame(int windowWidth = 1280, int windowHeight = 720) {
MlemGame.instance = this;
instance = this;
this.GraphicsDeviceManager = new GraphicsDeviceManager(this) {
PreferredBackBufferWidth = windowWidth,
@ -160,7 +160,7 @@ namespace MLEM.Startup {
/// <typeparam name="T">The type of content to load</typeparam>
/// <returns>The loaded content</returns>
public static T LoadContent<T>(string name) {
return MlemGame.instance.Content.Load<T>(name);
return instance.Content.Load<T>(name);
}
/// <summary>

View file

@ -652,7 +652,7 @@ namespace MLEM.Ui.Elements {
var newX = prevArea.Right + this.ScaledOffset.X;
// with awkward ui scale values, floating point rounding can cause an element that would usually
// be positioned correctly to be pushed into the next line due to a very small deviation
if (newX + newSize.X <= parentArea.Right + Element.Epsilon) {
if (newX + newSize.X <= parentArea.Right + Epsilon) {
pos.X = newX;
pos.Y = prevArea.Y + this.ScaledOffset.Y;
} else {
@ -715,7 +715,7 @@ namespace MLEM.Ui.Elements {
}
// we want to leave some leeway to prevent float rounding causing an infinite loop
if (!autoSize.Equals(this.UnscrolledArea.Size, Element.Epsilon)) {
if (!autoSize.Equals(this.UnscrolledArea.Size, Epsilon)) {
recursion++;
if (recursion >= 16) {
throw new ArithmeticException($"The area of {this} with root {this.Root.Name} has recursively updated too often. Does its child {foundChild} contain any conflicting auto-sizing settings?");

View file

@ -118,7 +118,7 @@ namespace MLEM.Ui.Elements {
/// <inheritdoc cref="KeybindButton(MLEM.Ui.Anchor,Microsoft.Xna.Framework.Vector2,MLEM.Input.Keybind,MLEM.Input.InputHandler,string,MLEM.Input.Keybind,string,System.Func{MLEM.Input.GenericInput,string},int,System.Func{MLEM.Input.GenericInput,System.Collections.Generic.IEnumerable{MLEM.Input.GenericInput},bool})"/>
public static Button KeybindButton(Anchor anchor, Vector2 size, Keybind keybind, InputHandler inputHandler, string activePlaceholder, GenericInput unbindKey = default, string unboundPlaceholder = "", Func<GenericInput, string> inputName = null, int index = 0, Func<GenericInput, IEnumerable<GenericInput>, bool> isKeybindAllowed = null) {
return ElementHelper.KeybindButton(anchor, size, keybind, inputHandler, activePlaceholder, new Keybind(unbindKey), unboundPlaceholder, inputName, index, isKeybindAllowed);
return KeybindButton(anchor, size, keybind, inputHandler, activePlaceholder, new Keybind(unbindKey), unboundPlaceholder, inputName, index, isKeybindAllowed);
}
/// <summary>
@ -139,9 +139,7 @@ namespace MLEM.Ui.Elements {
/// <param name="isKeybindAllowed">A function that can optionally determine whether a given input and modifier combination is allowed. If this is null, all combinations are allowed.</param>
/// <returns>A keybind button with the given settings</returns>
public static Button KeybindButton(Anchor anchor, Vector2 size, Keybind keybind, InputHandler inputHandler, string activePlaceholder, Keybind unbind = default, string unboundPlaceholder = "", Func<GenericInput, string> inputName = null, int index = 0, Func<GenericInput, IEnumerable<GenericInput>, bool> isKeybindAllowed = null) {
string GetCurrentName() {
return keybind.TryGetCombination(index, out var combination) ? combination.ToString(" + ", inputName) : unboundPlaceholder;
}
string GetCurrentName() => keybind.TryGetCombination(index, out var combination) ? combination.ToString(" + ", inputName) : unboundPlaceholder;
var button = new Button(anchor, size, GetCurrentName());
var activeNext = false;

View file

@ -121,7 +121,7 @@ namespace MLEM.Ui.Elements {
var offset = new Vector2(0, -this.ScrollBar.CurrentValue);
// we ignore false grandchildren so that the children of the scroll bar stay in place
foreach (var child in this.GetChildren(c => c != this.ScrollBar, true, true)) {
if (!child.ScrollOffset.Equals(offset, Element.Epsilon)) {
if (!child.ScrollOffset.Equals(offset, Epsilon)) {
child.ScrollOffset = offset;
this.relevantChildrenDirty = true;
}
@ -246,13 +246,13 @@ namespace MLEM.Ui.Elements {
// the max value of the scrollbar is the amount of non-scaled pixels taken up by overflowing components
var scrollBarMax = (childrenHeight - this.ChildPaddedArea.Height) / this.Scale;
if (!this.ScrollBar.MaxValue.Equals(scrollBarMax, Element.Epsilon)) {
if (!this.ScrollBar.MaxValue.Equals(scrollBarMax, Epsilon)) {
this.ScrollBar.MaxValue = scrollBarMax;
this.relevantChildrenDirty = true;
// update child padding based on whether the scroll bar is visible
var childOffset = this.ScrollBar.IsHidden ? 0 : this.ScrollerSize.Value.X + this.ScrollBarOffset;
if (!this.scrollBarChildOffset.Equals(childOffset, Element.Epsilon)) {
if (!this.scrollBarChildOffset.Equals(childOffset, Epsilon)) {
this.ChildPadding += new Padding(0, -this.scrollBarChildOffset + childOffset, 0, 0);
this.scrollBarChildOffset = childOffset;
this.SetAreaDirty();

View file

@ -60,7 +60,7 @@ namespace MLEM.Ui.Elements {
if (this.text != value) {
this.text = value;
this.SetTextDirty();
var force = string.IsNullOrWhiteSpace(this.text);
if (this.forceHide != force) {
this.forceHide = force;
@ -197,7 +197,7 @@ namespace MLEM.Ui.Elements {
protected void SetTextDirty() {
this.TokenizedText = null;
// only set our area dirty if our size changed as a result of this action
if (!this.AreaDirty && !this.CalcActualSize(this.ParentArea).Equals(this.DisplayArea.Size, Element.Epsilon))
if (!this.AreaDirty && !this.CalcActualSize(this.ParentArea).Equals(this.DisplayArea.Size, Epsilon))
this.SetAreaDirty();
}

View file

@ -45,7 +45,7 @@ namespace MLEM.Ui.Elements {
// force current value to be clamped
this.CurrentValue = this.CurrentValue;
// auto-hide if necessary
var shouldHide = this.maxValue <= Element.Epsilon;
var shouldHide = this.maxValue <= Epsilon;
if (this.AutoHideWhenEmpty && this.IsHidden != shouldHide) {
this.IsHidden = shouldHide;
this.OnAutoHide?.Invoke(this);
@ -188,7 +188,7 @@ namespace MLEM.Ui.Elements {
if (this.SmoothScrolling && this.scrollAdded != 0) {
this.scrollAdded *= this.SmoothScrollFactor;
if (Math.Abs(this.scrollAdded) <= Element.Epsilon)
if (Math.Abs(this.scrollAdded) <= Epsilon)
this.scrollAdded = 0;
this.OnValueChanged?.Invoke(this, this.CurrentValue);
}

View file

@ -24,7 +24,7 @@ namespace MLEM.Ui.Elements {
// we squish children in order of priority, since auto-anchoring is based on addition order
for (var i = 0; i < this.SortedChildren.Count; i++) {
var child = this.SortedChildren[i];
if (SquishingGroup.SquishChild(child, out var squished))
if (SquishChild(child, out var squished))
child.SetAreaAndUpdateChildren(squished);
}
}
@ -66,7 +66,7 @@ namespace MLEM.Ui.Elements {
}
}
}
if (!pos.Equals(element.Area.Location, Element.Epsilon) || !size.Equals(element.Area.Size, Element.Epsilon)) {
if (!pos.Equals(element.Area.Location, Epsilon) || !size.Equals(element.Area.Size, Epsilon)) {
squishedArea = new RectangleF(pos, size);
return true;
}

View file

@ -209,7 +209,7 @@ namespace MLEM.Ui.Elements {
/// <param name="text">The text that the text field should contain by default</param>
/// <param name="multiline">Whether the text field should support multi-line editing</param>
public TextField(Anchor anchor, Vector2 size, Rule rule = null, GenericFont font = null, string text = null, bool multiline = false) : base(anchor, size) {
this.InputRule = rule ?? TextField.DefaultRule;
this.InputRule = rule ?? DefaultRule;
this.Multiline = multiline;
if (font != null)
this.Font = font;

View file

@ -62,7 +62,7 @@ namespace MLEM.Ui.Parsers {
this.Style<VerticalSpace>(ElementType.VerticalSpace, v => v.Size = new Vector2(1, 5));
for (var i = 0; i < 6; i++) {
var level = i;
this.Style<Paragraph>(UiMarkdownParser.ElementTypes[Array.IndexOf(UiMarkdownParser.ElementTypes, ElementType.Header1) + i], p => {
this.Style<Paragraph>(ElementTypes[Array.IndexOf(ElementTypes, ElementType.Header1) + i], p => {
p.Alignment = TextAlignment.Center;
p.TextScaleMultiplier = 2 - level * 0.15F;
});
@ -107,7 +107,7 @@ namespace MLEM.Ui.Parsers {
/// <typeparam name="T">The type of elements that the given <see cref="ElementType"/> flags are expected to be.</typeparam>
/// <returns>This parser, for chaining.</returns>
public UiMarkdownParser Style<T>(ElementType types, Action<T> style, bool add = false) where T : Element {
foreach (var type in UiMarkdownParser.ElementTypes) {
foreach (var type in ElementTypes) {
if (types.HasFlag(type)) {
if (add && this.elementStyles.ContainsKey(type)) {
this.elementStyles[type] += Action;
@ -193,7 +193,7 @@ namespace MLEM.Ui.Parsers {
var parsedHeader = false;
for (var h = 6; h >= 1; h--) {
if (line.StartsWith(new string('#', h))) {
var type = UiMarkdownParser.ElementTypes[Array.IndexOf(UiMarkdownParser.ElementTypes, ElementType.Header1) + h - 1];
var type = ElementTypes[Array.IndexOf(ElementTypes, ElementType.Header1) + h - 1];
yield return (type, new Paragraph(Anchor.AutoLeft, 1, line.Substring(h).Trim()));
parsedHeader = true;
break;
@ -275,7 +275,7 @@ namespace MLEM.Ui.Parsers {
/// A combined flag that contains <see cref="Header1"/> through <see cref="Header6"/>.
/// This element type is a <see cref="Paragraph"/>.
/// </summary>
Headers = ElementType.Header1 | ElementType.Header2 | ElementType.Header3 | ElementType.Header4 | ElementType.Header5 | ElementType.Header6,
Headers = Header1 | Header2 | Header3 | Header4 | Header5 | Header6,
/// <summary>
/// A paragraph, which is one line of markdown text.
/// This element type is a <see cref="Paragraph"/>.

View file

@ -164,7 +164,7 @@ namespace MLEM.Cameras {
if (this.Max.Y > max.Y)
this.Max = new Vector2(this.Max.X, max.Y);
}
return !this.Position.Equals(lastPos, Camera.Epsilon);
return !this.Position.Equals(lastPos, Epsilon);
}
/// <summary>

View file

@ -15,9 +15,9 @@ namespace MLEM.Extensions {
/// <param name="c">The character to turn into a string</param>
/// <returns>A string representing the character</returns>
public static string ToCachedString(this char c) {
if (!CharExtensions.Cache.TryGetValue(c, out var ret)) {
if (!Cache.TryGetValue(c, out var ret)) {
ret = c.ToString();
CharExtensions.Cache.Add(c, ret);
Cache.Add(c, ret);
}
return ret;
}

View file

@ -50,7 +50,7 @@ namespace MLEM.Extensions {
/// <param name="value">The number to parse.</param>
/// <returns>The resulting color.</returns>
public static Color FromHexRgba(int value) {
return new Color(value >> 16 & 0xFF, value >> 8 & 0xFF, value >> 0 & 0xFF, value >> 24 & 0xFF);
return new Color((value >> 16) & 0xFF, (value >> 8) & 0xFF, (value >> 0) & 0xFF, (value >> 24) & 0xFF);
}
/// <summary>
@ -60,7 +60,7 @@ namespace MLEM.Extensions {
/// <param name="value">The number to parse.</param>
/// <returns>The resulting color.</returns>
public static Color FromHexRgb(int value) {
return new Color(value >> 16 & 0xFF, value >> 8 & 0xFF, value >> 0 & 0xFF);
return new Color((value >> 16) & 0xFF, (value >> 8) & 0xFF, (value >> 0) & 0xFF);
}
/// <summary>
@ -73,7 +73,7 @@ namespace MLEM.Extensions {
if (value.StartsWith("#"))
value = value.Substring(1);
var val = int.Parse(value, NumberStyles.HexNumber);
return value.Length > 6 ? ColorHelper.FromHexRgba(val) : ColorHelper.FromHexRgb(val);
return value.Length > 6 ? FromHexRgba(val) : FromHexRgb(val);
}
}

View file

@ -21,18 +21,18 @@ namespace MLEM.Extensions {
manager.IsFullScreen = fullscreen;
if (fullscreen) {
var view = manager.GraphicsDevice.Viewport;
GraphicsExtensions.lastWidth = view.Width;
GraphicsExtensions.lastHeight = view.Height;
lastWidth = view.Width;
lastHeight = view.Height;
var curr = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode;
manager.PreferredBackBufferWidth = curr.Width;
manager.PreferredBackBufferHeight = curr.Height;
} else {
if (GraphicsExtensions.lastWidth <= 0 || GraphicsExtensions.lastHeight <= 0)
if (lastWidth <= 0 || lastHeight <= 0)
throw new InvalidOperationException("Can't call SetFullscreen to change out of fullscreen mode without going into fullscreen mode first");
manager.PreferredBackBufferWidth = GraphicsExtensions.lastWidth;
manager.PreferredBackBufferHeight = GraphicsExtensions.lastHeight;
manager.PreferredBackBufferWidth = lastWidth;
manager.PreferredBackBufferHeight = lastHeight;
}
manager.ApplyChanges();
}

View file

@ -19,12 +19,12 @@ namespace MLEM.Extensions {
/// <param name="batch">The sprite batch</param>
/// <returns>A 1x1 pixel white texture</returns>
public static Texture2D GetBlankTexture(this SpriteBatch batch) {
if (SpriteBatchExtensions.blankTexture == null) {
SpriteBatchExtensions.blankTexture = new Texture2D(batch.GraphicsDevice, 1, 1);
SpriteBatchExtensions.blankTexture.SetData(new[] {Color.White});
SpriteBatchExtensions.AutoDispose(batch, SpriteBatchExtensions.blankTexture);
if (blankTexture == null) {
blankTexture = new Texture2D(batch.GraphicsDevice, 1, 1);
blankTexture.SetData(new[] {Color.White});
AutoDispose(batch, blankTexture);
}
return SpriteBatchExtensions.blankTexture;
return blankTexture;
}
/// <summary>
@ -43,7 +43,7 @@ namespace MLEM.Extensions {
outli, color, outli,
outli, outli, outli
});
SpriteBatchExtensions.AutoDispose(batch, tex);
AutoDispose(batch, tex);
return new NinePatch(tex, 1);
}
@ -57,7 +57,7 @@ namespace MLEM.Extensions {
public static Texture2D GenerateSquareTexture(this SpriteBatch batch, Color color) {
var tex = new Texture2D(batch.GraphicsDevice, 1, 1);
tex.SetData(new[] {color});
SpriteBatchExtensions.AutoDispose(batch, tex);
AutoDispose(batch, tex);
return tex;
}
@ -80,7 +80,7 @@ namespace MLEM.Extensions {
}
}
}
SpriteBatchExtensions.AutoDispose(batch, tex);
AutoDispose(batch, tex);
return tex;
}
@ -107,7 +107,7 @@ namespace MLEM.Extensions {
data[x, y] = Color.Lerp(top, btm, y / (float) height);
}
}
SpriteBatchExtensions.AutoDispose(batch, tex);
AutoDispose(batch, tex);
return tex;
}

View file

@ -21,7 +21,7 @@ namespace MLEM.Font {
public const char Emsp = '\u2003';
/// <inheritdoc cref="Emsp"/>
[Obsolete("Use the Emsp field instead.")]
public const char OneEmSpace = GenericFont.Emsp;
public const char OneEmSpace = Emsp;
/// <summary>
/// This field holds the unicode representation of a non-breaking space.
/// Whereas a regular <see cref="SpriteFont"/> would have to explicitly support this character for width calculations, generic fonts implicitly support it in <see cref="MeasureString(string,bool)"/>.
@ -185,17 +185,17 @@ namespace MLEM.Font {
xOffset = 0;
size.Y += this.LineHeight;
break;
case GenericFont.Emsp:
case Emsp:
xOffset += this.LineHeight;
break;
case GenericFont.Nbsp:
case Nbsp:
xOffset += font.MeasureChar(' ');
break;
case GenericFont.Zwsp:
case Zwsp:
// don't add width for a zero-width space
break;
case ' ':
if (ignoreTrailingSpaces && GenericFont.IsTrailingSpace(text, i)) {
if (ignoreTrailingSpaces && IsTrailingSpace(text, i)) {
// if this is a trailing space, we can skip remaining spaces too
i = text.Length - 1;
break;
@ -252,7 +252,7 @@ namespace MLEM.Font {
} else {
var font = fontFunction?.Invoke(i) ?? this;
var cWidth = font.MeasureString(c.ToCachedString()).X * scale;
if (c == ' ' || c == GenericFont.Emsp || c == GenericFont.Zwsp) {
if (c == ' ' || c == Emsp || c == Zwsp) {
// remember the location of this (breaking!) space
lastSpaceIndex = curr.Length;
widthSinceLastSpace = 0;

View file

@ -26,9 +26,9 @@ namespace MLEM.Font {
/// <param name="bold">A bold version of the font</param>
/// <param name="italic">An italic version of the font</param>
public GenericSpriteFont(SpriteFont font, SpriteFont bold = null, SpriteFont italic = null) {
this.Font = GenericSpriteFont.SetDefaults(font);
this.Bold = bold != null ? new GenericSpriteFont(GenericSpriteFont.SetDefaults(bold)) : this;
this.Italic = italic != null ? new GenericSpriteFont(GenericSpriteFont.SetDefaults(italic)) : this;
this.Font = SetDefaults(font);
this.Bold = bold != null ? new GenericSpriteFont(SetDefaults(bold)) : this;
this.Italic = italic != null ? new GenericSpriteFont(SetDefaults(italic)) : this;
}
/// <inheritdoc />

View file

@ -87,13 +87,13 @@ namespace MLEM.Formatting {
// if we've reached the end of the string
if (next == null) {
var sub = s.Substring(rawIndex, s.Length - rawIndex);
tokens.Add(new Token(codes.ToArray(), index, rawIndex, TextFormatter.StripFormatting(font, sub, codes), sub));
tokens.Add(new Token(codes.ToArray(), index, rawIndex, StripFormatting(font, sub, codes), sub));
break;
}
// create a new token for the content up to the next code
var ret = s.Substring(rawIndex, next.Match.Index - rawIndex);
var strippedRet = TextFormatter.StripFormatting(font, ret, codes);
var strippedRet = StripFormatting(font, ret, codes);
tokens.Add(new Token(codes.ToArray(), index, rawIndex, strippedRet, ret));
// move to the start of the next code
@ -104,7 +104,7 @@ namespace MLEM.Formatting {
codes.RemoveAll(c => c.EndsHere(next));
codes.Add(next);
}
return new TokenizedString(font, alignment, s, TextFormatter.StripFormatting(font, s, tokens.SelectMany(t => t.AppliedCodes)), tokens.ToArray());
return new TokenizedString(font, alignment, s, StripFormatting(font, s, tokens.SelectMany(t => t.AppliedCodes)), tokens.ToArray());
}
/// <summary>

View file

@ -123,12 +123,12 @@ namespace MLEM.Formatting {
var token = this.Tokens[t];
var drawFont = token.GetFont(font);
var drawColor = token.GetColor(color);
var indexInToken = 0;
for (var l = 0; l < token.SplitDisplayString.Length; l++) {
foreach (var c in token.SplitDisplayString[l]) {
var cString = c.ToCachedString();
if (indexInToken == 0)
token.DrawSelf(time, batch, pos + innerOffset, drawFont, color, scale, depth);
token.DrawCharacter(time, batch, c, cString, indexInToken, pos + innerOffset, drawFont, drawColor, scale, depth);
@ -136,7 +136,7 @@ namespace MLEM.Formatting {
innerOffset.X += drawFont.MeasureString(cString).X * scale;
indexInToken++;
}
// only split at a new line, not between tokens!
if (l < token.SplitDisplayString.Length - 1) {
innerOffset.X = token.InnerOffsets[l] * scale;

View file

@ -35,7 +35,7 @@ namespace MLEM.Graphics {
public static void DrawAutoTile(SpriteBatch batch, Vector2 pos, TextureRegion texture, ConnectsTo connectsTo, Color color, Vector2? origin = null, Vector2? scale = null, float layerDepth = 0) {
var orig = origin ?? Vector2.Zero;
var sc = scale ?? Vector2.One;
var (p1, r1, p2, r2, p3, r3, p4, r4) = AutoTiling.CalculateAutoTile(pos, texture.Area, connectsTo, sc);
var (p1, r1, p2, r2, p3, r3, p4, r4) = CalculateAutoTile(pos, texture.Area, connectsTo, sc);
batch.Draw(texture.Texture, p1, r1, color, 0, orig, sc, SpriteEffects.None, layerDepth);
batch.Draw(texture.Texture, p2, r2, color, 0, orig, sc, SpriteEffects.None, layerDepth);
batch.Draw(texture.Texture, p3, r3, color, 0, orig, sc, SpriteEffects.None, layerDepth);
@ -46,7 +46,7 @@ namespace MLEM.Graphics {
public static void AddAutoTile(StaticSpriteBatch batch, Vector2 pos, TextureRegion texture, ConnectsTo connectsTo, Color color, Vector2? origin = null, Vector2? scale = null, float layerDepth = 0, ICollection<StaticSpriteBatch.Item> items = null) {
var orig = origin ?? Vector2.Zero;
var sc = scale ?? Vector2.One;
var (p1, r1, p2, r2, p3, r3, p4, r4) = AutoTiling.CalculateAutoTile(pos, texture.Area, connectsTo, sc);
var (p1, r1, p2, r2, p3, r3, p4, r4) = CalculateAutoTile(pos, texture.Area, connectsTo, sc);
var a1 = batch.Add(texture.Texture, p1, r1, color, 0, orig, sc, SpriteEffects.None, layerDepth);
var a2 = batch.Add(texture.Texture, p2, r2, color, 0, orig, sc, SpriteEffects.None, layerDepth);
var a3 = batch.Add(texture.Texture, p3, r3, color, 0, orig, sc, SpriteEffects.None, layerDepth);
@ -88,7 +88,7 @@ namespace MLEM.Graphics {
var orig = origin ?? Vector2.Zero;
var sc = scale ?? Vector2.One;
var od = layerDepth + overlayDepthOffset;
var (r1, r2, r3, r4) = AutoTiling.CalculateExtendedAutoTile(pos, overlayTexture.Area, connectsTo, sc);
var (r1, r2, r3, r4) = CalculateExtendedAutoTile(pos, overlayTexture.Area, connectsTo, sc);
if (backgroundTexture != null)
batch.Draw(backgroundTexture, pos, backgroundColor, 0, orig, sc, SpriteEffects.None, layerDepth);
if (r1 != Rectangle.Empty)
@ -106,7 +106,7 @@ namespace MLEM.Graphics {
var orig = origin ?? Vector2.Zero;
var sc = scale ?? Vector2.One;
var od = layerDepth + overlayDepthOffset;
var (r1, r2, r3, r4) = AutoTiling.CalculateExtendedAutoTile(pos, overlayTexture.Area, connectsTo, sc);
var (r1, r2, r3, r4) = CalculateExtendedAutoTile(pos, overlayTexture.Area, connectsTo, sc);
if (backgroundTexture != null) {
var background = batch.Add(backgroundTexture, pos, backgroundColor, 0, orig, sc, SpriteEffects.None, layerDepth);
items?.Add(background);

View file

@ -14,7 +14,7 @@ namespace MLEM.Graphics {
// this maximum is limited by indices being a short
private const int MaxBatchItems = short.MaxValue / 6;
private static readonly VertexPositionColorTexture[] Data = new VertexPositionColorTexture[StaticSpriteBatch.MaxBatchItems * 4];
private static readonly VertexPositionColorTexture[] Data = new VertexPositionColorTexture[MaxBatchItems * 4];
/// <summary>
/// The amount of vertices that are currently batched.
@ -106,21 +106,21 @@ namespace MLEM.Graphics {
Texture2D texture = null;
foreach (var item in ordered) {
// if the texture changes, we also have to start a new buffer!
if (dataIndex > 0 && (item.Texture != texture || dataIndex >= StaticSpriteBatch.Data.Length)) {
this.FillBuffer(this.FilledBuffers++, texture, StaticSpriteBatch.Data);
if (dataIndex > 0 && (item.Texture != texture || dataIndex >= Data.Length)) {
this.FillBuffer(this.FilledBuffers++, texture, Data);
dataIndex = 0;
}
StaticSpriteBatch.Data[dataIndex++] = item.TopLeft;
StaticSpriteBatch.Data[dataIndex++] = item.TopRight;
StaticSpriteBatch.Data[dataIndex++] = item.BottomLeft;
StaticSpriteBatch.Data[dataIndex++] = item.BottomRight;
Data[dataIndex++] = item.TopLeft;
Data[dataIndex++] = item.TopRight;
Data[dataIndex++] = item.BottomLeft;
Data[dataIndex++] = item.BottomRight;
texture = item.Texture;
}
if (dataIndex > 0)
this.FillBuffer(this.FilledBuffers++, texture, StaticSpriteBatch.Data);
this.FillBuffer(this.FilledBuffers++, texture, Data);
// ensure we have enough indices
var maxItems = Math.Min(this.items.Count, StaticSpriteBatch.MaxBatchItems);
var maxItems = Math.Min(this.items.Count, MaxBatchItems);
// each item has 2 triangles which each have 3 indices
if (this.indices == null || this.indices.IndexCount < 6 * maxItems) {
var newIndices = new short[6 * maxItems];
@ -434,7 +434,7 @@ namespace MLEM.Graphics {
private void FillBuffer(int index, Texture2D texture, VertexPositionColorTexture[] data) {
if (this.vertexBuffers.Count <= index)
this.vertexBuffers.Add(new VertexBuffer(this.graphicsDevice, VertexPositionColorTexture.VertexDeclaration, StaticSpriteBatch.MaxBatchItems * 4, BufferUsage.WriteOnly));
this.vertexBuffers.Add(new VertexBuffer(this.graphicsDevice, VertexPositionColorTexture.VertexDeclaration, MaxBatchItems * 4, BufferUsage.WriteOnly));
this.vertexBuffers[index].SetData(data);
this.textures.Insert(index, texture);
}

View file

@ -24,7 +24,13 @@ namespace MLEM.Input {
/// Returns this generic input's <see cref="Keys"/>.
/// </summary>
/// <exception cref="InvalidOperationException">If this generic input's <see cref="Type"/> is not <see cref="InputType.Keyboard"/> or <see cref="InputType.None"/>.</exception>
public Keys Key => this.Type == InputType.None ? 0 : this.Type == InputType.Keyboard ? (Keys) this.value : throw new InvalidOperationException();
public Keys Key {
get {
if (this.Type == InputType.None)
return Keys.None;
return this.Type == InputType.Keyboard ? (Keys) this.value : throw new InvalidOperationException();
}
}
/// <summary>
/// Returns this generic input's <see cref="MouseButton"/>.
/// </summary>
@ -33,8 +39,8 @@ namespace MLEM.Input {
/// <summary>
/// Returns this generic input's <see cref="Buttons"/>.
/// </summary>
/// <exception cref="InvalidOperationException">If this generic input's <see cref="Type"/> is not <see cref="InputType.Gamepad"/> or <see cref="InputType.None"/>.</exception>
public Buttons Button => this.Type == InputType.None ? 0 : this.Type == InputType.Gamepad ? (Buttons) this.value : throw new InvalidOperationException();
/// <exception cref="InvalidOperationException">If this generic input's <see cref="Type"/> is not <see cref="InputType.Gamepad"/>.</exception>
public Buttons Button => this.Type == InputType.Gamepad ? (Buttons) this.value : throw new InvalidOperationException();
/// <summary>
/// Creates a new generic input from the given keyboard <see cref="Keys"/>.
@ -101,7 +107,7 @@ namespace MLEM.Input {
/// <summary>Returns the hash code for this instance.</summary>
/// <returns>A 32-bit signed integer that is the hash code for this instance.</returns>
public override int GetHashCode() {
return (int) this.Type * 397 ^ this.value;
return ((int) this.Type * 397) ^ this.value;
}
/// <summary>

View file

@ -829,9 +829,9 @@ namespace MLEM.Input {
/// <param name="gestures">The gestures to enable or disable</param>
public static void SetGesturesEnabled(bool enabled, params GestureType[] gestures) {
if (enabled) {
InputHandler.EnableGestures(gestures);
EnableGestures(gestures);
} else {
InputHandler.DisableGestures(gestures);
DisableGestures(gestures);
}
}

View file

@ -231,9 +231,9 @@ namespace MLEM.Input {
///
/// <list type="table"><listheader><term> Value</term><description> Meaning</description></listheader><item><term> Less than zero</term><description> This instance precedes <paramref name="obj" /> in the sort order.</description></item><item><term> Zero</term><description> This instance occurs in the same position in the sort order as <paramref name="obj" />.</description></item><item><term> Greater than zero</term><description> This instance follows <paramref name="obj" /> in the sort order.</description></item></list></returns>
public int CompareTo(object obj) {
if (object.ReferenceEquals(null, obj))
if (ReferenceEquals(null, obj))
return 1;
if (object.ReferenceEquals(this, obj))
if (ReferenceEquals(this, obj))
return 0;
if (!(obj is Keybind other))
throw new ArgumentException($"Object must be of type {nameof(Keybind)}");
@ -369,9 +369,9 @@ namespace MLEM.Input {
///
/// <list type="table"><listheader><term> Value</term><description> Meaning</description></listheader><item><term> Less than zero</term><description> This instance precedes <paramref name="obj" /> in the sort order.</description></item><item><term> Zero</term><description> This instance occurs in the same position in the sort order as <paramref name="obj" />.</description></item><item><term> Greater than zero</term><description> This instance follows <paramref name="obj" /> in the sort order.</description></item></list></returns>
public int CompareTo(object obj) {
if (object.ReferenceEquals(null, obj))
if (ReferenceEquals(null, obj))
return 1;
if (object.ReferenceEquals(this, obj))
if (ReferenceEquals(this, obj))
return 0;
if (!(obj is Combination other))
throw new ArgumentException($"Object must be of type {nameof(Combination)}");

View file

@ -18,7 +18,7 @@ namespace MLEM.Input {
{ModifierKey.Control, new[] {Keys.LeftControl, Keys.RightControl}},
{ModifierKey.Alt, new[] {Keys.LeftAlt, Keys.RightAlt}}
};
private static readonly Dictionary<Keys, ModifierKey> ModifiersLookup = KeysExtensions.KeysLookup
private static readonly Dictionary<Keys, ModifierKey> ModifiersLookup = KeysLookup
.SelectMany(kv => kv.Value.Select(v => (kv.Key, v)))
.ToDictionary(kv => kv.Item2, kv => kv.Item1);
@ -28,7 +28,7 @@ namespace MLEM.Input {
/// <param name="modifier">The modifier key</param>
/// <returns>All of the keys the modifier key represents</returns>
public static IEnumerable<Keys> GetKeys(this ModifierKey modifier) {
return KeysExtensions.KeysLookup.TryGetValue(modifier, out var keys) ? keys : Enumerable.Empty<Keys>();
return KeysLookup.TryGetValue(modifier, out var keys) ? keys : Enumerable.Empty<Keys>();
}
/// <summary>
@ -38,12 +38,12 @@ namespace MLEM.Input {
/// <param name="key">The key to convert to a modifier key</param>
/// <returns>The modifier key, or <see cref="ModifierKey.None"/></returns>
public static ModifierKey GetModifier(this Keys key) {
return KeysExtensions.ModifiersLookup.TryGetValue(key, out var mod) ? mod : ModifierKey.None;
return ModifiersLookup.TryGetValue(key, out var mod) ? mod : ModifierKey.None;
}
/// <inheritdoc cref="GetModifier(Microsoft.Xna.Framework.Input.Keys)"/>
public static ModifierKey GetModifier(this GenericInput input) {
return input.Type == GenericInput.InputType.Keyboard ? ((Keys) input).GetModifier() : ModifierKey.None;
return input.Type == GenericInput.InputType.Keyboard ? GetModifier((Keys) input) : ModifierKey.None;
}
/// <summary>
@ -52,12 +52,12 @@ namespace MLEM.Input {
/// <param name="key">The key</param>
/// <returns>If the key is a modifier key</returns>
public static bool IsModifier(this Keys key) {
return key.GetModifier() != ModifierKey.None;
return GetModifier(key) != ModifierKey.None;
}
/// <inheritdoc cref="IsModifier(Microsoft.Xna.Framework.Input.Keys)"/>
public static bool IsModifier(this GenericInput input) {
return input.GetModifier() != ModifierKey.None;
return GetModifier(input) != ModifierKey.None;
}
}

View file

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using Microsoft.Xna.Framework;
using static MLEM.Misc.Direction2;
namespace MLEM.Misc {
/// <summary>
@ -44,22 +45,22 @@ namespace MLEM.Misc {
/// The up and right direction, or +x, -y.
/// </summary>
[EnumMember]
UpRight = Direction2.Up | Direction2.Right,
UpRight = Up | Right,
/// <summary>
/// The down and right direction, or +x, +y.
/// </summary>
[EnumMember]
DownRight = Direction2.Down | Direction2.Right,
DownRight = Down | Right,
/// <summary>
/// The up and left direction, or -x, -y.
/// </summary>
[EnumMember]
UpLeft = Direction2.Up | Direction2.Left,
UpLeft = Up | Left,
/// <summary>
/// The down and left direction, or -x, +y.
/// </summary>
[EnumMember]
DownLeft = Direction2.Down | Direction2.Left
DownLeft = Down | Left
}
@ -75,18 +76,18 @@ namespace MLEM.Misc {
/// <summary>
/// The <see cref="Direction2.Up"/> through <see cref="Direction2.Left"/> directions
/// </summary>
public static readonly Direction2[] Adjacent = Direction2Helper.All.Where(Direction2Helper.IsAdjacent).ToArray();
public static readonly Direction2[] Adjacent = All.Where(IsAdjacent).ToArray();
/// <summary>
/// The <see cref="Direction2.UpRight"/> through <see cref="Direction2.UpLeft"/> directions
/// </summary>
public static readonly Direction2[] Diagonals = Direction2Helper.All.Where(Direction2Helper.IsDiagonal).ToArray();
public static readonly Direction2[] Diagonals = All.Where(IsDiagonal).ToArray();
/// <summary>
/// All directions except <see cref="Direction2.None"/>
/// </summary>
public static readonly Direction2[] AllExceptNone = Direction2Helper.All.Where(dir => dir != Direction2.None).ToArray();
public static readonly Direction2[] AllExceptNone = All.Where(dir => dir != None).ToArray();
private static readonly Direction2[] Clockwise = {Direction2.Up, Direction2.UpRight, Direction2.Right, Direction2.DownRight, Direction2.Down, Direction2.DownLeft, Direction2.Left, Direction2.UpLeft};
private static readonly Dictionary<Direction2, int> ClockwiseLookup = Direction2Helper.Clockwise.Select((d, i) => (d, i)).ToDictionary(kv => kv.d, kv => kv.i);
private static readonly Direction2[] Clockwise = {Up, UpRight, Right, DownRight, Down, DownLeft, Left, UpLeft};
private static readonly Dictionary<Direction2, int> ClockwiseLookup = Clockwise.Select((d, i) => (d, i)).ToDictionary(kv => kv.d, kv => kv.i);
/// <summary>
/// Returns if the given direction is considered an "adjacent" direction.
@ -95,7 +96,7 @@ namespace MLEM.Misc {
/// <param name="dir">The direction to query</param>
/// <returns>Whether the direction is adjacent</returns>
public static bool IsAdjacent(this Direction2 dir) {
return dir == Direction2.Up || dir == Direction2.Right || dir == Direction2.Down || dir == Direction2.Left;
return dir == Up || dir == Right || dir == Down || dir == Left;
}
/// <summary>
@ -104,7 +105,7 @@ namespace MLEM.Misc {
/// <param name="dir">The direction to query</param>
/// <returns>Whether the direction is diagonal</returns>
public static bool IsDiagonal(this Direction2 dir) {
return dir == Direction2.UpRight || dir == Direction2.DownRight || dir == Direction2.UpLeft || dir == Direction2.DownLeft;
return dir == UpRight || dir == DownRight || dir == UpLeft || dir == DownLeft;
}
/// <summary>
@ -115,21 +116,21 @@ namespace MLEM.Misc {
/// <returns>The direction's offset</returns>
public static Point Offset(this Direction2 dir) {
switch (dir) {
case Direction2.Up:
case Up:
return new Point(0, -1);
case Direction2.Right:
case Right:
return new Point(1, 0);
case Direction2.Down:
case Down:
return new Point(0, 1);
case Direction2.Left:
case Left:
return new Point(-1, 0);
case Direction2.UpRight:
case UpRight:
return new Point(1, -1);
case Direction2.DownRight:
case DownRight:
return new Point(1, 1);
case Direction2.DownLeft:
case DownLeft:
return new Point(-1, 1);
case Direction2.UpLeft:
case UpLeft:
return new Point(-1, -1);
default:
return Point.Zero;
@ -155,24 +156,24 @@ namespace MLEM.Misc {
/// <returns>The opposite of the direction</returns>
public static Direction2 Opposite(this Direction2 dir) {
switch (dir) {
case Direction2.Up:
return Direction2.Down;
case Direction2.Right:
return Direction2.Left;
case Direction2.Down:
return Direction2.Up;
case Direction2.Left:
return Direction2.Right;
case Direction2.UpRight:
return Direction2.DownLeft;
case Direction2.DownRight:
return Direction2.UpLeft;
case Direction2.DownLeft:
return Direction2.UpRight;
case Direction2.UpLeft:
return Direction2.DownRight;
case Up:
return Down;
case Right:
return Left;
case Down:
return Up;
case Left:
return Right;
case UpRight:
return DownLeft;
case DownRight:
return UpLeft;
case DownLeft:
return UpRight;
case UpLeft:
return DownRight;
default:
return Direction2.None;
return None;
}
}
@ -193,9 +194,9 @@ namespace MLEM.Misc {
/// <param name="fortyFiveDegrees">Whether to rotate by 45 degrees. If this is false, the rotation is 90 degrees instead.</param>
/// <returns>The rotated direction</returns>
public static Direction2 RotateCw(this Direction2 dir, bool fortyFiveDegrees = false) {
if (!Direction2Helper.ClockwiseLookup.TryGetValue(dir, out var dirIndex))
return Direction2.None;
return Direction2Helper.Clockwise[(dirIndex + (fortyFiveDegrees ? 1 : 2)) % Direction2Helper.Clockwise.Length];
if (!ClockwiseLookup.TryGetValue(dir, out var dirIndex))
return None;
return Clockwise[(dirIndex + (fortyFiveDegrees ? 1 : 2)) % Clockwise.Length];
}
/// <summary>
@ -205,10 +206,10 @@ namespace MLEM.Misc {
/// <param name="fortyFiveDegrees">Whether to rotate by 45 degrees. If this is false, the rotation is 90 degrees instead.</param>
/// <returns>The rotated direction</returns>
public static Direction2 RotateCcw(this Direction2 dir, bool fortyFiveDegrees = false) {
if (!Direction2Helper.ClockwiseLookup.TryGetValue(dir, out var dirIndex))
return Direction2.None;
if (!ClockwiseLookup.TryGetValue(dir, out var dirIndex))
return None;
var index = dirIndex - (fortyFiveDegrees ? 1 : 2);
return Direction2Helper.Clockwise[index < 0 ? index + Direction2Helper.Clockwise.Length : index];
return Clockwise[index < 0 ? index + Clockwise.Length : index];
}
/// <summary>
@ -218,11 +219,11 @@ namespace MLEM.Misc {
/// <returns>The vector's direction</returns>
public static Direction2 ToDirection(this Vector2 offset) {
var offsetAngle = (float) Math.Atan2(offset.Y, offset.X);
foreach (var dir in Direction2Helper.AllExceptNone) {
foreach (var dir in AllExceptNone) {
if (Math.Abs(dir.Angle() - offsetAngle) <= MathHelper.PiOver4 / 2)
return dir;
}
return Direction2.None;
return None;
}
/// <summary>
@ -233,10 +234,10 @@ namespace MLEM.Misc {
/// <returns>The vector's direction</returns>
public static Direction2 To90Direction(this Vector2 offset) {
if (offset.X == 0 && offset.Y == 0)
return Direction2.None;
return None;
if (Math.Abs(offset.X) > Math.Abs(offset.Y))
return offset.X > 0 ? Direction2.Right : Direction2.Left;
return offset.Y > 0 ? Direction2.Down : Direction2.Up;
return offset.X > 0 ? Right : Left;
return offset.Y > 0 ? Down : Up;
}
/// <summary>
@ -246,17 +247,17 @@ namespace MLEM.Misc {
/// <param name="reference">The direction to rotate by</param>
/// <param name="start">The direction to use as the default direction</param>
/// <returns>The direction, rotated by the reference direction</returns>
public static Direction2 RotateBy(this Direction2 dir, Direction2 reference, Direction2 start = Direction2.Up) {
if (!Direction2Helper.ClockwiseLookup.TryGetValue(reference, out var refIndex))
return Direction2.None;
if (!Direction2Helper.ClockwiseLookup.TryGetValue(start, out var startIndex))
return Direction2.None;
if (!Direction2Helper.ClockwiseLookup.TryGetValue(dir, out var dirIndex))
return Direction2.None;
public static Direction2 RotateBy(this Direction2 dir, Direction2 reference, Direction2 start = Up) {
if (!ClockwiseLookup.TryGetValue(reference, out var refIndex))
return None;
if (!ClockwiseLookup.TryGetValue(start, out var startIndex))
return None;
if (!ClockwiseLookup.TryGetValue(dir, out var dirIndex))
return None;
var diff = refIndex - startIndex;
if (diff < 0)
diff += Direction2Helper.Clockwise.Length;
return Direction2Helper.Clockwise[(dirIndex + diff) % Direction2Helper.Clockwise.Length];
diff += Clockwise.Length;
return Clockwise[(dirIndex + diff) % Clockwise.Length];
}
}

View file

@ -72,7 +72,7 @@ namespace MLEM.Misc {
public static readonly Easing InOutElastic = p => p == 0 ? 0 : p == 1 ? 1 : p < 0.5 ? -((float) Math.Pow(2, 20 * p - 10) * (float) Math.Sin((20 * p - 11.125) * 1.39626340159546F)) / 2 : (float) Math.Pow(2, -20 * p + 10) * (float) Math.Sin((20 * p - 11.125) * 1.39626340159546F) / 2 + 1;
/// <summary>https://easings.net/#easeInBounce</summary>
public static readonly Easing InBounce = p => 1 - Easings.OutBounce(1 - p);
public static readonly Easing InBounce = p => 1 - OutBounce(1 - p);
/// <summary>https://easings.net/#easeOutBounce</summary>
public static readonly Easing OutBounce = p => {
const float n1 = 7.5625F;
@ -88,7 +88,7 @@ namespace MLEM.Misc {
}
};
/// <summary>https://easings.net/#easeInOutBounce</summary>
public static readonly Easing InOutBounce = p => p < 0.5 ? (1 - Easings.OutBounce(1 - 2 * p)) / 2 : (1 + Easings.OutBounce(2 * p - 1)) / 2;
public static readonly Easing InOutBounce = p => p < 0.5 ? (1 - OutBounce(1 - 2 * p)) / 2 : (1 + OutBounce(2 * p - 1)) / 2;
/// <summary>
/// Scales the input of an easing function, which is usually between 0 and 1, to a given minimum and maximum.

View file

@ -12,11 +12,11 @@ namespace MLEM.Misc {
/// <summary>
/// All values of the <see cref="Buttons"/> enum.
/// </summary>
public static readonly Buttons[] Buttons = EnumHelper.GetValues<Buttons>().ToArray();
public static readonly Buttons[] Buttons = GetValues<Buttons>().ToArray();
/// <summary>
/// All values of the <see cref="Keys"/> enum.
/// </summary>
public static readonly Keys[] Keys = EnumHelper.GetValues<Keys>().ToArray();
public static readonly Keys[] Keys = GetValues<Keys>().ToArray();
/// <summary>
/// Returns all of the values of the given enum type.

View file

@ -50,7 +50,7 @@ namespace MLEM.Misc {
/// </summary>
/// <exception cref="InvalidOperationException">If <see cref="Current"/> is null</exception>
public static void EnsureExists() {
if (MlemPlatform.Current == null)
if (Current == null)
throw new InvalidOperationException("MlemPlatform was not initialized. For more information, see the MlemPlatform class or https://mlem.ellpeck.de/api/MLEM.Misc.MlemPlatform");
}

View file

@ -135,9 +135,9 @@ namespace MLEM.Misc {
/// <returns>A 32-bit signed integer that is the hash code for this instance.</returns>
public override int GetHashCode() {
var hashCode = this.Left.GetHashCode();
hashCode = hashCode * 397 ^ this.Right.GetHashCode();
hashCode = hashCode * 397 ^ this.Top.GetHashCode();
hashCode = hashCode * 397 ^ this.Bottom.GetHashCode();
hashCode = (hashCode * 397) ^ this.Right.GetHashCode();
hashCode = (hashCode * 397) ^ this.Top.GetHashCode();
hashCode = (hashCode * 397) ^ this.Bottom.GetHashCode();
return hashCode;
}

View file

@ -248,7 +248,7 @@ namespace MLEM.Misc {
var num2 = Math.Min(value1.Y + value1.Height, value2.Y + value2.Height);
return new RectangleF(x, y, num1 - x, num2 - y);
} else {
return RectangleF.Empty;
return Empty;
}
}

View file

@ -14,7 +14,6 @@ namespace MLEM.Pathfinding {
/// <summary>
/// A value that represents an infinite path cost, or a cost for a location that cannot possibly be reached.
/// </summary>
[Obsolete("This field is deprecated. Use float.PositiveInfinity or float.MaxValue instead.")]
public const float InfiniteCost = float.PositiveInfinity;
/// <summary>
/// The array of all directions that will be checked for path finding.
@ -111,7 +110,7 @@ namespace MLEM.Pathfinding {
closed.Add(current.Pos, current);
if (current.Pos.Equals(goal)) {
ret = AStar<T>.CompilePath(current);
ret = CompilePath(current);
break;
}
@ -168,7 +167,7 @@ namespace MLEM.Pathfinding {
/// <summary>
/// A cost function for a given path finding position.
/// If a path point should have the default cost, <see cref="AStar{T}.DefaultCost"/> should be returned.
/// If a path point should be unreachable, <see cref="float.PositiveInfinity"/> or <see cref="float.MaxValue"/> should be returned.
/// If a path point should be unreachable, <see cref="AStar{T}.InfiniteCost"/> should be returned.
/// </summary>
/// <param name="currPos">The current position in the path</param>
/// <param name="nextPos">The position we're trying to reach from the current position</param>
@ -219,7 +218,7 @@ namespace MLEM.Pathfinding {
/// <param name="other">An object to compare with this object.</param>
/// <returns>true if the current object is equal to the <paramref name="other">other</paramref> parameter; otherwise, false.</returns>
public bool Equals(PathPoint<T> other) {
return object.ReferenceEquals(this, other) || EqualityComparer<T>.Default.Equals(this.Pos, other.Pos);
return ReferenceEquals(this, other) || EqualityComparer<T>.Default.Equals(this.Pos, other.Pos);
}
/// <summary>Indicates whether this instance and a specified object are equal.</summary>

View file

@ -14,7 +14,7 @@ namespace MLEM.Pathfinding {
/// <inheritdoc />
public AStar2(GetCost defaultCostFunction, bool defaultAllowDiagonals, float defaultCost = 1, int defaultMaxTries = 10000) :
base(AStar2.AllDirs, AStar2.AdjacentDirs, defaultCostFunction, defaultAllowDiagonals, defaultCost, defaultMaxTries) {}
base(AllDirs, AdjacentDirs, defaultCostFunction, defaultAllowDiagonals, defaultCost, defaultMaxTries) {}
/// <inheritdoc />
protected override Point AddPositions(Point first, Point second) {

View file

@ -30,12 +30,12 @@ namespace MLEM.Pathfinding {
}
}
}
AStar3.AllDirs = dirs.ToArray();
AllDirs = dirs.ToArray();
}
/// <inheritdoc />
public AStar3(GetCost defaultCostFunction, bool defaultAllowDiagonals, float defaultCost = 1, int defaultMaxTries = 10000) :
base(AStar3.AllDirs, AStar3.AdjacentDirs, defaultCostFunction, defaultAllowDiagonals, defaultCost, defaultMaxTries) {}
base(AllDirs, AdjacentDirs, defaultCostFunction, defaultAllowDiagonals, defaultCost, defaultMaxTries) {}
/// <inheritdoc />
protected override Vector3 AddPositions(Vector3 first, Vector3 second) {

View file

@ -57,7 +57,7 @@ namespace MLEM.Sound {
public float GetRandomPitch() {
if (this.RandomPitchModifier == 0)
return this.Pitch;
return this.Pitch + ((float) SoundEffectInfo.Random.NextDouble() * 2 - 1) * this.RandomPitchModifier;
return this.Pitch + ((float) Random.NextDouble() * 2 - 1) * this.RandomPitchModifier;
}
/// <summary>

View file

@ -6,55 +6,55 @@ of the font in your game, and to change the characters which are available to dr
with.
-->
<XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics">
<Asset Type="Graphics:FontDescription">
<!--
Modify this string to change the font that will be imported.
-->
<FontName>Cadman_Roman.otf</FontName>
<!--
Size is a float value, measured in points. Modify this value to change
the size of the font.
-->
<Size>32</Size>
<!--
Spacing is a float value, measured in pixels. Modify this value to change
the amount of spacing in between characters.
-->
<Spacing>0</Spacing>
<!--
UseKerning controls the layout of the font. If this value is true, kerning information
will be used when placing characters.
-->
<UseKerning>true</UseKerning>
<!--
Style controls the style of the font. Valid entries are "Regular", "Bold", "Italic",
and "Bold, Italic", and are case sensitive.
-->
<Style>Regular</Style>
<!--
If you uncomment this line, the default character will be substituted if you draw
or measure text that contains characters which were not included in the font.
-->
<DefaultCharacter>*</DefaultCharacter>
<!--
CharacterRegions control what letters are available in the font. Every
character from Start to End will be built and made available for drawing. The
default range is from 32, (ASCII space), to 126, ('~'), covering the basic Latin
character set. The characters are ordered according to the Unicode standard.
See the documentation for more information.
-->
<CharacterRegions>
<CharacterRegion>
<Start>&#32;</Start>
<End>&#591;</End>
</CharacterRegion>
</CharacterRegions>
</Asset>
<Asset Type="Graphics:FontDescription">
<!--
Modify this string to change the font that will be imported.
-->
<FontName>Cadman_Roman.otf</FontName>
<!--
Size is a float value, measured in points. Modify this value to change
the size of the font.
-->
<Size>32</Size>
<!--
Spacing is a float value, measured in pixels. Modify this value to change
the amount of spacing in between characters.
-->
<Spacing>0</Spacing>
<!--
UseKerning controls the layout of the font. If this value is true, kerning information
will be used when placing characters.
-->
<UseKerning>true</UseKerning>
<!--
Style controls the style of the font. Valid entries are "Regular", "Bold", "Italic",
and "Bold, Italic", and are case sensitive.
-->
<Style>Regular</Style>
<!--
If you uncomment this line, the default character will be substituted if you draw
or measure text that contains characters which were not included in the font.
-->
<DefaultCharacter>*</DefaultCharacter>
<!--
CharacterRegions control what letters are available in the font. Every
character from Start to End will be built and made available for drawing. The
default range is from 32, (ASCII space), to 126, ('~'), covering the basic Latin
character set. The characters are ordered according to the Unicode standard.
See the documentation for more information.
-->
<CharacterRegions>
<CharacterRegion>
<Start>&#32;</Start>
<End>&#591;</End>
</CharacterRegion>
</CharacterRegions>
</Asset>
</XnaContent>

View file

@ -54,7 +54,7 @@ namespace Sandbox {
this.Components.Add(this.rawContent = new RawContentManager(this.Services));
this.map = MlemGame.LoadContent<TiledMap>("Tiled/Map");
this.map = LoadContent<TiledMap>("Tiled/Map");
this.mapRenderer = new IndividualTiledMapRenderer(this.map);
this.collisions = new TiledMapCollisions(this.map);
@ -78,7 +78,7 @@ namespace Sandbox {
//var font = new GenericSpriteFont(LoadContent<SpriteFont>("Fonts/TestFont"));
//var font = new GenericBitmapFont(LoadContent<BitmapFont>("Fonts/Regular"));
var font = new GenericStashFont(system.GetFont(32));
var spriteFont = new GenericSpriteFont(MlemGame.LoadContent<SpriteFont>("Fonts/TestFont"));
var spriteFont = new GenericSpriteFont(LoadContent<SpriteFont>("Fonts/TestFont"));
this.UiSystem.Style = new UntexturedStyle(this.SpriteBatch) {
Font = font,
TextScale = 0.5F,
@ -277,7 +277,7 @@ namespace Sandbox {
this.OnDraw += (g, time) => {
const string testString = "This is a\ntest string\n\twith long lines.\nLet's write some more stuff. Let's\r\nsplit lines weirdly.";
if (MlemGame.Input.IsKeyPressed(Keys.I)) {
if (Input.IsKeyPressed(Keys.I)) {
index++;
if (index == 1) {
scale = 2;
@ -295,7 +295,7 @@ namespace Sandbox {
}
this.SpriteBatch.Begin();
if (MlemGame.Input.IsKeyDown(Keys.LeftShift)) {
if (Input.IsKeyDown(Keys.LeftShift)) {
this.SpriteBatch.DrawString(regularFont, testString, pos, Color.Red, rotation, origin, scale, effects, 0);
} else {
genericFont.DrawString(this.SpriteBatch, testString, pos, Color.Green, rotation, origin, scale, effects, 0);
@ -363,8 +363,8 @@ namespace Sandbox {
/*if (Input.InputsDown.Length > 0)
Console.WriteLine("Down: " + string.Join(", ", Input.InputsDown));*/
if (MlemGame.Input.InputsPressed.Length > 0)
Console.WriteLine("Pressed: " + string.Join(", ", MlemGame.Input.InputsPressed));
if (Input.InputsPressed.Length > 0)
Console.WriteLine("Pressed: " + string.Join(", ", Input.InputsPressed));
}
protected override void DoDraw(GameTime gameTime) {

View file

@ -7,6 +7,7 @@ using MLEM.Data.Json;
using MLEM.Misc;
using Newtonsoft.Json;
using NUnit.Framework;
using static MLEM.Data.DynamicEnum;
using Vector2 = Microsoft.Xna.Framework.Vector2;
namespace Tests {
@ -40,27 +41,27 @@ namespace Tests {
public void TestDynamicEnum() {
var flags = new TestEnum[100];
for (var i = 0; i < flags.Length; i++)
flags[i] = DynamicEnum.AddFlag<TestEnum>("Flag" + i);
flags[i] = AddFlag<TestEnum>("Flag" + i);
Assert.AreEqual(DynamicEnum.GetValue(flags[7]), BigInteger.One << 7);
Assert.AreEqual(DynamicEnum.GetEnumValue<TestEnum>(BigInteger.One << 75), flags[75]);
Assert.AreEqual(GetValue(flags[7]), BigInteger.One << 7);
Assert.AreEqual(GetEnumValue<TestEnum>(BigInteger.One << 75), flags[75]);
Assert.AreEqual(DynamicEnum.GetValue(DynamicEnum.Or(flags[2], flags[17])), BigInteger.One << 2 | BigInteger.One << 17);
Assert.AreEqual(DynamicEnum.GetValue(DynamicEnum.And(flags[2], flags[3])), BigInteger.Zero);
Assert.AreEqual(DynamicEnum.And(DynamicEnum.Or(flags[24], flags[52]), DynamicEnum.Or(flags[52], flags[75])), flags[52]);
Assert.AreEqual(DynamicEnum.Xor(DynamicEnum.Or(flags[85], flags[73]), flags[73]), flags[85]);
Assert.AreEqual(DynamicEnum.Xor(DynamicEnum.Or(flags[85], DynamicEnum.Or(flags[73], flags[12])), flags[73]), DynamicEnum.Or(flags[85], flags[12]));
Assert.AreEqual(DynamicEnum.GetValue(DynamicEnum.Neg(flags[74])), ~(BigInteger.One << 74));
Assert.AreEqual(GetValue(Or(flags[2], flags[17])), (BigInteger.One << 2) | (BigInteger.One << 17));
Assert.AreEqual(GetValue(And(flags[2], flags[3])), BigInteger.Zero);
Assert.AreEqual(And(Or(flags[24], flags[52]), Or(flags[52], flags[75])), flags[52]);
Assert.AreEqual(Xor(Or(flags[85], flags[73]), flags[73]), flags[85]);
Assert.AreEqual(Xor(Or(flags[85], Or(flags[73], flags[12])), flags[73]), Or(flags[85], flags[12]));
Assert.AreEqual(GetValue(Neg(flags[74])), ~(BigInteger.One << 74));
Assert.AreEqual(DynamicEnum.Or(flags[24], flags[52]).HasFlag(flags[24]), true);
Assert.AreEqual(DynamicEnum.Or(flags[24], flags[52]).HasAnyFlag(flags[24]), true);
Assert.AreEqual(DynamicEnum.Or(flags[24], flags[52]).HasFlag(DynamicEnum.Or(flags[24], flags[26])), false);
Assert.AreEqual(DynamicEnum.Or(flags[24], flags[52]).HasAnyFlag(DynamicEnum.Or(flags[24], flags[26])), true);
Assert.AreEqual(Or(flags[24], flags[52]).HasFlag(flags[24]), true);
Assert.AreEqual(Or(flags[24], flags[52]).HasAnyFlag(flags[24]), true);
Assert.AreEqual(Or(flags[24], flags[52]).HasFlag(Or(flags[24], flags[26])), false);
Assert.AreEqual(Or(flags[24], flags[52]).HasAnyFlag(Or(flags[24], flags[26])), true);
Assert.AreEqual(DynamicEnum.Parse<TestEnum>("Flag24"), flags[24]);
Assert.AreEqual(DynamicEnum.Parse<TestEnum>("Flag24 | Flag43"), DynamicEnum.Or(flags[24], flags[43]));
Assert.AreEqual(Parse<TestEnum>("Flag24"), flags[24]);
Assert.AreEqual(Parse<TestEnum>("Flag24 | Flag43"), Or(flags[24], flags[43]));
Assert.AreEqual(flags[24].ToString(), "Flag24");
Assert.AreEqual(DynamicEnum.Or(flags[24], flags[43]).ToString(), "Flag24 | Flag43");
Assert.AreEqual(Or(flags[24], flags[43]).ToString(), "Flag24 | Flag43");
}
[Test]
@ -70,14 +71,14 @@ namespace Tests {
// normal generic data holder should crush the time span down to a string due to its custom serializer
var data = new GenericDataHolder();
data.SetData("Time", TimeSpan.FromMinutes(5));
var read = DataTests.SerializeAndDeserialize(serializer, data);
var read = SerializeAndDeserialize(serializer, data);
Assert.IsNotInstanceOf<TimeSpan>(read.GetData<object>("Time"));
Assert.Throws<InvalidCastException>(() => read.GetData<TimeSpan>("Time"));
// json type safe generic data holder should wrap the time span to ensure that it stays a time span
var safeData = new JsonTypeSafeGenericDataHolder();
safeData.SetData("Time", TimeSpan.FromMinutes(5));
var safeRead = DataTests.SerializeAndDeserialize(serializer, safeData);
var safeRead = SerializeAndDeserialize(serializer, safeData);
Assert.IsInstanceOf<TimeSpan>(safeRead.GetData<object>("Time"));
Assert.DoesNotThrow(() => safeRead.GetData<TimeSpan>("Time"));
}
@ -98,11 +99,11 @@ namespace Tests {
public TestObject(Vector2 test, string test2) {}
protected bool Equals(TestObject other) {
return this.Vec.Equals(other.Vec) && this.Point.Equals(other.Point) && object.Equals(this.OtherTest, other.OtherTest) && this.Dir == other.Dir;
return this.Vec.Equals(other.Vec) && this.Point.Equals(other.Point) && Equals(this.OtherTest, other.OtherTest) && this.Dir == other.Dir;
}
public override bool Equals(object obj) {
return object.ReferenceEquals(this, obj) || obj is TestObject other && this.Equals(other);
return ReferenceEquals(this, obj) || obj is TestObject other && this.Equals(other);
}
public override int GetHashCode() {

View file

@ -1,57 +1,58 @@
using Microsoft.Xna.Framework;
using MLEM.Misc;
using NUnit.Framework;
using static MLEM.Misc.Direction2;
namespace Tests {
public class DirectionTests {
[Test]
public void TestDirections() {
Assert.AreEqual(new Vector2(0.5F, 0.5F).ToDirection(), Direction2.DownRight);
Assert.AreEqual(new Vector2(0.25F, 0.5F).ToDirection(), Direction2.DownRight);
Assert.AreEqual(new Vector2(0.15F, 0.5F).ToDirection(), Direction2.Down);
Assert.AreEqual(new Vector2(0.5F, 0.5F).ToDirection(), DownRight);
Assert.AreEqual(new Vector2(0.25F, 0.5F).ToDirection(), DownRight);
Assert.AreEqual(new Vector2(0.15F, 0.5F).ToDirection(), Down);
}
[Test]
public void Test90Directions() {
Assert.AreEqual(new Vector2(0.75F, 0.5F).To90Direction(), Direction2.Right);
Assert.AreEqual(new Vector2(0.5F, 0.5F).To90Direction(), Direction2.Down);
Assert.AreEqual(new Vector2(0.25F, 0.5F).To90Direction(), Direction2.Down);
Assert.AreEqual(new Vector2(0.75F, 0.5F).To90Direction(), Right);
Assert.AreEqual(new Vector2(0.5F, 0.5F).To90Direction(), Down);
Assert.AreEqual(new Vector2(0.25F, 0.5F).To90Direction(), Down);
}
[Test]
public void TestRotations() {
// rotate cw
Assert.AreEqual(Direction2.Up.RotateCw(), Direction2.Right);
Assert.AreEqual(Direction2.Up.RotateCw(true), Direction2.UpRight);
Assert.AreEqual(Direction2.Left.RotateCw(), Direction2.Up);
Assert.AreEqual(Direction2.UpLeft.RotateCw(), Direction2.UpRight);
Assert.AreEqual(Up.RotateCw(), Right);
Assert.AreEqual(Up.RotateCw(true), UpRight);
Assert.AreEqual(Left.RotateCw(), Up);
Assert.AreEqual(UpLeft.RotateCw(), UpRight);
// rotate ccw
Assert.AreEqual(Direction2.Up.RotateCcw(), Direction2.Left);
Assert.AreEqual(Direction2.Up.RotateCcw(true), Direction2.UpLeft);
Assert.AreEqual(Direction2.Left.RotateCcw(), Direction2.Down);
Assert.AreEqual(Direction2.UpLeft.RotateCcw(), Direction2.DownLeft);
Assert.AreEqual(Up.RotateCcw(), Left);
Assert.AreEqual(Up.RotateCcw(true), UpLeft);
Assert.AreEqual(Left.RotateCcw(), Down);
Assert.AreEqual(UpLeft.RotateCcw(), DownLeft);
// rotate 360 degrees
foreach (var dir in Direction2Helper.AllExceptNone) {
Assert.AreEqual(DirectionTests.RotateMultipleTimes(dir, true, false, 4), dir);
Assert.AreEqual(DirectionTests.RotateMultipleTimes(dir, true, true, 8), dir);
Assert.AreEqual(DirectionTests.RotateMultipleTimes(dir, false, false, 4), dir);
Assert.AreEqual(DirectionTests.RotateMultipleTimes(dir, false, true, 8), dir);
Assert.AreEqual(RotateMultipleTimes(dir, true, false, 4), dir);
Assert.AreEqual(RotateMultipleTimes(dir, true, true, 8), dir);
Assert.AreEqual(RotateMultipleTimes(dir, false, false, 4), dir);
Assert.AreEqual(RotateMultipleTimes(dir, false, true, 8), dir);
}
// rotate by with start Up
Assert.AreEqual(Direction2.Right.RotateBy(Direction2.Right), Direction2.Down);
Assert.AreEqual(Direction2.Right.RotateBy(Direction2.Down), Direction2.Left);
Assert.AreEqual(Direction2.Right.RotateBy(Direction2.Left), Direction2.Up);
Assert.AreEqual(Direction2.Right.RotateBy(Direction2.Up), Direction2.Right);
Assert.AreEqual(Right.RotateBy(Right), Down);
Assert.AreEqual(Right.RotateBy(Down), Left);
Assert.AreEqual(Right.RotateBy(Left), Up);
Assert.AreEqual(Right.RotateBy(Up), Right);
// rotate by with start Left
Assert.AreEqual(Direction2.Up.RotateBy(Direction2.Right, Direction2.Left), Direction2.Down);
Assert.AreEqual(Direction2.Up.RotateBy(Direction2.Down, Direction2.Left), Direction2.Left);
Assert.AreEqual(Direction2.Up.RotateBy(Direction2.Left, Direction2.Left), Direction2.Up);
Assert.AreEqual(Direction2.Up.RotateBy(Direction2.Up, Direction2.Left), Direction2.Right);
Assert.AreEqual(Up.RotateBy(Right, Left), Down);
Assert.AreEqual(Up.RotateBy(Down, Left), Left);
Assert.AreEqual(Up.RotateBy(Left, Left), Up);
Assert.AreEqual(Up.RotateBy(Up, Left), Right);
}
private static Direction2 RotateMultipleTimes(Direction2 dir, bool clockwise, bool fortyFiveDegrees, int times) {

View file

@ -16,12 +16,12 @@ namespace Tests {
"XXXX"
};
var noDiagonals = PathfindingTests.FindPathInArea(new Point(1, 1), new Point(2, 2), area, false).ToArray();
var noDiagonals = FindPathInArea(new Point(1, 1), new Point(2, 2), area, false).ToArray();
Assert.AreEqual(noDiagonals.Length, 3);
Assert.AreEqual(noDiagonals[0], new Point(1, 1));
Assert.AreEqual(noDiagonals[2], new Point(2, 2));
var diagonals = PathfindingTests.FindPathInArea(new Point(1, 1), new Point(2, 2), area, true).ToArray();
var diagonals = FindPathInArea(new Point(1, 1), new Point(2, 2), area, true).ToArray();
Assert.AreEqual(diagonals.Length, 2);
Assert.AreEqual(diagonals[0], new Point(1, 1));
Assert.AreEqual(diagonals[1], new Point(2, 2));
@ -36,11 +36,11 @@ namespace Tests {
"XXXXXXXX"
};
var firstPath = PathfindingTests.FindPathInArea(new Point(1, 1), new Point(3, 1), area, false).ToArray();
var firstPath = FindPathInArea(new Point(1, 1), new Point(3, 1), area, false).ToArray();
var firstExpected = new[] {new Point(1, 1), new Point(1, 2), new Point(2, 2), new Point(3, 2), new Point(3, 1)};
Assert.AreEqual(firstPath, firstExpected);
var secondPath = PathfindingTests.FindPathInArea(new Point(1, 1), new Point(5, 2), area, false).ToArray();
var secondPath = FindPathInArea(new Point(1, 1), new Point(5, 2), area, false).ToArray();
var secondExpected = firstExpected.Concat(new[] {new Point(4, 1), new Point(5, 1), new Point(5, 2)}).ToArray();
Assert.AreEqual(secondPath, secondExpected);
}
@ -55,15 +55,15 @@ namespace Tests {
"XXXX"
};
// non-diagonal pathfinding should get stuck in the corner
Assert.IsNull(PathfindingTests.FindPathInArea(new Point(1, 1), new Point(2, 3), area, false));
Assert.IsNull(FindPathInArea(new Point(1, 1), new Point(2, 3), area, false));
// diagonal pathfinding should be able to cross the diagonal gap
Assert.IsNotNull(PathfindingTests.FindPathInArea(new Point(1, 1), new Point(2, 3), area, true));
Assert.IsNotNull(FindPathInArea(new Point(1, 1), new Point(2, 3), area, true));
}
private static Stack<Point> FindPathInArea(Point start, Point end, IEnumerable<string> area, bool allowDiagonals) {
var costs = area.Select(s => s.Select(c => c switch {
' ' => 1,
'X' => float.PositiveInfinity,
'X' => AStar2.InfiniteCost,
_ => (float) char.GetNumericValue(c)
}).ToArray()).ToArray();
var pathFinder = new AStar2((p1, p2) => costs[p2.Y][p2.X], allowDiagonals);

View file

@ -13,7 +13,7 @@ namespace Tests {
protected override void LoadContent() {
base.LoadContent();
this.RawContent = new RawContentManager(this.Services, this.Content.RootDirectory);
this.UiSystem.Style.Font = new GenericSpriteFont(MlemGame.LoadContent<SpriteFont>("TestFont"));
this.UiSystem.Style.Font = new GenericSpriteFont(LoadContent<SpriteFont>("TestFont"));
}
public static TestGame Create() {

View file

@ -43,8 +43,8 @@ namespace Tests {
[Test]
public void TestDisposal() {
using var packer = new RuntimeTexturePacker(128, disposeTextures: true);
packer.Add(new TextureRegion(this.disposedTestTexture), TexturePackerTests.StubResult);
packer.Add(new TextureRegion(this.disposedTestTexture, 0, 0, 8, 8), TexturePackerTests.StubResult);
packer.Add(new TextureRegion(this.disposedTestTexture), StubResult);
packer.Add(new TextureRegion(this.disposedTestTexture, 0, 0, 8, 8), StubResult);
packer.Pack(this.game.GraphicsDevice);
Assert.True(this.disposedTestTexture.IsDisposed);
Assert.False(packer.PackedTexture.IsDisposed);
@ -55,26 +55,26 @@ namespace Tests {
// test forced max width
using var packer = new RuntimeTexturePacker(128);
Assert.Throws<InvalidOperationException>(() => {
packer.Add(new TextureRegion(this.testTexture, 0, 0, 256, 128), TexturePackerTests.StubResult);
packer.Add(new TextureRegion(this.testTexture, 0, 0, 256, 128), StubResult);
});
// test auto-expanding width
using var packer2 = new RuntimeTexturePacker(128, true);
Assert.DoesNotThrow(() => {
packer2.Add(new TextureRegion(this.testTexture, 0, 0, 256, 128), TexturePackerTests.StubResult);
packer2.Add(new TextureRegion(this.testTexture, 0, 0, 256, 128), StubResult);
});
packer2.Pack(this.game.GraphicsDevice);
// test power of two forcing
using var packer3 = new RuntimeTexturePacker(128, forcePowerOfTwo: true);
packer3.Add(new TextureRegion(this.testTexture, 0, 0, 37, 170), TexturePackerTests.StubResult);
packer3.Add(new TextureRegion(this.testTexture, 0, 0, 37, 170), StubResult);
packer3.Pack(this.game.GraphicsDevice);
Assert.AreEqual(64, packer3.PackedTexture.Width);
Assert.AreEqual(256, packer3.PackedTexture.Height);
// test square forcing
using var packer4 = new RuntimeTexturePacker(128, forceSquare: true);
packer4.Add(new TextureRegion(this.testTexture, 0, 0, 37, 170), TexturePackerTests.StubResult);
packer4.Add(new TextureRegion(this.testTexture, 0, 0, 37, 170), StubResult);
packer4.Pack(this.game.GraphicsDevice);
Assert.AreEqual(170, packer4.PackedTexture.Width);
Assert.AreEqual(170, packer4.PackedTexture.Height);