1
0
mirror of https://github.com/ppy/osu.git synced 2025-03-05 12:32:58 +08:00

Merge pull request #1908 from andy840119/mania_stage_fix

Split the playfield columns and change the key number by mod
This commit is contained in:
Dean Herbert 2018-01-23 11:03:56 +09:00 committed by GitHub
commit 4f360eac56
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 627 additions and 303 deletions

View File

@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
/// <summary> /// <summary>
/// The definitions for each stage in a <see cref="ManiaPlayfield"/>. /// The definitions for each stage in a <see cref="ManiaPlayfield"/>.
/// </summary> /// </summary>
public readonly List<StageDefinition> Stages = new List<StageDefinition>(); public List<StageDefinition> Stages = new List<StageDefinition>();
/// <summary> /// <summary>
/// Total number of columns represented by all stages in this <see cref="ManiaBeatmap"/>. /// Total number of columns represented by all stages in this <see cref="ManiaBeatmap"/>.
@ -24,10 +24,10 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
/// <summary> /// <summary>
/// Creates a new <see cref="ManiaBeatmap"/>. /// Creates a new <see cref="ManiaBeatmap"/>.
/// </summary> /// </summary>
/// <param name="initialStage">The initial stage.</param> /// <param name="defaultStage">The initial stages.</param>
public ManiaBeatmap(StageDefinition initialStage) public ManiaBeatmap(StageDefinition defaultStage)
{ {
Stages.Add(initialStage); Stages.Add(defaultStage);
} }
} }
} }

View File

@ -17,8 +17,13 @@ namespace osu.Game.Rulesets.Mania
public enum ManiaAction public enum ManiaAction
{ {
[Description("Special")] [Description("Special 1")]
Special, Special1 = 1,
[Description("Special 2")]
Special2,
// This offsets the start value of normal keys in-case we add more special keys
// above at a later time, without breaking replays/configs.
[Description("Key 1")] [Description("Key 1")]
Key1 = 10, Key1 = 10,
[Description("Key 2")] [Description("Key 2")]
@ -36,6 +41,24 @@ namespace osu.Game.Rulesets.Mania
[Description("Key 8")] [Description("Key 8")]
Key8, Key8,
[Description("Key 9")] [Description("Key 9")]
Key9 Key9,
[Description("Key 10")]
Key10,
[Description("Key 11")]
Key11,
[Description("Key 12")]
Key12,
[Description("Key 13")]
Key13,
[Description("Key 14")]
Key14,
[Description("Key 15")]
Key15,
[Description("Key 16")]
Key16,
[Description("Key 17")]
Key17,
[Description("Key 18")]
Key18,
} }
} }

View File

