1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-11 13:37:25 +08:00

Merge branch 'master' into note-placement

This commit is contained in:
Dan Balasescu 2018-11-19 19:08:53 +09:00 committed by GitHub
commit 8cee4141e8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
53 changed files with 877 additions and 227 deletions

@ -1 +1 @@
Subproject commit 651e598b016b43e31ab1c1b29d5b30c92361b8d9
Subproject commit 694cb03f19c93106ed0f2593f3e506e835fb652a

View File

@ -1,12 +1,66 @@
// 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.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Catch.UI;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.UI;
using OpenTK;
namespace osu.Game.Rulesets.Catch.Mods
{
public class CatchModFlashlight : ModFlashlight
public class CatchModFlashlight : ModFlashlight<CatchHitObject>
{
public override double ScoreMultiplier => 1.12;
private const float default_flashlight_size = 350;
public override Flashlight CreateFlashlight() => new CatchFlashlight(playfield);
private CatchPlayfield playfield;
public override void ApplyToRulesetContainer(RulesetContainer<CatchHitObject> rulesetContainer)
{
playfield = (CatchPlayfield)rulesetContainer.Playfield;
base.ApplyToRulesetContainer(rulesetContainer);
}
private class CatchFlashlight : Flashlight
{
private readonly CatchPlayfield playfield;
public CatchFlashlight(CatchPlayfield playfield)
{
this.playfield = playfield;
FlashlightSize = new Vector2(0, getSizeFor(0));
}
protected override void Update()
{
base.Update();
var catcherArea = playfield.CatcherArea;
FlashlightPosition = catcherArea.ToSpaceOfOtherDrawable(catcherArea.MovableCatcher.DrawPosition, this);
}
private float getSizeFor(int combo)
{
if (combo > 200)
return default_flashlight_size * 0.8f;
else if (combo > 100)
return default_flashlight_size * 0.9f;
else
return default_flashlight_size;
}
protected override void OnComboChange(int newCombo)
{
this.TransformTo(nameof(FlashlightSize), new Vector2(0, getSizeFor(newCombo)), FLASHLIGHT_FADE_DURATION);
}
protected override string FragmentShader => "CircularFlashlight";
}
}
}

View File

@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Catch.UI
{
public const float BASE_WIDTH = 512;
private readonly CatcherArea catcherArea;
internal readonly CatcherArea CatcherArea;
public CatchPlayfield(BeatmapDifficulty difficulty, Func<CatchHitObject, DrawableHitObject<CatchHitObject>> getVisualRepresentation)
{
@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Catch.UI
{
RelativeSizeAxes = Axes.Both,
},
catcherArea = new CatcherArea(difficulty)
CatcherArea = new CatcherArea(difficulty)
{
GetVisualRepresentation = getVisualRepresentation,
ExplodingFruitTarget = explodingFruitContainer,
@ -50,7 +50,7 @@ namespace osu.Game.Rulesets.Catch.UI
};
}
public bool CheckIfWeCanCatch(CatchHitObject obj) => catcherArea.AttemptCatch(obj);
public bool CheckIfWeCanCatch(CatchHitObject obj) => CatcherArea.AttemptCatch(obj);
public override void Add(DrawableHitObject h)
{
@ -63,6 +63,6 @@ namespace osu.Game.Rulesets.Catch.UI
}
private void onNewResult(DrawableHitObject judgedObject, JudgementResult result)
=> catcherArea.OnResult((DrawableCatchHitObject)judgedObject, result);
=> CatcherArea.OnResult((DrawableCatchHitObject)judgedObject, result);
}
}

View File

@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Catch.UI
{
public const float CATCHER_SIZE = 100;
protected readonly Catcher MovableCatcher;
protected internal readonly Catcher MovableCatcher;
public Func<CatchHitObject, DrawableHitObject<CatchHitObject>> GetVisualRepresentation;

View File

@ -3,6 +3,7 @@
using System;
using osu.Game.Graphics;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Mania.Mods
@ -16,6 +17,6 @@ namespace osu.Game.Rulesets.Mania.Mods
public override string Description => @"Keys appear out of nowhere!";
public override double ScoreMultiplier => 1;
public override bool Ranked => true;
public override Type[] IncompatibleMods => new[] { typeof(ModFlashlight) };
public override Type[] IncompatibleMods => new[] { typeof(ModFlashlight<ManiaHitObject>) };
}
}

View File

@ -2,13 +2,60 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Framework.Caching;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mods;
using OpenTK;
namespace osu.Game.Rulesets.Mania.Mods
{
public class ManiaModFlashlight : ModFlashlight
public class ManiaModFlashlight : ModFlashlight<ManiaHitObject>
{
public override double ScoreMultiplier => 1;
public override Type[] IncompatibleMods => new[] { typeof(ModHidden) };
private const float default_flashlight_size = 180;
public override Flashlight CreateFlashlight() => new ManiaFlashlight();
private class ManiaFlashlight : Flashlight
{
private readonly Cached flashlightProperties = new Cached();
public ManiaFlashlight()
{
FlashlightSize = new Vector2(0, default_flashlight_size);
}
public override bool Invalidate(Invalidation invalidation = Invalidation.All, Drawable source = null, bool shallPropagate = true)
{
if ((invalidation & Invalidation.DrawSize) > 0)
{
flashlightProperties.Invalidate();
}
return base.Invalidate(invalidation, source, shallPropagate);
}
protected override void Update()
{
base.Update();
if (!flashlightProperties.IsValid)
{
FlashlightSize = new Vector2(DrawWidth, FlashlightSize.Y);
FlashlightPosition = DrawPosition + DrawSize / 2;
flashlightProperties.Validate();
}
}
protected override void OnComboChange(int newCombo)
{
}
protected override string FragmentShader => "RectangularFlashlight";
}
}
}

View File

@ -2,6 +2,7 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Mania.Mods
@ -10,6 +11,6 @@ namespace osu.Game.Rulesets.Mania.Mods
{
public override string Description => @"Keys fade out before you hit them!";
public override double ScoreMultiplier => 1;
public override Type[] IncompatibleMods => new[] { typeof(ModFlashlight) };
public override Type[] IncompatibleMods => new[] { typeof(ModFlashlight<ManiaHitObject>) };
}
}

View File

