1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-16 05:42:54 +08:00

Merge branch 'master' into new-option-search

This commit is contained in:
Dean Herbert 2017-05-11 21:04:37 +09:00 committed by GitHub
commit ca32caf9e4
29 changed files with 707 additions and 109 deletions

@ -1 +1 @@
Subproject commit 3dd870dc42474978c0465d4276641431eba16c91 Subproject commit a1a62c14a51654c933c5b077c725d566f167145b

View File

@ -0,0 +1,89 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Testing;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.Objects.Drawables;
using OpenTK.Graphics;
using OpenTK;
namespace osu.Desktop.VisualTests.Tests
{
internal class TestCaseManiaHitObjects : TestCase
{
public override void Reset()
{
base.Reset();
Add(new FillFlowContainer
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Y,
Direction = FillDirection.Horizontal,
Spacing = new Vector2(10, 0),
// Imagine that the containers containing the drawable notes are the "columns"
Children = new Drawable[]
{
new Container
{
Name = "Normal note column",
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Y,
Width = 50,
Children = new[]
{
new Container
{
Name = "Timing section",
RelativeSizeAxes = Axes.Both,
RelativeCoordinateSpace = new Vector2(1, 10000),
Children = new[]
{
new DrawableNote(new Note
{
StartTime = 5000
})
{
AccentColour = Color4.Red
}
}
}
}
},
new Container
{
Name = "Hold note column",
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Y,
Width = 50,
Children = new[]
{
new Container
{
Name = "Timing section",
RelativeSizeAxes = Axes.Both,
RelativeCoordinateSpace = new Vector2(1, 10000),
Children = new[]
{
new DrawableHoldNote(new HoldNote
{
StartTime = 5000,
Duration = 1000
})
{
AccentColour = Color4.Red
}
}
}
}
}
}
});
}
}
}

View File

@ -190,6 +190,7 @@
<Compile Include="Tests\TestCaseDrawings.cs" /> <Compile Include="Tests\TestCaseDrawings.cs" />
<Compile Include="Tests\TestCaseGamefield.cs" /> <Compile Include="Tests\TestCaseGamefield.cs" />
<Compile Include="Tests\TestCaseGraph.cs" /> <Compile Include="Tests\TestCaseGraph.cs" />
<Compile Include="Tests\TestCaseManiaHitObjects.cs" />
<Compile Include="Tests\TestCaseManiaPlayfield.cs" /> <Compile Include="Tests\TestCaseManiaPlayfield.cs" />
<Compile Include="Tests\TestCaseMenuOverlays.cs" /> <Compile Include="Tests\TestCaseMenuOverlays.cs" />
<Compile Include="Tests\TestCaseMusicController.cs" /> <Compile Include="Tests\TestCaseMusicController.cs" />

View File

