2019-01-24 16:43:03 +08:00
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
2018-04-13 17:19:50 +08:00
2019-11-01 18:22:07 +08:00
using System.Collections.Generic ;
using System.Linq ;
using osu.Framework.Extensions ;
2018-04-13 17:19:50 +08:00
using osu.Framework.Graphics ;
2019-11-01 14:34:24 +08:00
using osu.Framework.Graphics.Containers ;
2018-04-13 17:19:50 +08:00
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
{
2019-11-05 22:20:46 +08:00
/// <summary>
2019-11-06 15:33:42 +08:00
/// Visualises connections between <see cref="DrawableOsuHitObject"/>s.
2019-11-05 22:20:46 +08:00
/// </summary>
2020-02-23 03:37:04 +08:00
public class FollowPointRenderer : LifetimeManagementContainer
2018-04-13 17:19:50 +08:00
{
2019-11-05 22:20:46 +08:00
/// <summary>
2019-11-06 15:33:42 +08:00
/// All the <see cref="FollowPointConnection"/>s contained by this <see cref="FollowPointRenderer"/>.
2019-11-05 22:20:46 +08:00
/// </summary>
2019-11-06 15:33:42 +08:00
internal IReadOnlyList < FollowPointConnection > Connections = > connections ;
2019-11-05 18:31:58 +08:00
2019-11-06 15:33:42 +08:00
private readonly List < FollowPointConnection > connections = new List < FollowPointConnection > ( ) ;
2019-11-01 18:22:07 +08:00
2019-11-05 22:02:39 +08:00
public override bool RemoveCompletedTransforms = > false ;
2018-04-13 17:19:50 +08:00
/// <summary>
2019-11-01 14:39:23 +08:00
/// Adds the <see cref="FollowPoint"/>s around a <see cref="DrawableOsuHitObject"/>.
/// This includes <see cref="FollowPoint"/>s leading into <paramref name="hitObject"/>, and <see cref="FollowPoint"/>s exiting <paramref name="hitObject"/>.
2018-04-13 17:19:50 +08:00
/// </summary>
2019-11-01 14:39:23 +08:00
/// <param name="hitObject">The <see cref="DrawableOsuHitObject"/> to add <see cref="FollowPoint"/>s for.</param>
public void AddFollowPoints ( DrawableOsuHitObject hitObject )
2019-11-06 15:33:42 +08:00
= > addConnection ( new FollowPointConnection ( hitObject ) . With ( g = > g . StartTime . BindValueChanged ( _ = > onStartTimeChanged ( g ) ) ) ) ;
2019-11-01 18:22:07 +08:00
/// <summary>
/// Removes the <see cref="FollowPoint"/>s around a <see cref="DrawableOsuHitObject"/>.
/// This includes <see cref="FollowPoint"/>s leading into <paramref name="hitObject"/>, and <see cref="FollowPoint"/>s exiting <paramref name="hitObject"/>.
/// </summary>
/// <param name="hitObject">The <see cref="DrawableOsuHitObject"/> to remove <see cref="FollowPoint"/>s for.</param>
2019-11-06 15:33:42 +08:00
public void RemoveFollowPoints ( DrawableOsuHitObject hitObject ) = > removeGroup ( connections . Single ( g = > g . Start = = hitObject ) ) ;
2019-11-01 18:22:07 +08:00
/// <summary>
2019-11-06 15:33:42 +08:00
/// Adds a <see cref="FollowPointConnection"/> to this <see cref="FollowPointRenderer"/>.
2019-11-01 18:22:07 +08:00
/// </summary>
2019-11-06 15:33:42 +08:00
/// <param name="connection">The <see cref="FollowPointConnection"/> to add.</param>
/// <returns>The index of <paramref name="connection"/> in <see cref="connections"/>.</returns>
2019-11-06 15:36:12 +08:00
private void addConnection ( FollowPointConnection connection )
2018-04-13 17:19:50 +08:00
{
2019-11-06 15:33:42 +08:00
// Groups are sorted by their start time when added such that the index can be used to post-process other surrounding connections
int index = connections . AddInPlace ( connection , Comparer < FollowPointConnection > . Create ( ( g1 , g2 ) = > g1 . StartTime . Value . CompareTo ( g2 . StartTime . Value ) ) ) ;
2019-11-01 14:39:23 +08:00
2019-11-06 15:33:42 +08:00
if ( index < connections . Count - 1 )
2018-04-13 17:19:50 +08:00
{
2019-11-06 15:33:42 +08:00
// Update the connection's end point to the next connection's start point
2019-11-01 14:39:23 +08:00
// h1 -> -> -> h2
2019-11-06 15:33:42 +08:00
// connection nextGroup
2019-02-27 20:07:17 +08:00
2019-11-06 15:33:42 +08:00
FollowPointConnection nextConnection = connections [ index + 1 ] ;
connection . End = nextConnection . Start ;
2018-04-13 17:19:50 +08:00
}
2019-11-05 18:31:48 +08:00
else
2019-11-05 22:20:46 +08:00
{
// The end point may be non-null during re-ordering
2019-11-06 15:33:42 +08:00
connection . End = null ;
2019-11-05 22:20:46 +08:00
}
2019-02-27 20:07:17 +08:00
2019-11-01 18:22:07 +08:00
if ( index > 0 )
2018-04-13 17:19:50 +08:00
{
2019-11-06 15:33:42 +08:00
// Update the previous connection's end point to the current connection's start point
2019-11-01 14:39:23 +08:00
// h1 -> -> -> h2
2019-11-06 15:33:42 +08:00
// prevGroup connection
2019-02-27 20:07:17 +08:00
2019-11-06 15:33:42 +08:00
FollowPointConnection previousConnection = connections [ index - 1 ] ;
previousConnection . End = connection . Start ;
2018-04-13 17:19:50 +08:00
}
2020-02-23 03:37:04 +08:00
AddInternal ( connection ) ;
2018-04-13 17:19:50 +08:00
}
2019-11-01 14:39:23 +08:00
/// <summary>
2019-11-06 15:33:42 +08:00
/// Removes a <see cref="FollowPointConnection"/> from this <see cref="FollowPointRenderer"/>.
2019-11-01 14:39:23 +08:00
/// </summary>
2019-11-06 15:33:42 +08:00
/// <param name="connection">The <see cref="FollowPointConnection"/> to remove.</param>
/// <returns>Whether <paramref name="connection"/> was removed.</returns>
2019-11-06 15:36:12 +08:00
private void removeGroup ( FollowPointConnection connection )
2018-04-13 17:19:50 +08:00
{
2019-11-06 15:33:42 +08:00
RemoveInternal ( connection ) ;
2018-04-13 17:19:50 +08:00
2019-11-06 15:33:42 +08:00
int index = connections . IndexOf ( connection ) ;
2019-04-01 11:16:05 +08:00
2019-11-01 18:22:07 +08:00
if ( index > 0 )
2018-04-13 17:19:50 +08:00
{
2019-11-06 15:33:42 +08:00
// Update the previous connection's end point to the next connection's start point
2019-11-01 18:22:07 +08:00
// h1 -> -> -> h2 -> -> -> h3
2019-11-06 15:33:42 +08:00
// prevGroup connection nextGroup
// The current connection's end point is used since there may not be a next connection
FollowPointConnection previousConnection = connections [ index - 1 ] ;
previousConnection . End = connection . End ;
2018-04-13 17:19:50 +08:00
}
2019-11-01 14:39:23 +08:00
2019-11-06 15:36:12 +08:00
connections . Remove ( connection ) ;
2019-11-01 14:39:23 +08:00
}
2019-11-06 15:33:42 +08:00
private void onStartTimeChanged ( FollowPointConnection connection )
2019-11-01 14:39:23 +08:00
{
2019-11-05 22:20:46 +08:00
// Naive but can be improved if performance becomes an issue
2019-11-06 15:33:42 +08:00
removeGroup ( connection ) ;
addConnection ( connection ) ;
2018-04-13 17:19:50 +08:00
}
}
}