diff --git a/osu.Game.Modes.Osu/Objects/Drawables/Connections/ConnectionRenderer.cs b/osu.Game.Modes.Osu/Objects/Drawables/Connections/ConnectionRenderer.cs new file mode 100644 index 0000000000..a680c847ac --- /dev/null +++ b/osu.Game.Modes.Osu/Objects/Drawables/Connections/ConnectionRenderer.cs @@ -0,0 +1,21 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Graphics.Containers; +using osu.Game.Modes.Objects; +using System.Collections.Generic; + +namespace osu.Game.Modes.Osu.Objects.Drawables.Connections +{ + /// + /// Connects hit objects visually, for example with follow points. + /// + public abstract class ConnectionRenderer : Container + where T : HitObject + { + /// + /// Hit objects to create connections for + /// + public abstract IEnumerable HitObjects { get; set; } + } +} diff --git a/osu.Game.Modes.Osu/Objects/Drawables/Connections/FollowPoint.cs b/osu.Game.Modes.Osu/Objects/Drawables/Connections/FollowPoint.cs new file mode 100644 index 0000000000..bc24186e14 --- /dev/null +++ b/osu.Game.Modes.Osu/Objects/Drawables/Connections/FollowPoint.cs @@ -0,0 +1,67 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using OpenTK; +using OpenTK.Graphics; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Transformations; +using osu.Game.Graphics; + +namespace osu.Game.Modes.Osu.Objects.Drawables.Connections +{ + public class FollowPoint : Container + { + public double StartTime; + public double EndTime; + public Vector2 EndPosition; + + const float width = 8; + + public FollowPoint() + { + Origin = Anchor.Centre; + Alpha = 0; + + Masking = true; + AutoSizeAxes = Axes.Both; + CornerRadius = width / 2; + EdgeEffect = new EdgeEffect + { + Type = EdgeEffectType.Glow, + Colour = Color4.White.Opacity(0.2f), + Radius = 4, + }; + + Children = new Drawable[] + { + new Box + { + Size = new Vector2(width), + BlendingMode = BlendingMode.Additive, + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + Alpha = 0.5f, + }, + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + Delay(StartTime); + FadeIn(DrawableOsuHitObject.TIME_FADEIN); + ScaleTo(1.5f); + ScaleTo(1, DrawableOsuHitObject.TIME_FADEIN, EasingTypes.Out); + MoveTo(EndPosition, DrawableOsuHitObject.TIME_FADEIN, EasingTypes.Out); + + Delay(EndTime - StartTime); + FadeOut(DrawableOsuHitObject.TIME_FADEIN); + + Delay(DrawableOsuHitObject.TIME_FADEIN); + Expire(true); + } + } +} \ No newline at end of file diff --git a/osu.Game.Modes.Osu/Objects/Drawables/Connections/FollowPointRenderer.cs b/osu.Game.Modes.Osu/Objects/Drawables/Connections/FollowPointRenderer.cs new file mode 100644 index 0000000000..b57f0881bc --- /dev/null +++ b/osu.Game.Modes.Osu/Objects/Drawables/Connections/FollowPointRenderer.cs @@ -0,0 +1,97 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using OpenTK; +using osu.Game.Modes.Osu.Objects.Drawables.Connections; +using System; +using System.Collections.Generic; + +namespace osu.Game.Modes.Osu.Objects.Drawables +{ + public class FollowPointRenderer : ConnectionRenderer + { + private int pointDistance = 32; + /// + /// Determines how much space there is between points. + /// + public int PointDistance + { + get { return pointDistance; } + set + { + if (pointDistance == value) return; + pointDistance = value; + update(); + } + } + + private int preEmpt = 800; + /// + /// Follow points to the next hitobject start appearing for this many milliseconds before an hitobject's end time. + /// + public int PreEmpt + { + get { return preEmpt; } + set + { + if (preEmpt == value) return; + preEmpt = value; + update(); + } + } + + private IEnumerable hitObjects; + public override IEnumerable HitObjects + { + get { return hitObjects; } + set + { + hitObjects = value; + update(); + } + } + + private void update() + { + Clear(); + if (hitObjects == null) + return; + + OsuHitObject prevHitObject = null; + foreach (var currHitObject in hitObjects) + { + if (prevHitObject != null && !currHitObject.NewCombo && !(prevHitObject is Spinner) && !(currHitObject is Spinner)) + { + Vector2 startPosition = prevHitObject.EndPosition; + Vector2 endPosition = currHitObject.Position; + double startTime = prevHitObject.EndTime; + double endTime = currHitObject.StartTime; + + Vector2 distanceVector = endPosition - startPosition; + int distance = (int)distanceVector.Length; + float rotation = (float)Math.Atan2(distanceVector.Y, distanceVector.X); + double duration = endTime - startTime; + + for (int d = (int)(PointDistance * 1.5); d < distance - PointDistance; d += PointDistance) + { + float fraction = ((float)d / distance); + Vector2 pointStartPosition = startPosition + (fraction - 0.1f) * distanceVector; + Vector2 pointEndPosition = startPosition + fraction * distanceVector; + double fadeOutTime = startTime + fraction * duration; + double fadeInTime = fadeOutTime - PreEmpt; + + Add(new FollowPoint() + { + StartTime = fadeInTime, + EndTime = fadeOutTime, + Position = pointStartPosition, + EndPosition = pointEndPosition, + Rotation = rotation, + }); + } + } + prevHitObject = currHitObject; + } + } + } +} diff --git a/osu.Game.Modes.Osu/UI/OsuPlayfield.cs b/osu.Game.Modes.Osu/UI/OsuPlayfield.cs index 49c6869189..b6daffbb8b 100644 --- a/osu.Game.Modes.Osu/UI/OsuPlayfield.cs +++ b/osu.Game.Modes.Osu/UI/OsuPlayfield.cs @@ -1,13 +1,15 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using OpenTK; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Modes.Objects.Drawables; using osu.Game.Modes.Osu.Objects; using osu.Game.Modes.Osu.Objects.Drawables; +using osu.Game.Modes.Osu.Objects.Drawables.Connections; using osu.Game.Modes.UI; -using OpenTK; +using System.Linq; namespace osu.Game.Modes.Osu.UI { @@ -15,6 +17,7 @@ namespace osu.Game.Modes.Osu.UI { private Container approachCircles; private Container judgementLayer; + private ConnectionRenderer connectionLayer; public override Vector2 Size { @@ -36,6 +39,11 @@ namespace osu.Game.Modes.Osu.UI Add(new Drawable[] { + connectionLayer = new FollowPointRenderer + { + RelativeSizeAxes = Axes.Both, + Depth = 2, + }, judgementLayer = new Container { RelativeSizeAxes = Axes.Both, @@ -63,6 +71,13 @@ namespace osu.Game.Modes.Osu.UI base.Add(h); } + public override void PostProcess() + { + connectionLayer.HitObjects = HitObjects.Children + .Select(d => (OsuHitObject)d.HitObject) + .OrderBy(h => h.StartTime); + } + private void judgement(DrawableHitObject h, JudgementInfo j) { HitExplosion explosion = new HitExplosion((OsuJudgementInfo)j, (OsuHitObject)h.HitObject); diff --git a/osu.Game.Modes.Osu/osu.Game.Modes.Osu.csproj b/osu.Game.Modes.Osu/osu.Game.Modes.Osu.csproj index a659683c27..e0b9f5c904 100644 --- a/osu.Game.Modes.Osu/osu.Game.Modes.Osu.csproj +++ b/osu.Game.Modes.Osu/osu.Game.Modes.Osu.csproj @@ -46,9 +46,12 @@ + + + diff --git a/osu.Game/Modes/UI/HitRenderer.cs b/osu.Game/Modes/UI/HitRenderer.cs index aa2af83cb4..14d9599be6 100644 --- a/osu.Game/Modes/UI/HitRenderer.cs +++ b/osu.Game/Modes/UI/HitRenderer.cs @@ -83,6 +83,7 @@ namespace osu.Game.Modes.UI Playfield.Add(drawableObject); } + Playfield.PostProcess(); } private void onJudgement(DrawableHitObject o, JudgementInfo j) => TriggerOnJudgement(j); diff --git a/osu.Game/Modes/UI/Playfield.cs b/osu.Game/Modes/UI/Playfield.cs index 748c71a8b3..91eddce73c 100644 --- a/osu.Game/Modes/UI/Playfield.cs +++ b/osu.Game/Modes/UI/Playfield.cs @@ -1,10 +1,10 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using OpenTK; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Modes.Objects.Drawables; -using OpenTK; namespace osu.Game.Modes.UI { @@ -32,6 +32,10 @@ namespace osu.Game.Modes.UI }); } + public virtual void PostProcess() + { + } + public class ScaledContainer : Container { protected override Vector2 DrawScale => new Vector2(DrawSize.X / 512); diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 36ea7c5b49..7f2fa415d2 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -237,11 +237,10 @@ namespace osu.Game.Screens.Play { base.LoadComplete(); - Delay(250, true); + Content.Delay(250); Content.FadeIn(250); - Delay(500, true); - + Delay(750); Schedule(() => { sourceClock.Start();