Merge branch 'master' into editor-hitobject-overlays

This commit is contained in:
Dean Herbert
2018-02-26 17:53:50 +09:00
committed by GitHub
44 changed files with 1200 additions and 204 deletions

View File

@ -78,8 +78,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
bool isRepeatAtEnd = repeatPoint.RepeatIndex % 2 == 0;
List<Vector2> curve = drawableSlider.Body.CurrentCurve;
var positionOnCurve = isRepeatAtEnd ? end : start;
Position = positionOnCurve + drawableSlider.HitObject.StackOffset;
Position = isRepeatAtEnd ? end : start;
if (curve.Count < 2)
return;
@ -90,10 +89,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
// find the next vector2 in the curve which is not equal to our current position to infer a rotation.
for (int i = searchStart; i >= 0 && i < curve.Count; i += direction)
{
if (curve[i] == positionOnCurve)
if (curve[i] == Position)
continue;
Rotation = MathHelper.RadiansToDegrees((float)Math.Atan2(curve[i].Y - positionOnCurve.Y, curve[i].X - positionOnCurve.X));
Rotation = MathHelper.RadiansToDegrees((float)Math.Atan2(curve[i].Y - Position.Y, curve[i].X - Position.X));
break;
}
}

View File

@ -12,6 +12,7 @@ using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Osu.Judgements;
using osu.Framework.Graphics.Primitives;
using osu.Game.Configuration;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Osu.Objects.Drawables
@ -32,6 +33,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
{
slider = s;
Position = s.StackedPosition;
Container<DrawableSliderTick> ticks;
Container<DrawableRepeatPoint> repeatPoints;
@ -40,20 +43,20 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
Body = new SliderBody(s)
{
AccentColour = AccentColour,
Position = s.StackedPosition,
PathWidth = s.Scale * 64,
},
ticks = new Container<DrawableSliderTick>(),
repeatPoints = new Container<DrawableRepeatPoint>(),
ticks = new Container<DrawableSliderTick> { RelativeSizeAxes = Axes.Both },
repeatPoints = new Container<DrawableRepeatPoint> { RelativeSizeAxes = Axes.Both },
Ball = new SliderBall(s)
{
BypassAutoSizeAxes = Axes.Both,
Scale = new Vector2(s.Scale),
AccentColour = AccentColour,
AlwaysPresent = true,
Alpha = 0
},
HeadCircle = new DrawableHitCircle(s.HeadCircle),
TailCircle = new DrawableSliderTail(s.TailCircle)
HeadCircle = new DrawableHitCircle(s.HeadCircle) { Position = s.TailCircle.Position - s.Position },
TailCircle = new DrawableSliderTail(s.TailCircle) { Position = s.TailCircle.Position - s.Position }
};
components.Add(Body);
@ -66,10 +69,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
foreach (var tick in s.NestedHitObjects.OfType<SliderTick>())
{
var drawableTick = new DrawableSliderTick(tick)
{
Position = tick.StackedPosition
};
var drawableTick = new DrawableSliderTick(tick) { Position = tick.Position - s.Position };
ticks.Add(drawableTick);
components.Add(drawableTick);
@ -78,10 +78,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
foreach (var repeatPoint in s.NestedHitObjects.OfType<RepeatPoint>())
{
var drawableRepeatPoint = new DrawableRepeatPoint(repeatPoint, this)
{
Position = repeatPoint.StackedPosition
};
var drawableRepeatPoint = new DrawableRepeatPoint(repeatPoint, this) { Position = repeatPoint.Position - s.Position };
repeatPoints.Add(drawableRepeatPoint);
components.Add(drawableRepeatPoint);
@ -108,11 +105,22 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
//todo: we probably want to reconsider this before adding scoring, but it looks and feels nice.
if (!HeadCircle.IsHit)
HeadCircle.Position = slider.StackedPositionAt(completionProgress);
HeadCircle.Position = slider.CurvePositionAt(completionProgress);
foreach (var c in components.OfType<ISliderProgress>()) c.UpdateProgress(completionProgress);
foreach (var c in components.OfType<ITrackSnaking>()) c.UpdateSnakingPosition(slider.Curve.PositionAt(Body.SnakedStart ?? 0), slider.Curve.PositionAt(Body.SnakedEnd ?? 0));
foreach (var t in components.OfType<IRequireTracking>()) t.Tracking = Ball.Tracking;
Size = Body.Size;
OriginPosition = Body.PathOffset;
if (DrawSize != Vector2.Zero)
{
var childAnchorPosition = Vector2.Divide(OriginPosition, DrawSize);
foreach (var obj in NestedHitObjects)
obj.RelativeAnchorPosition = childAnchorPosition;
Ball.RelativeAnchorPosition = childAnchorPosition;
}
}
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
@ -155,6 +163,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
this.FadeOut(fade_out_time, Easing.OutQuint).Expire();
}
Expire(true);
}
public Drawable ProxiedLayer => HeadCircle.ApproachCircle;

