diff --git a/osu.Android.props b/osu.Android.props
index b147fdd05b..6db4220fad 100644
--- a/osu.Android.props
+++ b/osu.Android.props
@@ -52,6 +52,6 @@
-
+
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPoint.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPoint.cs
index 7e530ca047..8bb324d02e 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPoint.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPoint.cs
@@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
///
/// A single follow point positioned between two adjacent s.
///
- public class FollowPoint : Container
+ public class FollowPoint : Container, IAnimationTimeReference
{
private const float width = 8;
@@ -45,5 +45,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
}
}, confineMode: ConfineMode.NoScaling);
}
+
+ public double AnimationStartTime { get; set; }
}
}
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointConnection.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointConnection.cs
index d0935e46f7..6f09bbcd57 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointConnection.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointConnection.cs
@@ -116,6 +116,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
int point = 0;
+ ClearInternal();
+
for (int d = (int)(spacing * 1.5); d < distance - spacing; d += spacing)
{
float fraction = (float)d / distance;
@@ -126,13 +128,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
FollowPoint fp;
- if (InternalChildren.Count > point)
- {
- fp = (FollowPoint)InternalChildren[point];
- fp.ClearTransforms();
- }
- else
- AddInternal(fp = new FollowPoint());
+ AddInternal(fp = new FollowPoint());
fp.Position = pointStartPosition;
fp.Rotation = rotation;
@@ -142,6 +138,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
if (firstTransformStartTime == null)
firstTransformStartTime = fadeInTime;
+ fp.AnimationStartTime = fadeInTime;
+
using (fp.BeginAbsoluteSequence(fadeInTime))
{
fp.FadeIn(osuEnd.TimeFadeIn);
diff --git a/osu.Game/Skinning/IAnimationTimeReference.cs b/osu.Game/Skinning/IAnimationTimeReference.cs
new file mode 100644
index 0000000000..bcff10a24b
--- /dev/null
+++ b/osu.Game/Skinning/IAnimationTimeReference.cs
@@ -0,0 +1,25 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Allocation;
+using osu.Framework.Timing;
+
+namespace osu.Game.Skinning
+{
+ ///
+ /// Denotes an object which provides a reference time to start animations from.
+ ///
+ [Cached]
+ public interface IAnimationTimeReference
+ {
+ ///
+ /// The reference clock.
+ ///
+ IFrameBasedClock Clock { get; }
+
+ ///
+ /// The time which animations should be started from, relative to .
+ ///
+ double AnimationStartTime { get; }
+ }
+}
diff --git a/osu.Game/Skinning/LegacySkinExtensions.cs b/osu.Game/Skinning/LegacySkinExtensions.cs
index 52328d43b2..8765b161d4 100644
--- a/osu.Game/Skinning/LegacySkinExtensions.cs
+++ b/osu.Game/Skinning/LegacySkinExtensions.cs
@@ -3,10 +3,12 @@
using System.Collections.Generic;
using System.Linq;
+using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Animations;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
+using osu.Framework.Timing;
namespace osu.Game.Skinning
{
@@ -22,7 +24,7 @@ namespace osu.Game.Skinning
if (textures.Length > 0)
{
- var animation = new TextureAnimation
+ var animation = new SkinnableTextureAnimation
{
DefaultFrameLength = getFrameLength(source, applyConfigFrameRate, textures),
Repeat = looping,
@@ -53,6 +55,25 @@ namespace osu.Game.Skinning
}
}
+ public class SkinnableTextureAnimation : TextureAnimation
+ {
+ [Resolved(canBeNull: true)]
+ private IAnimationTimeReference timeReference { get; set; }
+
+ public SkinnableTextureAnimation()
+ : base(false)
+ {
+ }
+
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+
+ if (timeReference != null)
+ Clock = new FramedOffsetClock(timeReference.Clock) { Offset = -timeReference.AnimationStartTime };
+ }
+ }
+
private const double default_frame_time = 1000 / 60d;
private static double getFrameLength(ISkin source, bool applyConfigFrameRate, Texture[] textures)
diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj
index 781c566b5f..4163044273 100644
--- a/osu.Game/osu.Game.csproj
+++ b/osu.Game/osu.Game.csproj
@@ -23,7 +23,7 @@
-
+
diff --git a/osu.iOS.props b/osu.iOS.props
index a2c6106931..17430e4b25 100644
--- a/osu.iOS.props
+++ b/osu.iOS.props
@@ -71,7 +71,7 @@
-
+
@@ -79,7 +79,7 @@
-
+