@ -1,12 +1,14 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets.Mania.Mods; using osu.Game.Rulesets.Mania.Mods;
using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.Mania.UI;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Input.Bindings; using osu.Framework.Input.Bindings;
using osu.Game.Graphics; using osu.Game.Graphics;
@ -86,7 +88,7 @@ namespace osu.Game.Rulesets.Mania
}, },
}, },
new ManiaModRandom(), new ManiaModRandom(),
new ManiaModKeyCoop(), new ManiaModDualStages(),
new MultiMod new MultiMod
{ {
Mods = new Mod[] Mods = new Mod[]
@ -117,42 +119,189 @@ namespace osu.Game.Rulesets.Mania
{ {
} }
public override IEnumerable<int> AvailableVariants => new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; public override IEnumerable<int> AvailableVariants
{
get
{
for (int i = 1; i <= 9; i++)
yield return (int)PlayfieldType.Single + i;
for (int i = 2; i <= 18; i += 2)
yield return (int)PlayfieldType.Dual + i;
}
}
public override IEnumerable<KeyBinding> GetDefaultKeyBindings(int variant = 0) public override IEnumerable<KeyBinding> GetDefaultKeyBindings(int variant = 0)
{ {
var leftKeys = new[] switch (getPlayfieldType(variant))
{ {
InputKey.A, case PlayfieldType.Single:
InputKey.S, return new VariantMappingGenerator
InputKey.D, {
InputKey.F LeftKeys = new[]
}; {
InputKey.A,
InputKey.S,
InputKey.D,
InputKey.F
},
RightKeys = new[]
{
InputKey.J,
InputKey.K,
InputKey.L,
InputKey.Semicolon
},
SpecialKey = InputKey.Space,
SpecialAction = ManiaAction.Special1,
NormalActionStart = ManiaAction.Key1,
}.GenerateKeyBindingsFor(variant, out _);
case PlayfieldType.Dual:
int keys = getDualStageKeyCount(variant);
var rightKeys = new[] var stage1Bindings = new VariantMappingGenerator
{ {
InputKey.J, LeftKeys = new[]
InputKey.K, {
InputKey.L, InputKey.Number1,
InputKey.Semicolon InputKey.Number2,
}; InputKey.Number3,
InputKey.Number4,
},
RightKeys = new[]
{
InputKey.Z,
InputKey.X,
InputKey.C,
InputKey.V
},
SpecialKey = InputKey.Tilde,
SpecialAction = ManiaAction.Special1,
NormalActionStart = ManiaAction.Key1
}.GenerateKeyBindingsFor(keys, out var nextNormal);
ManiaAction currentKey = ManiaAction.Key1; var stage2Bindings = new VariantMappingGenerator
{
LeftKeys = new[]
{
InputKey.Number7,
InputKey.Number8,
InputKey.Number9,
InputKey.Number0
},
RightKeys = new[]
{
InputKey.O,
InputKey.P,
InputKey.BracketLeft,
InputKey.BracketRight
},
SpecialKey = InputKey.BackSlash,
SpecialAction = ManiaAction.Special2,
NormalActionStart = nextNormal
}.GenerateKeyBindingsFor(keys, out _);
var bindings = new List<KeyBinding>(); return stage1Bindings.Concat(stage2Bindings);
}
for (int i = leftKeys.Length - variant / 2; i < leftKeys.Length; i++) return new KeyBinding[0];
bindings.Add(new KeyBinding(leftKeys[i], currentKey++));
for (int i = 0; i < variant / 2; i++)
bindings.Add(new KeyBinding(rightKeys[i], currentKey++));
if (variant % 2 == 1)
bindings.Add(new KeyBinding(InputKey.Space, ManiaAction.Special));
return bindings;
} }
public override string GetVariantName(int variant) => $"{variant}K"; public override string GetVariantName(int variant)
{
switch (getPlayfieldType(variant))
{
default:
return $"{variant}K";
case PlayfieldType.Dual:
{
var keys = getDualStageKeyCount(variant);
return $"{keys}K + {keys}K";
}
}
}
/// <summary>
/// Finds the number of keys for each stage in a <see cref="PlayfieldType.Dual"/> variant.
/// </summary>
/// <param name="variant">The variant.</param>
private int getDualStageKeyCount(int variant) => (variant - (int)PlayfieldType.Dual) / 2;
/// <summary>
/// Finds the <see cref="PlayfieldType"/> that corresponds to a variant value.
/// </summary>
/// <param name="variant">The variant value.</param>
/// <returns>The <see cref="PlayfieldType"/> that corresponds to <paramref name="variant"/>.</returns>
private PlayfieldType getPlayfieldType(int variant)
{
return (PlayfieldType)Enum.GetValues(typeof(PlayfieldType)).Cast<int>().OrderByDescending(i => i).First(v => variant >= v);
}
private class VariantMappingGenerator
{
/// <summary>
/// All the <see cref="InputKey"/>s available to the left hand.
/// </summary>
public InputKey[] LeftKeys;
/// <summary>
/// All the <see cref="InputKey"/>s available to the right hand.
/// </summary>
public InputKey[] RightKeys;
/// <summary>
/// The <see cref="InputKey"/> for the special key.
/// </summary>
public InputKey SpecialKey;
/// <summary>
/// The <see cref="ManiaAction"/> at which the normal columns should begin.
/// </summary>
public ManiaAction NormalActionStart;
/// <summary>
/// The <see cref="ManiaAction"/> for the special column.
/// </summary>
public ManiaAction SpecialAction;
/// <summary>
/// Generates a list of <see cref="KeyBinding"/>s for a specific number of columns.
/// </summary>
/// <param name="columns">The number of columns that need to be bound.</param>
/// <param name="nextNormalAction">The next <see cref="ManiaAction"/> to use for normal columns.</param>
/// <returns>The keybindings.</returns>
public IEnumerable<KeyBinding> GenerateKeyBindingsFor(int columns, out ManiaAction nextNormalAction)
{
ManiaAction currentNormalAction = NormalActionStart;
var bindings = new List<KeyBinding>();
for (int i = LeftKeys.Length - columns / 2; i < LeftKeys.Length; i++)
bindings.Add(new KeyBinding(LeftKeys[i], currentNormalAction++));
for (int i = 0; i < columns / 2; i++)
bindings.Add(new KeyBinding(RightKeys[i], currentNormalAction++));
if (columns % 2 == 1)
bindings.Add(new KeyBinding(SpecialKey, SpecialAction));
nextNormalAction = currentNormalAction;
return bindings;
}
}
}
public enum PlayfieldType
{
/// <summary>
/// Columns are grouped into a single stage.
/// Number of columns in this stage lies at (item - Single).
/// </summary>
Single = 0,
/// <summary>
/// Columns are grouped into two stages.
/// Overall number of columns lies at (item - Dual), further computation is required for
/// number of columns in each individual stage.
/// </summary>
Dual = 1000,
} }
} }

View File

@ -0,0 +1,15 @@
// 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.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Mania.Mods
{
public interface IPlayfieldTypeMod : IApplicableMod
{
/// <summary>
/// The <see cref="PlayfieldType"/> which this <see cref="IPlayfieldTypeMod"/> requires.
/// </summary>
PlayfieldType PlayfieldType { get; }
}
}

View File

@ -0,0 +1,53 @@
// 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.Collections.Generic;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.UI;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.UI;
namespace osu.Game.Rulesets.Mania.Mods
{
public class ManiaModDualStages : Mod, IPlayfieldTypeMod, IApplicableToBeatmapConverter<ManiaHitObject>, IApplicableToRulesetContainer<ManiaHitObject>
{
public override string Name => "Dual Stages";
public override string ShortenedName => "DS";
public override string Description => @"Double the stages, double the fun!";
public override double ScoreMultiplier => 1;
public override bool Ranked => false;
public void ApplyToBeatmapConverter(BeatmapConverter<ManiaHitObject> beatmapConverter)
{
var mbc = (ManiaBeatmapConverter)beatmapConverter;
// Although this can work, for now let's not allow keymods for mania-specific beatmaps
if (mbc.IsForCurrentRuleset)
return;
mbc.TargetColumns *= 2;
}
public void ApplyToRulesetContainer(RulesetContainer<ManiaHitObject> rulesetContainer)
{
var mrc = (ManiaRulesetContainer)rulesetContainer;
// Although this can work, for now let's not allow keymods for mania-specific beatmaps
if (mrc.IsForCurrentRuleset)
return;
var newDefinitions = new List<StageDefinition>();
foreach (var existing in mrc.Beatmap.Stages)
{
newDefinitions.Add(new StageDefinition { Columns = existing.Columns / 2 });
newDefinitions.Add(new StageDefinition { Columns = existing.Columns / 2 });
}
mrc.Beatmap.Stages = newDefinitions;
}
public PlayfieldType PlayfieldType => PlayfieldType.Dual;
}
}

