1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-13 03:33:22 +08:00

Merge branch 'editor-position-snap' into mania-distance-snap-grid

This commit is contained in:
Dean Herbert 2020-05-22 11:27:36 +09:00
commit 6de2597958
19 changed files with 158 additions and 112 deletions

View File

@ -7,6 +7,7 @@ using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Timing; using osu.Framework.Timing;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Mania.Edit; using osu.Game.Rulesets.Mania.Edit;
using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.Mania.UI;
@ -43,12 +44,18 @@ namespace osu.Game.Rulesets.Mania.Tests
}); });
} }
protected override SnapResult SnapForBlueprint(PlacementBlueprint blueprint)
{
var time = column.TimeAtScreenSpacePosition(InputManager.CurrentState.Mouse.Position);
var pos = column.ScreenSpacePositionAtTime(time);
return new ManiaSnapResult(pos, time, column);
}
protected override Container CreateHitObjectContainer() => new ScrollingTestContainer(ScrollingDirection.Down) { RelativeSizeAxes = Axes.Both }; protected override Container CreateHitObjectContainer() => new ScrollingTestContainer(ScrollingDirection.Down) { RelativeSizeAxes = Axes.Both };
protected override void AddHitObject(DrawableHitObject hitObject) => column.Add((DrawableManiaHitObject)hitObject); protected override void AddHitObject(DrawableHitObject hitObject) => column.Add((DrawableManiaHitObject)hitObject);
public Column ColumnAt(Vector2 screenSpacePosition) => column;
public ManiaPlayfield Playfield => null; public ManiaPlayfield Playfield => null;
public Vector2 ScreenSpacePositionAtTime(double time, Column column = null) => Vector2.Zero; public Vector2 ScreenSpacePositionAtTime(double time, Column column = null) => Vector2.Zero;

View File

@ -66,7 +66,7 @@ namespace osu.Game.Rulesets.Mania.Tests
AddStep("move mouse downwards", () => AddStep("move mouse downwards", () =>
{ {
InputManager.MoveMouseTo(lastObject, new Vector2(0, lastObject.ScreenSpaceDrawQuad.Height * 2)); InputManager.MoveMouseTo(lastObject, new Vector2(0, lastObject.ScreenSpaceDrawQuad.Height * 4));
InputManager.ReleaseButton(MouseButton.Left); InputManager.ReleaseButton(MouseButton.Left);
}); });
@ -103,7 +103,7 @@ namespace osu.Game.Rulesets.Mania.Tests
AddStep("move mouse upwards", () => AddStep("move mouse upwards", () =>
{ {
InputManager.MoveMouseTo(lastObject, new Vector2(0, -lastObject.ScreenSpaceDrawQuad.Height * 2)); InputManager.MoveMouseTo(lastObject, new Vector2(0, -lastObject.ScreenSpaceDrawQuad.Height * 4));
InputManager.ReleaseButton(MouseButton.Left); InputManager.ReleaseButton(MouseButton.Left);
}); });

View File

@ -41,8 +41,8 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
if (Column != null) if (Column != null)
{ {
headPiece.Y = Parent.ToLocalSpace(composer.ScreenSpacePositionAtTime(HitObject.StartTime, Column)).Y; headPiece.Y = Parent.ToLocalSpace(Column.ScreenSpacePositionAtTime(HitObject.StartTime)).Y;
tailPiece.Y = Parent.ToLocalSpace(composer.ScreenSpacePositionAtTime(HitObject.EndTime, Column)).Y; tailPiece.Y = Parent.ToLocalSpace(Column.ScreenSpacePositionAtTime(HitObject.EndTime)).Y;
} }
var topPosition = new Vector2(headPiece.DrawPosition.X, Math.Min(headPiece.DrawPosition.Y, tailPiece.DrawPosition.Y)); var topPosition = new Vector2(headPiece.DrawPosition.X, Math.Min(headPiece.DrawPosition.Y, tailPiece.DrawPosition.Y));

View File

@ -50,6 +50,8 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
public override void UpdatePosition(SnapResult result) public override void UpdatePosition(SnapResult result)
{ {
base.UpdatePosition(result);
if (!PlacementActive) if (!PlacementActive)
Column = (result as ManiaSnapResult)?.Column; Column = (result as ManiaSnapResult)?.Column;
} }

View File