View File

@ -19,8 +19,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
public DrawableSliderTail(HitCircle hitCircle)
: base(hitCircle)
{
AlwaysPresent = true;
Origin = Anchor.Centre;
RelativeSizeAxes = Axes.Both;
FillMode = FillMode.Fit;
AlwaysPresent = true;
}
protected override void CheckForJudgements(bool userTriggered, double timeOffset)

View File

@ -6,30 +6,24 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Game.Skinning;
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
{
public class ApproachCircle : Container
{
private readonly Sprite approachCircle;
public ApproachCircle()
{
Anchor = Anchor.Centre;
Origin = Anchor.Centre;
AutoSizeAxes = Axes.Both;
Children = new Drawable[]
{
approachCircle = new Sprite()
};
RelativeSizeAxes = Axes.Both;
}
[BackgroundDependencyLoader]
private void load(TextureStore textures)
{
approachCircle.Texture = textures.Get(@"Play/osu/approachcircle");
Child = new SkinnableDrawable("Play/osu/approachcircle", name => new Sprite { Texture = textures.Get(name) });
}
}
}

View File

@ -2,20 +2,16 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Framework.Input.Bindings;
using osu.Game.Skinning;
using OpenTK;
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
{
public class CirclePiece : Container, IKeyBindingHandler<OsuAction>
{
private readonly Sprite disc;
public Func<bool> Hit;
public CirclePiece()
@ -27,26 +23,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
Anchor = Anchor.Centre;
Origin = Anchor.Centre;
Children = new Drawable[]
{
disc = new Sprite
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre
},
new TrianglesPiece
{
RelativeSizeAxes = Axes.Both,
Blending = BlendingMode.Additive,
Alpha = 0.5f,
}
};
}
[BackgroundDependencyLoader]
private void load(TextureStore textures)
{
disc.Texture = textures.Get(@"Play/osu/disc");
InternalChild = new SkinnableDrawable("Play/osu/hitcircle", _ => new DefaultCirclePiece());
}
public bool OnPressed(OsuAction action)

View File

@ -0,0 +1,35 @@
// 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.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
{
public class DefaultCirclePiece : Container
{
[BackgroundDependencyLoader]
private void load(TextureStore textures)
{
RelativeSizeAxes = Axes.Both;
Children = new Drawable[]
{
new Sprite
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Texture = textures.Get(@"Play/osu/disc"),
},
new TrianglesPiece
{
RelativeSizeAxes = Axes.Both,
Blending = BlendingMode.Additive,
Alpha = 0.5f,
}
};
}
}
}

View File

@ -6,34 +6,30 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Game.Skinning;
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
{
public class GlowPiece : Container
{
private readonly Sprite layer;
public GlowPiece()
{
Anchor = Anchor.Centre;
Origin = Anchor.Centre;
Children = new[]
{
layer = new Sprite
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Blending = BlendingMode.Additive,
Alpha = 0.5f
}
};
RelativeSizeAxes = Axes.Both;
}
[BackgroundDependencyLoader]
private void load(TextureStore textures)
{
layer.Texture = textures.Get(@"Play/osu/ring-glow");
Child = new SkinnableDrawable("Play/osu/ring-glow", name => new Sprite
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Texture = textures.Get(name),
Blending = BlendingMode.Additive,
Alpha = 0.5f
}, false);
}
}
}

View File

@ -8,6 +8,7 @@ using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics.Sprites;
using OpenTK.Graphics;
using osu.Framework.Graphics.Shapes;
using osu.Game.Skinning;
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
{
@ -28,7 +29,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
Children = new Drawable[]
{
new CircularContainer
new SkinnableDrawable("Play/osu/number-glow", name => new CircularContainer
{
Masking = true,
Origin = Anchor.Centre,
@ -38,11 +39,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
Radius = 60,
Colour = Color4.White.Opacity(0.5f),
},
Children = new[]
{
new Box()
}
},
Child = new Box()
}, false),
number = new OsuSpriteText
{
Text = @"1",

View File

@ -6,6 +6,7 @@ using osu.Framework.Graphics.Containers;
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Graphics.Shapes;
using osu.Game.Skinning;
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
{
@ -15,24 +16,26 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
{
Size = new Vector2(128);
Masking = true;
CornerRadius = Size.X / 2;
Anchor = Anchor.Centre;
Origin = Anchor.Centre;
BorderThickness = 10;
BorderColour = Color4.White;
Children = new Drawable[]
InternalChild = new SkinnableDrawable("Play/osu/hitcircleoverlay", _ => new Container
{
new Box
Masking = true,
CornerRadius = Size.X / 2,
BorderThickness = 10,
BorderColour = Color4.White,
RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
{
AlwaysPresent = true,
Alpha = 0,
RelativeSizeAxes = Axes.Both
new Box
{
AlwaysPresent = true,
Alpha = 0,
RelativeSizeAxes = Axes.Both
}
}
};
});
}
}
}

View File