@ -3,7 +3,6 @@
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
@ -11,11 +10,12 @@ using OpenTK;
namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components
{
public class HitCirclePiece : CompositeDrawable
public class HitCirclePiece : HitObjectPiece
{
private readonly HitCircle hitCircle;
public HitCirclePiece(HitCircle hitCircle)
: base(hitCircle)
{
this.hitCircle = hitCircle;
Origin = Anchor.Centre;
@ -25,10 +25,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components
CornerRadius = Size.X / 2;
InternalChild = new RingPiece();
hitCircle.PositionChanged += _ => UpdatePosition();
hitCircle.StackHeightChanged += _ => UpdatePosition();
hitCircle.ScaleChanged += _ => Scale = new Vector2(hitCircle.Scale);
}
[BackgroundDependencyLoader]
@ -36,7 +32,9 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components
{
Colour = colours.Yellow;
UpdatePosition();
PositionBindable.BindValueChanged(_ => UpdatePosition(), true);
StackHeightBindable.BindValueChanged(_ => UpdatePosition());
ScaleBindable.BindValueChanged(v => Scale = new Vector2(v), true);
}
protected virtual void UpdatePosition() => Position = hitCircle.StackedPosition;

View File

@ -0,0 +1,36 @@
// 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.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Osu.Objects;
using OpenTK;
namespace osu.Game.Rulesets.Osu.Edit.Blueprints
{
/// <summary>
/// A piece of a blueprint which responds to changes in the state of a <see cref="OsuHitObject"/>.
/// </summary>
public abstract class HitObjectPiece : CompositeDrawable
{
protected readonly IBindable<Vector2> PositionBindable = new Bindable<Vector2>();
protected readonly IBindable<int> StackHeightBindable = new Bindable<int>();
protected readonly IBindable<float> ScaleBindable = new Bindable<float>();
private readonly OsuHitObject hitObject;
protected HitObjectPiece(OsuHitObject hitObject)
{
this.hitObject = hitObject;
}
[BackgroundDependencyLoader]
private void load()
{
PositionBindable.BindTo(hitObject.PositionBindable);
StackHeightBindable.BindTo(hitObject.StackHeightBindable);
ScaleBindable.BindTo(hitObject.ScaleBindable);
}
}
}

View File

@ -0,0 +1,32 @@
// 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.Allocation;
using osu.Framework.Configuration;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Osu.Objects;
namespace osu.Game.Rulesets.Osu.Edit.Blueprints
{
/// <summary>
/// A piece of a blueprint which responds to changes in the state of a <see cref="Slider"/>.
/// </summary>
public abstract class SliderPiece : HitObjectPiece
{
protected readonly IBindable<SliderPath> PathBindable = new Bindable<SliderPath>();
private readonly Slider slider;
protected SliderPiece(Slider slider)
: base(slider)
{
this.slider = slider;
}
[BackgroundDependencyLoader]
private void load()
{
PathBindable.BindTo(slider.PathBindable);
}
}
}

View File

@ -1,26 +1,31 @@
// 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.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Osu.Objects;
namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
{
public class PathControlPointVisualiser : CompositeDrawable
public class PathControlPointVisualiser : SliderPiece
{
private readonly Slider slider;
private readonly Container<PathControlPointPiece> pieces;
public PathControlPointVisualiser(Slider slider)
: base(slider)
{
this.slider = slider;
InternalChild = pieces = new Container<PathControlPointPiece> { RelativeSizeAxes = Axes.Both };
}
slider.PathChanged += _ => updatePathControlPoints();
updatePathControlPoints();
[BackgroundDependencyLoader]
private void load()
{
PathBindable.BindValueChanged(_ => updatePathControlPoints(), true);
}
private void updatePathControlPoints()

View File

@ -3,7 +3,6 @@
using System.Collections.Generic;
using osu.Framework.Allocation;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
@ -12,12 +11,13 @@ using OpenTK.Graphics;
namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
{
public class SliderBodyPiece : CompositeDrawable
public class SliderBodyPiece : SliderPiece
{
private readonly Slider slider;
private readonly ManualSliderBody body;
public SliderBodyPiece(Slider slider)
: base(slider)
{
this.slider = slider;
@ -26,9 +26,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
AccentColour = Color4.Transparent,
PathWidth = slider.Scale * 64
};
slider.PositionChanged += _ => updatePosition();
slider.ScaleChanged += _ => body.PathWidth = slider.Scale * 64;
}
[BackgroundDependencyLoader]
@ -36,7 +33,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
{
body.BorderColour = colours.Yellow;
updatePosition();
PositionBindable.BindValueChanged(_ => updatePosition(), true);
ScaleBindable.BindValueChanged(v => body.PathWidth = v * 64, true);
}
private void updatePosition() => Position = slider.StackedPosition;

View File

@ -1,6 +1,9 @@
// 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.Allocation;
using osu.Framework.Configuration;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components;
using osu.Game.Rulesets.Osu.Objects;
@ -8,6 +11,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
{
public class SliderCirclePiece : HitCirclePiece
{
private readonly IBindable<SliderPath> pathBindable = new Bindable<SliderPath>();
private readonly Slider slider;
private readonly SliderPosition position;
@ -16,8 +21,13 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
{
this.slider = slider;
this.position = position;
}
slider.PathChanged += _ => UpdatePosition();
[BackgroundDependencyLoader]
private void load()
{
pathBindable.BindTo(slider.PathBindable);
pathBindable.BindValueChanged(_ => UpdatePosition(), true);
}
protected override void UpdatePosition()

View File

@ -12,12 +12,14 @@ using OpenTK;
namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners.Components
{
public class SpinnerPiece : CompositeDrawable
public class SpinnerPiece : HitObjectPiece
{
private readonly Spinner spinner;
private readonly CircularContainer circle;
private readonly RingPiece ring;
public SpinnerPiece(Spinner spinner)
: base(spinner)
{
this.spinner = spinner;
@ -27,7 +29,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners.Components
FillMode = FillMode.Fit;
Size = new Vector2(1.3f);
RingPiece ring;
InternalChildren = new Drawable[]
{
circle = new CircularContainer
@ -45,18 +46,16 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners.Components
};
ring.Scale = new Vector2(spinner.Scale);
spinner.PositionChanged += _ => updatePosition();
spinner.StackHeightChanged += _ => updatePosition();
spinner.ScaleChanged += _ => ring.Scale = new Vector2(spinner.Scale);
updatePosition();
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
Colour = colours.Yellow;
PositionBindable.BindValueChanged(_ => updatePosition(), true);
StackHeightBindable.BindValueChanged(_ => updatePosition());
ScaleBindable.BindValueChanged(v => ring.Scale = new Vector2(v), true);
}
private void updatePosition() => Position = spinner.Position;

View File

@ -37,6 +37,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners
isPlacingEnd = true;
piece.FadeTo(1f, 150, Easing.OutQuint);
BeginPlacement();
}
return true;

View File

@ -1,12 +1,52 @@
// 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.Input;
using osu.Framework.Input.Events;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Objects;
using OpenTK;
namespace osu.Game.Rulesets.Osu.Mods
{
public class OsuModFlashlight : ModFlashlight
public class OsuModFlashlight : ModFlashlight<OsuHitObject>
{
public override double ScoreMultiplier => 1.12;
private const float default_flashlight_size = 180;
public override Flashlight CreateFlashlight() => new OsuFlashlight();
private class OsuFlashlight : Flashlight, IRequireHighFrequencyMousePosition
{
public OsuFlashlight()
{
FlashlightSize = new Vector2(0, getSizeFor(0));
}
protected override bool OnMouseMove(MouseMoveEvent e)
{
FlashlightPosition = e.MousePosition;
return base.OnMouseMove(e);
}
private float getSizeFor(int combo)
{
if (combo > 200)
return default_flashlight_size * 0.8f;
else if (combo > 100)
return default_flashlight_size * 0.9f;
else
return default_flashlight_size;
}
protected override void OnComboChange(int newCombo)
{
this.TransformTo(nameof(FlashlightSize), new Vector2(0, getSizeFor(newCombo)), FLASHLIGHT_FADE_DURATION);
}
protected override string FragmentShader => "CircularFlashlight";
}
}
}

View File

@ -2,6 +2,8 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
@ -21,6 +23,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
private readonly NumberPiece number;
private readonly GlowPiece glow;
private readonly IBindable<Vector2> positionBindable = new Bindable<Vector2>();
private readonly IBindable<int> stackHeightBindable = new Bindable<int>();
private readonly IBindable<float> scaleBindable = new Bindable<float>();
public DrawableHitCircle(HitCircle h)
: base(h)
{
@ -59,10 +65,18 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
//may not be so correct
Size = circle.DrawSize;
}
HitObject.PositionChanged += _ => Position = HitObject.StackedPosition;
HitObject.StackHeightChanged += _ => Position = HitObject.StackedPosition;
HitObject.ScaleChanged += s => Scale = new Vector2(s);
[BackgroundDependencyLoader]
private void load()
{
positionBindable.BindValueChanged(_ => Position = HitObject.StackedPosition);
stackHeightBindable.BindValueChanged(_ => Position = HitObject.StackedPosition);
scaleBindable.BindValueChanged(v => Scale = new Vector2(v));
positionBindable.BindTo(HitObject.PositionBindable);
stackHeightBindable.BindTo(HitObject.StackHeightBindable);
scaleBindable.BindTo(HitObject.ScaleBindable);
}
public override Color4 AccentColour

View File

@ -8,8 +8,10 @@ using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Graphics.Containers;
using osu.Game.Configuration;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Scoring;
using OpenTK.Graphics;
@ -26,6 +28,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
public readonly SnakingSliderBody Body;
public readonly SliderBall Ball;
private readonly IBindable<Vector2> positionBindable = new Bindable<Vector2>();
private readonly IBindable<float> scaleBindable = new Bindable<float>();
private readonly IBindable<SliderPath> pathBindable = new Bindable<SliderPath>();
public DrawableSlider(Slider s)
: base(s)
{
@ -83,15 +89,26 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
components.Add(drawableRepeatPoint);
AddNested(drawableRepeatPoint);
}
}
HitObject.PositionChanged += _ => Position = HitObject.StackedPosition;
HitObject.ScaleChanged += _ =>
[BackgroundDependencyLoader]
private void load(OsuConfigManager config)
{
config.BindWith(OsuSetting.SnakingInSliders, Body.SnakingIn);
config.BindWith(OsuSetting.SnakingOutSliders, Body.SnakingOut);
positionBindable.BindValueChanged(_ => Position = HitObject.StackedPosition);
scaleBindable.BindValueChanged(v =>
{
Body.PathWidth = HitObject.Scale * 64;
Ball.Scale = new Vector2(HitObject.Scale);
};
});
slider.PathChanged += _ => Body.Refresh();
positionBindable.BindTo(HitObject.PositionBindable);
scaleBindable.BindTo(HitObject.ScaleBindable);
pathBindable.BindTo(slider.PathBindable);
pathBindable.BindValueChanged(_ => Body.Refresh());
}
public override Color4 AccentColour
@ -108,13 +125,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
}
}
[BackgroundDependencyLoader]
private void load(OsuConfigManager config)
{
config.BindWith(OsuSetting.SnakingInSliders, Body.SnakingIn);
config.BindWith(OsuSetting.SnakingOutSliders, Body.SnakingOut);
}
public bool Tracking;
protected override void Update()

View File

@ -2,6 +2,9 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types;
using OpenTK;
@ -9,17 +12,25 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
{
public class DrawableSliderHead : DrawableHitCircle
{
private readonly IBindable<Vector2> positionBindable = new Bindable<Vector2>();
private readonly IBindable<SliderPath> pathBindable = new Bindable<SliderPath>();
private readonly Slider slider;
public DrawableSliderHead(Slider slider, HitCircle h)
: base(h)
{
this.slider = slider;
}
h.PositionChanged += _ => updatePosition();
slider.PathChanged += _ => updatePosition();
[BackgroundDependencyLoader]
private void load()
{
positionBindable.BindTo(HitObject.PositionBindable);
pathBindable.BindTo(slider.PathBindable);
updatePosition();
positionBindable.BindValueChanged(_ => updatePosition());
pathBindable.BindValueChanged(_ => updatePosition(), true);
}
protected override void Update()

View File

@ -1,8 +1,11 @@
// 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.Configuration;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Scoring;
using OpenTK;
namespace osu.Game.Rulesets.Osu.Objects.Drawables
{
@ -17,6 +20,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
public bool Tracking { get; set; }
private readonly IBindable<Vector2> positionBindable = new Bindable<Vector2>();
private readonly IBindable<SliderPath> pathBindable = new Bindable<SliderPath>();
public DrawableSliderTail(Slider slider, SliderTailCircle hitCircle)
: base(hitCircle)
{
@ -29,10 +35,11 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
AlwaysPresent = true;
hitCircle.PositionChanged += _ => updatePosition();
slider.PathChanged += _ => updatePosition();
positionBindable.BindTo(hitCircle.PositionBindable);
pathBindable.BindTo(slider.PathBindable);
updatePosition();
positionBindable.BindValueChanged(_ => updatePosition());
pathBindable.BindValueChanged(_ => updatePosition(), true);
}
protected override void CheckForResult(bool userTriggered, double timeOffset)

View File

@ -11,6 +11,7 @@ using OpenTK.Graphics;
using osu.Game.Graphics;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Game.Screens.Ranking;
using osu.Game.Rulesets.Scoring;
@ -36,6 +37,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
private readonly Color4 baseColour = OsuColour.FromHex(@"002c3c");
private readonly Color4 fillColour = OsuColour.FromHex(@"005b7c");
private readonly IBindable<Vector2> positionBindable = new Bindable<Vector2>();
private Color4 normalColour;
private Color4 completeColour;
@ -112,8 +115,23 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
Alpha = 0
}
};
}
s.PositionChanged += _ => Position = s.Position;
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
normalColour = baseColour;
Background.AccentColour = normalColour;
completeColour = colours.YellowLight.Opacity(0.75f);
Disc.AccentColour = fillColour;
circle.Colour = colours.BlueDark;
glow.Colour = colours.BlueDark;
positionBindable.BindValueChanged(v => Position = v);
positionBindable.BindTo(HitObject.PositionBindable);
}
public float Progress => MathHelper.Clamp(Disc.RotationAbsolute / 360 / Spinner.SpinsRequired, 0, 1);
@ -153,20 +171,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
});
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
normalColour = baseColour;
Background.AccentColour = normalColour;
completeColour = colours.YellowLight.Opacity(0.75f);
Disc.AccentColour = fillColour;
circle.Colour = colours.BlueDark;
glow.Colour = colours.BlueDark;
}
protected override void Update()
{
Disc.Tracking = OsuActionInputManager?.PressedActions.Any(x => x == OsuAction.LeftButton || x == OsuAction.RightButton) ?? false;

View File

@ -1,7 +1,7 @@
// 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.Configuration;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Objects;
using OpenTK;
@ -14,26 +14,15 @@ namespace osu.Game.Rulesets.Osu.Objects
{
public const double OBJECT_RADIUS = 64;
public event Action<Vector2> PositionChanged;
public event Action<int> StackHeightChanged;
public event Action<float> ScaleChanged;
public double TimePreempt = 600;
public double TimeFadeIn = 400;
private Vector2 position;
public readonly Bindable<Vector2> PositionBindable = new Bindable<Vector2>();
public virtual Vector2 Position
{
get => position;
set
{
if (position == value)
return;
position = value;
PositionChanged?.Invoke(value);
}
get => PositionBindable;
set => PositionBindable.Value = value;
}
public float X => Position.X;
@ -45,38 +34,24 @@ namespace osu.Game.Rulesets.Osu.Objects
public Vector2 StackedEndPosition => EndPosition + StackOffset;
private int stackHeight;
public readonly Bindable<int> StackHeightBindable = new Bindable<int>();
public int StackHeight
{
get => stackHeight;
set
{
if (stackHeight == value)
return;
stackHeight = value;
StackHeightChanged?.Invoke(value);
}
get => StackHeightBindable;
set => StackHeightBindable.Value = value;
}
public Vector2 StackOffset => new Vector2(StackHeight * Scale * -6.4f);
public double Radius => OBJECT_RADIUS * Scale;
private float scale = 1;
public readonly Bindable<float> ScaleBindable = new Bindable<float>(1);
public float Scale
{
get => scale;
set
{
if (scale == value)
return;
scale = value;
ScaleChanged?.Invoke(value);
}
get => ScaleBindable;
set => ScaleBindable.Value = value;
}
public virtual bool NewCombo { get; set; }

View File

@ -7,6 +7,7 @@ using osu.Game.Rulesets.Objects.Types;
using System.Collections.Generic;
using osu.Game.Rulesets.Objects;
using System.Linq;
using osu.Framework.Configuration;
using osu.Game.Audio;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
@ -22,8 +23,6 @@ namespace osu.Game.Rulesets.Osu.Objects
/// </summary>
private const float base_scoring_distance = 100;
public event Action<SliderPath> PathChanged;
public double EndTime => StartTime + this.SpanCount() * Path.Distance / Velocity;
public double Duration => EndTime - StartTime;
@ -52,20 +51,12 @@ namespace osu.Game.Rulesets.Osu.Objects
}
}
private SliderPath path;
public readonly Bindable<SliderPath> PathBindable = new Bindable<SliderPath>();
public SliderPath Path
{
get => path;
set
{
path = value;
PathChanged?.Invoke(value);
if (TailCircle != null)
TailCircle.Position = EndPosition;
}
get => PathBindable.Value;
set => PathBindable.Value = value;
}
public double Distance => Path.Distance;
@ -164,7 +155,7 @@ namespace osu.Game.Rulesets.Osu.Objects
ComboIndex = ComboIndex,
};
TailCircle = new SliderTailCircle
TailCircle = new SliderTailCircle(this)
{
StartTime = EndTime,
Position = EndPosition,

View File

@ -1,13 +1,23 @@
// 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.Configuration;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Osu.Judgements;
namespace osu.Game.Rulesets.Osu.Objects
{
public class SliderTailCircle : SliderCircle
{
private readonly IBindable<SliderPath> pathBindable = new Bindable<SliderPath>();
public SliderTailCircle(Slider slider)
{
pathBindable.BindTo(slider.PathBindable);
pathBindable.BindValueChanged(_ => Position = slider.EndPosition);
}
public override Judgement CreateJudgement() => new OsuSliderTailJudgement();
}
}

View File

@ -84,5 +84,7 @@ namespace osu.Game.Rulesets.Osu.UI
judgementLayer.Add(explosion);
}
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => HitObjectContainer.ReceivePositionalInputAt(screenSpacePos);
}
}