@ -2,14 +2,11 @@
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.Mania.UI;
using osuTK;
namespace osu.Game.Rulesets.Mania.Edit namespace osu.Game.Rulesets.Mania.Edit
{ {
public interface IManiaHitObjectComposer public interface IManiaHitObjectComposer
{ {
ManiaPlayfield Playfield { get; } ManiaPlayfield Playfield { get; }
Vector2 ScreenSpacePositionAtTime(double time, Column column = null);
} }
} }

View File

@ -83,48 +83,17 @@ namespace osu.Game.Rulesets.Mania.Edit
if (column == null) if (column == null)
return new SnapResult(screenSpacePosition, null); return new SnapResult(screenSpacePosition, null);
var hoc = column.HitObjectContainer; double targetTime = column.TimeAtScreenSpacePosition(screenSpacePosition);
// convert to local space of column so we can snap and fetch correct location.
Vector2 localPosition = hoc.ToLocalSpace(screenSpacePosition);
var scrollInfo = drawableRuleset.ScrollingInfo;
if (scrollInfo.Direction.Value == ScrollingDirection.Down)
{
// We're dealing with screen coordinates in which the position decreases towards the centre of the screen resulting in an increase in start time.
// The scrolling algorithm instead assumes a top anchor meaning an increase in time corresponds to an increase in position,
// so when scrolling downwards the coordinates need to be flipped.
localPosition.Y = hoc.DrawHeight - localPosition.Y;
}
double targetTime = scrollInfo.Algorithm.TimeAt(localPosition.Y, EditorClock.CurrentTime, scrollInfo.TimeRange.Value, hoc.DrawHeight);
// apply beat snapping // apply beat snapping
targetTime = BeatSnapProvider.SnapTime(targetTime); targetTime = BeatSnapProvider.SnapTime(targetTime);
// convert back to screen space // convert back to screen space
screenSpacePosition = ScreenSpacePositionAtTime(targetTime, column); screenSpacePosition = column.ScreenSpacePositionAtTime(targetTime);
return new ManiaSnapResult(screenSpacePosition, targetTime, column); return new ManiaSnapResult(screenSpacePosition, targetTime, column);
} }
public Vector2 ScreenSpacePositionAtTime(double time, Column column = null)
{
var hoc = (column ?? Playfield.GetColumn(0)).HitObjectContainer;
var scrollInfo = drawableRuleset.ScrollingInfo;
var pos = scrollInfo.Algorithm.PositionAt(time, EditorClock.CurrentTime, scrollInfo.TimeRange.Value, hoc.DrawHeight);
if (scrollInfo.Direction.Value == ScrollingDirection.Down)
{
// as explained above
pos = hoc.DrawHeight - pos;
}
return hoc.ToScreenSpace(new Vector2(hoc.DrawWidth / 2, pos));
}
protected override DrawableRuleset<ManiaHitObject> CreateDrawableRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList<Mod> mods = null) protected override DrawableRuleset<ManiaHitObject> CreateDrawableRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList<Mod> mods = null)
{ {
drawableRuleset = new DrawableManiaEditRuleset(ruleset, beatmap, mods); drawableRuleset = new DrawableManiaEditRuleset(ruleset, beatmap, mods);

View File

@ -17,6 +17,7 @@ using osu.Game.Rulesets.UI.Scrolling;
using osu.Game.Skinning; using osu.Game.Skinning;
using osuTK; using osuTK;
using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
namespace osu.Game.Rulesets.Mania.UI namespace osu.Game.Rulesets.Mania.UI
{ {
@ -142,5 +143,54 @@ namespace osu.Game.Rulesets.Mania.UI
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) public override bool ReceivePositionalInputAt(Vector2 screenSpacePos)
// This probably shouldn't exist as is, but the columns in the stage are separated by a 1px border // This probably shouldn't exist as is, but the columns in the stage are separated by a 1px border
=> DrawRectangle.Inflate(new Vector2(Stage.COLUMN_SPACING / 2, 0)).Contains(ToLocalSpace(screenSpacePos)); => DrawRectangle.Inflate(new Vector2(Stage.COLUMN_SPACING / 2, 0)).Contains(ToLocalSpace(screenSpacePos));
/// <summary>
/// Given a time, return the screen space position within this column.
/// </summary>
public Vector2 ScreenSpacePositionAtTime(double time)
{
var pos = ScrollingInfo.Algorithm.PositionAt(time, Time.Current, ScrollingInfo.TimeRange.Value, HitObjectContainer.DrawHeight);
switch (ScrollingInfo.Direction.Value)
{
case ScrollingDirection.Down:
// We're dealing with screen coordinates in which the position decreases towards the centre of the screen resulting in an increase in start time.
// The scrolling algorithm instead assumes a top anchor meaning an increase in time corresponds to an increase in position,
// so when scrolling downwards the coordinates need to be flipped.
pos = HitObjectContainer.DrawHeight - pos;
// Blueprints are centred on the mouse position, such that the hitobject position is anchored at the top or bottom of the blueprint depending on the scroll direction.
pos -= DefaultNotePiece.NOTE_HEIGHT / 2;
break;
case ScrollingDirection.Up:
pos += DefaultNotePiece.NOTE_HEIGHT / 2;
break;
}
return HitObjectContainer.ToScreenSpace(new Vector2(HitObjectContainer.DrawWidth / 2, pos));
}
/// <summary>
/// Given a position in screen space, return the time within this column.
/// </summary>
public double TimeAtScreenSpacePosition(Vector2 screenSpacePosition)
{
// convert to local space of column so we can snap and fetch correct location.
Vector2 localPosition = HitObjectContainer.ToLocalSpace(screenSpacePosition);
switch (ScrollingInfo.Direction.Value)
{
case ScrollingDirection.Down:
// as above
localPosition.Y = HitObjectContainer.DrawHeight - localPosition.Y;
break;
}
// offset for the fact that blueprints are centered, as above.
localPosition.Y -= DefaultNotePiece.NOTE_HEIGHT / 2;
return ScrollingInfo.Algorithm.TimeAt(localPosition.Y, Time.Current, ScrollingInfo.TimeRange.Value, HitObjectContainer.DrawHeight);
}
} }
} }