@ -6,6 +6,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Input;
using osu.Game.Rulesets.Objects.Types;
using OpenTK;
using OpenTK.Graphics;
@ -141,7 +142,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
public void UpdateProgress(double completionProgress)
{
Position = slider.StackedPositionAt(completionProgress);
Position = slider.CurvePositionAt(completionProgress);
}
}
}

View File

@ -29,6 +29,13 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
set { path.PathWidth = value; }
}
/// <summary>
/// Offset in absolute coordinates from the start of the curve.
/// </summary>
public Vector2 PathOffset { get; private set; }
public readonly List<Vector2> CurrentCurve = new List<Vector2>();
public readonly Bindable<bool> SnakingIn = new Bindable<bool>();
public readonly Bindable<bool> SnakingOut = new Bindable<bool>();
@ -75,6 +82,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
private int textureWidth => (int)PathWidth * 2;
private Vector2 topLeftOffset;
private readonly Slider slider;
public SliderBody(Slider s)
{
@ -84,6 +93,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
{
container = new BufferedContainer
{
RelativeSizeAxes = Axes.Both,
CacheDrawnFrameBuffer = true,
Children = new Drawable[]
{
@ -107,11 +117,11 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
if (updateSnaking(p0, p1))
{
// Autosizing does not give us the desired behaviour here.
// We want the container to have the same size as the slider,
// and to be positioned such that the slider head is at (0,0).
container.Size = path.Size;
container.Position = -path.PositionInBoundingBox(slider.Curve.PositionAt(0) - CurrentCurve[0]);
// The path is generated such that its size encloses it. This change of size causes the path
// to move around while snaking, so we need to offset it to make sure it maintains the
// same position as when it is fully snaked.
var newTopLeftOffset = path.PositionInBoundingBox(Vector2.Zero);
path.Position = topLeftOffset - newTopLeftOffset;
container.ForceRedraw();
}
@ -121,6 +131,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
private void load()
{
reloadTexture();
computeSize();
}
private void reloadTexture()
@ -164,7 +175,19 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
path.Texture = texture;
}
public readonly List<Vector2> CurrentCurve = new List<Vector2>();
private void computeSize()
{
// Generate the entire curve
slider.Curve.GetPathToProgress(CurrentCurve, 0, 1);
foreach (Vector2 p in CurrentCurve)
path.AddVertex(p);
Size = path.Size;
topLeftOffset = path.PositionInBoundingBox(Vector2.Zero);
PathOffset = path.PositionInBoundingBox(CurrentCurve[0]);
}
private bool updateSnaking(double p0, double p1)
{
if (SnakedStart == p0 && SnakedEnd == p1) return false;
@ -176,7 +199,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
path.ClearVertices();
foreach (Vector2 p in CurrentCurve)
path.AddVertex(p - CurrentCurve[0]);
path.AddVertex(p);
return true;
}

View File

@ -23,8 +23,8 @@ namespace osu.Game.Rulesets.Osu.Objects
public double EndTime => StartTime + this.SpanCount() * Curve.Distance / Velocity;
public double Duration => EndTime - StartTime;
public Vector2 StackedPositionAt(double t) => this.PositionAt(t) + StackOffset;
public override Vector2 EndPosition => this.PositionAt(1);
public Vector2 StackedPositionAt(double t) => StackedPosition + this.CurvePositionAt(t);
public override Vector2 EndPosition => Position + this.CurvePositionAt(1);
public SliderCurve Curve { get; } = new SliderCurve();
@ -99,7 +99,7 @@ namespace osu.Game.Rulesets.Osu.Objects
HeadCircle = new HitCircle
{
StartTime = StartTime,
Position = StackedPosition,
Position = Position,
IndexInCurrentCombo = IndexInCurrentCombo,
ComboColour = ComboColour,
Samples = Samples,
@ -109,7 +109,7 @@ namespace osu.Game.Rulesets.Osu.Objects
TailCircle = new HitCircle
{
StartTime = EndTime,
Position = StackedEndPosition,
Position = EndPosition,
IndexInCurrentCombo = IndexInCurrentCombo,
ComboColour = ComboColour
};
@ -156,7 +156,7 @@ namespace osu.Game.Rulesets.Osu.Objects
SpanIndex = span,
SpanStartTime = spanStartTime,
StartTime = spanStartTime + timeProgress * SpanDuration,
Position = Curve.PositionAt(distanceProgress),
Position = Position + Curve.PositionAt(distanceProgress),
StackHeight = StackHeight,
Scale = Scale,
ComboColour = ComboColour,
@ -175,7 +175,7 @@ namespace osu.Game.Rulesets.Osu.Objects
RepeatIndex = repeatIndex,
SpanDuration = SpanDuration,
StartTime = StartTime + repeat * SpanDuration,
Position = Curve.PositionAt(repeat % 2),
Position = Position + Curve.PositionAt(repeat % 2),
StackHeight = StackHeight,
Scale = Scale,
ComboColour = ComboColour,