View File

@ -8,6 +8,7 @@ using osu.Game.Beatmaps;
using osu.Game.Rulesets.Difficulty;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.Taiko.Objects;
namespace osu.Game.Rulesets.Taiko.Difficulty
{
@ -82,7 +83,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
if (mods.Any(m => m is ModHidden))
strainValue *= 1.025;
if (mods.Any(m => m is ModFlashlight))
if (mods.Any(m => m is ModFlashlight<TaikoHitObject>))
// Apply length bonus again if flashlight is on simply because it becomes a lot harder on longer maps.
strainValue *= 1.05 * lengthBonus;

View File

@ -1,12 +1,80 @@
// 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.Caching;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Taiko.Objects;
using osu.Game.Rulesets.Taiko.UI;
using osu.Game.Rulesets.UI;
using OpenTK;
namespace osu.Game.Rulesets.Taiko.Mods
{
public class TaikoModFlashlight : ModFlashlight
public class TaikoModFlashlight : ModFlashlight<TaikoHitObject>
{
public override double ScoreMultiplier => 1.12;
private const float default_flashlight_size = 250;
public override Flashlight CreateFlashlight() => new TaikoFlashlight(playfield);
private TaikoPlayfield playfield;
public override void ApplyToRulesetContainer(RulesetContainer<TaikoHitObject> rulesetContainer)
{
playfield = (TaikoPlayfield)rulesetContainer.Playfield;
base.ApplyToRulesetContainer(rulesetContainer);
}
private class TaikoFlashlight : Flashlight
{
private readonly Cached flashlightProperties = new Cached();
private readonly TaikoPlayfield taikoPlayfield;
public TaikoFlashlight(TaikoPlayfield taikoPlayfield)
{
this.taikoPlayfield = taikoPlayfield;
FlashlightSize = new Vector2(0, getSizeFor(0));
}
private float getSizeFor(int combo)
{
if (combo > 200)
return default_flashlight_size * 0.8f;
else if (combo > 100)
return default_flashlight_size * 0.9f;
else
return default_flashlight_size;
}
protected override void OnComboChange(int newCombo)
{
this.TransformTo(nameof(FlashlightSize), new Vector2(0, getSizeFor(newCombo)), FLASHLIGHT_FADE_DURATION);
}
protected override string FragmentShader => "CircularFlashlight";
public override bool Invalidate(Invalidation invalidation = Invalidation.All, Drawable source = null, bool shallPropagate = true)
{
if ((invalidation & Invalidation.DrawSize) > 0)
{
flashlightProperties.Invalidate();
}
return base.Invalidate(invalidation, source, shallPropagate);
}
protected override void Update()
{
base.Update();
if (!flashlightProperties.IsValid)
{
FlashlightPosition = taikoPlayfield.HitTarget.ToSpaceOfOtherDrawable(taikoPlayfield.HitTarget.OriginPosition, this);
flashlightProperties.Validate();
}
}
}
}
}

View File

@ -41,6 +41,7 @@ namespace osu.Game.Rulesets.Taiko.UI
private readonly Container<HitExplosion> hitExplosionContainer;
private readonly Container<KiaiHitExplosion> kiaiExplosionContainer;
private readonly JudgementContainer<DrawableTaikoJudgement> judgementContainer;
internal readonly HitTarget HitTarget;
private readonly Container topLevelHitContainer;
@ -102,7 +103,7 @@ namespace osu.Game.Rulesets.Taiko.UI
FillMode = FillMode.Fit,
Blending = BlendingMode.Additive,
},
new HitTarget
HitTarget = new HitTarget
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.Centre,

