Skip to content

Commit

Permalink
End game statistics for hit distributions per button
Browse files Browse the repository at this point in the history
  • Loading branch information
goodtrailer committed Apr 10, 2021
1 parent 2e66415 commit fdbbdbd
Show file tree
Hide file tree
Showing 3 changed files with 152 additions and 1 deletion.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ An osu! ruleset mimicking Genshin Impact's Ballads of Breeze mini-game.
1. ✓ Mods (+HT, +DC, +DT, +NC, +HR, +EZ, +DA, +AT, +CN, +NF, +SD, +PF, +WU, +WD, +RD)
1. ✓ Replays
1. ✓ Kiai visuals
1. End-game statistics
1. End-game statistics
1. Difficulty calculation
1. Editor support (at the very least, prevent crashing)
1. Spinner mod (+SP)
Expand Down
61 changes: 61 additions & 0 deletions osu.Game.Rulesets.Soyokaze/SoyokazeRuleset.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,20 @@
using osu.Game.Rulesets.Difficulty;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Replays.Types;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.Soyokaze.Beatmaps;
using osu.Game.Rulesets.Soyokaze.Configuration;
using osu.Game.Rulesets.Soyokaze.Difficulty;
using osu.Game.Rulesets.Soyokaze.Extensions;
using osu.Game.Rulesets.Soyokaze.Mods;
using osu.Game.Rulesets.Soyokaze.Objects;
using osu.Game.Rulesets.Soyokaze.Replays;
using osu.Game.Rulesets.Soyokaze.Skinning.Legacy;
using osu.Game.Rulesets.Soyokaze.Statistics;
using osu.Game.Rulesets.Soyokaze.UI;
using osu.Game.Rulesets.UI;
using osu.Game.Scoring;
using osu.Game.Screens.Ranking.Statistics;
using osu.Game.Skinning;
using osuTK;

Expand Down Expand Up @@ -54,6 +60,61 @@ public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IRea

public override IConvertibleReplayFrame CreateConvertibleReplayFrame() => new SoyokazeReplayFrame();

public override StatisticRow[] CreateStatisticsForScore(ScoreInfo score, IBeatmap playableBeatmap)
{
List<HitEvent>[] HitEventsLists = new List<HitEvent>[8];
for (int i = 0; i < HitEventsLists.Length; i++)
HitEventsLists[i] = new List<HitEvent>();

foreach (HitEvent hitEvent in score.HitEvents)
{
if (!(hitEvent.HitObject is SoyokazeHitObject soyokazeObject))
continue;

HitEventsLists[(int)soyokazeObject.Button].Add(hitEvent);
}

Container accuracyGraphsContainer = new Container()
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
AutoSizeAxes = Axes.Both,
};

Vector2[] positions = PositionExtensions.GetPositions(250, 130, true, Anchor.Centre);
for (int i = 0; i < positions.Length; i++)
accuracyGraphsContainer.Add(new AccuracyGraph(HitEventsLists[i]) { Position = positions[i] });

return new StatisticRow[]
{
new StatisticRow
{
Columns = new StatisticItem[]
{
new StatisticItem("Button Accuracies", accuracyGraphsContainer),
},
},
new StatisticRow
{
Columns = new StatisticItem[]
{
new StatisticItem("Overall Distribution", new HitEventTimingDistributionGraph(score.HitEvents)
{
RelativeSizeAxes = Axes.X,
Size = new Vector2(1f, 100f)
}),
}
},
new StatisticRow
{
Columns = new StatisticItem[]
{
new StatisticItem("", new UnstableRate(score.HitEvents){ AutoSizeAxes = Axes.None, RelativeSizeAxes = Axes.X, Size = new Vector2(0.2f, 10f) }),
},
},
};
}

public override IEnumerable<Mod> GetModsFor(ModType type)
{
switch (type)
Expand Down
90 changes: 90 additions & 0 deletions osu.Game.Rulesets.Soyokaze/Statistics/AccuracyGraph.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// Copyright (c) Alden Wu <[email protected]>. Licensed under the MIT Licence.
// See the LICENSE file in the repository root for full licence text.

using System.Collections.Generic;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Scoring;
using osu.Game.Screens.Ranking.Statistics;
using osuTK;

namespace osu.Game.Rulesets.Soyokaze.Statistics
{
public class AccuracyGraph : FillFlowContainer
{
public AccuracyGraph(List<HitEvent> hitEvents)
{
Direction = FillDirection.Vertical;
Anchor = Anchor.Centre;
Origin = Anchor.Centre;
Size = new Vector2(200f, 140f);

AddRange(new Drawable[]
{
new SpriteText
{
Text = (calculateAccuracy(hitEvents) * 100).ToString("0.00") + "%",
Colour = Color4Extensions.FromHex("#66FFCC"),
Font = OsuFont.Torus.With(size: 56),
MaxWidth = 170f,
AllowMultiline = false,

Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Size = new Vector2(0.8f, 0.4f),
},
new UnstableRate(hitEvents)
{
AutoSizeAxes = Axes.None,

Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Size = new Vector2(0.8f, 0.13f),
},
new HitEventTimingDistributionGraph(hitEvents)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Size = new Vector2(1f, 0.4f),
},
new SpriteText
{
Text = hitEvents.Count.ToString() + " objects",
Colour = Color4Extensions.FromHex("#66FFCC"),
Font = OsuFont.Torus.With(size: 12),
AllowMultiline = false,

Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Size = new Vector2(0.3f, 0.07f),
},
});
}

private float calculateAccuracy(List<HitEvent> hitEvents)
{
int maxScore = 0;
int score = 0;

foreach (HitEvent hitEvent in hitEvents)
{
JudgementResult result = new JudgementResult(hitEvent.HitObject, hitEvent.HitObject.CreateJudgement())
{
Type = hitEvent.Result
};
score += result.Judgement.NumericResultFor(result);
maxScore += result.Judgement.MaxNumericResult;
}

return (float)score / maxScore;
}
}
}

0 comments on commit fdbbdbd

Please sign in to comment.