@ -11,11 +11,11 @@ using osu.Game.Rulesets.Objects;
namespace osu.Game.Rulesets.Mania.Beatmaps namespace osu.Game.Rulesets.Mania.Beatmaps
{ {
internal class ManiaBeatmapConverter : BeatmapConverter<ManiaBaseHit> internal class ManiaBeatmapConverter : BeatmapConverter<ManiaHitObject>
{ {
protected override IEnumerable<Type> ValidConversionTypes { get; } = new[] { typeof(IHasXPosition) }; protected override IEnumerable<Type> ValidConversionTypes { get; } = new[] { typeof(IHasXPosition) };
protected override IEnumerable<ManiaBaseHit> ConvertHitObject(HitObject original, Beatmap beatmap) protected override IEnumerable<ManiaHitObject> ConvertHitObject(HitObject original, Beatmap beatmap)
{ {
yield return null; yield return null;
} }

View File

@ -0,0 +1,179 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Database;
namespace osu.Game.Rulesets.Mania.Judgements
{
public class HitWindows
{
#region Constants
/// <summary>
/// PERFECT hit window at OD = 10.
/// </summary>
private const double perfect_min = 27.8;
/// <summary>
/// PERFECT hit window at OD = 5.
/// </summary>
private const double perfect_mid = 38.8;
/// <summary>
/// PERFECT hit window at OD = 0.
/// </summary>
private const double perfect_max = 44.8;
/// <summary>
/// GREAT hit window at OD = 10.
/// </summary>
private const double great_min = 68;
/// <summary>
/// GREAT hit window at OD = 5.
/// </summary>
private const double great_mid = 98;
/// <summary>
/// GREAT hit window at OD = 0.
/// </summary>
private const double great_max = 128;
/// <summary>
/// GOOD hit window at OD = 10.
/// </summary>
private const double good_min = 134;
/// <summary>
/// GOOD hit window at OD = 5.
/// </summary>
private const double good_mid = 164;
/// <summary>
/// GOOD hit window at OD = 0.
/// </summary>
private const double good_max = 194;
/// <summary>
/// OK hit window at OD = 10.
/// </summary>
private const double ok_min = 194;
/// <summary>
/// OK hit window at OD = 5.
/// </summary>
private const double ok_mid = 224;
/// <summary>
/// OK hit window at OD = 0.
/// </summary>
private const double ok_max = 254;
/// <summary>
/// BAD hit window at OD = 10.
/// </summary>
private const double bad_min = 242;
/// <summary>
/// BAD hit window at OD = 5.
/// </summary>
private const double bad_mid = 272;
/// <summary>
/// BAD hit window at OD = 0.
/// </summary>
private const double bad_max = 302;
/// <summary>
/// MISS hit window at OD = 10.
/// </summary>
private const double miss_min = 316;
/// <summary>
/// MISS hit window at OD = 5.
/// </summary>
private const double miss_mid = 346;
/// <summary>
/// MISS hit window at OD = 0.
/// </summary>
private const double miss_max = 376;
#endregion
/// <summary>
/// Hit window for a PERFECT hit.
/// </summary>
public double Perfect = perfect_mid;
/// <summary>
/// Hit window for a GREAT hit.
/// </summary>
public double Great = great_mid;
/// <summary>
/// Hit window for a GOOD hit.
/// </summary>
public double Good = good_mid;
/// <summary>
/// Hit window for an OK hit.
/// </summary>
public double Ok = ok_mid;
/// <summary>
/// Hit window for a BAD hit.
/// </summary>
public double Bad = bad_mid;
/// <summary>
/// Hit window for a MISS hit.
/// </summary>
public double Miss = miss_mid;
/// <summary>
/// Constructs default hit windows.
/// </summary>
public HitWindows()
{
}
/// <summary>
/// Constructs hit windows by fitting a parameter to a 2-part piecewise linear function for each hit window.
/// </summary>
/// <param name="difficulty">The parameter.</param>
public HitWindows(double difficulty)
{
Perfect = BeatmapDifficulty.DifficultyRange(difficulty, perfect_max, perfect_mid, perfect_min);
Great = BeatmapDifficulty.DifficultyRange(difficulty, great_max, great_mid, great_min);
Good = BeatmapDifficulty.DifficultyRange(difficulty, good_max, good_mid, good_min);
Ok = BeatmapDifficulty.DifficultyRange(difficulty, ok_max, ok_mid, ok_min);
Bad = BeatmapDifficulty.DifficultyRange(difficulty, bad_max, bad_mid, bad_min);
Miss = BeatmapDifficulty.DifficultyRange(difficulty, miss_max, miss_mid, miss_min);
}
/// <summary>
/// Constructs new hit windows which have been multiplied by a value.
/// </summary>
/// <param name="windows">The original hit windows.</param>
/// <param name="value">The value to multiply each hit window by.</param>
public static HitWindows operator *(HitWindows windows, double value)
{
return new HitWindows
{
Perfect = windows.Perfect * value,
Great = windows.Great * value,
Good = windows.Good * value,
Ok = windows.Ok * value,
Bad = windows.Bad * value,
Miss = windows.Miss * value
};
}
/// <summary>
/// Constructs new hit windows which have been divided by a value.
/// </summary>
/// <param name="windows">The original hit windows.</param>
/// <param name="value">The value to divide each hit window by.</param>
public static HitWindows operator /(HitWindows windows, double value)
{
return new HitWindows
{
Perfect = windows.Perfect / value,
Great = windows.Great / value,
Good = windows.Good / value,
Ok = windows.Ok / value,
Bad = windows.Bad / value,
Miss = windows.Miss / value
};
}
}
}

View File

@ -9,7 +9,7 @@ using System.Collections.Generic;
namespace osu.Game.Rulesets.Mania namespace osu.Game.Rulesets.Mania
{ {
public class ManiaDifficultyCalculator : DifficultyCalculator<ManiaBaseHit> public class ManiaDifficultyCalculator : DifficultyCalculator<ManiaHitObject>
{ {
public ManiaDifficultyCalculator(Beatmap beatmap) public ManiaDifficultyCalculator(Beatmap beatmap)
: base(beatmap) : base(beatmap)
@ -21,6 +21,6 @@ namespace osu.Game.Rulesets.Mania
return 0; return 0;
} }
protected override BeatmapConverter<ManiaBaseHit> CreateBeatmapConverter() => new ManiaBeatmapConverter(); protected override BeatmapConverter<ManiaHitObject> CreateBeatmapConverter() => new ManiaBeatmapConverter();
} }
} }

View File

@ -1,36 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Framework.Graphics.Transforms;
using osu.Framework.Graphics;
using OpenTK;
namespace osu.Game.Rulesets.Mania.Objects.Drawable
{
public class DrawableNote : Sprite
{
private readonly ManiaBaseHit note;
public DrawableNote(ManiaBaseHit note)
{
this.note = note;
Origin = Anchor.Centre;
Scale = new Vector2(0.1f);
}
[BackgroundDependencyLoader]
private void load(TextureStore textures)
{
Texture = textures.Get(@"Menu/logo");
const double duration = 0;
Transforms.Add(new TransformPositionY { StartTime = note.StartTime - 200, EndTime = note.StartTime, StartValue = -0.1f, EndValue = 0.9f });
Transforms.Add(new TransformAlpha { StartTime = note.StartTime + duration + 200, EndTime = note.StartTime + duration + 400, StartValue = 1, EndValue = 0 });
Expire(true);
}
}
}

View File

@ -0,0 +1,69 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Objects.Drawables;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
using OpenTK.Graphics;
namespace osu.Game.Rulesets.Mania.Objects.Drawables
{
public class DrawableHoldNote : DrawableManiaHitObject<HoldNote>
{
private readonly NotePiece headPiece;
private readonly BodyPiece bodyPiece;
private readonly NotePiece tailPiece;
public DrawableHoldNote(HoldNote hitObject)
: base(hitObject)
{
RelativeSizeAxes = Axes.Both;
Height = (float)HitObject.Duration;
Add(new Drawable[]
{
// For now the body piece covers the entire height of the container
// whereas possibly in the future we don't want to extend under the head/tail.
// This will be fixed when new designs are given or the current design is finalized.
bodyPiece = new BodyPiece
{
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
},
headPiece = new NotePiece
{
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre
},
tailPiece = new NotePiece
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre
}
});
// The "length" of the hold note stops at the "base" of the tail piece
// but we want to contain the tail piece within our bounds
Height += (float)HitObject.Duration / headPiece.Height;
}
public override Color4 AccentColour
{
get { return base.AccentColour; }
set
{
if (base.AccentColour == value)
return;
base.AccentColour = value;
headPiece.AccentColour = value;
bodyPiece.AccentColour = value;
tailPiece.AccentColour = value;
}
}
protected override void UpdateState(ArmedState state)
{
}
}
}

View File

@ -0,0 +1,67 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK.Graphics;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Game.Rulesets.Mania.Judgements;
using osu.Game.Rulesets.Objects.Drawables;
namespace osu.Game.Rulesets.Mania.Objects.Drawables
{
public abstract class DrawableManiaHitObject<TObject> : DrawableHitObject<ManiaHitObject, ManiaJudgement>
where TObject : ManiaHitObject
{
public new TObject HitObject;
private readonly Container glowContainer;
protected DrawableManiaHitObject(TObject hitObject)
: base(hitObject)
{
HitObject = hitObject;
Anchor = Anchor.TopCentre;
Origin = Anchor.BottomCentre;
RelativePositionAxes = Axes.Y;
Y = (float)HitObject.StartTime;
Add(glowContainer = new Container
{
RelativeSizeAxes = Axes.Both,
Masking = true,
Children = new[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Alpha = 0,
AlwaysPresent = true
}
}
});
}
public override Color4 AccentColour
{
get { return base.AccentColour; }
set
{
if (base.AccentColour == value)
return;
base.AccentColour = value;
glowContainer.EdgeEffect = new EdgeEffect
{
Type = EdgeEffectType.Glow,
Radius = 5,
Colour = value
};
}
}
protected override ManiaJudgement CreateJudgement() => new ManiaJudgement();
}
}