View File

@ -13,25 +13,25 @@ using OpenTK.Input;
namespace osu.Game.Tests.Visual
{
[Description("'Hold to Quit' UI element")]
public class TestCaseQuitButton : ManualInputManagerTestCase
public class TestCaseHoldForMenuButton : ManualInputManagerTestCase
{
private bool exitAction;
[BackgroundDependencyLoader]
private void load()
{
QuitButton quitButton;
HoldForMenuButton holdForMenuButton;
Add(quitButton = new QuitButton
Add(holdForMenuButton = new HoldForMenuButton
{
Origin = Anchor.BottomRight,
Anchor = Anchor.BottomRight,
Action = () => exitAction = true
});
var text = quitButton.Children.OfType<SpriteText>().First();
var text = holdForMenuButton.Children.OfType<SpriteText>().First();
AddStep("Trigger text fade in", () => InputManager.MoveMouseTo(quitButton));
AddStep("Trigger text fade in", () => InputManager.MoveMouseTo(holdForMenuButton));
AddUntilStep(() => text.IsPresent && !exitAction, "Text visible");
AddStep("Trigger text fade out", () => InputManager.MoveMouseTo(Vector2.One));
AddUntilStep(() => !text.IsPresent && !exitAction, "Text is not visible");
@ -39,7 +39,7 @@ namespace osu.Game.Tests.Visual
AddStep("Trigger exit action", () =>
{
exitAction = false;
InputManager.MoveMouseTo(quitButton);
InputManager.MoveMouseTo(holdForMenuButton);
InputManager.PressButton(MouseButton.Left);
});
@ -47,7 +47,7 @@ namespace osu.Game.Tests.Visual
AddAssert("action not triggered", () => !exitAction);
AddStep("Trigger exit action", () => InputManager.PressButton(MouseButton.Left));
AddUntilStep(() => exitAction, $"{nameof(quitButton.Action)} was triggered");
AddUntilStep(() => exitAction, $"{nameof(holdForMenuButton.Action)} was triggered");
}
}
}

View File

@ -2,9 +2,6 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.ComponentModel;
using System.Reflection;
using System.Collections.Generic;
namespace osu.Game.Graphics.UserInterface
{
@ -15,18 +12,7 @@ namespace osu.Game.Graphics.UserInterface
if (!typeof(T).IsEnum)
throw new InvalidOperationException("OsuEnumDropdown only supports enums as the generic type argument");
List<KeyValuePair<string, T>> items = new List<KeyValuePair<string, T>>();
foreach (var val in (T[])Enum.GetValues(typeof(T)))
{
var field = typeof(T).GetField(Enum.GetName(typeof(T), val));
items.Add(
new KeyValuePair<string, T>(
field.GetCustomAttribute<DescriptionAttribute>()?.Description ?? Enum.GetName(typeof(T), val),
val
)
);
}
Items = items;
Items = (T[])Enum.GetValues(typeof(T));
}
}
}