View File

@ -39,6 +39,10 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles
return base.OnMouseDown(e); return base.OnMouseDown(e);
} }
public override void UpdatePosition(SnapResult result) => HitObject.Position = ToLocalSpace(result.ScreenSpacePosition); public override void UpdatePosition(SnapResult result)
{
base.UpdatePosition(result);
HitObject.Position = ToLocalSpace(result.ScreenSpacePosition);
}
} }
} }

View File

@ -69,6 +69,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
public override void UpdatePosition(SnapResult result) public override void UpdatePosition(SnapResult result)
{ {
base.UpdatePosition(result);
switch (state) switch (state)
{ {
case PlacementState.Initial: case PlacementState.Initial:

View File

@ -59,9 +59,5 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners
return true; return true;
} }
public override void UpdatePosition(SnapResult result)
{
}
} }
} }

View File

@ -12,6 +12,7 @@ using osu.Framework.Input.Bindings;
using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Rulesets.Taiko.Audio; using osu.Game.Rulesets.Taiko.Audio;
using osu.Game.Screens.Play;
using osu.Game.Skinning; using osu.Game.Skinning;
namespace osu.Game.Rulesets.Taiko.UI namespace osu.Game.Rulesets.Taiko.UI
@ -145,6 +146,9 @@ namespace osu.Game.Rulesets.Taiko.UI
centreHit.Colour = colours.Pink; centreHit.Colour = colours.Pink;
} }
[Resolved(canBeNull: true)]
private GameplayClock gameplayClock { get; set; }
public bool OnPressed(TaikoAction action) public bool OnPressed(TaikoAction action)
{ {
Drawable target = null; Drawable target = null;
@ -157,6 +161,7 @@ namespace osu.Game.Rulesets.Taiko.UI
target = centreHit; target = centreHit;
back = centre; back = centre;
if (gameplayClock?.IsSeeking != true)
drumSample.Centre?.Play(); drumSample.Centre?.Play();
} }
else if (action == RimAction) else if (action == RimAction)
@ -164,6 +169,7 @@ namespace osu.Game.Rulesets.Taiko.UI
target = rimHit; target = rimHit;
back = rim; back = rim;
if (gameplayClock?.IsSeeking != true)
drumSample.Rim?.Play(); drumSample.Rim?.Play();
} }

View File