View File

@ -0,0 +1,45 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK.Graphics;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
using osu.Game.Rulesets.Objects.Drawables;
namespace osu.Game.Rulesets.Mania.Objects.Drawables
{
public class DrawableNote : DrawableManiaHitObject<Note>
{
private readonly NotePiece headPiece;
public DrawableNote(Note hitObject)
: base(hitObject)
{
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;
Add(headPiece = new NotePiece
{
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre
});
}
public override Color4 AccentColour
{
get { return base.AccentColour; }
set
{
if (base.AccentColour == value)
return;
base.AccentColour = value;
headPiece.AccentColour = value;
}
}
protected override void UpdateState(ArmedState state)
{
}
}
}

View File

@ -0,0 +1,48 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK.Graphics;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics;
namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
{
/// <summary>
/// Represents length-wise portion of a hold note.
/// </summary>
internal class BodyPiece : Container, IHasAccentColour
{
private readonly Box box;
public BodyPiece()
{
RelativeSizeAxes = Axes.Both;
Masking = true;
Children = new[]
{
box = new Box
{
RelativeSizeAxes = Axes.Both,
Alpha = 0.3f
}
};
}
private Color4 accentColour;
public Color4 AccentColour
{
get { return accentColour; }
set
{
if (accentColour == value)
return;
accentColour = value;
box.Colour = accentColour;
}
}
}
}

