mirror of
https://github.com/ppy/osu.git
synced 2024-11-11 10:18:22 +08:00
Merge remote-tracking branch 'origin/master' into editor-mask-placement
# Conflicts: # osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs # osu.Game.Rulesets.Mania/Edit/ManiaEditRulesetContainer.cs # osu.Game.Rulesets.Osu/Edit/OsuEditRulesetContainer.cs # osu.Game/Rulesets/UI/RulesetContainer.cs
This commit is contained in:
commit
70f1d17b7e
@ -27,9 +27,9 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="System.IO.Packaging" Version="4.5.0" />
|
||||
<PackageReference Include="ppy.squirrel.windows" Version="1.8.0.6" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.3" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.1.3" />
|
||||
<PackageReference Include="ppy.squirrel.windows" Version="1.8.0.8" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.1.4" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Resources">
|
||||
<EmbeddedResource Include="lazer.ico" />
|
||||
|
@ -2,9 +2,10 @@
|
||||
<Import Project="..\osu.TestProject.props" />
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.8.0" />
|
||||
<PackageReference Include="NUnit" Version="3.10.1" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
|
||||
<PackageReference Include="NUnit" Version="3.11.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.10.0" />
|
||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Project">
|
||||
<OutputType>WinExe</OutputType>
|
||||
|
@ -11,6 +11,7 @@ using osu.Game.Rulesets.Catch.Objects.Drawable;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.UI.Scrolling;
|
||||
using OpenTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.UI
|
||||
{
|
||||
@ -18,9 +19,6 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
{
|
||||
public const float BASE_WIDTH = 512;
|
||||
|
||||
protected override Container<Drawable> Content => content;
|
||||
private readonly Container<Drawable> content;
|
||||
|
||||
private readonly CatcherArea catcherArea;
|
||||
|
||||
protected override bool UserScrollSpeedAdjustment => false;
|
||||
@ -28,7 +26,6 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
protected override SpeedChangeVisualisationMethod VisualisationMethod => SpeedChangeVisualisationMethod.Constant;
|
||||
|
||||
public CatchPlayfield(BeatmapDifficulty difficulty, Func<CatchHitObject, DrawableHitObject<CatchHitObject>> getVisualRepresentation)
|
||||
: base(BASE_WIDTH)
|
||||
{
|
||||
Direction.Value = ScrollingDirection.Down;
|
||||
|
||||
@ -37,27 +34,27 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
Anchor = Anchor.TopCentre;
|
||||
Origin = Anchor.TopCentre;
|
||||
|
||||
base.Content.Anchor = Anchor.BottomLeft;
|
||||
base.Content.Origin = Anchor.BottomLeft;
|
||||
Size = new Vector2(0.86f); // matches stable's vertical offset for catcher plate
|
||||
|
||||
base.Content.AddRange(new Drawable[]
|
||||
InternalChild = new PlayfieldAdjustmentContainer
|
||||
{
|
||||
explodingFruitContainer = new Container
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
catcherArea = new CatcherArea(difficulty)
|
||||
{
|
||||
GetVisualRepresentation = getVisualRepresentation,
|
||||
ExplodingFruitTarget = explodingFruitContainer,
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Origin = Anchor.TopLeft,
|
||||
},
|
||||
content = new Container<Drawable>
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
});
|
||||
explodingFruitContainer = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
catcherArea = new CatcherArea(difficulty)
|
||||
{
|
||||
GetVisualRepresentation = getVisualRepresentation,
|
||||
ExplodingFruitTarget = explodingFruitContainer,
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Origin = Anchor.TopLeft,
|
||||
},
|
||||
HitObjectContainer
|
||||
}
|
||||
};
|
||||
|
||||
VisibleTimeRange.Value = BeatmapDifficulty.DifficultyRange(difficulty.ApproachRate, 1800, 1200, 450);
|
||||
}
|
||||
|
@ -13,7 +13,6 @@ using osu.Game.Rulesets.Replays;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osu.Game.Rulesets.UI.Scrolling;
|
||||
using OpenTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.UI
|
||||
{
|
||||
@ -32,8 +31,6 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
|
||||
public override PassThroughInputManager CreateInputManager() => new CatchInputManager(Ruleset.RulesetInfo);
|
||||
|
||||
protected override Vector2 PlayfieldArea => new Vector2(0.86f); // matches stable's vertical offset for catcher plate
|
||||
|
||||
public override DrawableHitObject<CatchHitObject> GetVisualRepresentation(CatchHitObject h)
|
||||
{
|
||||
switch (h)
|
||||
|
@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
{
|
||||
public class CatcherArea : Container
|
||||
{
|
||||
public const float CATCHER_SIZE = 84;
|
||||
public const float CATCHER_SIZE = 100;
|
||||
|
||||
protected readonly Catcher MovableCatcher;
|
||||
|
||||
|
42
osu.Game.Rulesets.Catch/UI/PlayfieldAdjustmentContainer.cs
Normal file
42
osu.Game.Rulesets.Catch/UI/PlayfieldAdjustmentContainer.cs
Normal file
@ -0,0 +1,42 @@
|
||||
// Copyright (c) 2007-2018 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 OpenTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.UI
|
||||
{
|
||||
public class PlayfieldAdjustmentContainer : Container
|
||||
{
|
||||
protected override Container<Drawable> Content => content;
|
||||
private readonly Container content;
|
||||
|
||||
public PlayfieldAdjustmentContainer()
|
||||
{
|
||||
InternalChild = new Container
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
FillMode = FillMode.Fit,
|
||||
FillAspectRatio = 4f / 3,
|
||||
Child = content = new ScalingContainer { RelativeSizeAxes = Axes.Both }
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A <see cref="Container"/> which scales its content relative to a target width.
|
||||
/// </summary>
|
||||
private class ScalingContainer : Container
|
||||
{
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
Scale = new Vector2(Parent.ChildSize.X / CatchPlayfield.BASE_WIDTH);
|
||||
Size = Vector2.Divide(Vector2.One, Scale);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -2,9 +2,10 @@
|
||||
<Import Project="..\osu.TestProject.props" />
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.8.0" />
|
||||
<PackageReference Include="NUnit" Version="3.10.1" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
|
||||
<PackageReference Include="NUnit" Version="3.11.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.10.0" />
|
||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Project">
|
||||
<OutputType>WinExe</OutputType>
|
||||
|
@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Mania.Configuration
|
||||
{
|
||||
base.InitialiseDefaults();
|
||||
|
||||
Set(ManiaSetting.ScrollTime, 1500.0, 50.0, 10000.0, 50.0);
|
||||
Set(ManiaSetting.ScrollTime, 2250.0, 50.0, 10000.0, 50.0);
|
||||
Set(ManiaSetting.ScrollDirection, ManiaScrollingDirection.Down);
|
||||
}
|
||||
|
||||
|
@ -32,9 +32,8 @@ namespace osu.Game.Rulesets.Mania.Edit
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Size = Vector2.One
|
||||
};
|
||||
|
||||
protected override Vector2 PlayfieldArea => Vector2.One;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -30,8 +30,6 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
internal readonly Container TopLevelContainer;
|
||||
private readonly Container explosionContainer;
|
||||
|
||||
protected override Container<Drawable> Content => hitObjectArea;
|
||||
|
||||
public Column()
|
||||
{
|
||||
RelativeSizeAxes = Axes.Y;
|
||||
@ -54,7 +52,10 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
hitObjectArea = new ColumnHitObjectArea { RelativeSizeAxes = Axes.Both },
|
||||
hitObjectArea = new ColumnHitObjectArea(HitObjectContainer)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
explosionContainer = new Container
|
||||
{
|
||||
Name = "Hit explosions",
|
||||
|
@ -8,28 +8,24 @@ using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osu.Game.Rulesets.UI.Scrolling;
|
||||
using OpenTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.UI.Components
|
||||
{
|
||||
public class ColumnHitObjectArea : Container, IHasAccentColour
|
||||
public class ColumnHitObjectArea : CompositeDrawable, IHasAccentColour
|
||||
{
|
||||
private const float hit_target_height = 10;
|
||||
private const float hit_target_bar_height = 2;
|
||||
|
||||
private Container<Drawable> content;
|
||||
protected override Container<Drawable> Content => content;
|
||||
|
||||
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
|
||||
|
||||
private Container hitTargetLine;
|
||||
private readonly Container hitTargetLine;
|
||||
private readonly Drawable hitTargetBar;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(IScrollingInfo scrollingInfo)
|
||||
public ColumnHitObjectArea(HitObjectContainer hitObjectContainer)
|
||||
{
|
||||
Drawable hitTargetBar;
|
||||
|
||||
InternalChildren = new[]
|
||||
{
|
||||
hitTargetBar = new Box
|
||||
@ -45,13 +41,13 @@ namespace osu.Game.Rulesets.Mania.UI.Components
|
||||
Masking = true,
|
||||
Child = new Box { RelativeSizeAxes = Axes.Both }
|
||||
},
|
||||
content = new Container
|
||||
{
|
||||
Name = "Hit objects",
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
hitObjectContainer
|
||||
};
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(IScrollingInfo scrollingInfo)
|
||||
{
|
||||
direction.BindTo(scrollingInfo.Direction);
|
||||
direction.BindValueChanged(direction =>
|
||||
{
|
||||
|
@ -10,6 +10,7 @@ using osu.Game.Rulesets.Mania.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Configuration;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using OpenTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.UI
|
||||
{
|
||||
@ -25,6 +26,8 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
if (stageDefinitions.Count <= 0)
|
||||
throw new ArgumentException("Can't have zero or fewer stages.");
|
||||
|
||||
Size = new Vector2(1, 0.8f);
|
||||
|
||||
GridContainer playfieldGrid;
|
||||
AddInternal(playfieldGrid = new GridContainer
|
||||
{
|
||||
|
@ -24,7 +24,6 @@ using osu.Game.Rulesets.Replays;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osu.Game.Rulesets.UI.Scrolling;
|
||||
using OpenTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.UI
|
||||
{
|
||||
@ -110,8 +109,6 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
}
|
||||
}
|
||||
|
||||
protected override Vector2 PlayfieldArea => new Vector2(1, 0.8f);
|
||||
|
||||
protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new ManiaFramedReplayInputHandler(replay);
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ using osu.Game.Rulesets.UI.Scrolling;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.UI
|
||||
{
|
||||
public class ManiaScrollingPlayfield : ScrollingPlayfield
|
||||
public abstract class ManiaScrollingPlayfield : ScrollingPlayfield
|
||||
{
|
||||
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
|
||||
|
||||
|
@ -30,8 +30,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
public IReadOnlyList<Column> Columns => columnFlow.Children;
|
||||
private readonly FillFlowContainer<Column> columnFlow;
|
||||
|
||||
protected override Container<Drawable> Content => barLineContainer;
|
||||
private readonly Container<Drawable> barLineContainer;
|
||||
private readonly Container barLineContainer;
|
||||
|
||||
public Container<DrawableManiaJudgement> Judgements => judgements;
|
||||
private readonly JudgementContainer<DrawableManiaJudgement> judgements;
|
||||
@ -105,6 +104,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Child = HitObjectContainer
|
||||
}
|
||||
},
|
||||
judgements = new JudgementContainer<DrawableManiaJudgement>
|
||||
|
@ -2,9 +2,10 @@
|
||||
<Import Project="..\osu.TestProject.props" />
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.8.0" />
|
||||
<PackageReference Include="NUnit" Version="3.10.1" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
|
||||
<PackageReference Include="NUnit" Version="3.11.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.10.0" />
|
||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Project">
|
||||
<OutputType>WinExe</OutputType>
|
||||
|
@ -10,6 +10,8 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
|
||||
{
|
||||
public class OsuBeatmapProcessor : BeatmapProcessor
|
||||
{
|
||||
private const int stack_distance = 3;
|
||||
|
||||
public OsuBeatmapProcessor(IBeatmap beatmap)
|
||||
: base(beatmap)
|
||||
{
|
||||
@ -18,17 +20,21 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
|
||||
public override void PostProcess()
|
||||
{
|
||||
base.PostProcess();
|
||||
applyStacking((Beatmap<OsuHitObject>)Beatmap);
|
||||
|
||||
var osuBeatmap = (Beatmap<OsuHitObject>)Beatmap;
|
||||
|
||||
// Reset stacking
|
||||
foreach (var h in osuBeatmap.HitObjects)
|
||||
h.StackHeight = 0;
|
||||
|
||||
if (Beatmap.BeatmapInfo.BeatmapVersion >= 6)
|
||||
applyStacking(osuBeatmap);
|
||||
else
|
||||
applyStackingOld(osuBeatmap);
|
||||
}
|
||||
|
||||
private void applyStacking(Beatmap<OsuHitObject> beatmap)
|
||||
{
|
||||
const int stack_distance = 3;
|
||||
|
||||
// Reset stacking
|
||||
for (int i = 0; i <= beatmap.HitObjects.Count - 1; i++)
|
||||
beatmap.HitObjects[i].StackHeight = 0;
|
||||
|
||||
// Extend the end index to include objects they are stacked on
|
||||
int extendedEndIndex = beatmap.HitObjects.Count - 1;
|
||||
for (int i = beatmap.HitObjects.Count - 1; i >= 0; i--)
|
||||
@ -167,5 +173,40 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void applyStackingOld(Beatmap<OsuHitObject> beatmap)
|
||||
{
|
||||
for (int i = 0; i < beatmap.HitObjects.Count; i++)
|
||||
{
|
||||
OsuHitObject currHitObject = beatmap.HitObjects[i];
|
||||
|
||||
if (currHitObject.StackHeight != 0 && !(currHitObject is Slider))
|
||||
continue;
|
||||
|
||||
double startTime = (currHitObject as IHasEndTime)?.EndTime ?? currHitObject.StartTime;
|
||||
int sliderStack = 0;
|
||||
|
||||
for (int j = i + 1; j < beatmap.HitObjects.Count; j++)
|
||||
{
|
||||
double stackThreshold = beatmap.HitObjects[i].TimePreempt * beatmap.BeatmapInfo.StackLeniency;
|
||||
|
||||
if (beatmap.HitObjects[j].StartTime - stackThreshold > startTime)
|
||||
break;
|
||||
|
||||
if (Vector2Extensions.Distance(beatmap.HitObjects[j].Position, currHitObject.Position) < stack_distance)
|
||||
{
|
||||
currHitObject.StackHeight++;
|
||||
startTime = (beatmap.HitObjects[j] as IHasEndTime)?.EndTime ?? beatmap.HitObjects[i].StartTime;
|
||||
}
|
||||
else if (Vector2Extensions.Distance(beatmap.HitObjects[j].Position, currHitObject.EndPosition) < stack_distance)
|
||||
{
|
||||
//Case for sliders - bump notes down and right, rather than up and left.
|
||||
sliderStack++;
|
||||
beatmap.HitObjects[j].StackHeight -= sliderStack;
|
||||
startTime = (beatmap.HitObjects[j] as IHasEndTime)?.EndTime ?? beatmap.HitObjects[i].StartTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
||||
double sectionLength = section_length * timeRate;
|
||||
|
||||
// The first object doesn't generate a strain, so we begin with an incremented section end
|
||||
double currentSectionEnd = 2 * sectionLength;
|
||||
double currentSectionEnd = Math.Ceiling(beatmap.HitObjects.First().StartTime / sectionLength) * sectionLength;
|
||||
|
||||
foreach (OsuDifficultyHitObject h in difficultyBeatmap)
|
||||
{
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
|
||||
@ -23,8 +24,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
|
||||
{
|
||||
// Sort OsuHitObjects by StartTime - they are not correctly ordered in some cases.
|
||||
// This should probably happen before the objects reach the difficulty calculator.
|
||||
objects.Sort((a, b) => a.StartTime.CompareTo(b.StartTime));
|
||||
difficultyObjects = createDifficultyObjectEnumerator(objects, timeRate);
|
||||
difficultyObjects = createDifficultyObjectEnumerator(objects.OrderBy(h => h.StartTime).ToList(), timeRate);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -21,15 +21,25 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
|
||||
public OsuHitObject BaseObject { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Normalized distance from the <see cref="OsuHitObject.StackedPosition"/> of the previous <see cref="OsuDifficultyHitObject"/>.
|
||||
/// Normalized distance from the end position of the previous <see cref="OsuDifficultyHitObject"/> to the start position of this <see cref="OsuDifficultyHitObject"/>.
|
||||
/// </summary>
|
||||
public double Distance { get; private set; }
|
||||
public double JumpDistance { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Normalized distance between the start and end position of the previous <see cref="OsuDifficultyHitObject"/>.
|
||||
/// </summary>
|
||||
public double TravelDistance { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Milliseconds elapsed since the StartTime of the previous <see cref="OsuDifficultyHitObject"/>.
|
||||
/// </summary>
|
||||
public double DeltaTime { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Milliseconds elapsed since the start time of the previous <see cref="OsuDifficultyHitObject"/>, with a minimum of 50ms.
|
||||
/// </summary>
|
||||
public double StrainTime { get; private set; }
|
||||
|
||||
private readonly OsuHitObject lastObject;
|
||||
private readonly double timeRate;
|
||||
|
||||
@ -51,31 +61,37 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
|
||||
private void setDistances()
|
||||
{
|
||||
// We will scale distances by this factor, so we can assume a uniform CircleSize among beatmaps.
|
||||
double scalingFactor = normalized_radius / BaseObject.Radius;
|
||||
float scalingFactor = normalized_radius / (float)BaseObject.Radius;
|
||||
if (BaseObject.Radius < 30)
|
||||
{
|
||||
double smallCircleBonus = Math.Min(30 - BaseObject.Radius, 5) / 50;
|
||||
float smallCircleBonus = Math.Min(30 - (float)BaseObject.Radius, 5) / 50;
|
||||
scalingFactor *= 1 + smallCircleBonus;
|
||||
}
|
||||
|
||||
Vector2 lastCursorPosition = lastObject.StackedPosition;
|
||||
float lastTravelDistance = 0;
|
||||
|
||||
var lastSlider = lastObject as Slider;
|
||||
if (lastSlider != null)
|
||||
{
|
||||
computeSliderCursorPosition(lastSlider);
|
||||
lastCursorPosition = lastSlider.LazyEndPosition ?? lastCursorPosition;
|
||||
lastTravelDistance = lastSlider.LazyTravelDistance;
|
||||
}
|
||||
|
||||
Distance = (lastTravelDistance + (BaseObject.StackedPosition - lastCursorPosition).Length) * scalingFactor;
|
||||
// Don't need to jump to reach spinners
|
||||
if (!(BaseObject is Spinner))
|
||||
JumpDistance = (BaseObject.StackedPosition * scalingFactor - lastCursorPosition * scalingFactor).Length;
|
||||
|
||||
// Todo: BUG!!! Last slider's travel distance is considered ONLY IF we ourselves are also a slider!
|
||||
if (BaseObject is Slider)
|
||||
TravelDistance = (lastSlider?.LazyTravelDistance ?? 0) * scalingFactor;
|
||||
}
|
||||
|
||||
private void setTimingValues()
|
||||
{
|
||||
// Every timing inverval is hard capped at the equivalent of 375 BPM streaming speed as a safety measure.
|
||||
DeltaTime = Math.Max(50, (BaseObject.StartTime - lastObject.StartTime) / timeRate);
|
||||
DeltaTime = (BaseObject.StartTime - lastObject.StartTime) / timeRate;
|
||||
|
||||
// Every strain interval is hard capped at the equivalent of 375 BPM streaming speed as a safety measure
|
||||
StrainTime = Math.Max(50, DeltaTime);
|
||||
}
|
||||
|
||||
private void computeSliderCursorPosition(Slider slider)
|
||||
@ -87,8 +103,14 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
|
||||
float approxFollowCircleRadius = (float)(slider.Radius * 3);
|
||||
var computeVertex = new Action<double>(t =>
|
||||
{
|
||||
double progress = ((int)t - (int)slider.StartTime) / (float)(int)slider.SpanDuration;
|
||||
if (progress % 2 > 1)
|
||||
progress = 1 - progress % 1;
|
||||
else
|
||||
progress = progress % 1;
|
||||
|
||||
// ReSharper disable once PossibleInvalidOperationException (bugged in current r# version)
|
||||
var diff = slider.StackedPositionAt(t) - slider.LazyEndPosition.Value;
|
||||
var diff = slider.StackedPosition + slider.Curve.PositionAt(progress) - slider.LazyEndPosition.Value;
|
||||
float dist = diff.Length;
|
||||
|
||||
if (dist > approxFollowCircleRadius)
|
||||
|
@ -14,6 +14,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
|
||||
protected override double SkillMultiplier => 26.25;
|
||||
protected override double StrainDecayBase => 0.15;
|
||||
|
||||
protected override double StrainValueOf(OsuDifficultyHitObject current) => Math.Pow(current.Distance, 0.99) / current.DeltaTime;
|
||||
protected override double StrainValueOf(OsuDifficultyHitObject current)
|
||||
=> (Math.Pow(current.TravelDistance, 0.99) + Math.Pow(current.JumpDistance, 0.99)) / current.StrainTime;
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
|
||||
|
||||
protected override double StrainValueOf(OsuDifficultyHitObject current)
|
||||
{
|
||||
double distance = current.Distance;
|
||||
double distance = current.TravelDistance + current.JumpDistance;
|
||||
|
||||
double speedValue;
|
||||
if (distance > single_spacing_threshold)
|
||||
@ -33,7 +33,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
|
||||
else
|
||||
speedValue = 0.95;
|
||||
|
||||
return speedValue / current.DeltaTime;
|
||||
return speedValue / current.StrainTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,9 +28,8 @@ namespace osu.Game.Rulesets.Osu.Edit
|
||||
{
|
||||
}
|
||||
|
||||
protected override Vector2 PlayfieldArea => Vector2.One;
|
||||
|
||||
protected override CursorContainer CreateCursor() => null;
|
||||
}
|
||||
protected override Playfield CreatePlayfield() => new OsuPlayfield { Size = Vector2.One };
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Edit;
|
||||
using osu.Game.Rulesets.Edit.Tools;
|
||||
@ -28,7 +29,7 @@ namespace osu.Game.Rulesets.Osu.Edit
|
||||
new HitCircleCompositionTool(),
|
||||
};
|
||||
|
||||
protected override ScalableContainer CreateLayerContainer() => new ScalableContainer(OsuPlayfield.BASE_SIZE.X) { RelativeSizeAxes = Axes.Both };
|
||||
protected override Container CreateLayerContainer() => new PlayfieldAdjustmentContainer { RelativeSizeAxes = Axes.Both };
|
||||
|
||||
public override SelectionMask CreateMaskFor(DrawableHitObject hitObject)
|
||||
{
|
||||
|
@ -37,6 +37,11 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
var osuObject = (OsuHitObject)drawable.HitObject;
|
||||
Vector2 origin = drawable.Position;
|
||||
|
||||
// Wiggle the repeat points with the slider instead of independently.
|
||||
// Also fixes an issue with repeat points being positioned incorrectly.
|
||||
if (osuObject is RepeatPoint)
|
||||
return;
|
||||
|
||||
Random objRand = new Random((int)osuObject.StartTime);
|
||||
|
||||
// Wiggle all objects during TimePreempt
|
||||
|
@ -8,26 +8,23 @@ using osu.Framework.Configuration;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Lines;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using OpenTK.Graphics.ES30;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Graphics.Primitives;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using OpenTK;
|
||||
using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
{
|
||||
public class SliderBody : Container, ISliderProgress
|
||||
{
|
||||
private readonly Path path;
|
||||
private readonly SliderPath path;
|
||||
private readonly BufferedContainer container;
|
||||
|
||||
public float PathWidth
|
||||
{
|
||||
get { return path.PathWidth; }
|
||||
set { path.PathWidth = value; }
|
||||
get => path.PathWidth;
|
||||
set => path.PathWidth = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -43,48 +40,40 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
public double? SnakedStart { get; private set; }
|
||||
public double? SnakedEnd { get; private set; }
|
||||
|
||||
private Color4 accentColour = Color4.White;
|
||||
|
||||
/// <summary>
|
||||
/// Used to colour the path.
|
||||
/// </summary>
|
||||
public Color4 AccentColour
|
||||
{
|
||||
get { return accentColour; }
|
||||
get => path.AccentColour;
|
||||
set
|
||||
{
|
||||
if (accentColour == value)
|
||||
if (path.AccentColour == value)
|
||||
return;
|
||||
accentColour = value;
|
||||
path.AccentColour = value;
|
||||
|
||||
if (LoadState >= LoadState.Ready)
|
||||
reloadTexture();
|
||||
container.ForceRedraw();
|
||||
}
|
||||
}
|
||||
|
||||
private Color4 borderColour = Color4.White;
|
||||
|
||||
/// <summary>
|
||||
/// Used to colour the path border.
|
||||
/// </summary>
|
||||
public new Color4 BorderColour
|
||||
{
|
||||
get { return borderColour; }
|
||||
get => path.BorderColour;
|
||||
set
|
||||
{
|
||||
if (borderColour == value)
|
||||
if (path.BorderColour == value)
|
||||
return;
|
||||
borderColour = value;
|
||||
path.BorderColour = value;
|
||||
|
||||
if (LoadState >= LoadState.Ready)
|
||||
reloadTexture();
|
||||
container.ForceRedraw();
|
||||
}
|
||||
}
|
||||
|
||||
public Quad PathDrawQuad => container.ScreenSpaceDrawQuad;
|
||||
|
||||
private int textureWidth => (int)PathWidth * 2;
|
||||
|
||||
private Vector2 topLeftOffset;
|
||||
|
||||
private readonly Slider slider;
|
||||
@ -101,7 +90,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
CacheDrawnFrameBuffer = true,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
path = new Path
|
||||
path = new SliderPath
|
||||
{
|
||||
Blending = BlendingMode.None,
|
||||
},
|
||||
@ -134,46 +123,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
reloadTexture();
|
||||
computeSize();
|
||||
}
|
||||
|
||||
private void reloadTexture()
|
||||
{
|
||||
var texture = new Texture(textureWidth, 1);
|
||||
|
||||
//initialise background
|
||||
var raw = new Image<Rgba32>(textureWidth, 1);
|
||||
|
||||
const float aa_portion = 0.02f;
|
||||
const float border_portion = 0.128f;
|
||||
const float gradient_portion = 1 - border_portion;
|
||||
|
||||
const float opacity_at_centre = 0.3f;
|
||||
const float opacity_at_edge = 0.8f;
|
||||
|
||||
for (int i = 0; i < textureWidth; i++)
|
||||
{
|
||||
float progress = (float)i / (textureWidth - 1);
|
||||
|
||||
if (progress <= border_portion)
|
||||
{
|
||||
raw[i, 0] = new Rgba32(BorderColour.R, BorderColour.G, BorderColour.B, Math.Min(progress / aa_portion, 1) * BorderColour.A);
|
||||
}
|
||||
else
|
||||
{
|
||||
progress -= border_portion;
|
||||
raw[i, 0] = new Rgba32(AccentColour.R, AccentColour.G, AccentColour.B,
|
||||
(opacity_at_edge - (opacity_at_edge - opacity_at_centre) * progress / gradient_portion) * AccentColour.A);
|
||||
}
|
||||
}
|
||||
|
||||
texture.SetData(new TextureUpload(raw));
|
||||
path.Texture = texture;
|
||||
|
||||
container.ForceRedraw();
|
||||
}
|
||||
|
||||
private void computeSize()
|
||||
{
|
||||
// Generate the entire curve
|
||||
@ -226,5 +178,53 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
|
||||
SetRange(start, end);
|
||||
}
|
||||
|
||||
private class SliderPath : SmoothPath
|
||||
{
|
||||
private const float border_portion = 0.128f;
|
||||
private const float gradient_portion = 1 - border_portion;
|
||||
|
||||
private const float opacity_at_centre = 0.3f;
|
||||
private const float opacity_at_edge = 0.8f;
|
||||
|
||||
private Color4 borderColour = Color4.White;
|
||||
|
||||
public Color4 BorderColour
|
||||
{
|
||||
get => borderColour;
|
||||
set
|
||||
{
|
||||
if (borderColour == value)
|
||||
return;
|
||||
borderColour = value;
|
||||
|
||||
InvalidateTexture();
|
||||
}
|
||||
}
|
||||
|
||||
private Color4 accentColour = Color4.White;
|
||||
|
||||
public Color4 AccentColour
|
||||
{
|
||||
get => accentColour;
|
||||
set
|
||||
{
|
||||
if (accentColour == value)
|
||||
return;
|
||||
accentColour = value;
|
||||
|
||||
InvalidateTexture();
|
||||
}
|
||||
}
|
||||
|
||||
protected override Color4 ColourAt(float position)
|
||||
{
|
||||
if (position <= border_portion)
|
||||
return BorderColour;
|
||||
|
||||
position -= border_portion;
|
||||
return new Color4(AccentColour.R, AccentColour.G, AccentColour.B, (opacity_at_edge - (opacity_at_edge - opacity_at_centre) * position / gradient_portion) * AccentColour.A);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -45,10 +45,10 @@ namespace osu.Game.Rulesets.Osu
|
||||
|
||||
public enum OsuAction
|
||||
{
|
||||
[Description("Left Button")]
|
||||
[Description("Left button")]
|
||||
LeftButton,
|
||||
|
||||
[Description("Right Button")]
|
||||
[Description("Right button")]
|
||||
RightButton
|
||||
}
|
||||
}
|
||||
|
@ -23,29 +23,35 @@ namespace osu.Game.Rulesets.Osu.UI
|
||||
public static readonly Vector2 BASE_SIZE = new Vector2(512, 384);
|
||||
|
||||
public OsuPlayfield()
|
||||
: base(BASE_SIZE.X)
|
||||
{
|
||||
Anchor = Anchor.Centre;
|
||||
Origin = Anchor.Centre;
|
||||
|
||||
AddRange(new Drawable[]
|
||||
Size = new Vector2(0.75f);
|
||||
|
||||
InternalChild = new PlayfieldAdjustmentContainer
|
||||
{
|
||||
connectionLayer = new FollowPointRenderer
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Depth = 2,
|
||||
},
|
||||
judgementLayer = new JudgementContainer<DrawableOsuJudgement>
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Depth = 1,
|
||||
},
|
||||
approachCircles = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Depth = -1,
|
||||
},
|
||||
});
|
||||
connectionLayer = new FollowPointRenderer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Depth = 2,
|
||||
},
|
||||
judgementLayer = new JudgementContainer<DrawableOsuJudgement>
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Depth = 1,
|
||||
},
|
||||
HitObjectContainer,
|
||||
approachCircles = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Depth = -1,
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public override void Add(DrawableHitObject h)
|
||||
|
@ -4,7 +4,6 @@
|
||||
using System.Linq;
|
||||
using osu.Framework.Graphics.Cursor;
|
||||
using osu.Framework.Input;
|
||||
using OpenTK;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Input.Handlers;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
@ -58,12 +57,6 @@ namespace osu.Game.Rulesets.Osu.UI
|
||||
}
|
||||
}
|
||||
|
||||
protected override Vector2 GetAspectAdjustedSize()
|
||||
{
|
||||
var aspectSize = DrawSize.X * 0.75f < DrawSize.Y ? new Vector2(DrawSize.X, DrawSize.X * 0.75f) : new Vector2(DrawSize.Y * 4f / 3f, DrawSize.Y);
|
||||
return new Vector2(aspectSize.X / DrawSize.X, aspectSize.Y / DrawSize.Y);
|
||||
}
|
||||
|
||||
protected override CursorContainer CreateCursor() => new GameplayCursor();
|
||||
}
|
||||
}
|
||||
|
42
osu.Game.Rulesets.Osu/UI/PlayfieldAdjustmentContainer.cs
Normal file
42
osu.Game.Rulesets.Osu/UI/PlayfieldAdjustmentContainer.cs
Normal file
@ -0,0 +1,42 @@
|
||||
// Copyright (c) 2007-2018 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 OpenTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.UI
|
||||
{
|
||||
public class PlayfieldAdjustmentContainer : Container
|
||||
{
|
||||
protected override Container<Drawable> Content => content;
|
||||
private readonly Container content;
|
||||
|
||||
public PlayfieldAdjustmentContainer()
|
||||
{
|
||||
InternalChild = new Container
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
FillMode = FillMode.Fit,
|
||||
FillAspectRatio = 4f / 3,
|
||||
Child = content = new ScalingContainer { RelativeSizeAxes = Axes.Both }
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A <see cref="Container"/> which scales its content relative to a target width.
|
||||
/// </summary>
|
||||
private class ScalingContainer : Container
|
||||
{
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
Scale = new Vector2(Parent.ChildSize.X / OsuPlayfield.BASE_SIZE.X);
|
||||
Size = Vector2.Divide(Vector2.One, Scale);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -2,9 +2,10 @@
|
||||
<Import Project="..\osu.TestProject.props" />
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.8.0" />
|
||||
<PackageReference Include="NUnit" Version="3.10.1" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
|
||||
<PackageReference Include="NUnit" Version="3.11.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.10.0" />
|
||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Project">
|
||||
<OutputType>WinExe</OutputType>
|
||||
|
@ -17,13 +17,13 @@ namespace osu.Game.Rulesets.Taiko
|
||||
|
||||
public enum TaikoAction
|
||||
{
|
||||
[Description("Left (Rim)")]
|
||||
[Description("Left (rim)")]
|
||||
LeftRim,
|
||||
[Description("Left (Centre)")]
|
||||
[Description("Left (centre)")]
|
||||
LeftCentre,
|
||||
[Description("Right (Centre)")]
|
||||
[Description("Right (centre)")]
|
||||
RightCentre,
|
||||
[Description("Right (Rim)")]
|
||||
[Description("Right (rim)")]
|
||||
RightRim
|
||||
}
|
||||
}
|
||||
|
22
osu.Game.Rulesets.Taiko/UI/PlayfieldAdjustmentContainer.cs
Normal file
22
osu.Game.Rulesets.Taiko/UI/PlayfieldAdjustmentContainer.cs
Normal file
@ -0,0 +1,22 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using OpenTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.UI
|
||||
{
|
||||
public class PlayfieldAdjustmentContainer : Container
|
||||
{
|
||||
private const float default_relative_height = TaikoPlayfield.DEFAULT_HEIGHT / 768;
|
||||
private const float default_aspect = 16f / 9f;
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
float aspectAdjust = MathHelper.Clamp(Parent.ChildSize.X / Parent.ChildSize.Y, 0.4f, 4) / default_aspect;
|
||||
Size = new Vector2(1, default_relative_height * aspectAdjust);
|
||||
}
|
||||
}
|
||||
}
|
@ -47,9 +47,6 @@ namespace osu.Game.Rulesets.Taiko.UI
|
||||
private readonly Container<KiaiHitExplosion> kiaiExplosionContainer;
|
||||
private readonly JudgementContainer<DrawableTaikoJudgement> judgementContainer;
|
||||
|
||||
protected override Container<Drawable> Content => content;
|
||||
private readonly Container content;
|
||||
|
||||
private readonly Container topLevelHitContainer;
|
||||
|
||||
private readonly Container barlineContainer;
|
||||
@ -64,140 +61,147 @@ namespace osu.Game.Rulesets.Taiko.UI
|
||||
{
|
||||
Direction.Value = ScrollingDirection.Left;
|
||||
|
||||
AddRangeInternal(new Drawable[]
|
||||
InternalChild = new PlayfieldAdjustmentContainer
|
||||
{
|
||||
backgroundContainer = new Container
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
Name = "Transparent playfield background",
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Masking = true,
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
backgroundContainer = new Container
|
||||
{
|
||||
Type = EdgeEffectType.Shadow,
|
||||
Colour = Color4.Black.Opacity(0.2f),
|
||||
Radius = 5,
|
||||
},
|
||||
Children = new Drawable[]
|
||||
{
|
||||
background = new Box
|
||||
Name = "Transparent playfield background",
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Masking = true,
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = 0.6f
|
||||
Type = EdgeEffectType.Shadow,
|
||||
Colour = Color4.Black.Opacity(0.2f),
|
||||
Radius = 5,
|
||||
},
|
||||
}
|
||||
},
|
||||
new Container
|
||||
{
|
||||
Name = "Right area",
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding { Left = left_area_size },
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Container
|
||||
Children = new Drawable[]
|
||||
{
|
||||
Name = "Masked elements before hit objects",
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding { Left = HIT_TARGET_OFFSET },
|
||||
Masking = true,
|
||||
Children = new Drawable[]
|
||||
background = new Box
|
||||
{
|
||||
hitExplosionContainer = new Container<HitExplosion>
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
FillMode = FillMode.Fit,
|
||||
Blending = BlendingMode.Additive,
|
||||
},
|
||||
new HitTarget
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
FillMode = FillMode.Fit
|
||||
}
|
||||
}
|
||||
},
|
||||
barlineContainer = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding { Left = HIT_TARGET_OFFSET }
|
||||
},
|
||||
content = new Container
|
||||
{
|
||||
Name = "Hit objects",
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding { Left = HIT_TARGET_OFFSET },
|
||||
Masking = true
|
||||
},
|
||||
kiaiExplosionContainer = new Container<KiaiHitExplosion>
|
||||
{
|
||||
Name = "Kiai hit explosions",
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
FillMode = FillMode.Fit,
|
||||
Margin = new MarginPadding { Left = HIT_TARGET_OFFSET },
|
||||
Blending = BlendingMode.Additive
|
||||
},
|
||||
judgementContainer = new JudgementContainer<DrawableTaikoJudgement>
|
||||
{
|
||||
Name = "Judgements",
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Margin = new MarginPadding { Left = HIT_TARGET_OFFSET },
|
||||
Blending = BlendingMode.Additive
|
||||
},
|
||||
}
|
||||
},
|
||||
overlayBackgroundContainer = new Container
|
||||
{
|
||||
Name = "Left overlay",
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Size = new Vector2(left_area_size, 1),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
overlayBackground = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
new InputDrum(controlPoints)
|
||||
{
|
||||
Anchor = Anchor.CentreRight,
|
||||
Origin = Anchor.CentreRight,
|
||||
Scale = new Vector2(0.9f),
|
||||
Margin = new MarginPadding { Right = 20 }
|
||||
},
|
||||
new Box
|
||||
{
|
||||
Anchor = Anchor.TopRight,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Width = 10,
|
||||
Colour = Framework.Graphics.Colour.ColourInfo.GradientHorizontal(Color4.Black.Opacity(0.6f), Color4.Black.Opacity(0)),
|
||||
},
|
||||
}
|
||||
},
|
||||
new Container
|
||||
{
|
||||
Name = "Border",
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Masking = true,
|
||||
MaskingSmoothness = 0,
|
||||
BorderThickness = 2,
|
||||
AlwaysPresent = true,
|
||||
Children = new[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = 0,
|
||||
AlwaysPresent = true
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = 0.6f
|
||||
},
|
||||
}
|
||||
},
|
||||
new Container
|
||||
{
|
||||
Name = "Right area",
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding { Left = left_area_size },
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Container
|
||||
{
|
||||
Name = "Masked elements before hit objects",
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding { Left = HIT_TARGET_OFFSET },
|
||||
Masking = true,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
hitExplosionContainer = new Container<HitExplosion>
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
FillMode = FillMode.Fit,
|
||||
Blending = BlendingMode.Additive,
|
||||
},
|
||||
new HitTarget
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
FillMode = FillMode.Fit
|
||||
}
|
||||
}
|
||||
},
|
||||
barlineContainer = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding { Left = HIT_TARGET_OFFSET }
|
||||
},
|
||||
new Container
|
||||
{
|
||||
Name = "Hit objects",
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding { Left = HIT_TARGET_OFFSET },
|
||||
Masking = true,
|
||||
Child = HitObjectContainer
|
||||
},
|
||||
kiaiExplosionContainer = new Container<KiaiHitExplosion>
|
||||
{
|
||||
Name = "Kiai hit explosions",
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
FillMode = FillMode.Fit,
|
||||
Margin = new MarginPadding { Left = HIT_TARGET_OFFSET },
|
||||
Blending = BlendingMode.Additive
|
||||
},
|
||||
judgementContainer = new JudgementContainer<DrawableTaikoJudgement>
|
||||
{
|
||||
Name = "Judgements",
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Margin = new MarginPadding { Left = HIT_TARGET_OFFSET },
|
||||
Blending = BlendingMode.Additive
|
||||
},
|
||||
}
|
||||
},
|
||||
overlayBackgroundContainer = new Container
|
||||
{
|
||||
Name = "Left overlay",
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Size = new Vector2(left_area_size, 1),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
overlayBackground = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
new InputDrum(controlPoints)
|
||||
{
|
||||
Anchor = Anchor.CentreRight,
|
||||
Origin = Anchor.CentreRight,
|
||||
Scale = new Vector2(0.9f),
|
||||
Margin = new MarginPadding { Right = 20 }
|
||||
},
|
||||
new Box
|
||||
{
|
||||
Anchor = Anchor.TopRight,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Width = 10,
|
||||
Colour = Framework.Graphics.Colour.ColourInfo.GradientHorizontal(Color4.Black.Opacity(0.6f), Color4.Black.Opacity(0)),
|
||||
},
|
||||
}
|
||||
},
|
||||
new Container
|
||||
{
|
||||
Name = "Border",
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Masking = true,
|
||||
MaskingSmoothness = 0,
|
||||
BorderThickness = 2,
|
||||
AlwaysPresent = true,
|
||||
Children = new[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = 0,
|
||||
AlwaysPresent = true
|
||||
}
|
||||
}
|
||||
},
|
||||
topLevelHitContainer = new Container
|
||||
{
|
||||
Name = "Top level hit objects",
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
}
|
||||
},
|
||||
topLevelHitContainer = new Container
|
||||
{
|
||||
Name = "Top level hit objects",
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
VisibleTimeRange.Value = 6000;
|
||||
VisibleTimeRange.Value = 7000;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
|
@ -2,7 +2,6 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
@ -13,7 +12,6 @@ using osu.Game.Rulesets.Taiko.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Taiko.Scoring;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osu.Game.Rulesets.Taiko.Replays;
|
||||
using OpenTK;
|
||||
using System.Linq;
|
||||
using osu.Framework.Input;
|
||||
using osu.Game.Input.Handlers;
|
||||
@ -74,27 +72,11 @@ namespace osu.Game.Rulesets.Taiko.UI
|
||||
}
|
||||
}
|
||||
|
||||
protected override Vector2 GetAspectAdjustedSize()
|
||||
{
|
||||
const float default_relative_height = TaikoPlayfield.DEFAULT_HEIGHT / 768;
|
||||
const float default_aspect = 16f / 9f;
|
||||
|
||||
float aspectAdjust = MathHelper.Clamp(DrawWidth / DrawHeight, 0.4f, 4) / default_aspect;
|
||||
|
||||
return new Vector2(1, default_relative_height * aspectAdjust);
|
||||
}
|
||||
|
||||
protected override Vector2 PlayfieldArea => Vector2.One;
|
||||
|
||||
public override ScoreProcessor CreateScoreProcessor() => new TaikoScoreProcessor(this);
|
||||
|
||||
public override PassThroughInputManager CreateInputManager() => new TaikoInputManager(Ruleset.RulesetInfo);
|
||||
|
||||
protected override Playfield CreatePlayfield() => new TaikoPlayfield(Beatmap.ControlPointInfo)
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft
|
||||
};
|
||||
protected override Playfield CreatePlayfield() => new TaikoPlayfield(Beatmap.ControlPointInfo);
|
||||
|
||||
public override DrawableHitObject<TaikoHitObject> GetVisualRepresentation(TaikoHitObject h)
|
||||
{
|
||||
|
@ -165,7 +165,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDecodeBeatmapColors()
|
||||
public void TestDecodeBeatmapColours()
|
||||
{
|
||||
var decoder = new LegacySkinDecoder();
|
||||
using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
|
||||
@ -181,6 +181,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
new Color4(128, 255, 128, 255),
|
||||
new Color4(255, 187, 255, 255),
|
||||
new Color4(255, 177, 140, 255),
|
||||
new Color4(100, 100, 100, 100),
|
||||
};
|
||||
Assert.AreEqual(expectedColors.Length, comboColors.Count);
|
||||
for (int i = 0; i < expectedColors.Length; i++)
|
||||
|
@ -101,6 +101,7 @@ Combo3 : 128,255,255
|
||||
Combo4 : 128,255,128
|
||||
Combo5 : 255,187,255
|
||||
Combo6 : 255,177,140
|
||||
Combo7 : 100,100,100,100
|
||||
|
||||
[HitObjects]
|
||||
192,168,956,6,0,P|184:128|200:80,1,90,4|0,1:2|0:0,0:0:0:0:
|
||||
|
@ -121,14 +121,21 @@ namespace osu.Game.Tests.Visual
|
||||
Direction = direction;
|
||||
|
||||
Padding = new MarginPadding(2);
|
||||
Content.Masking = true;
|
||||
|
||||
AddInternal(new Box
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = 0.5f,
|
||||
Depth = float.MaxValue
|
||||
});
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = 0.5f,
|
||||
},
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Masking = true,
|
||||
Child = HitObjectContainer
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,9 +2,11 @@
|
||||
<Import Project="..\osu.TestProject.props" />
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.8.0" />
|
||||
<PackageReference Include="NUnit" Version="3.10.1" />
|
||||
<PackageReference Include="DeepEqual" Version="1.6.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
|
||||
<PackageReference Include="NUnit" Version="3.11.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.10.0" />
|
||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Project">
|
||||
<OutputType>WinExe</OutputType>
|
||||
|
@ -16,7 +16,7 @@ namespace osu.Game.Beatmaps.ControlPoints
|
||||
/// <summary>
|
||||
/// The beat length at this control point.
|
||||
/// </summary>
|
||||
public double BeatLength
|
||||
public virtual double BeatLength
|
||||
{
|
||||
get => beatLength;
|
||||
set => beatLength = MathHelper.Clamp(value, 6, 60000);
|
||||
|
@ -318,12 +318,12 @@ namespace osu.Game.Beatmaps.Formats
|
||||
|
||||
if (timingChange)
|
||||
{
|
||||
handleTimingControlPoint(new TimingControlPoint
|
||||
{
|
||||
Time = time,
|
||||
BeatLength = beatLength,
|
||||
TimeSignature = timeSignature
|
||||
});
|
||||
var controlPoint = CreateTimingControlPoint();
|
||||
controlPoint.Time = time;
|
||||
controlPoint.BeatLength = beatLength;
|
||||
controlPoint.TimeSignature = timeSignature;
|
||||
|
||||
handleTimingControlPoint(controlPoint);
|
||||
}
|
||||
|
||||
handleDifficultyControlPoint(new DifficultyControlPoint
|
||||
@ -418,6 +418,8 @@ namespace osu.Game.Beatmaps.Formats
|
||||
|
||||
private double getOffsetTime(double time) => time + (ApplyOffsets ? offset : 0);
|
||||
|
||||
protected virtual TimingControlPoint CreateTimingControlPoint() => new TimingControlPoint();
|
||||
|
||||
[Flags]
|
||||
internal enum EffectFlags
|
||||
{
|
||||
|
@ -85,13 +85,19 @@ namespace osu.Game.Beatmaps.Formats
|
||||
|
||||
string[] split = pair.Value.Split(',');
|
||||
|
||||
if (split.Length != 3)
|
||||
throw new InvalidOperationException($@"Color specified in incorrect format (should be R,G,B): {pair.Value}");
|
||||
if (split.Length != 3 && split.Length != 4)
|
||||
throw new InvalidOperationException($@"Color specified in incorrect format (should be R,G,B or R,G,B,A): {pair.Value}");
|
||||
|
||||
if (!byte.TryParse(split[0], out var r) || !byte.TryParse(split[1], out var g) || !byte.TryParse(split[2], out var b))
|
||||
Color4 colour;
|
||||
|
||||
try
|
||||
{
|
||||
colour = new Color4(byte.Parse(split[0]), byte.Parse(split[1]), byte.Parse(split[2]), split.Length == 4 ? byte.Parse(split[3]) : (byte)255);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new InvalidOperationException(@"Color must be specified with 8-bit integer components");
|
||||
|
||||
Color4 colour = new Color4(r, g, b, 255);
|
||||
}
|
||||
|
||||
if (isCombo)
|
||||
{
|
||||
|
@ -0,0 +1,37 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System.Linq;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
|
||||
namespace osu.Game.Beatmaps.Formats
|
||||
{
|
||||
/// <summary>
|
||||
/// A <see cref="LegacyBeatmapDecoder"/> built for difficulty calculation of legacy <see cref="Beatmap"/>s
|
||||
/// <remarks>
|
||||
/// To use this, the decoder must be registered by the application through <see cref="LegacyDifficultyCalculatorBeatmapDecoder.Register"/>.
|
||||
/// Doing so will override any existing <see cref="Beatmap"/> decoders.
|
||||
/// </remarks>
|
||||
/// </summary>
|
||||
public class LegacyDifficultyCalculatorBeatmapDecoder : LegacyBeatmapDecoder
|
||||
{
|
||||
public LegacyDifficultyCalculatorBeatmapDecoder(int version = LATEST_VERSION)
|
||||
: base(version)
|
||||
{
|
||||
ApplyOffsets = false;
|
||||
}
|
||||
|
||||
public new static void Register()
|
||||
{
|
||||
AddDecoder<Beatmap>(@"osu file format v", m => new LegacyDifficultyCalculatorBeatmapDecoder(int.Parse(m.Split('v').Last())));
|
||||
}
|
||||
|
||||
protected override TimingControlPoint CreateTimingControlPoint()
|
||||
=> new LegacyDifficultyCalculatorControlPoint();
|
||||
|
||||
private class LegacyDifficultyCalculatorControlPoint : TimingControlPoint
|
||||
{
|
||||
public override double BeatLength { get; set; } = 1000;
|
||||
}
|
||||
}
|
||||
}
|
@ -69,7 +69,7 @@ namespace osu.Game.Graphics.UserInterface
|
||||
{
|
||||
Masking = true,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Child = path = new Path { RelativeSizeAxes = Axes.Both, PathWidth = 1 }
|
||||
Child = path = new SmoothPath { RelativeSizeAxes = Axes.Both, PathWidth = 1 }
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -51,6 +51,8 @@ namespace osu.Game.Graphics.UserInterface
|
||||
#region OsuDropdownMenu
|
||||
protected class OsuDropdownMenu : DropdownMenu, IHasAccentColour
|
||||
{
|
||||
public override bool HandleNonPositionalInput => State == MenuState.Open;
|
||||
|
||||
// todo: this uses the same styling as OsuMenu. hopefully we can just use OsuMenu in the future with some refactoring
|
||||
public OsuDropdownMenu()
|
||||
{
|
||||
|
@ -71,17 +71,17 @@ namespace osu.Game.Input.Bindings
|
||||
ToggleSettings,
|
||||
[Description("Toggle osu!direct")]
|
||||
ToggleDirect,
|
||||
[Description("Increase Volume")]
|
||||
[Description("Increase volume")]
|
||||
IncreaseVolume,
|
||||
[Description("Decrease Volume")]
|
||||
[Description("Decrease volume")]
|
||||
DecreaseVolume,
|
||||
[Description("Toggle mute")]
|
||||
ToggleMute,
|
||||
|
||||
// In-Game Keybindings
|
||||
[Description("Skip Cutscene")]
|
||||
[Description("Skip cutscene")]
|
||||
SkipCutscene,
|
||||
[Description("Quick Retry (Hold)")]
|
||||
[Description("Quick retry (hold)")]
|
||||
QuickRetry,
|
||||
|
||||
[Description("Take screenshot")]
|
||||
|
@ -65,7 +65,8 @@ namespace osu.Game
|
||||
|
||||
private BeatmapSetOverlay beatmapSetOverlay;
|
||||
|
||||
private ScreenshotManager screenshotManager;
|
||||
[Cached]
|
||||
private readonly ScreenshotManager screenshotManager = new ScreenshotManager();
|
||||
|
||||
protected RavenLogger RavenLogger;
|
||||
|
||||
@ -289,9 +290,6 @@ namespace osu.Game
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
// this needs to be cached before base.LoadComplete as it is used by MenuCursorContainer.
|
||||
dependencies.Cache(screenshotManager = new ScreenshotManager());
|
||||
|
||||
base.LoadComplete();
|
||||
|
||||
// The next time this is updated is in UpdateAfterChildren, which occurs too late and results
|
||||
|
@ -291,7 +291,7 @@ namespace osu.Game.Overlays
|
||||
messageRequest?.Cancel();
|
||||
|
||||
ListChannelsRequest req = new ListChannelsRequest();
|
||||
req.Success += delegate (List<Channel> channels)
|
||||
req.Success += delegate(List<Channel> channels)
|
||||
{
|
||||
AvailableChannels = channels;
|
||||
|
||||
@ -323,10 +323,7 @@ namespace osu.Game.Overlays
|
||||
|
||||
protected Channel CurrentChannel
|
||||
{
|
||||
get
|
||||
{
|
||||
return currentChannel;
|
||||
}
|
||||
get { return currentChannel; }
|
||||
|
||||
set
|
||||
{
|
||||
@ -445,13 +442,7 @@ namespace osu.Game.Overlays
|
||||
if (updates?.Presence != null)
|
||||
{
|
||||
foreach (var channel in updates.Presence)
|
||||
{
|
||||
if (careChannels.Find(c => c.Id == channel.Id) == null)
|
||||
{
|
||||
channel.Joined.Value = true;
|
||||
addChannel(channel);
|
||||
}
|
||||
}
|
||||
addChannel(AvailableChannels.Find(c => c.Id == channel.Id));
|
||||
|
||||
foreach (var group in updates.Messages.GroupBy(m => m.ChannelId))
|
||||
careChannels.Find(c => c.Id == group.Key)?.AddNewMessages(group.ToArray());
|
||||
@ -462,10 +453,7 @@ namespace osu.Game.Overlays
|
||||
fetchReq = null;
|
||||
};
|
||||
|
||||
fetchReq.Failure += delegate
|
||||
{
|
||||
fetchReq = null;
|
||||
};
|
||||
fetchReq.Failure += delegate { fetchReq = null; };
|
||||
|
||||
api.Queue(fetchReq);
|
||||
}
|
||||
|
@ -196,10 +196,16 @@ namespace osu.Game.Overlays
|
||||
playlist.StateChanged += s => playlistButton.FadeColour(s == Visibility.Visible ? colours.Yellow : Color4.White, 200, Easing.OutQuint);
|
||||
}
|
||||
|
||||
private ScheduledDelegate seekDelegate;
|
||||
|
||||
private void attemptSeek(double progress)
|
||||
{
|
||||
if (!beatmap.Disabled)
|
||||
current?.Track.Seek(progress);
|
||||
seekDelegate?.Cancel();
|
||||
seekDelegate = Schedule(() =>
|
||||
{
|
||||
if (!beatmap.Disabled)
|
||||
current?.Track.Seek(progress);
|
||||
});
|
||||
}
|
||||
|
||||
private void playlistOrderChanged(BeatmapSetInfo beatmapSetInfo, int index)
|
||||
|
@ -386,10 +386,13 @@ namespace osu.Game.Overlays.Profile
|
||||
infoTextLeft.AddText(new DrawableJoinDate(user.JoinDate), boldItalic);
|
||||
}
|
||||
|
||||
infoTextLeft.NewLine();
|
||||
infoTextLeft.AddText("Last seen ", lightText);
|
||||
infoTextLeft.AddText(new DrawableDate(user.LastVisit), boldItalic);
|
||||
infoTextLeft.NewParagraph();
|
||||
if (user.LastVisit.HasValue)
|
||||
{
|
||||
infoTextLeft.NewLine();
|
||||
infoTextLeft.AddText("Last seen ", lightText);
|
||||
infoTextLeft.AddText(new DrawableDate(user.LastVisit.Value), boldItalic);
|
||||
infoTextLeft.NewParagraph();
|
||||
}
|
||||
|
||||
if (user.PlayStyle?.Length > 0)
|
||||
{
|
||||
|
@ -19,7 +19,7 @@ namespace osu.Game.Overlays.Settings.Sections.Audio
|
||||
{
|
||||
new SettingsSlider<double, OffsetSlider>
|
||||
{
|
||||
LabelText = "Audio Offset",
|
||||
LabelText = "Audio offset",
|
||||
Bindable = config.GetBindable<double>(OsuSetting.AudioOffset),
|
||||
KeyboardStep = 1f
|
||||
},
|
||||
|
@ -18,7 +18,7 @@ namespace osu.Game.Overlays.Settings.Sections.Audio
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new SettingsSlider<double> { LabelText = "Master", Bindable = audio.Volume, KeyboardStep = 0.01f },
|
||||
new SettingsSlider<double> { LabelText = "Master (Window Inactive)", Bindable = config.GetBindable<double>(OsuSetting.VolumeInactive), KeyboardStep = 0.01f },
|
||||
new SettingsSlider<double> { LabelText = "Master (window inactive)", Bindable = config.GetBindable<double>(OsuSetting.VolumeInactive), KeyboardStep = 0.01f },
|
||||
new SettingsSlider<double> { LabelText = "Effect", Bindable = audio.VolumeSample, KeyboardStep = 0.01f },
|
||||
new SettingsSlider<double> { LabelText = "Music", Bindable = audio.VolumeTrack, KeyboardStep = 0.01f },
|
||||
};
|
||||
|
@ -15,7 +15,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
||||
{
|
||||
new SettingsButton
|
||||
{
|
||||
Text = "Key Configuration",
|
||||
Text = "Key configuration",
|
||||
Action = keyConfig.ToggleVisibility
|
||||
},
|
||||
};
|
||||
|
@ -26,12 +26,12 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
||||
{
|
||||
new SettingsCheckbox
|
||||
{
|
||||
LabelText = "Raw Input",
|
||||
LabelText = "Raw input",
|
||||
Bindable = rawInputToggle
|
||||
},
|
||||
sensitivity = new SensitivitySetting
|
||||
{
|
||||
LabelText = "Cursor Sensitivity",
|
||||
LabelText = "Cursor sensitivity",
|
||||
Bindable = config.GetBindable<double>(FrameworkSetting.CursorSensitivity)
|
||||
},
|
||||
new SettingsCheckbox
|
||||
|
@ -105,6 +105,8 @@ namespace osu.Game.Overlays.Toolbar
|
||||
public override bool HandleNonPositionalInput => !ruleset.Disabled && base.HandleNonPositionalInput;
|
||||
public override bool HandlePositionalInput => !ruleset.Disabled && base.HandlePositionalInput;
|
||||
|
||||
public override bool PropagatePositionalInputSubTree => !ruleset.Disabled && base.PropagatePositionalInputSubTree;
|
||||
|
||||
private void disabledChanged(bool isDisabled) => this.FadeColour(isDisabled ? Color4.Gray : Color4.White, 300);
|
||||
|
||||
protected override void Update()
|
||||
|
@ -189,6 +189,6 @@ namespace osu.Game.Rulesets.Edit
|
||||
/// <summary>
|
||||
/// Creates a <see cref="ScalableContainer"/> which provides a layer above or below the <see cref="Playfield"/>.
|
||||
/// </summary>
|
||||
protected virtual ScalableContainer CreateLayerContainer() => new ScalableContainer { RelativeSizeAxes = Axes.Both };
|
||||
protected virtual Container CreateLayerContainer() => new Container { RelativeSizeAxes = Axes.Both };
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ namespace osu.Game.Rulesets.Mods
|
||||
{
|
||||
/// <summary>
|
||||
/// Applies this <see cref="IApplicableToDrawableHitObjects"/> to a list of <see cref="DrawableHitObject"/>s.
|
||||
/// This will only be invoked with top-level <see cref="DrawableHitObject"/>s. Access <see cref="DrawableHitObject.NestedHitObjects"/> if adjusting nested objects is necessary.
|
||||
/// </summary>
|
||||
/// <param name="drawables">The list of <see cref="DrawableHitObject"/>s to apply to.</param>
|
||||
void ApplyToDrawableHitObjects(IEnumerable<DrawableHitObject> drawables);
|
||||
|
@ -145,7 +145,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
||||
public event Action<DrawableHitObject, ArmedState> ApplyCustomUpdateState;
|
||||
|
||||
/// <summary>
|
||||
/// Plays all the hitsounds for this <see cref="DrawableHitObject"/>.
|
||||
/// Plays all the hit sounds for this <see cref="DrawableHitObject"/>.
|
||||
/// </summary>
|
||||
public void PlaySamples() => Samples?.Play();
|
||||
|
||||
|
@ -1,10 +1,8 @@
|
||||
// Copyright (c) 2007-2018 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 Newtonsoft.Json;
|
||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||
using osu.Framework.Lists;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Beatmaps;
|
||||
@ -58,10 +56,10 @@ namespace osu.Game.Rulesets.Objects
|
||||
/// </summary>
|
||||
public HitWindows HitWindows { get; set; }
|
||||
|
||||
private readonly Lazy<SortedList<HitObject>> nestedHitObjects = new Lazy<SortedList<HitObject>>(() => new SortedList<HitObject>((h1, h2) => h1.StartTime.CompareTo(h2.StartTime)));
|
||||
private readonly SortedList<HitObject> nestedHitObjects = new SortedList<HitObject>(compareObjects);
|
||||
|
||||
[JsonIgnore]
|
||||
public IReadOnlyList<HitObject> NestedHitObjects => nestedHitObjects.Value;
|
||||
public IReadOnlyList<HitObject> NestedHitObjects => nestedHitObjects;
|
||||
|
||||
/// <summary>
|
||||
/// Applies default values to this HitObject.
|
||||
@ -72,18 +70,14 @@ namespace osu.Game.Rulesets.Objects
|
||||
{
|
||||
ApplyDefaultsToSelf(controlPointInfo, difficulty);
|
||||
|
||||
if (nestedHitObjects.IsValueCreated)
|
||||
nestedHitObjects.Value.Clear();
|
||||
nestedHitObjects.Clear();
|
||||
|
||||
CreateNestedHitObjects();
|
||||
|
||||
if (nestedHitObjects.IsValueCreated)
|
||||
foreach (var h in nestedHitObjects)
|
||||
{
|
||||
nestedHitObjects.Value.ForEach(h =>
|
||||
{
|
||||
h.HitWindows = HitWindows;
|
||||
h.ApplyDefaults(controlPointInfo, difficulty);
|
||||
});
|
||||
h.HitWindows = HitWindows;
|
||||
h.ApplyDefaults(controlPointInfo, difficulty);
|
||||
}
|
||||
}
|
||||
|
||||
@ -104,7 +98,7 @@ namespace osu.Game.Rulesets.Objects
|
||||
{
|
||||
}
|
||||
|
||||
protected void AddNested(HitObject hitObject) => nestedHitObjects.Value.Add(hitObject);
|
||||
protected void AddNested(HitObject hitObject) => nestedHitObjects.Add(hitObject);
|
||||
|
||||
/// <summary>
|
||||
/// Creates the <see cref="Judgement"/> that represents the scoring information for this <see cref="HitObject"/>.
|
||||
@ -120,5 +114,7 @@ namespace osu.Game.Rulesets.Objects
|
||||
/// </para>
|
||||
/// </summary>
|
||||
protected virtual HitWindows CreateHitWindows() => new HitWindows();
|
||||
|
||||
private static int compareObjects(HitObject first, HitObject second) => first.StartTime.CompareTo(second.StartTime);
|
||||
}
|
||||
}
|
||||
|
@ -18,9 +18,14 @@ namespace osu.Game.Rulesets.Timing
|
||||
public double StartTime;
|
||||
|
||||
/// <summary>
|
||||
/// The multiplier which this <see cref="MultiplierControlPoint"/> provides.
|
||||
/// The aggregate multiplier which this <see cref="MultiplierControlPoint"/> provides.
|
||||
/// </summary>
|
||||
public double Multiplier => 1000 / TimingPoint.BeatLength * DifficultyPoint.SpeedMultiplier;
|
||||
public double Multiplier => Velocity * DifficultyPoint.SpeedMultiplier * 1000 / TimingPoint.BeatLength;
|
||||
|
||||
/// <summary>
|
||||
/// The velocity multiplier.
|
||||
/// </summary>
|
||||
public double Velocity = 1;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="TimingControlPoint"/> that provides the timing information for this <see cref="MultiplierControlPoint"/>.
|
||||
@ -48,18 +53,6 @@ namespace osu.Game.Rulesets.Timing
|
||||
StartTime = startTime;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a <see cref="MultiplierControlPoint"/> by copying another <see cref="MultiplierControlPoint"/>.
|
||||
/// </summary>
|
||||
/// <param name="startTime">The start time of this <see cref="MultiplierControlPoint"/>.</param>
|
||||
/// <param name="other">The <see cref="MultiplierControlPoint"/> to copy.</param>
|
||||
public MultiplierControlPoint(double startTime, MultiplierControlPoint other)
|
||||
: this(startTime)
|
||||
{
|
||||
TimingPoint = other.TimingPoint;
|
||||
DifficultyPoint = other.DifficultyPoint;
|
||||
}
|
||||
|
||||
// ReSharper disable once ImpureMethodCallOnReadonlyValueField
|
||||
public int CompareTo(MultiplierControlPoint other) => StartTime.CompareTo(other?.StartTime);
|
||||
}
|
||||
|
@ -14,6 +14,11 @@ namespace osu.Game.Rulesets.UI
|
||||
public IEnumerable<DrawableHitObject> Objects => InternalChildren.Cast<DrawableHitObject>().OrderBy(h => h.HitObject.StartTime);
|
||||
public IEnumerable<DrawableHitObject> AliveObjects => AliveInternalChildren.Cast<DrawableHitObject>().OrderBy(h => h.HitObject.StartTime);
|
||||
|
||||
public HitObjectContainer()
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
}
|
||||
|
||||
public virtual void Add(DrawableHitObject hitObject) => AddInternal(hitObject);
|
||||
public virtual bool Remove(DrawableHitObject hitObject) => RemoveInternal(hitObject);
|
||||
|
||||
|
@ -9,17 +9,26 @@ using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using OpenTK;
|
||||
|
||||
namespace osu.Game.Rulesets.UI
|
||||
{
|
||||
public abstract class Playfield : ScalableContainer
|
||||
public abstract class Playfield : CompositeDrawable
|
||||
{
|
||||
/// <summary>
|
||||
/// The <see cref="DrawableHitObject"/> contained in this Playfield.
|
||||
/// </summary>
|
||||
public HitObjectContainer HitObjectContainer { get; private set; }
|
||||
public HitObjectContainer HitObjectContainer => hitObjectContainerLazy.Value;
|
||||
|
||||
private readonly Lazy<HitObjectContainer> hitObjectContainerLazy;
|
||||
|
||||
/// <summary>
|
||||
/// A function that converts gamefield coordinates to screen space.
|
||||
/// </summary>
|
||||
public Func<Vector2, Vector2> GamefieldToScreenSpace => HitObjectContainer.ToScreenSpace;
|
||||
|
||||
/// <summary>
|
||||
/// All the <see cref="DrawableHitObject"/>s contained in this <see cref="Playfield"/> and all <see cref="NestedPlayfields"/>.
|
||||
@ -39,18 +48,13 @@ namespace osu.Game.Rulesets.UI
|
||||
public readonly BindableBool DisplayJudgements = new BindableBool(true);
|
||||
|
||||
/// <summary>
|
||||
/// A container for keeping track of DrawableHitObjects.
|
||||
/// Creates a new <see cref="Playfield"/>.
|
||||
/// </summary>
|
||||
/// <param name="customWidth">The width to scale the internal coordinate space to.
|
||||
/// May be null if scaling based on <paramref name="customHeight"/> is desired. If <paramref name="customHeight"/> is also null, no scaling will occur.
|
||||
/// </param>
|
||||
/// <param name="customHeight">The height to scale the internal coordinate space to.
|
||||
/// May be null if scaling based on <paramref name="customWidth"/> is desired. If <paramref name="customWidth"/> is also null, no scaling will occur.
|
||||
/// </param>
|
||||
protected Playfield(float? customWidth = null, float? customHeight = null)
|
||||
: base(customWidth, customHeight)
|
||||
protected Playfield()
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
|
||||
hitObjectContainerLazy = new Lazy<HitObjectContainer>(CreateHitObjectContainer);
|
||||
}
|
||||
|
||||
private WorkingBeatmap beatmap;
|
||||
@ -59,11 +63,6 @@ namespace osu.Game.Rulesets.UI
|
||||
private void load(IBindableBeatmap beatmap)
|
||||
{
|
||||
this.beatmap = beatmap.Value;
|
||||
|
||||
HitObjectContainer = CreateHitObjectContainer();
|
||||
HitObjectContainer.RelativeSizeAxes = Axes.Both;
|
||||
|
||||
Add(HitObjectContainer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -94,10 +93,14 @@ namespace osu.Game.Rulesets.UI
|
||||
nestedPlayfields.Value.Add(otherPlayfield);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the container that will be used to contain the <see cref="DrawableHitObject"/>s.
|
||||
/// </summary>
|
||||
protected virtual HitObjectContainer CreateHitObjectContainer() => new HitObjectContainer();
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
// in the case a consumer forgets to add the HitObjectContainer, we will add it here.
|
||||
if (HitObjectContainer.Parent == null)
|
||||
AddInternal(HitObjectContainer);
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
@ -108,5 +111,10 @@ namespace osu.Game.Rulesets.UI
|
||||
if (mod is IUpdatableByPlayfield updatable)
|
||||
updatable.Update(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the container that will be used to contain the <see cref="DrawableHitObject"/>s.
|
||||
/// </summary>
|
||||
protected virtual HitObjectContainer CreateHitObjectContainer() => new HitObjectContainer();
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,6 @@ using osu.Game.Overlays;
|
||||
using osu.Game.Rulesets.Configuration;
|
||||
using osu.Game.Rulesets.Replays;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using OpenTK;
|
||||
|
||||
namespace osu.Game.Rulesets.UI
|
||||
{
|
||||
@ -316,25 +315,6 @@ namespace osu.Game.Rulesets.UI
|
||||
Playfield.Add(drawableObject);
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
Playfield.Size = GetAspectAdjustedSize() * PlayfieldArea;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes the size of the <see cref="Playfield"/> in relative coordinate space after aspect adjustments.
|
||||
/// </summary>
|
||||
/// <returns>The aspect-adjusted size.</returns>
|
||||
protected virtual Vector2 GetAspectAdjustedSize() => Vector2.One;
|
||||
|
||||
/// <summary>
|
||||
/// The area of this <see cref="RulesetContainer"/> that is available for the <see cref="Playfield"/> to use.
|
||||
/// Must be specified in relative coordinate space to this <see cref="RulesetContainer"/>.
|
||||
/// This affects the final size of the <see cref="Playfield"/> but does not affect the <see cref="Playfield"/>'s scale.
|
||||
/// </summary>
|
||||
protected virtual Vector2 PlayfieldArea => new Vector2(0.75f); // A sane default
|
||||
|
||||
/// <summary>
|
||||
/// Creates a DrawableHitObject from a HitObject.
|
||||
|
@ -73,12 +73,10 @@ namespace osu.Game.Rulesets.UI
|
||||
#region IHasReplayHandler
|
||||
|
||||
private ReplayInputHandler replayInputHandler;
|
||||
|
||||
public ReplayInputHandler ReplayInputHandler
|
||||
{
|
||||
get
|
||||
{
|
||||
return replayInputHandler;
|
||||
}
|
||||
get => replayInputHandler;
|
||||
set
|
||||
{
|
||||
if (replayInputHandler != null) RemoveHandler(replayInputHandler);
|
||||
@ -208,16 +206,20 @@ namespace osu.Game.Rulesets.UI
|
||||
mouseDisabled = config.GetBindable<bool>(OsuSetting.MouseDisableButtons);
|
||||
}
|
||||
|
||||
protected override bool OnMouseDown(MouseDownEvent e)
|
||||
protected override bool Handle(UIEvent e)
|
||||
{
|
||||
if (mouseDisabled.Value && (e.Button == MouseButton.Left || e.Button == MouseButton.Right)) return false;
|
||||
return base.OnMouseDown(e);
|
||||
}
|
||||
|
||||
protected override bool OnMouseUp(MouseUpEvent e)
|
||||
{
|
||||
if (!CurrentState.Mouse.IsPressed(e.Button)) return false;
|
||||
return base.OnMouseUp(e);
|
||||
switch (e)
|
||||
{
|
||||
case MouseDownEvent mouseDown when mouseDown.Button == MouseButton.Left || mouseDown.Button == MouseButton.Right:
|
||||
if (mouseDisabled.Value)
|
||||
return false;
|
||||
break;
|
||||
case MouseUpEvent mouseUp:
|
||||
if (!CurrentState.Mouse.IsPressed(mouseUp.Button))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
return base.Handle(e);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@ -269,7 +271,7 @@ namespace osu.Game.Rulesets.UI
|
||||
}
|
||||
|
||||
public class RulesetInputManagerInputState<T> : InputState
|
||||
where T : struct
|
||||
where T : struct
|
||||
{
|
||||
public ReplayState<T> LastReplayState;
|
||||
|
||||
|
@ -1,99 +0,0 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using OpenTK;
|
||||
|
||||
namespace osu.Game.Rulesets.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// A <see cref="Container"/> which can have its internal coordinate system scaled to a specific size.
|
||||
/// </summary>
|
||||
public class ScalableContainer : Container
|
||||
{
|
||||
/// <summary>
|
||||
/// A function that converts coordinates from gamefield to screen space.
|
||||
/// </summary>
|
||||
public Func<Vector2, Vector2> GamefieldToScreenSpace => scaledContent.GamefieldToScreenSpace;
|
||||
|
||||
/// <summary>
|
||||
/// The scaled content.
|
||||
/// </summary>
|
||||
private readonly ScaledContainer scaledContent;
|
||||
protected override Container<Drawable> Content => scaledContent;
|
||||
|
||||
/// <summary>
|
||||
/// A <see cref="Container"/> which can have its internal coordinate system scaled to a specific size.
|
||||
/// </summary>
|
||||
/// <param name="customWidth">The width to scale the internal coordinate space to.
|
||||
/// May be null if scaling based on <paramref name="customHeight"/> is desired. If <paramref name="customHeight"/> is also null, no scaling will occur.
|
||||
/// </param>
|
||||
/// <param name="customHeight">The height to scale the internal coordinate space to.
|
||||
/// May be null if scaling based on <paramref name="customWidth"/> is desired. If <paramref name="customWidth"/> is also null, no scaling will occur.
|
||||
/// </param>
|
||||
public ScalableContainer(float? customWidth = null, float? customHeight = null)
|
||||
{
|
||||
AddInternal(scaledContent = new ScaledContainer
|
||||
{
|
||||
CustomWidth = customWidth,
|
||||
CustomHeight = customHeight,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
});
|
||||
}
|
||||
|
||||
private class ScaledContainer : Container
|
||||
{
|
||||
/// <summary>
|
||||
/// A function that converts coordinates from gamefield to screen space.
|
||||
/// </summary>
|
||||
public Func<Vector2, Vector2> GamefieldToScreenSpace => content.ToScreenSpace;
|
||||
|
||||
/// <summary>
|
||||
/// The value to scale the width of the content to match.
|
||||
/// If null, <see cref="CustomHeight"/> is used.
|
||||
/// </summary>
|
||||
public float? CustomWidth;
|
||||
|
||||
/// <summary>
|
||||
/// The value to scale the height of the content to match.
|
||||
/// if null, <see cref="CustomWidth"/> is used.
|
||||
/// </summary>
|
||||
public float? CustomHeight;
|
||||
|
||||
private readonly Container content;
|
||||
protected override Container<Drawable> Content => content;
|
||||
|
||||
public ScaledContainer()
|
||||
{
|
||||
AddInternal(content = new Container { RelativeSizeAxes = Axes.Both });
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
content.Scale = sizeScale;
|
||||
content.Size = Vector2.Divide(Vector2.One, sizeScale);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The scale that is required for the size of the content to match <see cref="CustomWidth"/> and <see cref="CustomHeight"/>.
|
||||
/// </summary>
|
||||
private Vector2 sizeScale
|
||||
{
|
||||
get
|
||||
{
|
||||
if (CustomWidth.HasValue && CustomHeight.HasValue)
|
||||
return Vector2.Divide(DrawSize, new Vector2(CustomWidth.Value, CustomHeight.Value));
|
||||
if (CustomWidth.HasValue)
|
||||
return new Vector2(DrawSize.X / CustomWidth.Value);
|
||||
if (CustomHeight.HasValue)
|
||||
return new Vector2(DrawSize.Y / CustomHeight.Value);
|
||||
return Vector2.One;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -6,19 +6,19 @@ namespace osu.Game.Rulesets.UI.Scrolling
|
||||
public enum ScrollingDirection
|
||||
{
|
||||
/// <summary>
|
||||
/// Hitobjects will scroll vertically from the bottom of the hitobject container.
|
||||
/// Hit objects will scroll vertically from the bottom of the hitobject container.
|
||||
/// </summary>
|
||||
Up,
|
||||
/// <summary>
|
||||
/// Hitobjects will scroll vertically from the top of the hitobject container.
|
||||
/// Hit objects will scroll vertically from the top of the hitobject container.
|
||||
/// </summary>
|
||||
Down,
|
||||
/// <summary>
|
||||
/// Hitobjects will scroll horizontally from the right of the hitobject container.
|
||||
/// Hit objects will scroll horizontally from the right of the hitobject container.
|
||||
/// </summary>
|
||||
Left,
|
||||
/// <summary>
|
||||
/// Hitobjects will scroll horizontally from the left of the hitobject container.
|
||||
/// Hit objects will scroll horizontally from the left of the hitobject container.
|
||||
/// </summary>
|
||||
Right
|
||||
}
|
||||
|
@ -65,20 +65,6 @@ namespace osu.Game.Rulesets.UI.Scrolling
|
||||
|
||||
protected virtual SpeedChangeVisualisationMethod VisualisationMethod => SpeedChangeVisualisationMethod.Sequential;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="ScrollingPlayfield"/>.
|
||||
/// </summary>
|
||||
/// <param name="customWidth">The width to scale the internal coordinate space to.
|
||||
/// May be null if scaling based on <paramref name="customHeight"/> is desired. If <paramref name="customHeight"/> is also null, no scaling will occur.
|
||||
/// </param>
|
||||
/// <param name="customHeight">The height to scale the internal coordinate space to.
|
||||
/// May be null if scaling based on <paramref name="customWidth"/> is desired. If <paramref name="customWidth"/> is also null, no scaling will occur.
|
||||
/// </param>
|
||||
protected ScrollingPlayfield(float? customWidth = null, float? customHeight = null)
|
||||
: base(customWidth, customHeight)
|
||||
{
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
|
@ -60,6 +60,7 @@ namespace osu.Game.Rulesets.UI.Scrolling
|
||||
|
||||
return new MultiplierControlPoint(c.Time)
|
||||
{
|
||||
Velocity = Beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier,
|
||||
TimingPoint = lastTimingPoint,
|
||||
DifficultyPoint = lastDifficultyPoint
|
||||
};
|
||||
@ -78,7 +79,7 @@ namespace osu.Game.Rulesets.UI.Scrolling
|
||||
|
||||
// If we have no control points, add a default one
|
||||
if (DefaultControlPoints.Count == 0)
|
||||
DefaultControlPoints.Add(new MultiplierControlPoint());
|
||||
DefaultControlPoints.Add(new MultiplierControlPoint { Velocity = Beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier });
|
||||
|
||||
DefaultControlPoints.ForEach(c => applySpeedAdjustment(c, Playfield));
|
||||
}
|
||||
@ -88,22 +89,5 @@ namespace osu.Game.Rulesets.UI.Scrolling
|
||||
playfield.HitObjects.AddControlPoint(controlPoint);
|
||||
playfield.NestedPlayfields?.OfType<ScrollingPlayfield>().ForEach(p => applySpeedAdjustment(controlPoint, p));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates a <see cref="MultiplierControlPoint"/> with the default timing change/difficulty change from the beatmap at a time.
|
||||
/// </summary>
|
||||
/// <param name="time">The time to create the control point at.</param>
|
||||
/// <returns>The default <see cref="MultiplierControlPoint"/> at <paramref name="time"/>.</returns>
|
||||
public MultiplierControlPoint CreateControlPointAt(double time)
|
||||
{
|
||||
if (DefaultControlPoints.Count == 0)
|
||||
return new MultiplierControlPoint(time);
|
||||
|
||||
int index = DefaultControlPoints.BinarySearch(new MultiplierControlPoint(time));
|
||||
if (index < 0)
|
||||
return new MultiplierControlPoint(time);
|
||||
|
||||
return new MultiplierControlPoint(time, DefaultControlPoints[index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ namespace osu.Game.Screens.Edit.Components
|
||||
new OsuSpriteText
|
||||
{
|
||||
Origin = Anchor.BottomLeft,
|
||||
Text = "Playback Speed",
|
||||
Text = "Playback speed",
|
||||
RelativePositionAxes = Axes.Y,
|
||||
Y = 0.5f,
|
||||
Padding = new MarginPadding { Left = 45 }
|
||||
|
@ -59,8 +59,8 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline
|
||||
Spacing = new Vector2(0, 4),
|
||||
Children = new[]
|
||||
{
|
||||
hitObjectsCheckbox = new OsuCheckbox { LabelText = "Hitobjects" },
|
||||
hitSoundsCheckbox = new OsuCheckbox { LabelText = "Hitsounds" },
|
||||
hitObjectsCheckbox = new OsuCheckbox { LabelText = "Hit objects" },
|
||||
hitSoundsCheckbox = new OsuCheckbox { LabelText = "Hit sounds" },
|
||||
waveformCheckbox = new OsuCheckbox { LabelText = "Waveform" }
|
||||
}
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ namespace osu.Game.Screens.Play.PlayerSettings
|
||||
},
|
||||
showStoryboardToggle = new PlayerCheckbox { LabelText = "Storyboards" },
|
||||
beatmapSkinsToggle = new PlayerCheckbox { LabelText = "Beatmap skins" },
|
||||
beatmapHitsoundsToggle = new PlayerCheckbox { LabelText = "Beatmap hitsounds" }
|
||||
beatmapHitsoundsToggle = new PlayerCheckbox { LabelText = "Beatmap hit sounds" }
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -327,11 +327,6 @@ namespace osu.Game.Screens.Select
|
||||
TextSize = 14,
|
||||
},
|
||||
},
|
||||
textFlow = new OsuTextFlowContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
@ -350,6 +345,8 @@ namespace osu.Game.Screens.Select
|
||||
}
|
||||
}
|
||||
|
||||
public override bool IsPresent => base.IsPresent || textFlow == null; // Visibility is updated in the LoadComponentAsync callback
|
||||
|
||||
private void setTextAsync(string text)
|
||||
{
|
||||
LoadComponentAsync(new OsuTextFlowContainer(s => s.TextSize = 14)
|
||||
|
@ -21,8 +21,8 @@ namespace osu.Game.Screens.Select.Filter
|
||||
DateAdded,
|
||||
[Description("Difficulty")]
|
||||
Difficulty,
|
||||
[Description("Favorites")]
|
||||
Favorites,
|
||||
[Description("Favourites")]
|
||||
Favourites,
|
||||
[Description("Length")]
|
||||
Length,
|
||||
[Description("My Maps")]
|
||||
|
@ -65,7 +65,7 @@ namespace osu.Game.Screens.Select
|
||||
|
||||
BeatmapOptions.AddButton(@"Remove", @"from unplayed", FontAwesome.fa_times_circle_o, colours.Purple, null, Key.Number1);
|
||||
BeatmapOptions.AddButton(@"Clear", @"local scores", FontAwesome.fa_eraser, colours.Purple, null, Key.Number2);
|
||||
BeatmapOptions.AddButton(@"Edit", @"Beatmap", FontAwesome.fa_pencil, colours.Yellow, () =>
|
||||
BeatmapOptions.AddButton(@"Edit", @"beatmap", FontAwesome.fa_pencil, colours.Yellow, () =>
|
||||
{
|
||||
ValidForResume = false;
|
||||
Push(new Editor());
|
||||
|
@ -204,7 +204,7 @@ namespace osu.Game.Screens.Select
|
||||
Footer.AddButton(@"random", colours.Green, triggerRandom, Key.F2);
|
||||
Footer.AddButton(@"options", colours.Blue, BeatmapOptions, Key.F3);
|
||||
|
||||
BeatmapOptions.AddButton(@"Delete", @"Beatmap", FontAwesome.fa_trash, colours.Pink, () => delete(Beatmap.Value.BeatmapSetInfo), Key.Number4, float.MaxValue);
|
||||
BeatmapOptions.AddButton(@"Delete", @"all difficulties", FontAwesome.fa_trash, colours.Pink, () => delete(Beatmap.Value.BeatmapSetInfo), Key.Number4, float.MaxValue);
|
||||
}
|
||||
|
||||
if (this.beatmaps == null)
|
||||
|
@ -41,7 +41,7 @@ namespace osu.Game.Storyboards.Drawables
|
||||
{
|
||||
base.Update();
|
||||
|
||||
// TODO: this logic will need to be consolidated with other game samples like hitsounds.
|
||||
// TODO: this logic will need to be consolidated with other game samples like hit sounds.
|
||||
if (Time.Current < sample.Time)
|
||||
{
|
||||
// We've rewound before the start time of the sample
|
||||
|
@ -83,8 +83,8 @@ namespace osu.Game.Users
|
||||
[JsonProperty(@"location")]
|
||||
public string Location;
|
||||
|
||||
[JsonProperty(@"lastvisit")]
|
||||
public DateTimeOffset LastVisit;
|
||||
[JsonProperty(@"last_visit")]
|
||||
public DateTimeOffset? LastVisit;
|
||||
|
||||
[JsonProperty(@"twitter")]
|
||||
public string Twitter;
|
||||
|
@ -14,13 +14,13 @@
|
||||
<ProjectReference Include="..\osu-resources\osu.Game.Resources\osu.Game.Resources.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Humanizer" Version="2.4.2" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.2" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.1.3" />
|
||||
<PackageReference Include="Humanizer" Version="2.5.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.1.4" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2018.1002.0" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2018.1012.0" />
|
||||
<PackageReference Include="SharpCompress" Version="0.22.0" />
|
||||
<PackageReference Include="NUnit" Version="3.10.1" />
|
||||
<PackageReference Include="NUnit" Version="3.11.0" />
|
||||
<PackageReference Include="SharpRaven" Version="2.4.0" />
|
||||
<PackageReference Include="System.ComponentModel.Annotations" Version="4.5.0" />
|
||||
</ItemGroup>
|
||||
|
@ -10,10 +10,6 @@
|
||||
<ProjectReference Include="..\osu.Game\osu.Game.csproj" />
|
||||
<ProjectReference Include="..\osu-resources\osu.Game.Resources\osu.Game.Resources.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.3" />
|
||||
<PackageReference Include="DeepEqual" Version="1.6.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="..\osu.Game\Tests\VisualTestRunner.cs">
|
||||
<Link>VisualTestRunner.cs</Link>
|
||||
|
@ -666,6 +666,7 @@ Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/maste
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpRenamePlacementToArrangementMigration/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpUseContinuousIndentInsideBracesMigration/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EAddAccessorOwnerDeclarationBracesMigration/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EAlwaysTreatStructAsNotReorderableMigration/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002ECSharpPlaceAttributeOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
|
||||
|
Loading…
Reference in New Issue
Block a user