View File

@ -1,16 +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 osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Mania.Mods
{
public class ManiaModKeyCoop : Mod
{
public override string Name => "KeyCoop";
public override string ShortenedName => "2P";
public override string Description => @"Double the key amount, double the fun!";
public override double ScoreMultiplier => 1;
public override bool Ranked => true;
}
}

View File

@ -78,7 +78,7 @@ namespace osu.Game.Rulesets.Mania.Tests
RelativeChildSize = new Vector2(1, 10000), RelativeChildSize = new Vector2(1, 10000),
Children = new[] Children = new[]
{ {
new DrawableHoldNote(new HoldNote { Duration = 1 }, ManiaAction.Key1) new DrawableHoldNote(new HoldNote { Duration = 1000 } , ManiaAction.Key1)
{ {
Y = 5000, Y = 5000,
Height = 1000, Height = 1000,

View File

@ -2,11 +2,13 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Timing; using osu.Framework.Timing;
using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.Judgements; using osu.Game.Rulesets.Mania.Judgements;
using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Mania.Objects.Drawables;
@ -31,15 +33,43 @@ namespace osu.Game.Rulesets.Mania.Tests
{ {
var rng = new Random(1337); var rng = new Random(1337);
AddStep("1 column", () => createPlayfield(1, SpecialColumnPosition.Normal)); AddStep("1 column", () => createPlayfield(1));
AddStep("4 columns", () => createPlayfield(4, SpecialColumnPosition.Normal)); AddStep("4 columns", () => createPlayfield(4));
AddStep("Left special style", () => createPlayfield(4, SpecialColumnPosition.Left)); AddStep("5 columns", () => createPlayfield(5));
AddStep("Right special style", () => createPlayfield(4, SpecialColumnPosition.Right)); AddStep("8 columns", () => createPlayfield(8));
AddStep("5 columns", () => createPlayfield(5, SpecialColumnPosition.Normal)); AddStep("4 + 4 columns", () =>
AddStep("8 columns", () => createPlayfield(8, SpecialColumnPosition.Normal)); {
AddStep("Left special style", () => createPlayfield(8, SpecialColumnPosition.Left)); var stages = new List<StageDefinition>
AddStep("Right special style", () => createPlayfield(8, SpecialColumnPosition.Right)); {
AddStep("Reversed", () => createPlayfield(4, SpecialColumnPosition.Normal, true)); new StageDefinition { Columns = 4 },
new StageDefinition { Columns = 4 },
};
createPlayfield(stages);
});
AddStep("2 + 4 + 2 columns", () =>
{
var stages = new List<StageDefinition>
{
new StageDefinition { Columns = 2 },
new StageDefinition { Columns = 4 },
new StageDefinition { Columns = 2 },
};
createPlayfield(stages);
});
AddStep("1 + 8 + 1 columns", () =>
{
var stages = new List<StageDefinition>
{
new StageDefinition { Columns = 1 },
new StageDefinition { Columns = 8 },
new StageDefinition { Columns = 1 },
};
createPlayfield(stages);
});
AddStep("Reversed", () => createPlayfield(4, true));
AddStep("Notes with input", () => createPlayfieldWithNotes()); AddStep("Notes with input", () => createPlayfieldWithNotes());
AddStep("Notes with input (reversed)", () => createPlayfieldWithNotes(true)); AddStep("Notes with input (reversed)", () => createPlayfieldWithNotes(true));
@ -48,7 +78,7 @@ namespace osu.Game.Rulesets.Mania.Tests
AddStep("Hit explosion", () => AddStep("Hit explosion", () =>
{ {
var playfield = createPlayfield(4, SpecialColumnPosition.Normal); var playfield = createPlayfield(4);
int col = rng.Next(0, 4); int col = rng.Next(0, 4);
@ -58,6 +88,7 @@ namespace osu.Game.Rulesets.Mania.Tests
}; };
playfield.OnJudgement(note, new ManiaJudgement { Result = HitResult.Perfect }); playfield.OnJudgement(note, new ManiaJudgement { Result = HitResult.Perfect });
playfield.Columns[col].OnJudgement(note, new ManiaJudgement { Result = HitResult.Perfect });
}); });
} }
@ -67,19 +98,29 @@ namespace osu.Game.Rulesets.Mania.Tests
maniaRuleset = rulesets.GetRuleset(3); maniaRuleset = rulesets.GetRuleset(3);
} }
private ManiaPlayfield createPlayfield(int cols, SpecialColumnPosition specialPos, bool inverted = false) private ManiaPlayfield createPlayfield(int cols, bool inverted = false)
{
var stages = new List<StageDefinition>
{
new StageDefinition { Columns = cols },
};
return createPlayfield(stages, inverted);
}
private ManiaPlayfield createPlayfield(List<StageDefinition> stages, bool inverted = false)
{ {
Clear(); Clear();
var inputManager = new ManiaInputManager(maniaRuleset, cols) { RelativeSizeAxes = Axes.Both }; var inputManager = new ManiaInputManager(maniaRuleset, stages.Sum(g => g.Columns)) { RelativeSizeAxes = Axes.Both };
Add(inputManager); Add(inputManager);
ManiaPlayfield playfield; ManiaPlayfield playfield;
inputManager.Add(playfield = new ManiaPlayfield(cols)
inputManager.Add(playfield = new ManiaPlayfield(stages)
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
SpecialColumnPosition = specialPos
}); });
playfield.Inverted.Value = inverted; playfield.Inverted.Value = inverted;
@ -97,7 +138,12 @@ namespace osu.Game.Rulesets.Mania.Tests
Add(inputManager); Add(inputManager);
ManiaPlayfield playfield; ManiaPlayfield playfield;
inputManager.Add(playfield = new ManiaPlayfield(4) var stages = new List<StageDefinition>
{
new StageDefinition { Columns = 4 },
};
inputManager.Add(playfield = new ManiaPlayfield(stages)
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,

View File

@ -47,6 +47,7 @@ namespace osu.Game.Rulesets.Mania.UI
public Column() public Column()
: base(ScrollingDirection.Up) : base(ScrollingDirection.Up)
{ {
RelativeSizeAxes = Axes.Y;
Width = column_width; Width = column_width;
InternalChildren = new Drawable[] InternalChildren = new Drawable[]
@ -61,7 +62,7 @@ namespace osu.Game.Rulesets.Mania.UI
{ {
Name = "Hit target + hit objects", Name = "Hit target + hit objects",
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Top = ManiaPlayfield.HIT_TARGET_POSITION }, Padding = new MarginPadding { Top = ManiaStage.HIT_TARGET_POSITION },
Children = new Drawable[] Children = new Drawable[]
{ {
new Container new Container
@ -115,7 +116,7 @@ namespace osu.Game.Rulesets.Mania.UI
{ {
Name = "Key", Name = "Key",
RelativeSizeAxes = Axes.X, RelativeSizeAxes = Axes.X,
Height = ManiaPlayfield.HIT_TARGET_POSITION, Height = ManiaStage.HIT_TARGET_POSITION,
Children = new Drawable[] Children = new Drawable[]
{ {
new Box new Box
@ -205,12 +206,12 @@ namespace osu.Game.Rulesets.Mania.UI
{ {
hitObject.Depth = (float)hitObject.HitObject.StartTime; hitObject.Depth = (float)hitObject.HitObject.StartTime;
hitObject.AccentColour = AccentColour; hitObject.AccentColour = AccentColour;
hitObject.OnJudgement += onJudgement; hitObject.OnJudgement += OnJudgement;
HitObjects.Add(hitObject); HitObjects.Add(hitObject);
} }
private void onJudgement(DrawableHitObject judgedObject, Judgement judgement) internal void OnJudgement(DrawableHitObject judgedObject, Judgement judgement)
{ {
if (!judgement.IsHit) if (!judgement.IsHit)
return; return;

View File

@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Mania.UI
internal class DrawableManiaJudgement : DrawableJudgement internal class DrawableManiaJudgement : DrawableJudgement
{ {
public DrawableManiaJudgement(Judgement judgement) public DrawableManiaJudgement(Judgement judgement)
: base(judgement) : base(judgement)
{ {
JudgementText.TextSize = 25; JudgementText.TextSize = 25;
} }

View File

@ -3,237 +3,84 @@
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects;
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using System; using System;
using osu.Game.Graphics;
using osu.Framework.Allocation;
using System.Linq;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using osu.Framework.Configuration; using osu.Framework.Configuration;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Framework.Graphics.Shapes;
using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Rulesets.UI.Scrolling;
namespace osu.Game.Rulesets.Mania.UI namespace osu.Game.Rulesets.Mania.UI
{ {
public class ManiaPlayfield : ScrollingPlayfield public class ManiaPlayfield : ScrollingPlayfield
{ {
public const float HIT_TARGET_POSITION = 50;
private SpecialColumnPosition specialColumnPosition;
/// <summary>
/// The style to use for the special column.
/// </summary>
public SpecialColumnPosition SpecialColumnPosition
{
get { return specialColumnPosition; }
set
{
if (IsLoaded)
throw new InvalidOperationException($"Setting {nameof(SpecialColumnPosition)} after the playfield is loaded requires re-creating the playfield.");
specialColumnPosition = value;
}
}
/// <summary> /// <summary>
/// Whether this playfield should be inverted. This flips everything inside the playfield. /// Whether this playfield should be inverted. This flips everything inside the playfield.
/// </summary> /// </summary>
public readonly Bindable<bool> Inverted = new Bindable<bool>(true); public readonly Bindable<bool> Inverted = new Bindable<bool>(true);
private readonly FlowContainer<Column> columns; public List<Column> Columns => stages.SelectMany(x => x.Columns).ToList();
public IEnumerable<Column> Columns => columns.Children; private readonly List<ManiaStage> stages = new List<ManiaStage>();
protected override Container<Drawable> Content => content; public ManiaPlayfield(List<StageDefinition> stageDefinitions)
private readonly Container<Drawable> content;
private List<Color4> normalColumnColours = new List<Color4>();
private Color4 specialColumnColour;
private readonly Container<DrawableManiaJudgement> judgements;
private readonly int columnCount;
public ManiaPlayfield(int columnCount)
: base(ScrollingDirection.Up) : base(ScrollingDirection.Up)
{ {
this.columnCount = columnCount; if (stageDefinitions == null)
throw new ArgumentNullException(nameof(stageDefinitions));
if (columnCount <= 0) if (stageDefinitions.Count <= 0)
throw new ArgumentException("Can't have zero or fewer columns."); throw new ArgumentException("Can't have zero or fewer stages.");
Inverted.Value = true; Inverted.Value = true;
Container topLevelContainer; GridContainer playfieldGrid;
InternalChildren = new Drawable[] InternalChild = playfieldGrid = new GridContainer
{ {
new Container RelativeSizeAxes = Axes.Both,
{ Content = new[] { new Drawable[stageDefinitions.Count] }
Name = "Playfield elements",
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
RelativeSizeAxes = Axes.Y,
AutoSizeAxes = Axes.X,
Children = new Drawable[]
{
new Container
{
Name = "Columns mask",
RelativeSizeAxes = Axes.Y,
AutoSizeAxes = Axes.X,
Masking = true,
Children = new Drawable[]
{
new Box
{
Name = "Background",
RelativeSizeAxes = Axes.Both,
Colour = Color4.Black
},
columns = new FillFlowContainer<Column>
{
Name = "Columns",
RelativeSizeAxes = Axes.Y,
AutoSizeAxes = Axes.X,
Direction = FillDirection.Horizontal,
Padding = new MarginPadding { Left = 1, Right = 1 },
Spacing = new Vector2(1, 0)
},
}
},
new Container
{
Name = "Barlines mask",
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
RelativeSizeAxes = Axes.Y,
Width = 1366, // Bar lines should only be masked on the vertical axis
BypassAutoSizeAxes = Axes.Both,
Masking = true,
Child = content = new Container
{
Name = "Bar lines",
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
RelativeSizeAxes = Axes.Y,
Padding = new MarginPadding { Top = HIT_TARGET_POSITION }
}
},
judgements = new Container<DrawableManiaJudgement>
{
Anchor = Anchor.TopCentre,
Origin = Anchor.Centre,
AutoSizeAxes = Axes.Both,
Y = HIT_TARGET_POSITION + 150,
BypassAutoSizeAxes = Axes.Both
},
topLevelContainer = new Container { RelativeSizeAxes = Axes.Both }
}
}
}; };
var currentAction = ManiaAction.Key1; var normalColumnAction = ManiaAction.Key1;
for (int i = 0; i < columnCount; i++) var specialColumnAction = ManiaAction.Special1;
int firstColumnIndex = 0;
for (int i = 0; i < stageDefinitions.Count; i++)
{ {
var c = new Column(); var newStage = new ManiaStage(firstColumnIndex, stageDefinitions[i], ref normalColumnAction, ref specialColumnAction);
c.VisibleTimeRange.BindTo(VisibleTimeRange); newStage.VisibleTimeRange.BindTo(VisibleTimeRange);
newStage.Inverted.BindTo(Inverted);
c.IsSpecial = isSpecialColumn(i); playfieldGrid.Content[0][i] = newStage;
c.Action = c.IsSpecial ? ManiaAction.Special : currentAction++;
topLevelContainer.Add(c.TopLevelContainer.CreateProxy()); stages.Add(newStage);
AddNested(newStage);
columns.Add(c); firstColumnIndex += newStage.Columns.Count;
AddNested(c);
} }
Inverted.ValueChanged += invertedChanged;
Inverted.TriggerChange();
} }
private void invertedChanged(bool newValue) public override void Add(DrawableHitObject h) => getStageByColumn(((ManiaHitObject)h.HitObject).Column).Add(h);
public void Add(BarLine barline) => stages.ForEach(s => s.Add(barline));
private ManiaStage getStageByColumn(int column)
{ {
Scale = new Vector2(1, newValue ? -1 : 1); int sum = 0;
judgements.Scale = Scale; foreach (var stage in stages)
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
normalColumnColours = new List<Color4>
{ {
colours.RedDark, sum = sum + stage.Columns.Count;
colours.GreenDark if (sum > column)
}; return stage;
specialColumnColour = colours.BlueDark;
// Set the special column + colour + key
foreach (var column in Columns)
{
if (!column.IsSpecial)
continue;
column.AccentColour = specialColumnColour;
} }
var nonSpecialColumns = Columns.Where(c => !c.IsSpecial).ToList(); return null;
// We'll set the colours of the non-special columns in a separate loop, because the non-special
// column colours are mirrored across their centre and special styles mess with this
for (int i = 0; i < Math.Ceiling(nonSpecialColumns.Count / 2f); i++)
{
Color4 colour = normalColumnColours[i % normalColumnColours.Count];
nonSpecialColumns[i].AccentColour = colour;
nonSpecialColumns[nonSpecialColumns.Count - 1 - i].AccentColour = colour;
}
} }
internal void OnJudgement(DrawableHitObject judgedObject, Judgement judgement) internal void OnJudgement(DrawableHitObject judgedObject, Judgement judgement)
{ {
judgements.Clear(); getStageByColumn(((ManiaHitObject)judgedObject.HitObject).Column).OnJudgement(judgedObject, judgement);
judgements.Add(new DrawableManiaJudgement(judgement)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
});
}
/// <summary>
/// Whether the column index is a special column for this playfield.
/// </summary>
/// <param name="column">The 0-based column index.</param>
/// <returns>Whether the column is a special column.</returns>
private bool isSpecialColumn(int column)
{
switch (SpecialColumnPosition)
{
default:
case SpecialColumnPosition.Normal:
return columnCount % 2 == 1 && column == columnCount / 2;
case SpecialColumnPosition.Left:
return column == 0;
case SpecialColumnPosition.Right:
return column == columnCount - 1;
}
}
public override void Add(DrawableHitObject h)
{
h.OnJudgement += OnJudgement;
Columns.ElementAt(((ManiaHitObject)h.HitObject).Column).Add(h);
}
public void Add(DrawableBarLine barline) => HitObjects.Add(barline);
protected override void Update()
{
// Due to masking differences, it is not possible to get the width of the columns container automatically
// While masking on effectively only the Y-axis, so we need to set the width of the bar line container manually
content.Width = columns.Width;
} }
} }
} }

View File

@ -3,7 +3,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using OpenTK;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
@ -12,6 +11,7 @@ using osu.Framework.MathUtils;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.Mods;
using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.Mania.Replays; using osu.Game.Rulesets.Mania.Replays;
@ -22,6 +22,7 @@ using osu.Game.Rulesets.Replays;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Rulesets.UI.Scrolling;
using OpenTK;
namespace osu.Game.Rulesets.Mania.UI namespace osu.Game.Rulesets.Mania.UI
{ {
@ -29,7 +30,7 @@ namespace osu.Game.Rulesets.Mania.UI
{ {
public new ManiaBeatmap Beatmap => (ManiaBeatmap)base.Beatmap; public new ManiaBeatmap Beatmap => (ManiaBeatmap)base.Beatmap;
public IEnumerable<DrawableBarLine> BarLines; public IEnumerable<BarLine> BarLines;
public ManiaRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap, bool isForCurrentRuleset) public ManiaRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap, bool isForCurrentRuleset)
: base(ruleset, beatmap, isForCurrentRuleset) : base(ruleset, beatmap, isForCurrentRuleset)
@ -38,7 +39,7 @@ namespace osu.Game.Rulesets.Mania.UI
double lastObjectTime = (Objects.LastOrDefault() as IHasEndTime)?.EndTime ?? Objects.LastOrDefault()?.StartTime ?? double.MaxValue; double lastObjectTime = (Objects.LastOrDefault() as IHasEndTime)?.EndTime ?? Objects.LastOrDefault()?.StartTime ?? double.MaxValue;
var timingPoints = Beatmap.ControlPointInfo.TimingPoints; var timingPoints = Beatmap.ControlPointInfo.TimingPoints;
var barLines = new List<DrawableBarLine>(); var barLines = new List<BarLine>();
for (int i = 0; i < timingPoints.Count; i++) for (int i = 0; i < timingPoints.Count; i++)
{ {
@ -50,12 +51,12 @@ namespace osu.Game.Rulesets.Mania.UI
int index = 0; int index = 0;
for (double t = timingPoints[i].Time; Precision.DefinitelyBigger(endTime, t); t += point.BeatLength, index++) for (double t = timingPoints[i].Time; Precision.DefinitelyBigger(endTime, t); t += point.BeatLength, index++)
{ {
barLines.Add(new DrawableBarLine(new BarLine barLines.Add(new BarLine
{ {
StartTime = t, StartTime = t,
ControlPoint = point, ControlPoint = point,
BeatIndex = index BeatIndex = index
})); });
} }
} }
@ -68,7 +69,7 @@ namespace osu.Game.Rulesets.Mania.UI
BarLines.ForEach(Playfield.Add); BarLines.ForEach(Playfield.Add);
} }
protected sealed override Playfield CreatePlayfield() => new ManiaPlayfield(Beatmap.TotalColumns) protected sealed override Playfield CreatePlayfield() => new ManiaPlayfield(Beatmap.Stages)
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
@ -76,7 +77,11 @@ namespace osu.Game.Rulesets.Mania.UI
public override ScoreProcessor CreateScoreProcessor() => new ManiaScoreProcessor(this); public override ScoreProcessor CreateScoreProcessor() => new ManiaScoreProcessor(this);
public override PassThroughInputManager CreateInputManager() => new ManiaInputManager(Ruleset.RulesetInfo, Beatmap.TotalColumns); public override PassThroughInputManager CreateInputManager()
{
var variantType = Mods.OfType<IPlayfieldTypeMod>().FirstOrDefault()?.PlayfieldType ?? PlayfieldType.Single;
return new ManiaInputManager(Ruleset.RulesetInfo, (int)variantType + Beatmap.TotalColumns);
}
protected override BeatmapConverter<ManiaHitObject> CreateBeatmapConverter() => new ManiaBeatmapConverter(IsForCurrentRuleset, WorkingBeatmap.Beatmap); protected override BeatmapConverter<ManiaHitObject> CreateBeatmapConverter() => new ManiaBeatmapConverter(IsForCurrentRuleset, WorkingBeatmap.Beatmap);

View File

@ -0,0 +1,229 @@
// 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 System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.UI.Scrolling;
using OpenTK;
using OpenTK.Graphics;
namespace osu.Game.Rulesets.Mania.UI
{
/// <summary>
/// A collection of <see cref="Column"/>s.
/// </summary>
internal class ManiaStage : ScrollingPlayfield
{
public const float HIT_TARGET_POSITION = 50;
/// <summary>
/// Whether this playfield should be inverted. This flips everything inside the playfield.
/// </summary>
public readonly Bindable<bool> Inverted = new Bindable<bool>(true);
public IReadOnlyList<Column> Columns => columnFlow.Children;
private readonly FillFlowContainer<Column> columnFlow;
protected override Container<Drawable> Content => content;
private readonly Container<Drawable> content;
public Container<DrawableManiaJudgement> Judgements => judgements;
private readonly Container<DrawableManiaJudgement> judgements;
private readonly Container topLevelContainer;
private List<Color4> normalColumnColours = new List<Color4>();
private Color4 specialColumnColour;
private readonly int firstColumnIndex;
private readonly StageDefinition definition;
public ManiaStage(int firstColumnIndex, StageDefinition definition, ref ManiaAction normalColumnStartAction, ref ManiaAction specialColumnStartAction)
: base(ScrollingDirection.Up)
{
this.firstColumnIndex = firstColumnIndex;
this.definition = definition;
Name = "Stage";
Anchor = Anchor.Centre;
Origin = Anchor.Centre;
RelativeSizeAxes = Axes.Y;
AutoSizeAxes = Axes.X;
InternalChildren = new Drawable[]
{
new Container
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
RelativeSizeAxes = Axes.Y,
AutoSizeAxes = Axes.X,
Children = new Drawable[]
{
new Container
{
Name = "Columns mask",
RelativeSizeAxes = Axes.Y,
AutoSizeAxes = Axes.X,
Masking = true,
Children = new Drawable[]
{
new Box
{
Name = "Background",
RelativeSizeAxes = Axes.Both,
Colour = Color4.Black
},
columnFlow = new FillFlowContainer<Column>
{
Name = "Columns",
RelativeSizeAxes = Axes.Y,
AutoSizeAxes = Axes.X,
Direction = FillDirection.Horizontal,
Padding = new MarginPadding { Left = 1, Right = 1 },
Spacing = new Vector2(1, 0)
},
}
},
new Container
{
Name = "Barlines mask",
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
RelativeSizeAxes = Axes.Y,
Width = 1366, // Bar lines should only be masked on the vertical axis
BypassAutoSizeAxes = Axes.Both,
Masking = true,
Child = content = new Container
{
Name = "Bar lines",
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
RelativeSizeAxes = Axes.Y,
Padding = new MarginPadding { Top = HIT_TARGET_POSITION }
}
},
judgements = new Container<DrawableManiaJudgement>
{
Anchor = Anchor.TopCentre,
Origin = Anchor.Centre,
AutoSizeAxes = Axes.Both,
Y = HIT_TARGET_POSITION + 150,
BypassAutoSizeAxes = Axes.Both
},
topLevelContainer = new Container { RelativeSizeAxes = Axes.Both }
}
}
};
for (int i = 0; i < definition.Columns; i++)
{
var isSpecial = isSpecialColumn(i);
var column = new Column
{
IsSpecial = isSpecial,
Action = isSpecial ? specialColumnStartAction++ : normalColumnStartAction++
};
AddColumn(column);
}
Inverted.ValueChanged += invertedChanged;
Inverted.TriggerChange();
}
private void invertedChanged(bool newValue)
{
Scale = new Vector2(1, newValue ? -1 : 1);
Judgements.Scale = Scale;
}
public void AddColumn(Column c)
{
c.VisibleTimeRange.BindTo(VisibleTimeRange);
topLevelContainer.Add(c.TopLevelContainer.CreateProxy());
columnFlow.Add(c);
AddNested(c);
}
/// <summary>
/// Whether the column index is a special column for this playfield.
/// </summary>
/// <param name="column">The 0-based column index.</param>
/// <returns>Whether the column is a special column.</returns>
private bool isSpecialColumn(int column) => definition.Columns % 2 == 1 && column == definition.Columns / 2;
public override void Add(DrawableHitObject h)
{
var maniaObject = (ManiaHitObject)h.HitObject;
int columnIndex = maniaObject.Column - firstColumnIndex;
Columns.ElementAt(columnIndex).Add(h);
h.OnJudgement += OnJudgement;
}
public void Add(BarLine barline) => base.Add(new DrawableBarLine(barline));
internal void OnJudgement(DrawableHitObject judgedObject, Judgement judgement)
{
judgements.Clear();
judgements.Add(new DrawableManiaJudgement(judgement)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
});
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
normalColumnColours = new List<Color4>
{
colours.RedDark,
colours.GreenDark
};
specialColumnColour = colours.BlueDark;
// Set the special column + colour + key
foreach (var column in Columns)
{
if (!column.IsSpecial)
continue;
column.AccentColour = specialColumnColour;
}
var nonSpecialColumns = Columns.Where(c => !c.IsSpecial).ToList();
// We'll set the colours of the non-special columns in a separate loop, because the non-special
// column colours are mirrored across their centre and special styles mess with this
for (int i = 0; i < Math.Ceiling(nonSpecialColumns.Count / 2f); i++)
{
Color4 colour = normalColumnColours[i % normalColumnColours.Count];
nonSpecialColumns[i].AccentColour = colour;
nonSpecialColumns[nonSpecialColumns.Count - 1 - i].AccentColour = colour;
}
}
protected override void Update()
{
// Due to masking differences, it is not possible to get the width of the columns container automatically
// While masking on effectively only the Y-axis, so we need to set the width of the bar line container manually
content.Width = columnFlow.Width;
}
}
}

View File

@ -1,21 +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
namespace osu.Game.Rulesets.Mania.UI
{
public enum SpecialColumnPosition
{
/// <summary>
/// The special column will lie in the center of the columns.
/// </summary>
Normal,
/// <summary>
/// The special column will lie to the left of the columns.
/// </summary>
Left,
/// <summary>
/// The special column will lie to the right of the columns.
/// </summary>
Right
}
}

View File

@ -64,6 +64,7 @@
<Compile Include="Judgements\HoldNoteTickJudgement.cs" /> <Compile Include="Judgements\HoldNoteTickJudgement.cs" />
<Compile Include="Judgements\ManiaJudgement.cs" /> <Compile Include="Judgements\ManiaJudgement.cs" />
<Compile Include="ManiaDifficultyCalculator.cs" /> <Compile Include="ManiaDifficultyCalculator.cs" />
<Compile Include="Mods\IPlayfieldTypeMod.cs" />
<Compile Include="Mods\ManiaKeyMod.cs" /> <Compile Include="Mods\ManiaKeyMod.cs" />
<Compile Include="Mods\ManiaModAutoplay.cs" /> <Compile Include="Mods\ManiaModAutoplay.cs" />
<Compile Include="Mods\ManiaModDaycore.cs" /> <Compile Include="Mods\ManiaModDaycore.cs" />
@ -83,7 +84,7 @@
<Compile Include="Mods\ManiaModKey7.cs" /> <Compile Include="Mods\ManiaModKey7.cs" />
<Compile Include="Mods\ManiaModKey8.cs" /> <Compile Include="Mods\ManiaModKey8.cs" />
<Compile Include="Mods\ManiaModKey9.cs" /> <Compile Include="Mods\ManiaModKey9.cs" />
<Compile Include="Mods\ManiaModKeyCoop.cs" /> <Compile Include="Mods\ManiaModDualStages.cs" />
<Compile Include="Mods\ManiaModNightcore.cs" /> <Compile Include="Mods\ManiaModNightcore.cs" />
<Compile Include="Mods\ManiaModPerfect.cs" /> <Compile Include="Mods\ManiaModPerfect.cs" />
<Compile Include="Mods\ManiaModRandom.cs" /> <Compile Include="Mods\ManiaModRandom.cs" />
@ -115,12 +116,12 @@
<Compile Include="Tests\TestCasePerformancePoints.cs" /> <Compile Include="Tests\TestCasePerformancePoints.cs" />
<Compile Include="UI\Column.cs" /> <Compile Include="UI\Column.cs" />
<Compile Include="UI\DrawableManiaJudgement.cs" /> <Compile Include="UI\DrawableManiaJudgement.cs" />
<Compile Include="UI\ManiaStage.cs" />
<Compile Include="UI\HitExplosion.cs" /> <Compile Include="UI\HitExplosion.cs" />
<Compile Include="UI\ManiaRulesetContainer.cs" /> <Compile Include="UI\ManiaRulesetContainer.cs" />
<Compile Include="UI\ManiaPlayfield.cs" /> <Compile Include="UI\ManiaPlayfield.cs" />
<Compile Include="ManiaRuleset.cs" /> <Compile Include="ManiaRuleset.cs" />
<Compile Include="Mods\ManiaModNoFail.cs" /> <Compile Include="Mods\ManiaModNoFail.cs" />
<Compile Include="UI\SpecialColumnPosition.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="app.config" /> <None Include="app.config" />

View File

@ -23,7 +23,7 @@ namespace osu.Game.Input.Bindings
private KeyBindingStore store; private KeyBindingStore store;
public override IEnumerable<KeyBinding> DefaultKeyBindings => ruleset.CreateInstance().GetDefaultKeyBindings(); public override IEnumerable<KeyBinding> DefaultKeyBindings => ruleset.CreateInstance().GetDefaultKeyBindings(variant ?? 0);
/// <summary> /// <summary>
/// Create a new instance. /// Create a new instance.

View File

@ -1,7 +1,6 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Collections.Generic; using System.Collections.Generic;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
@ -36,8 +35,7 @@ namespace osu.Game.Rulesets.UI
/// <param name="customWidth">Whether we want our internal coordinate system to be scaled to a specified width.</param> /// <param name="customWidth">Whether we want our internal coordinate system to be scaled to a specified width.</param>
protected Playfield(float? customWidth = null) protected Playfield(float? customWidth = null)
{ {
// Default height since we force relative size axes RelativeSizeAxes = Axes.Both;
Size = Vector2.One;
AddInternal(ScaledContent = new ScaledContainer AddInternal(ScaledContent = new ScaledContainer
{ {
@ -62,12 +60,6 @@ namespace osu.Game.Rulesets.UI
Add(HitObjects); Add(HitObjects);
} }
public override Axes RelativeSizeAxes
{
get { return Axes.Both; }
set { throw new InvalidOperationException($@"{nameof(Playfield)}'s {nameof(RelativeSizeAxes)} should never be changed from {Axes.Both}"); }
}
/// <summary> /// <summary>
/// Performs post-processing tasks (if any) after all DrawableHitObjects are loaded into this Playfield. /// Performs post-processing tasks (if any) after all DrawableHitObjects are loaded into this Playfield.
/// </summary> /// </summary>

View File

@ -154,7 +154,7 @@ namespace osu.Game.Rulesets.UI
/// <summary> /// <summary>
/// Whether the specified beatmap is assumed to be specific to the current ruleset. /// Whether the specified beatmap is assumed to be specific to the current ruleset.
/// </summary> /// </summary>
protected readonly bool IsForCurrentRuleset; public readonly bool IsForCurrentRuleset;
public override ScoreProcessor CreateScoreProcessor() => new ScoreProcessor<TObject>(this); public override ScoreProcessor CreateScoreProcessor() => new ScoreProcessor<TObject>(this);