Skip to content

Commit

Permalink
Merge circle segments when chaining them
Browse files Browse the repository at this point in the history
  • Loading branch information
LumpBloom7 committed Aug 12, 2023
1 parent e2d97af commit bdf049c
Show file tree
Hide file tree
Showing 3 changed files with 157 additions and 10 deletions.
2 changes: 1 addition & 1 deletion .globalconfig
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ dotnet_diagnostic.IDE0003.severity = warning
dotnet_diagnostic.IDE0004.severity = warning

# IDE0005: Remove unnecessary imports
dotnet_diagnostic.IDE0005.severity = warning
dotnet_diagnostic.IDE0005.severity = suggestion

# IDE0034: Simplify default literal
dotnet_diagnostic.IDE0034.severity = warning
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Pooling;
using osu.Framework.Graphics.Shapes;
using osu.Game.Rulesets.Sentakki.Objects;
using osu.Game.Rulesets.Sentakki.Objects.Drawables.Pieces.Slides;
using osu.Game.Rulesets.Sentakki.UI;
using osu.Game.Rulesets.Sentakki.UI.Components;
using osu.Game.Tests.Visual;
using osuTK;
using osuTK.Graphics;

namespace osu.Game.Rulesets.Sentakki.Tests.Objects.Slides
{
[TestFixture]
public partial class TestSceneCircleChaining : OsuTestScene
{
protected override Ruleset CreateRuleset() => new SentakkiRuleset();

private bool mirrored;

private readonly SlideVisual slide;
private readonly Container nodes;

[Cached]
private readonly DrawablePool<SlideChevron> chevronPool = null!;

[Cached]
private readonly SlideFanChevrons fanChevrons = null!;

public TestSceneCircleChaining()
{
Add(chevronPool = new DrawablePool<SlideChevron>(62));
Add(fanChevrons = new SlideFanChevrons());

Add(new SentakkiRing
{
RelativeSizeAxes = Axes.None,
Size = new Vector2(SentakkiPlayfield.RINGSIZE)
});

Add(slide = new SlideVisual());

AddToggleStep("Mirrored second part", b =>
{
mirrored = b;
RefreshSlide();
});

AddStep("Perform entry animation", () => slide.PerformEntryAnimation(1000));
AddWaitStep("Wait for transforms", 5);

AddStep("Perform exit animation", () => slide.PerformExitAnimation(1000));
AddWaitStep("Wait for transforms", 5);

Add(nodes = new Container
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
});
}

protected SentakkiSlidePath CreatePattern()
{
var pathParameters = new[]{
new SlideBodyPart(SlidePaths.PathShapes.Circle, endOffset: 4, false),
new SlideBodyPart(SlidePaths.PathShapes.Circle, endOffset: 4, mirrored),
};

return SlidePaths.CreateSlidePath(pathParameters);
}
protected override void LoadComplete()
{
base.LoadComplete();
RefreshSlide();
}

protected void RefreshSlide()
{
slide.Path = CreatePattern();
nodes.Clear();

foreach (var node in slide.Path.SlideSegments.SelectMany(s => s.ControlPoints))
{
nodes.Add(new CircularContainer
{
Size = new Vector2(10),
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Position = node.Position,
Masking = true,
Child = new Box
{
Colour = Color4.Green,
RelativeSizeAxes = Axes.Both
}
});
}
}
}
}
61 changes: 52 additions & 9 deletions osu.Game.Rulesets.Sentakki/Objects/SlidePaths.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,10 @@ public static SentakkiSlidePath CreateSlidePath(int startOffset, params SlideBod
{
List<SliderPath> slideSegments = new List<SliderPath>();

foreach (var path in pathParameters)
for (int i = 0; i < pathParameters.Length; ++i)
{
var path = pathParameters[i];

switch (path.Shape)
{
case PathShapes.Straight:
Expand All @@ -98,7 +100,22 @@ public static SentakkiSlidePath CreateSlidePath(int startOffset, params SlideBod
break;

case PathShapes.Circle:
slideSegments.Add(generateCirclePattern(startOffset, path.EndOffset, path.Mirrored ? RotationDirection.Counterclockwise : RotationDirection.Clockwise));

var newSegment = generateCirclePattern(startOffset, path.EndOffset, path.Mirrored ? RotationDirection.Counterclockwise : RotationDirection.Clockwise);

// Combine Circle paths in the same direction
if (i > 0)
{
var prevPath = pathParameters[i - 1];

if (prevPath.Shape == PathShapes.Circle && prevPath.Mirrored == path.Mirrored)
{
slideSegments[^1].ControlPoints.AddRange(newSegment.ControlPoints);
break;
}
}

slideSegments.Add(newSegment);
break;

case PathShapes.V:
Expand All @@ -123,6 +140,7 @@ public static SentakkiSlidePath CreateSlidePath(int startOffset, params SlideBod
}

startOffset += path.EndOffset;

}

return new SentakkiSlidePath(slideSegments.ToArray(), startOffset, pathParameters[^1].Shape == PathShapes.Fan);
Expand Down Expand Up @@ -243,16 +261,41 @@ private static IEnumerable<SliderPath> generateLPattern(int offset, int end, boo
// DX Circle Pattern
private static SliderPath generateCirclePattern(int offset, int end, RotationDirection direction = RotationDirection.Clockwise)
{
float centre = ((offset.GetRotationForLane() + (end + offset).GetRotationForLane()) / 2) + (direction == RotationDirection.Counterclockwise ? 180 : 0);
Vector2 centreNode = SentakkiExtensions.GetCircularPosition(SentakkiPlayfield.INTERSECTDISTANCE, centre == offset.GetRotationForLane() ? centre + 180 : centre);
bool isFullCircle = end.NormalizePath() == 0;
bool isCounterClockwise = direction == RotationDirection.Counterclockwise;

float startAngle = offset.GetRotationForLane();
float endAngle = (end + offset).GetRotationForLane();

float centreAngle;

if (isFullCircle)
{
// If it is a full circle, we simply put the centre node across that start point
centreAngle = (offset + 4).GetRotationForLane();
}
else
{
// Find the angle between the start and end points
centreAngle = (startAngle + endAngle) / 2;

// If the direction is Counterclockwise, then we flip the centre to the otherside;
if (isCounterClockwise)
centreAngle += 180;
}

// This is a slight angle tweak to help SliderPath determine which direction the path goes
float angleTweak = 0.1f * (isCounterClockwise ? -1 : 1);

Vector2 node0Pos = SentakkiExtensions.GetCircularPosition(SentakkiPlayfield.INTERSECTDISTANCE, startAngle + angleTweak);
Vector2 node1Pos = SentakkiExtensions.GetCircularPosition(SentakkiPlayfield.INTERSECTDISTANCE, centreAngle);
Vector2 node2Pos = SentakkiExtensions.GetCircularPosition(SentakkiPlayfield.INTERSECTDISTANCE, endAngle);

return new SliderPath(new[]
{
new PathControlPoint(
SentakkiExtensions.GetCircularPosition(SentakkiPlayfield.INTERSECTDISTANCE, offset.GetRotationForLane() + (direction == RotationDirection.Counterclockwise ? -.5f : .5f)),
PathType.PerfectCurve),
new PathControlPoint(centreNode),
new PathControlPoint(SentakkiExtensions.GetPositionAlongLane(SentakkiPlayfield.INTERSECTDISTANCE, end + offset), PathType.PerfectCurve)
new PathControlPoint(node0Pos, PathType.PerfectCurve),
new PathControlPoint(node1Pos),
new PathControlPoint(node2Pos, PathType.PerfectCurve)
});
}

Expand Down

0 comments on commit bdf049c

Please sign in to comment.