@ -244,8 +244,6 @@ namespace osu.Game.Rulesets.Edit
public void BeginPlacement(HitObject hitObject) public void BeginPlacement(HitObject hitObject)
{ {
EditorBeatmap.PlacementObject.Value = hitObject; EditorBeatmap.PlacementObject.Value = hitObject;
hitObject.StartTime = SnapScreenSpacePositionToValidTime(inputManager.CurrentState.Mouse.Position).Time ?? EditorClock.CurrentTime;
} }
public void EndPlacement(HitObject hitObject, bool commit) public void EndPlacement(HitObject hitObject, bool commit)
@ -256,7 +254,8 @@ namespace osu.Game.Rulesets.Edit
{ {
EditorBeatmap.Add(hitObject); EditorBeatmap.Add(hitObject);
adjustableClock.Seek(hitObject.GetEndTime()); if (adjustableClock.CurrentTime < hitObject.StartTime)
adjustableClock.Seek(hitObject.StartTime);
} }
showGridFor(Enumerable.Empty<HitObject>()); showGridFor(Enumerable.Empty<HitObject>());

View File

@ -83,11 +83,18 @@ namespace osu.Game.Rulesets.Edit
PlacementActive = false; PlacementActive = false;
} }
[Resolved(canBeNull: true)]
private IFrameBasedClock editorClock { get; set; }
/// <summary> /// <summary>
/// Updates the position of this <see cref="PlacementBlueprint"/> to a new screen-space position. /// Updates the position of this <see cref="PlacementBlueprint"/> to a new screen-space position.
/// </summary> /// </summary>
/// <param name="snapResult">The snap result information.</param> /// <param name="snapResult">The snap result information.</param>
public abstract void UpdatePosition(SnapResult snapResult); public virtual void UpdatePosition(SnapResult snapResult)
{
if (!PlacementActive)
HitObject.StartTime = snapResult.Time ?? editorClock?.CurrentTime ?? Time.Current;
}
/// <summary> /// <summary>
/// Invokes <see cref="Objects.HitObject.ApplyDefaults(ControlPointInfo,BeatmapDifficulty)"/>, /// Invokes <see cref="Objects.HitObject.ApplyDefaults(ControlPointInfo,BeatmapDifficulty)"/>,

View File

@ -11,13 +11,13 @@ using osu.Framework.Extensions.TypeExtensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Primitives; using osu.Framework.Graphics.Primitives;
using osu.Framework.Threading; using osu.Framework.Threading;
using osu.Framework.Audio;
using osu.Game.Audio; using osu.Game.Audio;
using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osu.Game.Skinning; using osu.Game.Skinning;
using osu.Game.Configuration; using osu.Game.Configuration;
using osu.Game.Screens.Play;
using osuTK.Graphics; using osuTK.Graphics;
namespace osu.Game.Rulesets.Objects.Drawables namespace osu.Game.Rulesets.Objects.Drawables
@ -96,8 +96,6 @@ namespace osu.Game.Rulesets.Objects.Drawables
/// </remarks> /// </remarks>
protected virtual float SamplePlaybackPosition => 0.5f; protected virtual float SamplePlaybackPosition => 0.5f;
private readonly BindableDouble balanceAdjust = new BindableDouble();
private BindableList<HitSampleInfo> samplesBindable; private BindableList<HitSampleInfo> samplesBindable;
private Bindable<double> startTimeBindable; private Bindable<double> startTimeBindable;
private Bindable<bool> userPositionalHitSounds; private Bindable<bool> userPositionalHitSounds;
@ -173,7 +171,6 @@ namespace osu.Game.Rulesets.Objects.Drawables
} }
Samples = new SkinnableSound(samples.Select(s => HitObject.SampleControlPoint.ApplyTo(s))); Samples = new SkinnableSound(samples.Select(s => HitObject.SampleControlPoint.ApplyTo(s)));
Samples.AddAdjustment(AdjustableProperty.Balance, balanceAdjust);
AddInternal(Samples); AddInternal(Samples);
} }
@ -352,6 +349,9 @@ namespace osu.Game.Rulesets.Objects.Drawables
{ {
} }
[Resolved(canBeNull: true)]
private GameplayClock gameplayClock { get; set; }
/// <summary> /// <summary>
/// Plays all the hit sounds for this <see cref="DrawableHitObject"/>. /// Plays all the hit sounds for this <see cref="DrawableHitObject"/>.
/// This is invoked automatically when this <see cref="DrawableHitObject"/> is hit. /// This is invoked automatically when this <see cref="DrawableHitObject"/> is hit.
@ -360,8 +360,11 @@ namespace osu.Game.Rulesets.Objects.Drawables
{ {
const float balance_adjust_amount = 0.4f; const float balance_adjust_amount = 0.4f;
balanceAdjust.Value = balance_adjust_amount * (userPositionalHitSounds.Value ? SamplePlaybackPosition - 0.5f : 0); if (Samples != null && gameplayClock?.IsSeeking != true)
Samples?.Play(); {
Samples.Balance.Value = balance_adjust_amount * (userPositionalHitSounds.Value ? SamplePlaybackPosition - 0.5f : 0);
Samples.Play();
}
} }
protected override void Update() protected override void Update()

