extended hitobject tests

This commit is contained in:
Aergwyn 2018-01-01 11:55:24 +01:00
parent b269282407
commit 481a16b491
9 changed files with 231 additions and 114 deletions

View File

@ -26,7 +26,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
Origin = Anchor.Centre;
Position = HitObject.StackedPosition;
Scale = new Vector2(HitObject.Scale);
Scale = new Vector2(h.Scale);
Children = new Drawable[]
{

View File

@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
{
public class DrawableSpinner : DrawableOsuHitObject
{
private readonly Spinner spinner;
protected readonly Spinner Spinner;
public readonly SpinnerDisc Disc;
public readonly SpinnerTicks Ticks;
@ -50,7 +50,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
// we are slightly bigger than our parent, to clip the top and bottom of the circle
Height = 1.3f;
spinner = s;
Spinner = s;
Children = new Drawable[]
{
@ -91,7 +91,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
},
Disc = new SpinnerDisc(spinner)
Disc = new SpinnerDisc(Spinner)
{
Scale = Vector2.Zero,
Anchor = Anchor.Centre,
@ -115,7 +115,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
};
}
public float Progress => MathHelper.Clamp(Disc.RotationAbsolute / 360 / spinner.SpinsRequired, 0, 1);
public float Progress => MathHelper.Clamp(Disc.RotationAbsolute / 360 / Spinner.SpinsRequired, 0, 1);
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
{
@ -136,7 +136,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
glow.FadeColour(completeColour, duration);
}
if (!userTriggered && Time.Current >= spinner.EndTime)
if (!userTriggered && Time.Current >= Spinner.EndTime)
{
if (Progress >= 1)
AddJudgement(new OsuJudgement { Result = HitResult.Great });
@ -144,7 +144,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
AddJudgement(new OsuJudgement { Result = HitResult.Good });
else if (Progress > .75)
AddJudgement(new OsuJudgement { Result = HitResult.Meh });
else if (Time.Current >= spinner.EndTime)
else if (Time.Current >= Spinner.EndTime)
AddJudgement(new OsuJudgement { Result = HitResult.Miss });
}
}
@ -180,7 +180,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
Ticks.Rotation = Disc.Rotation;
spmCounter.SetRotation(Disc.RotationAbsolute);
float relativeCircleScale = spinner.Scale * circle.DrawHeight / mainContainer.DrawHeight;
float relativeCircleScale = Spinner.Scale * circle.DrawHeight / mainContainer.DrawHeight;
Disc.ScaleTo(relativeCircleScale + (1 - relativeCircleScale) * Progress, 200, Easing.OutQuint);
symbol.RotateTo(Disc.Rotation / 2, 500, Easing.OutQuint);
@ -190,22 +190,22 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
{
base.UpdatePreemptState();
circleContainer.ScaleTo(spinner.Scale * 0.3f);
circleContainer.ScaleTo(spinner.Scale, TIME_PREEMPT / 1.4f, Easing.OutQuint);
circleContainer.ScaleTo(Spinner.Scale * 0.3f);
circleContainer.ScaleTo(Spinner.Scale, TIME_PREEMPT / 1.4f, Easing.OutQuint);
Disc.RotateTo(-720);
symbol.RotateTo(-720);
mainContainer
.ScaleTo(0)
.ScaleTo(spinner.Scale * circle.DrawHeight / DrawHeight * 1.4f, TIME_PREEMPT - 150, Easing.OutQuint)
.ScaleTo(Spinner.Scale * circle.DrawHeight / DrawHeight * 1.4f, TIME_PREEMPT - 150, Easing.OutQuint)
.Then()
.ScaleTo(1, 500, Easing.OutQuint);
}
protected override void UpdateCurrentState(ArmedState state)
{
var sequence = this.Delay(spinner.Duration).FadeOut(160);
var sequence = this.Delay(Spinner.Duration).FadeOut(160);
switch (state)
{

View File

@ -11,11 +11,13 @@ using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables;
using osu.Game.Tests.Visual;
using OpenTK;
using osu.Game.Rulesets.Osu.Mods;
using OpenTK.Graphics;
using osu.Game.Rulesets.Osu.Judgements;
using System.Collections.Generic;
using System;
using osu.Game.Rulesets.Mods;
using System.Linq;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Osu.Tests
{
@ -25,32 +27,34 @@ namespace osu.Game.Rulesets.Osu.Tests
public override IReadOnlyList<Type> RequiredTypes => new[]
{
typeof(HitCircle),
typeof(OsuModHidden),
typeof(DrawableHitCircle)
};
private readonly Container content;
protected override Container<Drawable> Content => content;
private bool auto;
private bool hidden;
private int depthIndex;
private int circleSize;
private float circleScale = 1;
protected readonly List<Mod> Mods = new List<Mod>();
public TestCaseHitCircle()
{
base.Content.Add(content = new OsuInputManager(new RulesetInfo { ID = 0 }));
AddStep("Single", () => testSingle());
AddStep("Stream", testStream);
AddToggleStep("Auto", v => auto = v);
AddToggleStep("Hidden", v => hidden = v);
AddSliderStep("CircleSize", 0, 10, 0, s => circleSize = s);
AddSliderStep("CircleScale", 0.5f, 2, 1, s => circleScale = s);
AddStep("Miss Big Single", () => testSingle(2));
AddStep("Miss Medium Single", () => testSingle(5));
AddStep("Miss Small Single", () => testSingle(7));
AddStep("Hit Big Single", () => testSingle(2, true));
AddStep("Hit Medium Single", () => testSingle(5, true));
AddStep("Hit Small Single", () => testSingle(7, true));
AddStep("Miss Big Stream", () => testStream(2));
AddStep("Miss Medium Stream", () => testStream(5));
AddStep("Miss Small Stream", () => testStream(7));
AddStep("Hit Big Stream", () => testStream(2, true));
AddStep("Hit Medium Stream", () => testStream(5, true));
AddStep("Hit Small Stream", () => testStream(7, true));
}
private void testSingle(double timeOffset = 0, Vector2? positionOffset = null)
private void testSingle(float circleSize, bool auto = false, double timeOffset = 0, Vector2? positionOffset = null)
{
positionOffset = positionOffset ?? Vector2.Zero;
@ -66,27 +70,23 @@ namespace osu.Game.Rulesets.Osu.Tests
var drawable = new TestDrawableHitCircle(circle, auto)
{
Anchor = Anchor.Centre,
Scale = new Vector2(circleScale),
Depth = depthIndex++
};
if (auto)
drawable.State.Value = ArmedState.Hit;
if (hidden)
new OsuModHidden().ApplyToDrawableHitObjects(new [] { drawable });
foreach (var mod in Mods.OfType<IApplicableToDrawableHitObjects>())
mod.ApplyToDrawableHitObjects(new[] { drawable });
Add(drawable);
}
private void testStream()
private void testStream(float circleSize, bool auto = false)
{
Vector2 pos = Vector2.Zero;
Vector2 pos = new Vector2(-250, 0);
for (int i = 0; i <= 1000; i += 100)
{
testSingle(i, pos);
pos += new Vector2(10);
testSingle(circleSize, auto, i, pos);
pos.X += 50;
}
}
@ -103,13 +103,15 @@ namespace osu.Game.Rulesets.Osu.Tests
{
if (auto && !userTriggered && timeOffset > 0)
{
// pretend we really hit it
// force success
AddJudgement(new OsuJudgement
{
Result = HitObject.ScoreResultForOffset(timeOffset)
Result = HitResult.Great
});
State.Value = ArmedState.Hit;
}
base.CheckForJudgements(userTriggered, timeOffset);
else
base.CheckForJudgements(userTriggered, timeOffset);
}
}
}

View File

@ -0,0 +1,26 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Collections.Generic;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables;
namespace osu.Game.Rulesets.Osu.Tests
{
public class TestCaseHitCircleHidden : TestCaseHitCircle
{
public override IReadOnlyList<Type> RequiredTypes => new[]
{
typeof(HitCircle),
typeof(OsuModHidden),
typeof(DrawableHitCircle)
};
public TestCaseHitCircleHidden()
{
Mods.Add(new OsuModHidden());
}
}
}

View File

@ -13,8 +13,9 @@ using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables;
using osu.Game.Tests.Visual;
using OpenTK;
using osu.Game.Rulesets.Osu.Mods;
using OpenTK.Graphics;
using osu.Game.Rulesets.Mods;
using System.Linq;
namespace osu.Game.Rulesets.Osu.Tests
{
@ -25,7 +26,8 @@ namespace osu.Game.Rulesets.Osu.Tests
{
typeof(Slider),
typeof(HitCircle),
typeof(OsuModHidden),
typeof(SliderTick),
typeof(RepeatPoint),
typeof(DrawableSlider),
typeof(DrawableHitCircle),
typeof(DrawableSliderTick),
@ -35,58 +37,84 @@ namespace osu.Game.Rulesets.Osu.Tests
private readonly Container content;
protected override Container<Drawable> Content => content;
private bool hidden;
private int repeats;
private int depthIndex;
private int circleSize;
private float circleScale = 1;
private double speedMultiplier = 2;
private double sliderMultiplier = 2;
protected readonly List<Mod> Mods = new List<Mod>();
public TestCaseSlider()
{
base.Content.Add(content = new OsuInputManager(new RulesetInfo { ID = 0 }));
AddStep("Single", () => testSingle());
AddStep("Stream", testStream);
AddStep("Repeated", () => testRepeated(repeats));
AddToggleStep("Hidden", v => hidden = v);
AddSliderStep("Repeats", 1, 10, 1, s => repeats = s);
AddSliderStep("CircleSize", 0, 10, 0, s => circleSize = s);
AddSliderStep("CircleScale", 0.5f, 2, 1, s => circleScale = s);
AddSliderStep("SpeedMultiplier", 0.1, 10, 2, s => speedMultiplier = s);
AddSliderStep("SliderMultiplier", 0.1, 10, 2, s => sliderMultiplier = s);
AddStep("Big Single", () => testSimpleBig());
AddStep("Medium Single", () => testSimpleMedium());
AddStep("Small Single", () => testSimpleSmall());
AddStep("Big 1 Repeat", () => testSimpleBig(1));
AddStep("Medium 1 Repeat", () => testSimpleMedium(1));
AddStep("Small 1 Repeat", () => testSimpleSmall(1));
AddStep("Big 2 Repeats", () => testSimpleBig(2));
AddStep("Medium 2 Repeats", () => testSimpleMedium(2));
AddStep("Small 2 Repeats", () => testSimpleSmall(2));
AddStep("Slow Slider", testSlowSpeed); // slow long sliders take ages already so no repeat steps
AddStep("Slow Short Slider", () => testShortSlowSpeed());
AddStep("Slow Short Slider 1 Repeats", () => testShortSlowSpeed(1));
AddStep("Slow Short Slider 2 Repeats", () => testShortSlowSpeed(2));
AddStep("Fast Slider", () => testHighSpeed());
AddStep("Fast Slider 1 Repeat", () => testHighSpeed(1));
AddStep("Fast Slider 2 Repeats", () => testHighSpeed(2));
AddStep("Fast Short Slider", () => testHighSpeed());
AddStep("Fast Short Slider 1 Repeat", () => testHighSpeed(1));
AddStep("Fast Short Slider 2 Repeats", () => testHighSpeed(2));
AddStep("Perfect Curve", testCurve);
// TODO more curve types?
}
private void testSingle(double timeOffset = 0, Vector2? positionOffset = null)
private void testSimpleBig(int repeats = 0) => createSlider(2, repeats: repeats);
private void testSimpleMedium(int repeats = 0) => createSlider(5, repeats: repeats);
private void testSimpleSmall(int repeats = 0) => createSlider(7, repeats: repeats);
private void testSlowSpeed() => createSlider(speedMultiplier: 0.5);
private void testShortSlowSpeed(int repeats = 0) => createSlider(distance: 100, repeats: repeats, speedMultiplier: 0.5);
private void testHighSpeed(int repeats = 0) => createSlider(repeats: repeats, speedMultiplier: 15);
private void testShortHighSpeed(int repeats = 0) => createSlider(distance: 100, repeats: repeats, speedMultiplier: 15);
private void createSlider(float circleSize = 2, float distance = 800, int repeats = 0, double speedMultiplier = 2)
{
positionOffset = positionOffset ?? Vector2.Zero;
repeats++; // The first run through the slider is considered a repeat
var repeatSamples = new List<List<SampleInfo>>();
if (repeats > 1)
{
for (int i = 0; i < repeats; i++)
repeatSamples.Add(new List<SampleInfo>());
}
var slider = new Slider
{
StartTime = Time.Current + 1000 + timeOffset,
Position = new Vector2(-200, 0) + positionOffset.Value,
StartTime = Time.Current + 1000,
Position = new Vector2(-(distance / 2), 0),
ComboColour = Color4.LightSeaGreen,
ControlPoints = new List<Vector2>
{
new Vector2(-200, 0) + positionOffset.Value,
new Vector2(400, 0) + positionOffset.Value,
new Vector2(-(distance / 2), 0),
new Vector2(distance / 2, 0),
},
Distance = 400
Distance = distance,
RepeatCount = repeats,
RepeatSamples = repeatSamples
};
addSlider(slider);
addSlider(slider, circleSize, speedMultiplier);
}
private void testRepeated(int repeats)
private void testCurve()
{
// The first run through the slider is considered a repeat
repeats++;
var repeatSamples = new List<List<SampleInfo>>();
for (int i = 0; i < repeats; i++)
repeatSamples.Add(new List<SampleInfo>());
var slider = new Slider
{
StartTime = Time.Current + 1000,
@ -95,52 +123,32 @@ namespace osu.Game.Rulesets.Osu.Tests
ControlPoints = new List<Vector2>
{
new Vector2(-200, 0),
new Vector2(400, 0),
new Vector2(0, 200),
new Vector2(200, 0)
},
Distance = 400,
RepeatCount = repeats,
RepeatSamples = repeatSamples
Distance = 600
};
addSlider(slider);
addSlider(slider, 2, 3);
}
private void testStream()
{
Vector2 pos = Vector2.Zero;
for (int i = 0; i <= 1000; i += 100)
{
testSingle(i, pos);
pos += new Vector2(10);
}
}
private void addSlider(Slider slider)
private void addSlider(Slider slider, float circleSize, double speedMultiplier)
{
var cpi = new ControlPointInfo();
cpi.DifficultyPoints.Add(new DifficultyControlPoint { SpeedMultiplier = speedMultiplier });
var difficulty = new BeatmapDifficulty
{
SliderMultiplier = (float)sliderMultiplier,
CircleSize = circleSize
};
slider.ApplyDefaults(cpi, difficulty);
slider.ApplyDefaults(cpi, new BeatmapDifficulty { CircleSize = circleSize });
var drawable = new DrawableSlider(slider)
{
Anchor = Anchor.Centre,
Scale = new Vector2(circleScale),
Depth = depthIndex++
};
if (hidden)
new OsuModHidden().ApplyToDrawableHitObjects(new [] { drawable });
foreach (var mod in Mods.OfType<IApplicableToDrawableHitObjects>())
mod.ApplyToDrawableHitObjects(new[] { drawable });
Add(drawable);
}
}
}

View File

@ -0,0 +1,32 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Collections.Generic;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables;
namespace osu.Game.Rulesets.Osu.Tests
{
public class TestCaseSliderHidden : TestCaseSlider
{
public override IReadOnlyList<Type> RequiredTypes => new[]
{
typeof(Slider),
typeof(HitCircle),
typeof(SliderTick),
typeof(RepeatPoint),
typeof(OsuModHidden),
typeof(DrawableSlider),
typeof(DrawableHitCircle),
typeof(DrawableSliderTick),
typeof(DrawableRepeatPoint)
};
public TestCaseSliderHidden()
{
Mods.Add(new OsuModHidden());
}
}
}

View File

@ -3,13 +3,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using OpenTK;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables;
using osu.Game.Tests.Visual;
@ -22,45 +22,65 @@ namespace osu.Game.Rulesets.Osu.Tests
public override IReadOnlyList<Type> RequiredTypes => new[]
{
typeof(Spinner),
typeof(OsuModHidden),
typeof(DrawableSpinner)
};
private readonly Container content;
protected override Container<Drawable> Content => content;
private bool hidden;
private int depthIndex;
private int circleSize;
private float circleScale = 1;
protected readonly List<Mod> Mods = new List<Mod>();
public TestCaseSpinner()
{
base.Content.Add(content = new OsuInputManager(new RulesetInfo { ID = 0 }));
AddStep("Single", testSingle);
AddToggleStep("Hidden", v => hidden = v);
AddSliderStep("CircleSize", 0, 10, 0, s => circleSize = s);
AddSliderStep("CircleScale", 0.5f, 2, 1, s => circleScale = s);
AddStep("Miss Big", () => testSingle(2));
AddStep("Miss Medium", () => testSingle(5));
AddStep("Miss Small", () => testSingle(7));
AddStep("Hit Big", () => testSingle(2, true));
AddStep("Hit Medium", () => testSingle(5, true));
AddStep("Hit Small", () => testSingle(7, true));
}
private void testSingle()
private void testSingle(float circleSize, bool auto = false)
{
var spinner = new Spinner { StartTime = Time.Current + 1000, EndTime = Time.Current + 4000 };
spinner.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty { CircleSize = circleSize });
var drawable = new DrawableSpinner(spinner)
var drawable = new TestDrawableSpinner(spinner, auto)
{
Anchor = Anchor.Centre,
Scale = new Vector2(circleScale),
Depth = depthIndex++
};
if (hidden)
new OsuModHidden().ApplyToDrawableHitObjects(new [] { drawable });
foreach (var mod in Mods.OfType<IApplicableToDrawableHitObjects>())
mod.ApplyToDrawableHitObjects(new[] { drawable });
Add(drawable);
}
private class TestDrawableSpinner : DrawableSpinner
{
private bool auto;
public TestDrawableSpinner(Spinner s, bool auto) : base(s)
{
this.auto = auto;
}
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
{
if (auto && !userTriggered && Time.Current > Spinner.StartTime + Spinner.Duration / 2 && Progress < 1)
{
// force completion only once to not break human interaction
Disc.RotationAbsolute = Spinner.SpinsRequired * 360;
auto = false;
}
base.CheckForJudgements(userTriggered, timeOffset);
}
}
}
}