View File

@ -2,6 +2,7 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Framework.Allocation;
namespace osu.Game.Graphics.UserInterface
{
@ -25,6 +26,9 @@ namespace osu.Game.Graphics.UserInterface
Current.Value = DisplayedCount = 1.0f;
}
[BackgroundDependencyLoader]
private void load(OsuColour colours) => AccentColour = colours.BlueLighter;
protected override string FormatCount(double count)
{
return $@"{count:P2}";

View File

@ -1,6 +1,7 @@
// 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.Allocation;
using osu.Framework.Graphics;
namespace osu.Game.Graphics.UserInterface
@ -31,6 +32,9 @@ namespace osu.Game.Graphics.UserInterface
LeadingZeroes = leading;
}
[BackgroundDependencyLoader]
private void load(OsuColour colours) => AccentColour = colours.BlueLighter;
protected override double GetProportionalDuration(double currentValue, double newValue)
{
return currentValue > newValue ? currentValue - newValue : newValue - currentValue;

View File

@ -2,6 +2,7 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Framework.Allocation;
namespace osu.Game.Graphics.UserInterface
{
@ -17,6 +18,9 @@ namespace osu.Game.Graphics.UserInterface
Current.Value = DisplayedCount = 0;
}
[BackgroundDependencyLoader]
private void load(OsuColour colours) => AccentColour = colours.BlueLighter;
protected override string FormatCount(int count)
{
return $@"{count}x";

View File

@ -0,0 +1,41 @@
// 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.Input;
using osu.Framework.Input.Bindings;
using osu.Framework.Input.Events;
namespace osu.Game.Input
{
public class IdleTracker : Component, IKeyBindingHandler<PlatformAction>
{
private double lastInteractionTime;
public double IdleTime => Clock.CurrentTime - lastInteractionTime;
private bool updateLastInteractionTime()
{
lastInteractionTime = Clock.CurrentTime;
return false;
}
public bool OnPressed(PlatformAction action) => updateLastInteractionTime();
public bool OnReleased(PlatformAction action) => updateLastInteractionTime();
protected override bool Handle(UIEvent e)
{
switch (e)
{
case KeyDownEvent _:
case KeyUpEvent _:
case MouseDownEvent _:
case MouseUpEvent _:
case MouseMoveEvent _:
return updateLastInteractionTime();
default:
return base.Handle(e);
}
}
}
}

View File

@ -26,6 +26,7 @@ using osu.Framework.Platform;
using osu.Framework.Threading;
using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Input;
using osu.Game.Rulesets.Scoring;
using osu.Game.Overlays.Notifications;
using osu.Game.Rulesets;
@ -86,6 +87,8 @@ namespace osu.Game
public float ToolbarOffset => Toolbar.Position.Y + Toolbar.DrawHeight;
private IdleTracker idleTracker;
public readonly Bindable<OverlayActivation> OverlayActivationMode = new Bindable<OverlayActivation>();
private OsuScreen screenStack;
@ -311,6 +314,7 @@ namespace osu.Game
},
mainContent = new Container { RelativeSizeAxes = Axes.Both },
overlayContent = new Container { RelativeSizeAxes = Axes.Both, Depth = float.MinValue },
idleTracker = new IdleTracker { RelativeSizeAxes = Axes.Both }
});
loadComponentSingleFile(screenStack = new Loader(), d =>
@ -372,6 +376,7 @@ namespace osu.Game
Depth = -6,
}, overlayContent.Add);
dependencies.Cache(idleTracker);
dependencies.Cache(settings);
dependencies.Cache(onscreenDisplay);
dependencies.Cache(social);

View File

@ -1,7 +1,6 @@
// 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.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
@ -37,7 +36,7 @@ namespace osu.Game.Overlays.Music
new CollectionsDropdown<PlaylistCollection>
{
RelativeSizeAxes = Axes.X,
Items = new[] { new KeyValuePair<string, PlaylistCollection>(@"All", PlaylistCollection.All) },
Items = new[] { PlaylistCollection.All },
}
},
},

View File

@ -6,6 +6,7 @@ using osu.Framework.Audio;
using osu.Framework.Graphics;
using System.Collections.Generic;
using System.Linq;
using osu.Game.Graphics.UserInterface;
namespace osu.Game.Overlays.Settings.Sections.Audio
{
@ -35,12 +36,12 @@ namespace osu.Game.Overlays.Settings.Sections.Audio
private void updateItems()
{
var deviceItems = new List<KeyValuePair<string, string>> { new KeyValuePair<string, string>("Default", string.Empty) };
deviceItems.AddRange(audio.AudioDeviceNames.Select(d => new KeyValuePair<string, string>(d, d)));
var deviceItems = new List<string> { string.Empty };
deviceItems.AddRange(audio.AudioDeviceNames);
var preferredDeviceName = audio.AudioDevice.Value;
if (deviceItems.All(kv => kv.Value != preferredDeviceName))
deviceItems.Add(new KeyValuePair<string, string>(preferredDeviceName, preferredDeviceName));
if (deviceItems.All(kv => kv != preferredDeviceName))
deviceItems.Add(preferredDeviceName);
// The option dropdown for audio device selection lists all audio
// device names. Dropdowns, however, may not have multiple identical
@ -59,7 +60,7 @@ namespace osu.Game.Overlays.Settings.Sections.Audio
Children = new Drawable[]
{
dropdown = new SettingsDropdown<string>()
dropdown = new AudioDeviceSettingsDropdown()
};
updateItems();
@ -69,5 +70,16 @@ namespace osu.Game.Overlays.Settings.Sections.Audio
audio.OnNewDevice += onDeviceChanged;
audio.OnLostDevice += onDeviceChanged;
}
private class AudioDeviceSettingsDropdown : SettingsDropdown<string>
{
protected override OsuDropdown<string> CreateDropdown() => new AudioDeviceDropdownControl { Items = Items };
private class AudioDeviceDropdownControl : DropdownControl
{
protected override string GenerateItemText(string item)
=> string.IsNullOrEmpty(item) ? "Default" : base.GenerateItemText(item);
}
}
}
}

View File