View File

@ -29,14 +29,16 @@ namespace osu.Game.Rulesets.UI
/// </summary> /// </summary>
internal bool FrameStablePlayback = true; internal bool FrameStablePlayback = true;
[Cached] public GameplayClock GameplayClock => stabilityGameplayClock;
public GameplayClock GameplayClock { get; }
[Cached(typeof(GameplayClock))]
private readonly StabilityGameplayClock stabilityGameplayClock;
public FrameStabilityContainer(double gameplayStartTime = double.MinValue) public FrameStabilityContainer(double gameplayStartTime = double.MinValue)
{ {
RelativeSizeAxes = Axes.Both; RelativeSizeAxes = Axes.Both;
GameplayClock = new GameplayClock(framedClock = new FramedClock(manualClock = new ManualClock())); stabilityGameplayClock = new StabilityGameplayClock(framedClock = new FramedClock(manualClock = new ManualClock()));
this.gameplayStartTime = gameplayStartTime; this.gameplayStartTime = gameplayStartTime;
} }
@ -57,7 +59,7 @@ namespace osu.Game.Rulesets.UI
{ {
if (clock != null) if (clock != null)
{ {
parentGameplayClock = clock; stabilityGameplayClock.ParentGameplayClock = parentGameplayClock = clock;
GameplayClock.IsPaused.BindTo(clock.IsPaused); GameplayClock.IsPaused.BindTo(clock.IsPaused);
} }
} }
@ -187,5 +189,17 @@ namespace osu.Game.Rulesets.UI
} }
public ReplayInputHandler ReplayInputHandler { get; set; } public ReplayInputHandler ReplayInputHandler { get; set; }
private class StabilityGameplayClock : GameplayClock
{
public IFrameBasedClock ParentGameplayClock;
public StabilityGameplayClock(FramedClock underlyingClock)
: base(underlyingClock)
{
}
public override bool IsSeeking => ParentGameplayClock != null && Math.Abs(CurrentTime - ParentGameplayClock.CurrentTime) > 200;
}
} }
} }

View File

@ -15,12 +15,12 @@ namespace osu.Game.Rulesets.UI.Scrolling
protected readonly IBindable<ScrollingDirection> Direction = new Bindable<ScrollingDirection>(); protected readonly IBindable<ScrollingDirection> Direction = new Bindable<ScrollingDirection>();
[Resolved] [Resolved]
private IScrollingInfo scrollingInfo { get; set; } protected IScrollingInfo ScrollingInfo { get; private set; }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
Direction.BindTo(scrollingInfo.Direction); Direction.BindTo(ScrollingInfo.Direction);
} }
protected sealed override HitObjectContainer CreateHitObjectContainer() => new ScrollingHitObjectContainer(); protected sealed override HitObjectContainer CreateHitObjectContainer() => new ScrollingHitObjectContainer();

View File