View File

@ -0,0 +1,26 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Collections.Generic;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables;
namespace osu.Game.Rulesets.Osu.Tests
{
public class TestCaseSpinnerHidden : TestCaseSpinner
{
public override IReadOnlyList<Type> RequiredTypes => new[]
{
typeof(Spinner),
typeof(OsuModHidden),
typeof(DrawableSpinner)
};
public TestCaseSpinnerHidden()
{
Mods.Add(new OsuModHidden());
}
}
}

View File

@ -88,9 +88,12 @@
<Compile Include="OsuInputManager.cs" />
<Compile Include="Replays\OsuReplayInputHandler.cs" />
<Compile Include="Tests\TestCaseHitCircle.cs" />
<Compile Include="Tests\TestCaseHitCircleHidden.cs" />
<Compile Include="Tests\TestCasePerformancePoints.cs" />
<Compile Include="Tests\TestCaseSlider.cs" />
<Compile Include="Tests\TestCaseSliderHidden.cs" />
<Compile Include="Tests\TestCaseSpinner.cs" />
<Compile Include="Tests\TestCaseSpinnerHidden.cs" />
<Compile Include="UI\Cursor\CursorTrail.cs" />
<Compile Include="UI\Cursor\GameplayCursor.cs" />
<Compile Include="UI\OsuSettings.cs" />