View File

@ -0,0 +1,59 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK.Graphics;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics;
namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
{
/// <summary>
/// Represents the static hit markers of notes.
/// </summary>
internal class NotePiece : Container, IHasAccentColour
{
private const float head_height = 10;
private const float head_colour_height = 6;
private readonly Box colouredBox;
public NotePiece()
{
RelativeSizeAxes = Axes.X;
Height = head_height;
Children = new[]
{
new Box
{
RelativeSizeAxes = Axes.Both
},
colouredBox = new Box
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
RelativeSizeAxes = Axes.X,
Height = head_colour_height,
Alpha = 0.2f
}
};
}
private Color4 accentColour;
public Color4 AccentColour
{
get { return accentColour; }
set
{
if (accentColour == value)
return;
accentColour = value;
colouredBox.Colour = AccentColour.Lighten(0.9f);
}
}
}
}

View File

@ -1,9 +1,37 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Beatmaps.Timing;
using osu.Game.Database;
using osu.Game.Rulesets.Mania.Judgements;
using osu.Game.Rulesets.Objects.Types;
namespace osu.Game.Rulesets.Mania.Objects namespace osu.Game.Rulesets.Mania.Objects
{ {
public class HoldNote : Note /// <summary>
/// Represents a hit object which requires pressing, holding, and releasing a key.
/// </summary>
public class HoldNote : Note, IHasEndTime
{ {
/// <summary>
/// Lenience of release hit windows. This is to make cases where the hold note release
/// is timed alongside presses of other hit objects less awkward.
/// </summary>
private const double release_window_lenience = 1.5;
public double Duration { get; set; }
public double EndTime => StartTime + Duration;
/// <summary>
/// The key-release hit windows for this hold note.
/// </summary>
protected HitWindows ReleaseHitWindows = new HitWindows();
public override void ApplyDefaults(TimingInfo timing, BeatmapDifficulty difficulty)
{
base.ApplyDefaults(timing, difficulty);
ReleaseHitWindows = HitWindows * release_window_lenience;
}
} }
} }

View File

@ -1,12 +1,13 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Mania.Objects.Types;
using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects;
namespace osu.Game.Rulesets.Mania.Objects namespace osu.Game.Rulesets.Mania.Objects
{ {
public abstract class ManiaBaseHit : HitObject public abstract class ManiaHitObject : HitObject, IHasColumn
{ {
public int Column; public int Column { get; set; }
} }
} }

View File