@ -31,6 +31,11 @@ namespace osu.Game.Screens.Play
public bool IsRunning => underlyingClock.IsRunning; public bool IsRunning => underlyingClock.IsRunning;
/// <summary>
/// Whether an ongoing seek operation is active.
/// </summary>
public virtual bool IsSeeking => false;
public void ProcessFrame() public void ProcessFrame()
{ {
// we do not want to process the underlying clock. // we do not want to process the underlying clock.

View File

@ -4,11 +4,11 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Audio.Track; using osu.Framework.Audio.Track;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics.Audio;
using osu.Framework.Graphics.Containers;
using osu.Game.Audio; using osu.Game.Audio;
namespace osu.Game.Skinning namespace osu.Game.Skinning
@ -17,25 +17,32 @@ namespace osu.Game.Skinning
{ {
private readonly ISampleInfo[] hitSamples; private readonly ISampleInfo[] hitSamples;
private List<(AdjustableProperty property, BindableDouble bindable)> adjustments;
private SampleChannel[] channels;
[Resolved] [Resolved]
private ISampleStore samples { get; set; } private ISampleStore samples { get; set; }
public SkinnableSound(ISampleInfo hitSamples)
: this(new[] { hitSamples })
{
}
public SkinnableSound(IEnumerable<ISampleInfo> hitSamples) public SkinnableSound(IEnumerable<ISampleInfo> hitSamples)
{ {
this.hitSamples = hitSamples.ToArray(); this.hitSamples = hitSamples.ToArray();
} InternalChild = samplesContainer = new AudioContainer<DrawableSample>();
public SkinnableSound(ISampleInfo hitSamples)
{
this.hitSamples = new[] { hitSamples };
} }
private bool looping; private bool looping;
private readonly AudioContainer<DrawableSample> samplesContainer;
public BindableNumber<double> Volume => samplesContainer.Volume;
public BindableNumber<double> Balance => samplesContainer.Balance;
public BindableNumber<double> Frequency => samplesContainer.Frequency;
public BindableNumber<double> Tempo => samplesContainer.Tempo;
public bool Looping public bool Looping
{ {
get => looping; get => looping;
@ -45,33 +52,23 @@ namespace osu.Game.Skinning
looping = value; looping = value;
channels?.ForEach(c => c.Looping = looping); samplesContainer.ForEach(c => c.Looping = looping);
} }
} }
public void Play() => channels?.ForEach(c => c.Play()); public void Play() => samplesContainer.ForEach(c =>
public void Stop() => channels?.ForEach(c => c.Stop());
public void AddAdjustment(AdjustableProperty type, BindableDouble adjustBindable)
{ {
if (adjustments == null) adjustments = new List<(AdjustableProperty, BindableDouble)>(); if (c.AggregateVolume.Value > 0)
c.Play();
});
adjustments.Add((type, adjustBindable)); public void Stop() => samplesContainer.ForEach(c => c.Stop());
channels?.ForEach(c => c.AddAdjustment(type, adjustBindable));
}
public void RemoveAdjustment(AdjustableProperty type, BindableDouble adjustBindable)
{
adjustments?.Remove((type, adjustBindable));
channels?.ForEach(c => c.RemoveAdjustment(type, adjustBindable));
}
public override bool IsPresent => Scheduler.HasPendingTasks; public override bool IsPresent => Scheduler.HasPendingTasks;
protected override void SkinChanged(ISkinSource skin, bool allowFallback) protected override void SkinChanged(ISkinSource skin, bool allowFallback)
{ {
channels = hitSamples.Select(s => var channels = hitSamples.Select(s =>
{ {
var ch = skin.GetSample(s); var ch = skin.GetSample(s);
@ -88,27 +85,12 @@ namespace osu.Game.Skinning
{ {
ch.Looping = looping; ch.Looping = looping;
ch.Volume.Value = s.Volume / 100.0; ch.Volume.Value = s.Volume / 100.0;
if (adjustments != null)
{
foreach (var (property, bindable) in adjustments)
ch.AddAdjustment(property, bindable);
}
} }
return ch; return ch;
}).Where(c => c != null).ToArray(); }).Where(c => c != null);
}
protected override void Dispose(bool isDisposing) samplesContainer.ChildrenEnumerable = channels.Select(c => new DrawableSample(c));
{
base.Dispose(isDisposing);
if (channels != null)
{
foreach (var c in channels)
c.Dispose();
}
} }
} }
} }

View File

@ -71,9 +71,12 @@ namespace osu.Game.Tests.Visual
{ {
base.Update(); base.Update();
currentBlueprint.UpdatePosition(new SnapResult(InputManager.CurrentState.Mouse.Position, null)); currentBlueprint.UpdatePosition(SnapForBlueprint(currentBlueprint));
} }
protected virtual SnapResult SnapForBlueprint(PlacementBlueprint blueprint) =>
new SnapResult(InputManager.CurrentState.Mouse.Position, null);
public override void Add(Drawable drawable) public override void Add(Drawable drawable)
{ {
base.Add(drawable); base.Add(drawable);
@ -81,7 +84,7 @@ namespace osu.Game.Tests.Visual
if (drawable is PlacementBlueprint blueprint) if (drawable is PlacementBlueprint blueprint)
{ {
blueprint.Show(); blueprint.Show();
blueprint.UpdatePosition(new SnapResult(InputManager.CurrentState.Mouse.Position, null)); blueprint.UpdatePosition(SnapForBlueprint(blueprint));
} }
} }