@ -6,9 +6,9 @@ using System.Drawing;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics.UserInterface;
namespace osu.Game.Overlays.Settings.Sections.Graphics
{
@ -85,7 +85,7 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
if (resolutions.Count > 1)
{
resolutionSettingsContainer.Child = resolutionDropdown = new SettingsDropdown<Size>
resolutionSettingsContainer.Child = resolutionDropdown = new ResolutionSettingsDropdown
{
LabelText = "Resolution",
ShowsDefaultIndicator = false,
@ -115,18 +115,36 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
}, true);
}
private IReadOnlyList<KeyValuePair<string, Size>> getResolutions()
private IReadOnlyList<Size> getResolutions()
{
var resolutions = new KeyValuePair<string, Size>("Default", new Size(9999, 9999)).Yield();
var resolutions = new List<Size> { new Size(9999, 9999) };
if (game.Window != null)
resolutions = resolutions.Concat(game.Window.AvailableResolutions
.Where(r => r.Width >= 800 && r.Height >= 600)
.OrderByDescending(r => r.Width)
.ThenByDescending(r => r.Height)
.Select(res => new KeyValuePair<string, Size>($"{res.Width}x{res.Height}", new Size(res.Width, res.Height)))
.Distinct());
return resolutions.ToList();
{
resolutions.AddRange(game.Window.AvailableResolutions
.Where(r => r.Width >= 800 && r.Height >= 600)
.OrderByDescending(r => r.Width)
.ThenByDescending(r => r.Height)
.Select(res => new Size(res.Width, res.Height))
.Distinct());
}
return resolutions;
}
private class ResolutionSettingsDropdown : SettingsDropdown<Size>
{
protected override OsuDropdown<Size> CreateDropdown() => new ResolutionDropdownControl { Items = Items };
private class ResolutionDropdownControl : DropdownControl
{
protected override string GenerateItemText(Size item)
{
if (item == new Size(9999, 9999))
return "Default";
return $"{item.Width}x{item.Height}";
}
}
}
}
}

View File

@ -1,9 +1,9 @@
// 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 System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Game.Configuration;
using osu.Game.Graphics;
@ -15,12 +15,15 @@ namespace osu.Game.Overlays.Settings.Sections
{
public class SkinSection : SettingsSection
{
private SettingsDropdown<int> skinDropdown;
private SkinSettingsDropdown skinDropdown;
public override string Header => "Skin";
public override FontAwesome Icon => FontAwesome.fa_paint_brush;
private readonly Bindable<SkinInfo> dropdownBindable = new Bindable<SkinInfo>();
private readonly Bindable<int> configBindable = new Bindable<int>();
private SkinManager skins;
[BackgroundDependencyLoader]
@ -31,7 +34,7 @@ namespace osu.Game.Overlays.Settings.Sections
FlowContent.Spacing = new Vector2(0, 5);
Children = new Drawable[]
{
skinDropdown = new SettingsDropdown<int>(),
skinDropdown = new SkinSettingsDropdown(),
new SettingsSlider<double, SizeSlider>
{
LabelText = "Menu cursor size",
@ -54,19 +57,21 @@ namespace osu.Game.Overlays.Settings.Sections
skins.ItemAdded += itemAdded;
skins.ItemRemoved += itemRemoved;
skinDropdown.Items = skins.GetAllUsableSkins().Select(s => new KeyValuePair<string, int>(s.ToString(), s.ID));
config.BindWith(OsuSetting.Skin, configBindable);
var skinBindable = config.GetBindable<int>(OsuSetting.Skin);
skinDropdown.Bindable = dropdownBindable;
skinDropdown.Items = skins.GetAllUsableSkins().ToArray();
// Todo: This should not be necessary when OsuConfigManager is databased
if (skinDropdown.Items.All(s => s.Value != skinBindable.Value))
skinBindable.Value = 0;
if (skinDropdown.Items.All(s => s.ID != configBindable.Value))
configBindable.Value = 0;
skinDropdown.Bindable = skinBindable;
configBindable.BindValueChanged(v => dropdownBindable.Value = skinDropdown.Items.Single(s => s.ID == v), true);
dropdownBindable.BindValueChanged(v => configBindable.Value = v.ID);
}
private void itemRemoved(SkinInfo s) => skinDropdown.Items = skinDropdown.Items.Where(i => i.Value != s.ID);
private void itemAdded(SkinInfo s) => skinDropdown.Items = skinDropdown.Items.Append(new KeyValuePair<string, int>(s.ToString(), s.ID));
private void itemRemoved(SkinInfo s) => skinDropdown.Items = skinDropdown.Items.Where(i => i.ID != s.ID).ToArray();
private void itemAdded(SkinInfo s) => skinDropdown.Items = skinDropdown.Items.Append(s).ToArray();
protected override void Dispose(bool isDisposing)
{
@ -83,5 +88,15 @@ namespace osu.Game.Overlays.Settings.Sections
{
public override string TooltipText => Current.Value.ToString(@"0.##x");
}
private class SkinSettingsDropdown : SettingsDropdown<SkinInfo>
{
protected override OsuDropdown<SkinInfo> CreateDropdown() => new SkinDropdownControl { Items = Items };
private class SkinDropdownControl : DropdownControl
{
protected override string GenerateItemText(SkinInfo item) => item.ToString();
}
}
}
}

View File

@ -2,36 +2,41 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Graphics;
using osu.Framework.Graphics.UserInterface;
using osu.Game.Graphics.UserInterface;
namespace osu.Game.Overlays.Settings
{
public class SettingsDropdown<T> : SettingsItem<T>
{
private Dropdown<T> dropdown;
protected new OsuDropdown<T> Control => (OsuDropdown<T>)base.Control;
private IEnumerable<KeyValuePair<string, T>> items = new KeyValuePair<string, T>[] { };
public IEnumerable<KeyValuePair<string, T>> Items
private IEnumerable<T> items = Enumerable.Empty<T>();
public IEnumerable<T> Items
{
get
{
return items;
}
get => items;
set
{
items = value;
if (dropdown != null)
dropdown.Items = value;
if (Control != null)
Control.Items = value;
}
}
protected override Drawable CreateControl() => dropdown = new OsuDropdown<T>
protected sealed override Drawable CreateControl() => CreateDropdown();
protected virtual OsuDropdown<T> CreateDropdown() => new DropdownControl { Items = Items };
protected class DropdownControl : OsuDropdown<T>
{
Margin = new MarginPadding { Top = 5 },
RelativeSizeAxes = Axes.X,
Items = Items,
};
public DropdownControl()
{
Margin = new MarginPadding { Top = 5 };
RelativeSizeAxes = Axes.X;
}
}
}
}

View File

@ -8,10 +8,15 @@ namespace osu.Game.Overlays.Settings
{
public class SettingsEnumDropdown<T> : SettingsDropdown<T>
{
protected override Drawable CreateControl() => new OsuEnumDropdown<T>
protected override OsuDropdown<T> CreateDropdown() => new DropdownControl();
protected class DropdownControl : OsuEnumDropdown<T>
{
Margin = new MarginPadding { Top = 5 },
RelativeSizeAxes = Axes.X,
};
public DropdownControl()
{
Margin = new MarginPadding { Top = 5 };
RelativeSizeAxes = Axes.X;
}
}
}
}

View File

@ -8,6 +8,10 @@ namespace osu.Game.Overlays.Settings
{
public class SettingsTextBox : SettingsItem<string>
{
protected override Drawable CreateControl() => new OsuTextBox();
protected override Drawable CreateControl() => new OsuTextBox
{
Margin = new MarginPadding { Top = 5 },
RelativeSizeAxes = Axes.X,
};
}
}

View File

@ -8,6 +8,7 @@ using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input;
using osu.Framework.Logging;
using osu.Framework.Timing;
using osu.Game.Beatmaps;
@ -37,6 +38,8 @@ namespace osu.Game.Rulesets.Edit
private BlueprintContainer blueprintContainer;
private InputManager inputManager;
internal HitObjectComposer(Ruleset ruleset)
{
Ruleset = ruleset;
@ -114,6 +117,13 @@ namespace osu.Game.Rulesets.Edit
toolboxCollection.Items[0].Select();
}
protected override void LoadComplete()
{
base.LoadComplete();
inputManager = GetContainingInputManager();
}
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
{
var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
@ -137,6 +147,11 @@ namespace osu.Game.Rulesets.Edit
});
}
/// <summary>
/// Whether the user's cursor is currently in an area of the <see cref="HitObjectComposer"/> that is valid for placement.
/// </summary>
public virtual bool CursorInPlacementArea => rulesetContainer.Playfield.ReceivePositionalInputAt(inputManager.CurrentState.Mouse.Position);
/// <summary>
/// Adds a <see cref="HitObject"/> to the <see cref="Beatmaps.Beatmap"/> and visualises it.
/// </summary>