@ -1,9 +1,27 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Beatmaps.Timing;
using osu.Game.Database;
using osu.Game.Rulesets.Mania.Judgements;
namespace osu.Game.Rulesets.Mania.Objects namespace osu.Game.Rulesets.Mania.Objects
{ {
public class Note : ManiaBaseHit /// <summary>
/// Represents a hit object which has a single hit press.
/// </summary>
public class Note : ManiaHitObject
{ {
/// <summary>
/// The key-press hit window for this note.
/// </summary>
protected HitWindows HitWindows = new HitWindows();
public override void ApplyDefaults(TimingInfo timing, BeatmapDifficulty difficulty)
{
base.ApplyDefaults(timing, difficulty);
HitWindows = new HitWindows(difficulty.OverallDifficulty);
}
} }
} }

View File

@ -0,0 +1,16 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
namespace osu.Game.Rulesets.Mania.Objects.Types
{
/// <summary>
/// A type of hit object which lies in one of a number of predetermined columns.
/// </summary>
public interface IHasColumn
{
/// <summary>
/// The column which the hit object lies in.
/// </summary>
int Column { get; }
}
}

View File

@ -8,13 +8,13 @@ using osu.Game.Rulesets.UI;
namespace osu.Game.Rulesets.Mania.Scoring namespace osu.Game.Rulesets.Mania.Scoring
{ {
internal class ManiaScoreProcessor : ScoreProcessor<ManiaBaseHit, ManiaJudgement> internal class ManiaScoreProcessor : ScoreProcessor<ManiaHitObject, ManiaJudgement>
{ {
public ManiaScoreProcessor() public ManiaScoreProcessor()
{ {
} }
public ManiaScoreProcessor(HitRenderer<ManiaBaseHit, ManiaJudgement> hitRenderer) public ManiaScoreProcessor(HitRenderer<ManiaHitObject, ManiaJudgement> hitRenderer)
: base(hitRenderer) : base(hitRenderer)
{ {
} }

View File

@ -13,7 +13,7 @@ using osu.Game.Rulesets.UI;
namespace osu.Game.Rulesets.Mania.UI namespace osu.Game.Rulesets.Mania.UI
{ {
public class ManiaHitRenderer : HitRenderer<ManiaBaseHit, ManiaJudgement> public class ManiaHitRenderer : HitRenderer<ManiaHitObject, ManiaJudgement>
{ {
private readonly int columns; private readonly int columns;
@ -25,10 +25,10 @@ namespace osu.Game.Rulesets.Mania.UI
public override ScoreProcessor CreateScoreProcessor() => new ManiaScoreProcessor(this); public override ScoreProcessor CreateScoreProcessor() => new ManiaScoreProcessor(this);
protected override BeatmapConverter<ManiaBaseHit> CreateBeatmapConverter() => new ManiaBeatmapConverter(); protected override BeatmapConverter<ManiaHitObject> CreateBeatmapConverter() => new ManiaBeatmapConverter();
protected override Playfield<ManiaBaseHit, ManiaJudgement> CreatePlayfield() => new ManiaPlayfield(columns); protected override Playfield<ManiaHitObject, ManiaJudgement> CreatePlayfield() => new ManiaPlayfield(columns);
protected override DrawableHitObject<ManiaBaseHit, ManiaJudgement> GetVisualRepresentation(ManiaBaseHit h) => null; protected override DrawableHitObject<ManiaHitObject, ManiaJudgement> GetVisualRepresentation(ManiaHitObject h) => null;
} }
} }

View File

@ -19,7 +19,7 @@ using System.Collections.Generic;
namespace osu.Game.Rulesets.Mania.UI namespace osu.Game.Rulesets.Mania.UI
{ {
public class ManiaPlayfield : Playfield<ManiaBaseHit, ManiaJudgement> public class ManiaPlayfield : Playfield<ManiaHitObject, ManiaJudgement>
{ {
/// <summary> /// <summary>
/// Default column keys, expanding outwards from the middle as more column are added. /// Default column keys, expanding outwards from the middle as more column are added.

View File

@ -48,12 +48,18 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Beatmaps\ManiaBeatmapConverter.cs" /> <Compile Include="Beatmaps\ManiaBeatmapConverter.cs" />
<Compile Include="Judgements\HitWindows.cs" />
<Compile Include="Judgements\ManiaJudgement.cs" /> <Compile Include="Judgements\ManiaJudgement.cs" />
<Compile Include="ManiaDifficultyCalculator.cs" /> <Compile Include="ManiaDifficultyCalculator.cs" />
<Compile Include="Objects\Drawables\DrawableHoldNote.cs" />
<Compile Include="Objects\Drawables\DrawableManiaHitObject.cs" />
<Compile Include="Objects\Drawables\DrawableNote.cs" />
<Compile Include="Objects\Drawables\Pieces\BodyPiece.cs" />
<Compile Include="Objects\Drawables\Pieces\NotePiece.cs" />
<Compile Include="Objects\Types\IHasColumn.cs" />
<Compile Include="Scoring\ManiaScoreProcessor.cs" /> <Compile Include="Scoring\ManiaScoreProcessor.cs" />
<Compile Include="Objects\Drawable\DrawableNote.cs" />
<Compile Include="Objects\HoldNote.cs" /> <Compile Include="Objects\HoldNote.cs" />
<Compile Include="Objects\ManiaBaseHit.cs" /> <Compile Include="Objects\ManiaHitObject.cs" />
<Compile Include="Objects\Note.cs" /> <Compile Include="Objects\Note.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="UI\Column.cs" /> <Compile Include="UI\Column.cs" />

View File

@ -53,6 +53,12 @@ namespace osu.Game.Rulesets.Taiko.UI
public TaikoPlayfield() public TaikoPlayfield()
{ {
AddInternal(new Drawable[] AddInternal(new Drawable[]
{
new ScaleFixContainer
{
RelativeSizeAxes = Axes.X,
Height = DEFAULT_PLAYFIELD_HEIGHT,
Children = new[]
{ {
rightBackgroundContainer = new Container rightBackgroundContainer = new Container
{ {
@ -75,12 +81,6 @@ namespace osu.Game.Rulesets.Taiko.UI
}, },
} }
}, },
new ScaleFixContainer
{
RelativeSizeAxes = Axes.X,
Height = DEFAULT_PLAYFIELD_HEIGHT,
Children = new[]
{
new Container new Container
{ {
Name = "Transparent playfield elements", Name = "Transparent playfield elements",

View File

@ -142,7 +142,7 @@ namespace osu.Game.Tests.Beatmaps.IO
Assert.IsTrue(waitAction.BeginInvoke(null, null).AsyncWaitHandle.WaitOne(timeout), Assert.IsTrue(waitAction.BeginInvoke(null, null).AsyncWaitHandle.WaitOne(timeout),
@"Beatmaps did not import to the database in allocated time"); @"Beatmaps did not import to the database in allocated time");
var set = host.Dependencies.Get<BeatmapDatabase>().GetChildren(resultSets.First(), true); var set = host.Dependencies.Get<BeatmapDatabase>().GetChildren(resultSets.First());
Assert.IsTrue(set.Beatmaps.Count == resultBeatmaps.Count(), Assert.IsTrue(set.Beatmaps.Count == resultBeatmaps.Count(),
$@"Incorrect database beatmap count post-import ({resultBeatmaps.Count()} but should be {set.Beatmaps.Count})."); $@"Incorrect database beatmap count post-import ({resultBeatmaps.Count()} but should be {set.Beatmaps.Count}).");

View File

@ -267,6 +267,9 @@ namespace osu.Game.Database
public WorkingBeatmap GetWorkingBeatmap(BeatmapInfo beatmapInfo, WorkingBeatmap previous = null, bool withStoryboard = false) public WorkingBeatmap GetWorkingBeatmap(BeatmapInfo beatmapInfo, WorkingBeatmap previous = null, bool withStoryboard = false)
{ {
if (beatmapInfo.BeatmapSet == null)
beatmapInfo = GetChildren(beatmapInfo, true);
if (beatmapInfo.BeatmapSet == null) if (beatmapInfo.BeatmapSet == null)
throw new InvalidOperationException($@"Beatmap set {beatmapInfo.BeatmapSetInfoID} is not in the local database."); throw new InvalidOperationException($@"Beatmap set {beatmapInfo.BeatmapSetInfoID} is not in the local database.");

View File

@ -48,11 +48,9 @@ namespace osu.Game.Database
return Connection.Table<T>(); return Connection.Table<T>();
} }
public T GetWithChildren<T>(object id, bool recursive = false) where T : class /// <summary>
{ /// This is expensive. Use with caution.
return Connection.GetWithChildren<T>(id, recursive); /// </summary>
}
public List<T> GetAllWithChildren<T>(Expression<Func<T, bool>> filter = null, bool recursive = true) public List<T> GetAllWithChildren<T>(Expression<Func<T, bool>> filter = null, bool recursive = true)
where T : class where T : class
{ {

View File

@ -110,12 +110,18 @@ namespace osu.Game.Overlays
{ {
MoveToY(0, transition_length, EasingTypes.OutQuint); MoveToY(0, transition_length, EasingTypes.OutQuint);
FadeIn(transition_length, EasingTypes.OutQuint); FadeIn(transition_length, EasingTypes.OutQuint);
inputTextBox.HoldFocus = true;
base.PopIn();
} }
protected override void PopOut() protected override void PopOut()
{ {
MoveToY(DrawSize.Y, transition_length, EasingTypes.InSine); MoveToY(DrawSize.Y, transition_length, EasingTypes.InSine);
FadeOut(transition_length, EasingTypes.InSine); FadeOut(transition_length, EasingTypes.InSine);
inputTextBox.HoldFocus = false;
base.PopOut();
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]

View File

@ -3,7 +3,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using osu.Framework;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Audio; using osu.Framework.Audio;
using osu.Framework.Audio.Sample; using osu.Framework.Audio.Sample;
@ -12,12 +11,23 @@ using Container = osu.Framework.Graphics.Containers.Container;
using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Objects.Types;
using OpenTK.Graphics; using OpenTK.Graphics;
using osu.Game.Audio; using osu.Game.Audio;
using System.Linq;
namespace osu.Game.Rulesets.Objects.Drawables namespace osu.Game.Rulesets.Objects.Drawables
{ {
public abstract class DrawableHitObject<TJudgement> : Container, IStateful<ArmedState> public abstract class DrawableHitObject<TObject, TJudgement> : Container
where TObject : HitObject
where TJudgement : Judgement where TJudgement : Judgement
{ {
public event Action<DrawableHitObject<TObject, TJudgement>> OnJudgement;
public TObject HitObject;
/// <summary>
/// The colour used for various elements of this DrawableHitObject.
/// </summary>
public virtual Color4 AccentColour { get; set; }
public override bool HandleInput => Interactive; public override bool HandleInput => Interactive;
public bool Interactive = true; public bool Interactive = true;
@ -56,14 +66,6 @@ namespace osu.Game.Rulesets.Objects.Drawables
Samples.ForEach(s => s?.Play()); Samples.ForEach(s => s?.Play());
} }
[BackgroundDependencyLoader]
private void load()
{
//we may be setting a custom judgement in test cases or what not.
if (Judgement == null)
Judgement = CreateJudgement();
}
protected override void LoadComplete() protected override void LoadComplete()
{ {
base.LoadComplete(); base.LoadComplete();
@ -71,20 +73,11 @@ namespace osu.Game.Rulesets.Objects.Drawables
//force application of the state that was set before we loaded. //force application of the state that was set before we loaded.
UpdateState(State); UpdateState(State);
} }
}
public abstract class DrawableHitObject<TObject, TJudgement> : DrawableHitObject<TJudgement>
where TObject : HitObject
where TJudgement : Judgement
{
public event Action<DrawableHitObject<TObject, TJudgement>> OnJudgement;
public TObject HitObject;
/// <summary> /// <summary>
/// The colour used for various elements of this DrawableHitObject. /// Whether this hit object and all of its nested hit objects have been judged.
/// </summary> /// </summary>
public Color4 AccentColour { get; protected set; } public bool Judged => (Judgement?.Result ?? HitResult.None) != HitResult.None && (NestedHitObjects?.All(h => h.Judged) ?? true);
protected DrawableHitObject(TObject hitObject) protected DrawableHitObject(TObject hitObject)
{ {
@ -97,7 +90,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
/// <returns>Whether a hit was processed.</returns> /// <returns>Whether a hit was processed.</returns>
protected bool UpdateJudgement(bool userTriggered) protected bool UpdateJudgement(bool userTriggered)
{ {
IPartialJudgement partial = Judgement as IPartialJudgement; var partial = Judgement as IPartialJudgement;
// Never re-process non-partial hits // Never re-process non-partial hits
if (Judgement.Result != HitResult.None && partial == null) if (Judgement.Result != HitResult.None && partial == null)
@ -166,10 +159,13 @@ namespace osu.Game.Rulesets.Objects.Drawables
channel.Volume.Value = sample.Volume; channel.Volume.Value = sample.Volume;
Samples.Add(channel); Samples.Add(channel);
} }
//we may be setting a custom judgement in test cases or what not.
if (Judgement == null)
Judgement = CreateJudgement();
} }
private List<DrawableHitObject<TObject, TJudgement>> nestedHitObjects; private List<DrawableHitObject<TObject, TJudgement>> nestedHitObjects;
protected IEnumerable<DrawableHitObject<TObject, TJudgement>> NestedHitObjects => nestedHitObjects; protected IEnumerable<DrawableHitObject<TObject, TJudgement>> NestedHitObjects => nestedHitObjects;
protected void AddNested(DrawableHitObject<TObject, TJudgement> h) protected void AddNested(DrawableHitObject<TObject, TJudgement> h)

View File

@ -187,17 +187,19 @@ namespace osu.Game.Rulesets.UI
public sealed override bool ProvidingUserCursor => !HasReplayLoaded && Playfield.ProvidingUserCursor; public sealed override bool ProvidingUserCursor => !HasReplayLoaded && Playfield.ProvidingUserCursor;
protected override Container<Drawable> Content => content; public override IEnumerable<HitObject> Objects => Beatmap.HitObjects;
protected override bool AllObjectsJudged => Playfield.HitObjects.Children.All(h => h.Judgement.Result != HitResult.None);
protected override bool AllObjectsJudged => drawableObjects.All(h => h.Judged);
/// <summary> /// <summary>
/// The playfield. /// The playfield.
/// </summary> /// </summary>
protected Playfield<TObject, TJudgement> Playfield; protected Playfield<TObject, TJudgement> Playfield;
protected override Container<Drawable> Content => content;
private readonly Container content; private readonly Container content;
public override IEnumerable<HitObject> Objects => Beatmap.HitObjects; private readonly List<DrawableHitObject<TObject, TJudgement>> drawableObjects = new List<DrawableHitObject<TObject, TJudgement>>();
protected HitRenderer(WorkingBeatmap beatmap) protected HitRenderer(WorkingBeatmap beatmap)
: base(beatmap) : base(beatmap)
@ -224,6 +226,8 @@ namespace osu.Game.Rulesets.UI
private void loadObjects() private void loadObjects()
{ {
drawableObjects.Capacity = Beatmap.HitObjects.Count;
foreach (TObject h in Beatmap.HitObjects) foreach (TObject h in Beatmap.HitObjects)
{ {
var drawableObject = GetVisualRepresentation(h); var drawableObject = GetVisualRepresentation(h);
@ -233,6 +237,7 @@ namespace osu.Game.Rulesets.UI
drawableObject.OnJudgement += onJudgement; drawableObject.OnJudgement += onJudgement;
drawableObjects.Add(drawableObject);
Playfield.Add(drawableObject); Playfield.Add(drawableObject);
} }

View File

@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.UI
/// <summary> /// <summary>
/// The HitObjects contained in this Playfield. /// The HitObjects contained in this Playfield.
/// </summary> /// </summary>
public HitObjectContainer<DrawableHitObject<TObject, TJudgement>> HitObjects; protected HitObjectContainer<DrawableHitObject<TObject, TJudgement>> HitObjects;
internal Container<Drawable> ScaledContent; internal Container<Drawable> ScaledContent;

View File

@ -79,7 +79,7 @@ namespace osu.Game.Screens.Menu
if (count > 0) if (count > 0)
{ {
var beatmap = query.ElementAt(RNG.Next(0, count - 1)); var beatmap = query.ElementAt(RNG.Next(0, count - 1));
beatmaps.GetChildren(beatmap, true); beatmaps.GetChildren(beatmap);
Beatmap = beatmaps.GetWorkingBeatmap(beatmap.Beatmaps[0]); Beatmap = beatmaps.GetWorkingBeatmap(beatmap.Beatmaps[0]);
} }
} }