mirror of
https://github.com/ppy/osu.git
synced 2024-12-14 21:02:55 +08:00
Use new naming structure + VisibleTimeRange bindable.
This commit is contained in:
parent
3e3e64eb39
commit
d11002e499
@ -46,7 +46,7 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
const double start_time = 500;
|
||||
const double duration = 500;
|
||||
|
||||
Func<double, bool, DrawableTimingSection> createTimingChange = (time, gravity) => new DrawableManiaTimingSection(new TimingSection
|
||||
Func<double, bool, SpeedAdjustmentContainer> createTimingChange = (time, gravity) => new ManiaSpeedAdjustmentContainer(new SpeedAdjustment
|
||||
{
|
||||
BeatLength = 1000,
|
||||
Time = time
|
||||
|
@ -32,11 +32,11 @@ namespace osu.Game.Rulesets.Mania.Mods
|
||||
{
|
||||
var maniaHitRenderer = (ManiaHitRenderer)hitRenderer;
|
||||
|
||||
maniaHitRenderer.HitObjectTimingChanges = new List<DrawableTimingSection>[maniaHitRenderer.PreferredColumns];
|
||||
maniaHitRenderer.BarlineTimingChanges = new List<DrawableTimingSection>();
|
||||
maniaHitRenderer.HitObjectTimingChanges = new List<SpeedAdjustmentContainer>[maniaHitRenderer.PreferredColumns];
|
||||
maniaHitRenderer.BarlineTimingChanges = new List<SpeedAdjustmentContainer>();
|
||||
|
||||
for (int i = 0; i < maniaHitRenderer.PreferredColumns; i++)
|
||||
maniaHitRenderer.HitObjectTimingChanges[i] = new List<DrawableTimingSection>();
|
||||
maniaHitRenderer.HitObjectTimingChanges[i] = new List<SpeedAdjustmentContainer>();
|
||||
|
||||
foreach (HitObject obj in maniaHitRenderer.Objects)
|
||||
{
|
||||
@ -44,7 +44,7 @@ namespace osu.Game.Rulesets.Mania.Mods
|
||||
if (maniaObject == null)
|
||||
continue;
|
||||
|
||||
maniaHitRenderer.HitObjectTimingChanges[maniaObject.Column].Add(new DrawableManiaTimingSection(new TimingSection
|
||||
maniaHitRenderer.HitObjectTimingChanges[maniaObject.Column].Add(new ManiaSpeedAdjustmentContainer(new SpeedAdjustment
|
||||
{
|
||||
Time = obj.StartTime,
|
||||
BeatLength = 1000
|
||||
@ -63,7 +63,7 @@ namespace osu.Game.Rulesets.Mania.Mods
|
||||
|
||||
for (double t = timingPoints[i].Time; Precision.DefinitelyBigger(endTime, t); t += point.BeatLength)
|
||||
{
|
||||
maniaHitRenderer.BarlineTimingChanges.Add(new DrawableManiaTimingSection(new TimingSection
|
||||
maniaHitRenderer.BarlineTimingChanges.Add(new ManiaSpeedAdjustmentContainer(new SpeedAdjustment
|
||||
{
|
||||
Time = t,
|
||||
BeatLength = 1000
|
||||
|
@ -7,11 +7,11 @@ using osu.Game.Rulesets.Timing.Drawables;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Timing.Drawables
|
||||
{
|
||||
internal class BasicScrollingHitObjectCollection : HitObjectCollection
|
||||
internal class BasicScrollingDrawableTimingSection : DrawableTimingSection
|
||||
{
|
||||
private readonly TimingSection timingSection;
|
||||
private readonly SpeedAdjustment timingSection;
|
||||
|
||||
public BasicScrollingHitObjectCollection(TimingSection timingSection)
|
||||
public BasicScrollingDrawableTimingSection(SpeedAdjustment timingSection)
|
||||
: base(Axes.Y)
|
||||
{
|
||||
this.timingSection = timingSection;
|
@ -8,16 +8,14 @@ using osu.Game.Rulesets.Timing.Drawables;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Timing.Drawables
|
||||
{
|
||||
internal class GravityScrollingHitObjectCollection : HitObjectCollection
|
||||
internal class GravityScrollingDrawableTimingSection : DrawableTimingSection
|
||||
{
|
||||
private readonly TimingSection timingSection;
|
||||
private readonly Func<double> timeSpan;
|
||||
private readonly SpeedAdjustment timingSection;
|
||||
|
||||
public GravityScrollingHitObjectCollection(TimingSection timingSection, Func<double> timeSpan)
|
||||
public GravityScrollingDrawableTimingSection(SpeedAdjustment timingSection)
|
||||
: base(Axes.Y)
|
||||
{
|
||||
this.timingSection = timingSection;
|
||||
this.timeSpan = timeSpan;
|
||||
}
|
||||
|
||||
protected override void UpdateAfterChildren()
|
||||
@ -45,19 +43,19 @@ namespace osu.Game.Rulesets.Mania.Timing.Drawables
|
||||
// The sign of the relative time, this is used to apply backwards acceleration leading into startTime
|
||||
double sign = relativeTime < 0 ? -1 : 1;
|
||||
|
||||
return timeSpan() - acceleration * relativeTime * relativeTime * sign;
|
||||
return VisibleTimeRange - acceleration * relativeTime * relativeTime * sign;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The acceleration due to "gravity" of the content of this container.
|
||||
/// </summary>
|
||||
private double acceleration => 1 / timeSpan();
|
||||
private double acceleration => 1 / VisibleTimeRange;
|
||||
|
||||
/// <summary>
|
||||
/// Computes the current time relative to <paramref name="time"/>, accounting for <see cref="timeSpan"/>.
|
||||
/// </summary>
|
||||
/// <param name="time">The non-offset time.</param>
|
||||
/// <returns>The current time relative to <paramref name="time"/> - <see cref="timeSpan"/>. </returns>
|
||||
private double relativeTimeAt(double time) => Time.Current - time + timeSpan();
|
||||
private double relativeTimeAt(double time) => Time.Current - time + VisibleTimeRange;
|
||||
}
|
||||
}
|
@ -7,11 +7,11 @@ using osu.Game.Rulesets.Timing.Drawables;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Timing.Drawables
|
||||
{
|
||||
public class DrawableManiaTimingSection : DrawableTimingSection
|
||||
public class ManiaSpeedAdjustmentContainer : SpeedAdjustmentContainer
|
||||
{
|
||||
private readonly ScrollingAlgorithm scrollingAlgorithm;
|
||||
|
||||
public DrawableManiaTimingSection(TimingSection timingSection, ScrollingAlgorithm scrollingAlgorithm)
|
||||
public ManiaSpeedAdjustmentContainer(SpeedAdjustment timingSection, ScrollingAlgorithm scrollingAlgorithm)
|
||||
: base(timingSection, Axes.Y)
|
||||
{
|
||||
this.scrollingAlgorithm = scrollingAlgorithm;
|
||||
@ -21,25 +21,25 @@ namespace osu.Game.Rulesets.Mania.Timing.Drawables
|
||||
{
|
||||
base.UpdateAfterChildren();
|
||||
|
||||
var parent = Parent as TimingSectionCollection;
|
||||
var parent = Parent as SpeedAdjustmentCollection;
|
||||
|
||||
if (parent == null)
|
||||
return;
|
||||
|
||||
// This is very naive and can be improved, but is adequate for now
|
||||
LifetimeStart = TimingSection.Time - parent.TimeSpan;
|
||||
LifetimeStart = TimingSection.Time - VisibleTimeRange;
|
||||
LifetimeEnd = TimingSection.Time + Content.Height * 2;
|
||||
}
|
||||
|
||||
protected override HitObjectCollection CreateHitObjectCollection()
|
||||
protected override DrawableTimingSection CreateTimingSection()
|
||||
{
|
||||
switch (scrollingAlgorithm)
|
||||
{
|
||||
default:
|
||||
case ScrollingAlgorithm.Basic:
|
||||
return new BasicScrollingHitObjectCollection(TimingSection);
|
||||
return new BasicScrollingDrawableTimingSection(TimingSection);
|
||||
case ScrollingAlgorithm.Gravity:
|
||||
return new GravityScrollingHitObjectCollection(TimingSection, () => RelativeChildSize.Y);
|
||||
return new GravityScrollingDrawableTimingSection(TimingSection);
|
||||
}
|
||||
}
|
||||
}
|
@ -31,6 +31,13 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
private const float column_width = 45;
|
||||
private const float special_column_width = 70;
|
||||
|
||||
private readonly BindableDouble visibleTimeRange = new BindableDouble();
|
||||
public BindableDouble VisibleTimeRange
|
||||
{
|
||||
get { return visibleTimeRange; }
|
||||
set { visibleTimeRange.BindTo(value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The key that will trigger input actions for this column and hit objects contained inside it.
|
||||
/// </summary>
|
||||
@ -40,7 +47,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
private readonly Container hitTargetBar;
|
||||
private readonly Container keyIcon;
|
||||
|
||||
private readonly TimingSectionCollection timingChanges;
|
||||
private readonly SpeedAdjustmentCollection speedAdjustments;
|
||||
|
||||
public Column()
|
||||
{
|
||||
@ -91,10 +98,11 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
}
|
||||
}
|
||||
},
|
||||
timingChanges = new TimingSectionCollection
|
||||
speedAdjustments = new SpeedAdjustmentCollection
|
||||
{
|
||||
Name = "Hit objects",
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
VisibleTimeRange = VisibleTimeRange
|
||||
},
|
||||
// For column lighting, we need to capture input events before the notes
|
||||
new InputTarget
|
||||
@ -185,17 +193,11 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
}
|
||||
}
|
||||
|
||||
public double TimeSpan
|
||||
{
|
||||
get { return timingChanges.TimeSpan; }
|
||||
set { timingChanges.TimeSpan = value; }
|
||||
}
|
||||
|
||||
public void Add(DrawableTimingSection timingChange) => timingChanges.Add(timingChange);
|
||||
public void Add(SpeedAdjustmentContainer speedAdjustment) => speedAdjustments.Add(speedAdjustment);
|
||||
public void Add(DrawableHitObject hitObject)
|
||||
{
|
||||
hitObject.AccentColour = AccentColour;
|
||||
timingChanges.Add(hitObject);
|
||||
speedAdjustments.Add(hitObject);
|
||||
}
|
||||
|
||||
private bool onKeyDown(InputState state, KeyDownEventArgs args)
|
||||
|
@ -41,12 +41,12 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
/// <summary>
|
||||
/// Per-column timing changes.
|
||||
/// </summary>
|
||||
public List<DrawableTimingSection>[] HitObjectTimingChanges;
|
||||
public List<SpeedAdjustmentContainer>[] HitObjectTimingChanges;
|
||||
|
||||
/// <summary>
|
||||
/// Bar line timing changes.
|
||||
/// </summary>
|
||||
public List<DrawableTimingSection> BarlineTimingChanges;
|
||||
public List<SpeedAdjustmentContainer> BarlineTimingChanges;
|
||||
|
||||
/// <summary>
|
||||
/// Number of columns in the playfield of this hit renderer. Null if the play field hasn't been generated yet.
|
||||
@ -66,11 +66,11 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
if (HitObjectTimingChanges != null || BarlineTimingChanges != null)
|
||||
return;
|
||||
|
||||
HitObjectTimingChanges = new List<DrawableTimingSection>[PreferredColumns];
|
||||
BarlineTimingChanges = new List<DrawableTimingSection>();
|
||||
HitObjectTimingChanges = new List<SpeedAdjustmentContainer>[PreferredColumns];
|
||||
BarlineTimingChanges = new List<SpeedAdjustmentContainer>();
|
||||
|
||||
for (int i = 0; i < PreferredColumns; i++)
|
||||
HitObjectTimingChanges[i] = new List<DrawableTimingSection>();
|
||||
HitObjectTimingChanges[i] = new List<SpeedAdjustmentContainer>();
|
||||
|
||||
double lastSpeedMultiplier = 1;
|
||||
double lastBeatLength = 500;
|
||||
@ -92,7 +92,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
if (difficultyPoint != null)
|
||||
lastSpeedMultiplier = difficultyPoint.SpeedMultiplier;
|
||||
|
||||
return new TimingSection
|
||||
return new SpeedAdjustment
|
||||
{
|
||||
Time = c.Time,
|
||||
BeatLength = lastBeatLength,
|
||||
@ -115,9 +115,9 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
timingChanges.ForEach(t =>
|
||||
{
|
||||
for (int i = 0; i < PreferredColumns; i++)
|
||||
HitObjectTimingChanges[i].Add(new DrawableManiaTimingSection(t, ScrollingAlgorithm.Basic));
|
||||
HitObjectTimingChanges[i].Add(new ManiaSpeedAdjustmentContainer(t, ScrollingAlgorithm.Basic));
|
||||
|
||||
BarlineTimingChanges.Add(new DrawableManiaTimingSection(t, ScrollingAlgorithm.Basic));
|
||||
BarlineTimingChanges.Add(new ManiaSpeedAdjustmentContainer(t, ScrollingAlgorithm.Basic));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,7 @@ using osu.Framework.MathUtils;
|
||||
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Timing;
|
||||
using osu.Game.Rulesets.Timing.Drawables;
|
||||
using osu.Framework.Configuration;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.UI
|
||||
{
|
||||
@ -59,7 +60,13 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
private readonly FlowContainer<Column> columns;
|
||||
public IEnumerable<Column> Columns => columns.Children;
|
||||
|
||||
private readonly TimingSectionCollection barLineContainer;
|
||||
private readonly BindableDouble visibleTimeRange = new BindableDouble(time_span_default)
|
||||
{
|
||||
MinValue = TIME_SPAN_MIN,
|
||||
MaxValue = TIME_SPAN_MAX
|
||||
};
|
||||
|
||||
private readonly SpeedAdjustmentCollection barLineContainer;
|
||||
|
||||
private List<Color4> normalColumnColours = new List<Color4>();
|
||||
private Color4 specialColumnColour;
|
||||
@ -117,7 +124,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
Padding = new MarginPadding { Top = HIT_TARGET_POSITION },
|
||||
Children = new[]
|
||||
{
|
||||
barLineContainer = new TimingSectionCollection
|
||||
barLineContainer = new SpeedAdjustmentCollection
|
||||
{
|
||||
Name = "Bar lines",
|
||||
Anchor = Anchor.TopCentre,
|
||||
@ -132,9 +139,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
};
|
||||
|
||||
for (int i = 0; i < columnCount; i++)
|
||||
columns.Add(new Column());
|
||||
|
||||
TimeSpan = time_span_default;
|
||||
columns.Add(new Column { VisibleTimeRange = visibleTimeRange });
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
@ -209,7 +214,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
|
||||
public override void Add(DrawableHitObject<ManiaHitObject, ManiaJudgement> h) => Columns.ElementAt(h.HitObject.Column).Add(h);
|
||||
|
||||
public void Add(DrawableTimingSection timingChange) => barLineContainer.Add(timingChange);
|
||||
public void Add(SpeedAdjustmentContainer timingChange) => barLineContainer.Add(timingChange);
|
||||
public void Add(DrawableBarLine barline) => barLineContainer.Add(barline);
|
||||
|
||||
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
|
||||
@ -219,10 +224,10 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
switch (args.Key)
|
||||
{
|
||||
case Key.Minus:
|
||||
transformTimeSpanTo(TimeSpan + time_span_step, 200, EasingTypes.OutQuint);
|
||||
transformVisibleTimeRangeTo(visibleTimeRange + time_span_step, 200, EasingTypes.OutQuint);
|
||||
break;
|
||||
case Key.Plus:
|
||||
transformTimeSpanTo(TimeSpan - time_span_step, 200, EasingTypes.OutQuint);
|
||||
transformVisibleTimeRangeTo(visibleTimeRange - time_span_step, 200, EasingTypes.OutQuint);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -230,29 +235,9 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
return false;
|
||||
}
|
||||
|
||||
private double timeSpan;
|
||||
/// <summary>
|
||||
/// The amount of time which the length of the playfield spans.
|
||||
/// </summary>
|
||||
public double TimeSpan
|
||||
private void transformVisibleTimeRangeTo(double newTimeRange, double duration = 0, EasingTypes easing = EasingTypes.None)
|
||||
{
|
||||
get { return timeSpan; }
|
||||
set
|
||||
{
|
||||
if (timeSpan == value)
|
||||
return;
|
||||
timeSpan = value;
|
||||
|
||||
timeSpan = MathHelper.Clamp(timeSpan, TIME_SPAN_MIN, TIME_SPAN_MAX);
|
||||
|
||||
barLineContainer.TimeSpan = value;
|
||||
Columns.ForEach(c => c.TimeSpan = value);
|
||||
}
|
||||
}
|
||||
|
||||
private void transformTimeSpanTo(double newTimeSpan, double duration = 0, EasingTypes easing = EasingTypes.None)
|
||||
{
|
||||
TransformTo(() => TimeSpan, newTimeSpan, duration, easing, new TransformTimeSpan());
|
||||
TransformTo(() => visibleTimeRange.Value, newTimeRange, duration, easing, new TransformTimeSpan());
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
@ -281,7 +266,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
base.Apply(d);
|
||||
|
||||
var p = (ManiaPlayfield)d;
|
||||
p.TimeSpan = (float)CurrentValue;
|
||||
p.visibleTimeRange.Value = (float)CurrentValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -77,8 +77,8 @@
|
||||
<Compile Include="Objects\ManiaHitObject.cs" />
|
||||
<Compile Include="Objects\Note.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Timing\Drawables\BasicScrollingHitObjectCollection.cs" />
|
||||
<Compile Include="Timing\Drawables\GravityScrollingHitObjectCollection.cs" />
|
||||
<Compile Include="Timing\Drawables\BasicScrollingDrawableTimingSection.cs" />
|
||||
<Compile Include="Timing\Drawables\GravityScrollingDrawableTimingSection.cs" />
|
||||
<Compile Include="Timing\ScrollingAlgorithm.cs" />
|
||||
<Compile Include="UI\Column.cs" />
|
||||
<Compile Include="UI\ManiaHitRenderer.cs" />
|
||||
@ -87,7 +87,7 @@
|
||||
<Compile Include="Mods\ManiaMod.cs" />
|
||||
<Compile Include="Mods\ManiaModGravity.cs" />
|
||||
<Compile Include="UI\SpecialColumnPosition.cs" />
|
||||
<Compile Include="Timing\Drawables\DrawableManiaTimingSection.cs" />
|
||||
<Compile Include="Timing\Drawables\ManiaSpeedAdjustmentContainer.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\osu-framework\osu.Framework\osu.Framework.csproj">
|
||||
|
@ -1,46 +1,67 @@
|
||||
// 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
|
||||
|
||||
using System;
|
||||
using osu.Framework.Allocation;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Caching;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using OpenTK;
|
||||
using osu.Framework.Configuration;
|
||||
|
||||
namespace osu.Game.Rulesets.Timing.Drawables
|
||||
{
|
||||
/// <summary>
|
||||
/// A container for hit objects which applies applies the speed changes defined by the <see cref="Timing.TimingSection.BeatLength"/> and <see cref="Timing.TimingSection.SpeedMultiplier"/>
|
||||
/// properties to its <see cref="Container{T}.Content"/> to affect the <see cref="HitObjectCollection"/> scroll speed.
|
||||
/// A collection of hit objects which scrolls within a <see cref="SpeedAdjustmentContainer"/>.
|
||||
///
|
||||
/// <para>
|
||||
/// This container handles the conversion between time and position through <see cref="Container{T}.RelativeChildSize"/> and
|
||||
/// <see cref="Container{T}.RelativeChildOffset"/> such that hit objects added to this container should have time values set as their
|
||||
/// positions/sizes to make proper use of this container.
|
||||
/// </para>
|
||||
///
|
||||
/// <para>
|
||||
/// This container will auto-size to the total size of its children along the desired auto-sizing axes such that the reasulting size
|
||||
/// of this container will also be a time value.
|
||||
/// </para>
|
||||
///
|
||||
/// <para>
|
||||
/// This container will always be relatively-sized and positioned to its parent through the use of <see cref="Drawable.RelativeSizeAxes"/>
|
||||
/// and <see cref="Drawable.RelativePositionAxes"/> such that the parent can utilise <see cref="Container{T}.RelativeChildSize"/> and
|
||||
/// <see cref="Container{T}.RelativeChildOffset"/> to apply further time offsets to this collection of hit objects.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public abstract class DrawableTimingSection : Container<DrawableHitObject>
|
||||
{
|
||||
public readonly TimingSection TimingSection;
|
||||
private readonly BindableDouble visibleTimeRange = new BindableDouble();
|
||||
public BindableDouble VisibleTimeRange
|
||||
{
|
||||
get { return visibleTimeRange; }
|
||||
set { visibleTimeRange.BindTo(value); }
|
||||
}
|
||||
|
||||
protected override Container<DrawableHitObject> Content => content;
|
||||
private Container<DrawableHitObject> content;
|
||||
protected override IComparer<Drawable> DepthComparer => new HitObjectReverseStartTimeComparer();
|
||||
|
||||
private readonly Axes scrollingAxes;
|
||||
private readonly Axes autoSizingAxes;
|
||||
|
||||
private Cached layout = new Cached();
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="DrawableTimingSection"/>.
|
||||
/// </summary>
|
||||
/// <param name="timingSection">The encapsulated timing section that provides the speed changes.</param>
|
||||
/// <param name="scrollingAxes">The axes through which this drawable timing section scrolls through.</param>
|
||||
protected DrawableTimingSection(TimingSection timingSection, Axes scrollingAxes)
|
||||
/// <param name="autoSizingAxes">The axes on which to auto-size to the total size of items in the container.</param>
|
||||
protected DrawableTimingSection(Axes autoSizingAxes)
|
||||
{
|
||||
this.scrollingAxes = scrollingAxes;
|
||||
this.autoSizingAxes = autoSizingAxes;
|
||||
|
||||
TimingSection = timingSection;
|
||||
// We need a default size since RelativeSizeAxes is overridden
|
||||
Size = Vector2.One;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
AddInternal(content = CreateHitObjectCollection());
|
||||
content.RelativeChildOffset = new Vector2((scrollingAxes & Axes.X) > 0 ? (float)TimingSection.Time : 0, (scrollingAxes & Axes.Y) > 0 ? (float)TimingSection.Time : 0);
|
||||
}
|
||||
public override Axes AutoSizeAxes { set { throw new InvalidOperationException($"{nameof(DrawableTimingSection)} must always be relatively-sized."); } }
|
||||
|
||||
public override Axes RelativeSizeAxes
|
||||
{
|
||||
@ -48,29 +69,55 @@ namespace osu.Game.Rulesets.Timing.Drawables
|
||||
set { throw new InvalidOperationException($"{nameof(DrawableTimingSection)} must always be relatively-sized."); }
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
public override Axes RelativePositionAxes
|
||||
{
|
||||
var parent = Parent as TimingSectionCollection;
|
||||
|
||||
if (parent == null)
|
||||
return;
|
||||
|
||||
float speedAdjustedSize = (float)(1000 / TimingSection.BeatLength / TimingSection.SpeedMultiplier);
|
||||
|
||||
// The application of speed changes happens by modifying our size while maintaining the parent's time span as our relative child size
|
||||
Size = new Vector2((scrollingAxes & Axes.X) > 0 ? speedAdjustedSize : 1, (scrollingAxes & Axes.Y) > 0 ? speedAdjustedSize : 1);
|
||||
RelativeChildSize = new Vector2((scrollingAxes & Axes.X) > 0 ? (float)parent.TimeSpan : 1, (scrollingAxes & Axes.Y) > 0 ? (float)parent.TimeSpan : 1);
|
||||
get { return Axes.Both; }
|
||||
set { throw new InvalidOperationException($"{nameof(DrawableTimingSection)} must always be relatively-positioned."); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether this timing section can contain a hit object. This is true if the hit object occurs after this timing section with respect to time.
|
||||
/// </summary>
|
||||
public bool CanContain(DrawableHitObject hitObject) => TimingSection.Time <= hitObject.HitObject.StartTime;
|
||||
public override void InvalidateFromChild(Invalidation invalidation)
|
||||
{
|
||||
// We only want to re-compute our size when a child's size or position has changed
|
||||
if ((invalidation & Invalidation.RequiredParentSizeToFit) == 0)
|
||||
{
|
||||
base.InvalidateFromChild(invalidation);
|
||||
return;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the container which handles the movement of a collection of hit objects.
|
||||
/// </summary>
|
||||
/// <returns>The hit object collection.</returns>
|
||||
protected abstract HitObjectCollection CreateHitObjectCollection();
|
||||
layout.Invalidate();
|
||||
|
||||
base.InvalidateFromChild(invalidation);
|
||||
}
|
||||
|
||||
protected override void UpdateAfterChildren()
|
||||
{
|
||||
base.UpdateAfterChildren();
|
||||
|
||||
if (!layout.EnsureValid())
|
||||
{
|
||||
layout.Refresh(() =>
|
||||
{
|
||||
if (!Children.Any())
|
||||
return;
|
||||
|
||||
//double maxDuration = Children.Select(c => (c.HitObject as IHasEndTime)?.EndTime ?? c.HitObject.StartTime).Max();
|
||||
//float width = (float)maxDuration - RelativeChildOffset.X;
|
||||
//float height = (float)maxDuration - RelativeChildOffset.Y;
|
||||
|
||||
|
||||
// Auto-size to the total size of our children
|
||||
// This ends up being the total duration of our children, however for now this is a more sure-fire way to calculate this
|
||||
// than the above due to some undesired masking optimisations causing some hit objects to be culled...
|
||||
// Todo: When this is investigated more we should use the above method as it is a little more exact
|
||||
float width = Children.Select(child => child.X + child.Width).Max() - RelativeChildOffset.X;
|
||||
float height = Children.Select(child => child.Y + child.Height).Max() - RelativeChildOffset.Y;
|
||||
|
||||
// Consider that width/height are time values. To have ourselves span these time values 1:1, we first need to set our size
|
||||
Size = new Vector2((autoSizingAxes & Axes.X) > 0 ? width : Size.X, (autoSizingAxes & Axes.Y) > 0 ? height : Size.Y);
|
||||
// Then to make our position-space be time values again, we need our relative child size to follow our size
|
||||
RelativeChildSize = Size;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,115 +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 System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Caching;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using OpenTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Timing.Drawables
|
||||
{
|
||||
/// <summary>
|
||||
/// A collection of hit objects which scrolls within a <see cref="DrawableTimingSection"/>.
|
||||
///
|
||||
/// <para>
|
||||
/// This container handles the conversion between time and position through <see cref="Container{T}.RelativeChildSize"/> and
|
||||
/// <see cref="Container{T}.RelativeChildOffset"/> such that hit objects added to this container should have time values set as their
|
||||
/// positions/sizes to make proper use of this container.
|
||||
/// </para>
|
||||
///
|
||||
/// <para>
|
||||
/// This container will auto-size to the total size of its children along the desired auto-sizing axes such that the reasulting size
|
||||
/// of this container will also be a time value.
|
||||
/// </para>
|
||||
///
|
||||
/// <para>
|
||||
/// This container will always be relatively-sized and positioned to its parent through the use of <see cref="Drawable.RelativeSizeAxes"/>
|
||||
/// and <see cref="Drawable.RelativePositionAxes"/> such that the parent can utilise <see cref="Container{T}.RelativeChildSize"/> and
|
||||
/// <see cref="Container{T}.RelativeChildOffset"/> to apply further time offsets to this collection of hit objects.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public abstract class HitObjectCollection : Container<DrawableHitObject>
|
||||
{
|
||||
protected override IComparer<Drawable> DepthComparer => new HitObjectReverseStartTimeComparer();
|
||||
|
||||
private readonly Axes autoSizingAxes;
|
||||
|
||||
private Cached layout = new Cached();
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="HitObjectCollection"/>.
|
||||
/// </summary>
|
||||
/// <param name="autoSizingAxes">The axes on which to auto-size to the total size of items in the container.</param>
|
||||
protected HitObjectCollection(Axes autoSizingAxes)
|
||||
{
|
||||
this.autoSizingAxes = autoSizingAxes;
|
||||
|
||||
// We need a default size since RelativeSizeAxes is overridden
|
||||
Size = Vector2.One;
|
||||
}
|
||||
|
||||
public override Axes AutoSizeAxes { set { throw new InvalidOperationException($"{nameof(HitObjectCollection)} must always be relatively-sized."); } }
|
||||
|
||||
public override Axes RelativeSizeAxes
|
||||
{
|
||||
get { return Axes.Both; }
|
||||
set { throw new InvalidOperationException($"{nameof(HitObjectCollection)} must always be relatively-sized."); }
|
||||
}
|
||||
|
||||
public override Axes RelativePositionAxes
|
||||
{
|
||||
get { return Axes.Both; }
|
||||
set { throw new InvalidOperationException($"{nameof(HitObjectCollection)} must always be relatively-positioned."); }
|
||||
}
|
||||
|
||||
public override void InvalidateFromChild(Invalidation invalidation)
|
||||
{
|
||||
// We only want to re-compute our size when a child's size or position has changed
|
||||
if ((invalidation & Invalidation.RequiredParentSizeToFit) == 0)
|
||||
{
|
||||
base.InvalidateFromChild(invalidation);
|
||||
return;
|
||||
}
|
||||
|
||||
layout.Invalidate();
|
||||
|
||||
base.InvalidateFromChild(invalidation);
|
||||
}
|
||||
|
||||
protected override void UpdateAfterChildren()
|
||||
{
|
||||
base.UpdateAfterChildren();
|
||||
|
||||
if (!layout.EnsureValid())
|
||||
{
|
||||
layout.Refresh(() =>
|
||||
{
|
||||
if (!Children.Any())
|
||||
return;
|
||||
|
||||
//double maxDuration = Children.Select(c => (c.HitObject as IHasEndTime)?.EndTime ?? c.HitObject.StartTime).Max();
|
||||
//float width = (float)maxDuration - RelativeChildOffset.X;
|
||||
//float height = (float)maxDuration - RelativeChildOffset.Y;
|
||||
|
||||
|
||||
// Auto-size to the total size of our children
|
||||
// This ends up being the total duration of our children, however for now this is a more sure-fire way to calculate this
|
||||
// than the above due to some undesired masking optimisations causing some hit objects to be culled...
|
||||
// Todo: When this is investigated more we should use the above method as it is a little more exact
|
||||
float width = Children.Select(child => child.X + child.Width).Max() - RelativeChildOffset.X;
|
||||
float height = Children.Select(child => child.Y + child.Height).Max() - RelativeChildOffset.Y;
|
||||
|
||||
// Consider that width/height are time values. To have ourselves span these time values 1:1, we first need to set our size
|
||||
Size = new Vector2((autoSizingAxes & Axes.X) > 0 ? width : Size.X, (autoSizingAxes & Axes.Y) > 0 ? height : Size.Y);
|
||||
// Then to make our position-space be time values again, we need our relative child size to follow our size
|
||||
RelativeChildSize = Size;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
// 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 osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using OpenTK;
|
||||
using osu.Framework.Configuration;
|
||||
|
||||
namespace osu.Game.Rulesets.Timing.Drawables
|
||||
{
|
||||
/// <summary>
|
||||
/// A container for hit objects which applies applies the speed changes defined by the <see cref="Timing.SpeedAdjustment.BeatLength"/> and <see cref="Timing.SpeedAdjustment.SpeedMultiplier"/>
|
||||
/// properties to its <see cref="Container{T}.Content"/> to affect the <see cref="Drawables.DrawableTimingSection"/> scroll speed.
|
||||
/// </summary>
|
||||
public abstract class SpeedAdjustmentContainer : Container<DrawableHitObject>
|
||||
{
|
||||
private readonly Bindable<double> visibleTimeRange = new Bindable<double>();
|
||||
public Bindable<double> VisibleTimeRange
|
||||
{
|
||||
get { return visibleTimeRange; }
|
||||
set { visibleTimeRange.BindTo(value); }
|
||||
}
|
||||
|
||||
public readonly SpeedAdjustment TimingSection;
|
||||
|
||||
protected override Container<DrawableHitObject> Content => content;
|
||||
private Container<DrawableHitObject> content;
|
||||
|
||||
private readonly Axes scrollingAxes;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="SpeedAdjustmentContainer"/>.
|
||||
/// </summary>
|
||||
/// <param name="timingSection">The encapsulated timing section that provides the speed changes.</param>
|
||||
/// <param name="scrollingAxes">The axes through which this drawable timing section scrolls through.</param>
|
||||
protected SpeedAdjustmentContainer(SpeedAdjustment timingSection, Axes scrollingAxes)
|
||||
{
|
||||
this.scrollingAxes = scrollingAxes;
|
||||
|
||||
TimingSection = timingSection;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
DrawableTimingSection timingSection = CreateTimingSection();
|
||||
|
||||
timingSection.VisibleTimeRange.BindTo(VisibleTimeRange);
|
||||
timingSection.RelativeChildOffset = new Vector2((scrollingAxes & Axes.X) > 0 ? (float)TimingSection.Time : 0, (scrollingAxes & Axes.Y) > 0 ? (float)TimingSection.Time : 0);
|
||||
|
||||
AddInternal(content = timingSection);
|
||||
}
|
||||
|
||||
public override Axes RelativeSizeAxes
|
||||
{
|
||||
get { return Axes.Both; }
|
||||
set { throw new InvalidOperationException($"{nameof(SpeedAdjustmentContainer)} must always be relatively-sized."); }
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
float speedAdjustedSize = (float)(1000 / TimingSection.BeatLength / TimingSection.SpeedMultiplier);
|
||||
|
||||
// The speed adjustment happens by modifying our size while maintaining the visible time range as the relatve size for our children
|
||||
Size = new Vector2((scrollingAxes & Axes.X) > 0 ? speedAdjustedSize : 1, (scrollingAxes & Axes.Y) > 0 ? speedAdjustedSize : 1);
|
||||
RelativeChildSize = new Vector2((scrollingAxes & Axes.X) > 0 ? (float)VisibleTimeRange : 1, (scrollingAxes & Axes.Y) > 0 ? (float)VisibleTimeRange : 1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether this speed adjustment can contain a hit object. This is true if the hit object occurs after this speed adjustment with respect to time.
|
||||
/// </summary>
|
||||
public bool CanContain(DrawableHitObject hitObject) => TimingSection.Time <= hitObject.HitObject.StartTime;
|
||||
|
||||
/// <summary>
|
||||
/// Creates the container which handles the movement of a collection of hit objects.
|
||||
/// </summary>
|
||||
/// <returns>The drawable timing section.</returns>
|
||||
protected abstract DrawableTimingSection CreateTimingSection();
|
||||
}
|
||||
}
|
@ -3,7 +3,7 @@
|
||||
|
||||
namespace osu.Game.Rulesets.Timing
|
||||
{
|
||||
public class TimingSection
|
||||
public class SpeedAdjustment
|
||||
{
|
||||
/// <summary>
|
||||
/// The time in milliseconds at which this timing section starts.
|
@ -4,6 +4,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
@ -12,20 +13,24 @@ using osu.Game.Rulesets.Timing.Drawables;
|
||||
namespace osu.Game.Rulesets.Timing
|
||||
{
|
||||
/// <summary>
|
||||
/// A collection of timing sections which contain hit objects.
|
||||
///
|
||||
/// A collection of <see cref="SpeedAdjustmentContainer"/>s.
|
||||
///
|
||||
/// <para>
|
||||
/// This container provides <see cref="TimeSpan"/> for the timing sections. This is a value that indicates the amount of time
|
||||
/// that is visible throughout the span of this container.
|
||||
/// For example, only hit objects with start time less than or equal to 1000 will be visible with <see cref="TimeSpan"/> = 1000.
|
||||
/// This container provides <see cref="VisibleTimeRange"/> for the <see cref="SpeedAdjustmentContainer"/>s.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public class TimingSectionCollection : Container<DrawableTimingSection>
|
||||
public class SpeedAdjustmentCollection : Container<SpeedAdjustmentContainer>
|
||||
{
|
||||
private readonly BindableDouble visibleTimeRange = new BindableDouble();
|
||||
/// <summary>
|
||||
/// The length of time visible throughout the span of this container.
|
||||
/// The amount of time visible by span of this container.
|
||||
/// For example, only hit objects with start time less than or equal to 1000 will be visible with <see cref="VisibleTimeRange"/> = 1000.
|
||||
/// </summary>
|
||||
public double TimeSpan;
|
||||
public Bindable<double> VisibleTimeRange
|
||||
{
|
||||
get { return visibleTimeRange; }
|
||||
set { visibleTimeRange.BindTo(value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a hit object to the most applicable timing section in this container.
|
||||
@ -41,6 +46,12 @@ namespace osu.Game.Rulesets.Timing
|
||||
target.Add(hitObject);
|
||||
}
|
||||
|
||||
public override void Add(SpeedAdjustmentContainer speedAdjustment)
|
||||
{
|
||||
speedAdjustment.VisibleTimeRange.BindTo(VisibleTimeRange);
|
||||
base.Add(speedAdjustment);
|
||||
}
|
||||
|
||||
protected override IComparer<Drawable> DepthComparer => new TimingSectionReverseStartTimeComparer();
|
||||
|
||||
/// <summary>
|
||||
@ -49,7 +60,7 @@ namespace osu.Game.Rulesets.Timing
|
||||
/// </summary>
|
||||
/// <param name="hitObject">The hit object to contain.</param>
|
||||
/// <returns>The last (time-wise) timing section which can contain <paramref name="hitObject"/>. Null if no timing section exists.</returns>
|
||||
private DrawableTimingSection timingSectionFor(DrawableHitObject hitObject) => Children.FirstOrDefault(c => c.CanContain(hitObject)) ?? Children.LastOrDefault();
|
||||
private SpeedAdjustmentContainer timingSectionFor(DrawableHitObject hitObject) => Children.FirstOrDefault(c => c.CanContain(hitObject)) ?? Children.LastOrDefault();
|
||||
|
||||
/// <summary>
|
||||
/// Compares two timing sections by their start time, falling back to creation order if their start time is equal.
|
||||
@ -59,8 +70,8 @@ namespace osu.Game.Rulesets.Timing
|
||||
{
|
||||
public override int Compare(Drawable x, Drawable y)
|
||||
{
|
||||
var timingChangeX = x as DrawableTimingSection;
|
||||
var timingChangeY = y as DrawableTimingSection;
|
||||
var timingChangeX = x as SpeedAdjustmentContainer;
|
||||
var timingChangeY = y as SpeedAdjustmentContainer;
|
||||
|
||||
// If either of the two drawables are not hit objects, fall back to the base comparer
|
||||
if (timingChangeX?.TimingSection == null || timingChangeY?.TimingSection == null)
|
@ -195,10 +195,10 @@
|
||||
<Compile Include="Database\RulesetDatabase.cs" />
|
||||
<Compile Include="Rulesets\Scoring\Score.cs" />
|
||||
<Compile Include="Rulesets\Scoring\ScoreProcessor.cs" />
|
||||
<Compile Include="Rulesets\Timing\Drawables\SpeedAdjustmentContainer.cs" />
|
||||
<Compile Include="Rulesets\Timing\Drawables\DrawableTimingSection.cs" />
|
||||
<Compile Include="Rulesets\Timing\Drawables\HitObjectCollection.cs" />
|
||||
<Compile Include="Rulesets\Timing\TimingSection.cs" />
|
||||
<Compile Include="Rulesets\Timing\TimingSectionCollection.cs" />
|
||||
<Compile Include="Rulesets\Timing\SpeedAdjustment.cs" />
|
||||
<Compile Include="Rulesets\Timing\SpeedAdjustmentCollection.cs" />
|
||||
<Compile Include="Screens\Menu\MenuSideFlashes.cs" />
|
||||
<Compile Include="Screens\Play\HUD\HealthDisplay.cs" />
|
||||
<Compile Include="Screens\Play\HUDOverlay.cs" />
|
||||
|
Loading…
Reference in New Issue
Block a user