View File

@ -1,6 +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 osu.Framework;
using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
@ -18,8 +20,18 @@ namespace osu.Game.Rulesets.Edit
/// <summary>
/// A blueprint which governs the creation of a new <see cref="HitObject"/> to actualisation.
/// </summary>
public abstract class PlacementBlueprint : CompositeDrawable, IRequireHighFrequencyMousePosition
public abstract class PlacementBlueprint : CompositeDrawable, IStateful<PlacementState>, IRequireHighFrequencyMousePosition
{
/// <summary>
/// Invoked when <see cref="State"/> has changed.
/// </summary>
public event Action<PlacementState> StateChanged;
/// <summary>
/// Whether the <see cref="HitObject"/> is currently being placed, but has not necessarily finished being placed.
/// </summary>
public bool PlacementBegun { get; private set; }
/// <summary>
/// The <see cref="HitObject"/> that is being placed.
/// </summary>
@ -37,6 +49,8 @@ namespace osu.Game.Rulesets.Edit
HitObject = hitObject;
RelativeSizeAxes = Axes.Both;
Alpha = 0;
}
[BackgroundDependencyLoader]
@ -49,7 +63,25 @@ namespace osu.Game.Rulesets.Edit
ApplyDefaultsToHitObject();
}
private bool placementBegun;
private PlacementState state;
public PlacementState State
{
get => state;
set
{
if (state == value)
return;
state = value;
if (state == PlacementState.Shown)
Show();
else
Hide();
StateChanged?.Invoke(value);
}
}
/// <summary>
/// Signals that the placement of <see cref="HitObject"/> has started.
@ -57,7 +89,7 @@ namespace osu.Game.Rulesets.Edit
protected void BeginPlacement()
{
placementHandler.BeginPlacement(HitObject);
placementBegun = true;
PlacementBegun = true;
}
/// <summary>
@ -66,7 +98,7 @@ namespace osu.Game.Rulesets.Edit
/// </summary>
protected void EndPlacement()
{
if (!placementBegun)
if (!PlacementBegun)
BeginPlacement();
placementHandler.EndPlacement(HitObject);
}
@ -93,4 +125,10 @@ namespace osu.Game.Rulesets.Edit
}
}
}
public enum PlacementState
{
Hidden,
Shown,
}
}

View File

@ -1,11 +1,27 @@
// 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 osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.OpenGL.Vertices;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Graphics.Shaders;
using osu.Framework.Graphics.Textures;
using osu.Game.Beatmaps.Timing;
using osu.Game.Graphics;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI;
using OpenTK;
using OpenTK.Graphics;
namespace osu.Game.Rulesets.Mods
{
public abstract class ModFlashlight : Mod
public abstract class ModFlashlight<T> : Mod, IApplicableToRulesetContainer<T>, IApplicableToScoreProcessor
where T : HitObject
{
public override string Name => "Flashlight";
public override string ShortenedName => "FL";
@ -13,5 +29,125 @@ namespace osu.Game.Rulesets.Mods
public override ModType Type => ModType.DifficultyIncrease;
public override string Description => "Restricted view area.";
public override bool Ranked => true;
public const double FLASHLIGHT_FADE_DURATION = 800;
protected readonly BindableInt Combo = new BindableInt();
public void ApplyToScoreProcessor(ScoreProcessor scoreProcessor)
{
Combo.BindTo(scoreProcessor.Combo);
}
public virtual void ApplyToRulesetContainer(RulesetContainer<T> rulesetContainer)
{
var flashlight = CreateFlashlight();
flashlight.Combo = Combo;
flashlight.RelativeSizeAxes = Axes.Both;
flashlight.Colour = Color4.Black;
rulesetContainer.KeyBindingInputManager.Add(flashlight);
flashlight.Breaks = rulesetContainer.Beatmap.Breaks;
}
public abstract Flashlight CreateFlashlight();
public abstract class Flashlight : Drawable
{
internal BindableInt Combo;
private Shader shader;
protected override DrawNode CreateDrawNode() => new FlashlightDrawNode();
public override bool RemoveCompletedTransforms => false;
public List<BreakPeriod> Breaks;
protected override void ApplyDrawNode(DrawNode node)
{
base.ApplyDrawNode(node);
var flashNode = (FlashlightDrawNode)node;
flashNode.Shader = shader;
flashNode.ScreenSpaceDrawQuad = ScreenSpaceDrawQuad;
flashNode.FlashlightPosition = Vector2Extensions.Transform(FlashlightPosition, DrawInfo.Matrix);
flashNode.FlashlightSize = Vector2Extensions.Transform(FlashlightSize, DrawInfo.Matrix);
}
[BackgroundDependencyLoader]
private void load(ShaderManager shaderManager)
{
shader = shaderManager.Load("PositionAndColour", FragmentShader);
}
protected override void LoadComplete()
{
base.LoadComplete();
Combo.ValueChanged += OnComboChange;
this.FadeInFromZero(FLASHLIGHT_FADE_DURATION);
foreach (var breakPeriod in Breaks)
{
if (breakPeriod.Duration < FLASHLIGHT_FADE_DURATION * 2) continue;
this.Delay(breakPeriod.StartTime + FLASHLIGHT_FADE_DURATION).FadeOutFromOne(FLASHLIGHT_FADE_DURATION);
this.Delay(breakPeriod.EndTime - FLASHLIGHT_FADE_DURATION).FadeInFromZero(FLASHLIGHT_FADE_DURATION);
}
}
protected abstract void OnComboChange(int newCombo);
protected abstract string FragmentShader { get; }
private Vector2 flashlightPosition;
protected Vector2 FlashlightPosition
{
get => flashlightPosition;
set
{
if (flashlightPosition == value) return;
flashlightPosition = value;
Invalidate(Invalidation.DrawNode);
}
}
private Vector2 flashlightSize;
protected Vector2 FlashlightSize
{
get => flashlightSize;
set
{
if (flashlightSize == value) return;
flashlightSize = value;
Invalidate(Invalidation.DrawNode);
}
}
}
private class FlashlightDrawNode : DrawNode
{
public Shader Shader;
public Quad ScreenSpaceDrawQuad;
public Vector2 FlashlightPosition;
public Vector2 FlashlightSize;
public override void Draw(Action<TexturedVertex2D> vertexAction)
{
base.Draw(vertexAction);
Shader.Bind();
Shader.GetUniform<Vector2>("flashlightPos").UpdateValue(ref FlashlightPosition);
Shader.GetUniform<Vector2>("flashlightSize").UpdateValue(ref FlashlightSize);
Texture.WhitePixel.DrawQuad(ScreenSpaceDrawQuad, DrawColourInfo.Colour, vertexAction: vertexAction);
Shader.Unbind();
}
}
}
}

View File

@ -18,7 +18,10 @@ namespace osu.Game.Screens.Edit.Compose.Components
public class BlueprintContainer : CompositeDrawable
{
private SelectionBlueprintContainer selectionBlueprints;
private Container<PlacementBlueprint> placementBlueprintContainer;
private PlacementBlueprint currentPlacement;
private SelectionBox selectionBox;
private IEnumerable<SelectionBlueprint> selections => selectionBlueprints.Children.Where(c => c.IsAlive);
@ -117,19 +120,32 @@ namespace osu.Game.Screens.Edit.Compose.Components
return true;
}
protected override void Update()
{
base.Update();
if (currentPlacement != null)
{
if (composer.CursorInPlacementArea)
currentPlacement.State = PlacementState.Shown;
else if (currentPlacement?.PlacementBegun == false)
currentPlacement.State = PlacementState.Hidden;
}
}
/// <summary>
/// Refreshes the current placement tool.
/// </summary>
private void refreshTool()
{
placementBlueprintContainer.Clear();
currentPlacement = null;
var blueprint = CurrentTool?.CreatePlacementBlueprint();
if (blueprint != null)
placementBlueprintContainer.Child = blueprint;
placementBlueprintContainer.Child = currentPlacement = blueprint;
}
/// <summary>
/// Select all masks in a given rectangle selection area.
/// </summary>

View File

@ -14,6 +14,7 @@ using osu.Framework.Input.Bindings;
using osu.Framework.Logging;
using osu.Framework.Threading;
using osu.Game.Graphics;
using osu.Game.Input;
using osu.Game.Input.Bindings;
using osu.Game.Overlays;
using OpenTK;
@ -64,6 +65,8 @@ namespace osu.Game.Screens.Menu
private SampleChannel sampleBack;
private IdleTracker idleTracker;
public ButtonSystem()
{
RelativeSizeAxes = Axes.Both;
@ -102,9 +105,10 @@ namespace osu.Game.Screens.Menu
private OsuGame game;
[BackgroundDependencyLoader(true)]
private void load(AudioManager audio, OsuGame game)
private void load(AudioManager audio, OsuGame game, IdleTracker idleTracker)
{
this.game = game;
this.idleTracker = idleTracker;
sampleBack = audio.Sample.Get(@"Menu/button-back-select");
}
@ -266,8 +270,8 @@ namespace osu.Game.Screens.Menu
protected override void Update()
{
//if (OsuGame.IdleTime > 6000 && State != MenuState.Exit)
// State = MenuState.Initial;
if (idleTracker?.IdleTime > 6000 && State != ButtonSystemState.Exit)
State = ButtonSystemState.Initial;
base.Update();

View File

@ -8,16 +8,18 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input.Bindings;
using osu.Framework.Input.Events;
using osu.Framework.MathUtils;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osu.Game.Input.Bindings;
using OpenTK;
namespace osu.Game.Screens.Play.HUD
{
public class QuitButton : FillFlowContainer
public class HoldForMenuButton : FillFlowContainer
{
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true;
@ -30,7 +32,7 @@ namespace osu.Game.Screens.Play.HUD
private readonly OsuSpriteText text;
public QuitButton()
public HoldForMenuButton()
{
Direction = FillDirection.Horizontal;
Spacing = new Vector2(20, 0);
@ -75,11 +77,11 @@ namespace osu.Game.Screens.Play.HUD
Alpha = 1;
else
Alpha = Interpolation.ValueAt(
MathHelper.Clamp(Clock.ElapsedFrameTime, 0, 1000),
MathHelper.Clamp(Clock.ElapsedFrameTime, 0, 200),
Alpha, MathHelper.Clamp(1 - positionalAdjust, 0.04f, 1), 0, 200, Easing.OutQuint);
}
private class Button : HoldToConfirmContainer
private class Button : HoldToConfirmContainer, IKeyBindingHandler<GlobalAction>
{
private SpriteIcon icon;
private CircularProgress circularProgress;
@ -90,6 +92,30 @@ namespace osu.Game.Screens.Play.HUD
public Action HoverGained;
public Action HoverLost;
public bool OnPressed(GlobalAction action)
{
switch (action)
{
case GlobalAction.Back:
BeginConfirm();
return true;
}
return false;
}
public bool OnReleased(GlobalAction action)
{
switch (action)
{
case GlobalAction.Back:
AbortConfirm();
return true;
}
return false;
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{

View File

@ -2,6 +2,7 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
@ -92,6 +93,13 @@ namespace osu.Game.Screens.Play.HUD
};
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
AccentColour = colours.BlueLighter;
GlowColour = colours.BlueDarker;
}
public void Flash(JudgementResult result)
{
if (result.Type == HitResult.Miss)

View File

@ -9,7 +9,6 @@ using osu.Framework.Input.Events;
using osu.Framework.Timing;
using osu.Game.Beatmaps;
using osu.Game.Configuration;
using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface;
using osu.Game.Overlays;
using osu.Game.Overlays.Notifications;
@ -34,7 +33,7 @@ namespace osu.Game.Screens.Play
public readonly HealthDisplay HealthDisplay;
public readonly SongProgress Progress;
public readonly ModDisplay ModDisplay;
public readonly QuitButton HoldToQuit;
public readonly HoldForMenuButton HoldToQuit;
public readonly PlayerSettingsOverlay PlayerSettingsOverlay;
private Bindable<bool> showHud;
@ -69,7 +68,7 @@ namespace osu.Game.Screens.Play
Children = new Drawable[]
{
KeyCounter = CreateKeyCounter(adjustableClock as IFrameBasedClock),
HoldToQuit = CreateQuitButton(),
HoldToQuit = CreateHoldForMenuButton(),
}
}
}
@ -89,7 +88,7 @@ namespace osu.Game.Screens.Play
}
[BackgroundDependencyLoader(true)]
private void load(OsuConfigManager config, NotificationOverlay notificationOverlay, OsuColour colours)
private void load(OsuConfigManager config, NotificationOverlay notificationOverlay)
{
showHud = config.GetBindable<bool>(OsuSetting.ShowInterface);
showHud.ValueChanged += hudVisibility => content.FadeTo(hudVisibility ? 1 : 0, duration);
@ -104,18 +103,6 @@ namespace osu.Game.Screens.Play
Text = @"The score overlay is currently disabled. You can toggle this by pressing Shift+Tab."
});
}
// todo: the stuff below should probably not be in this base implementation, but in each individual class.
ComboCounter.AccentColour = colours.BlueLighter;
AccuracyCounter.AccentColour = colours.BlueLighter;
ScoreCounter.AccentColour = colours.BlueLighter;
var shd = HealthDisplay as StandardHealthDisplay;
if (shd != null)
{
shd.AccentColour = colours.BlueLighter;
shd.GlowColour = colours.BlueDarker;
}
}
protected override void LoadComplete()
@ -219,7 +206,7 @@ namespace osu.Game.Screens.Play
RelativeSizeAxes = Axes.X,
};
protected virtual QuitButton CreateQuitButton() => new QuitButton
protected virtual HoldForMenuButton CreateHoldForMenuButton() => new HoldForMenuButton
{
Anchor = Anchor.BottomRight,
Origin = Anchor.BottomRight,

View File

@ -35,6 +35,8 @@ namespace osu.Game.Screens.Play
{
public class Player : ScreenWithBeatmapBackground, IProvideCursor
{
protected override bool AllowBackButton => false; // handled by HoldForMenuButton
protected override float BackgroundParallaxAmount => 0.1f;
protected override bool HideOverlaysOnEnter => true;

View File

@ -1,7 +1,6 @@
// 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.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Game.Graphics.Sprites;
@ -25,7 +24,7 @@ namespace osu.Game.Screens.Play.PlayerSettings
new CollectionsDropdown<PlaylistCollection>
{
RelativeSizeAxes = Axes.X,
Items = new[] { new KeyValuePair<string, PlaylistCollection>(@"All", PlaylistCollection.All) },
Items = new[] { PlaylistCollection.All },
},
};
}

View File

@ -18,7 +18,7 @@
<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.1112.0" />
<PackageReference Include="ppy.osu.Framework" Version="2018.1114.0" />
<PackageReference Include="SharpCompress" Version="0.22.0" />
<PackageReference Include="NUnit" Version="3.11.0" />
<PackageReference Include="SharpRaven" Version="2.4.0" />