/// <summary> /// Connect two objects that occur at the same time with a line. /// </summary> private pSprite Connect(HitObject h1, HitObject h2, bool useEnd = false) { Vector2 p1 = useEnd ? h1.EndPosition : h1.Position; Vector2 p2 = h2.Position; HitObject firstObject = h1.CompareTo(h2) <= 0 ? h1 : h2; float length = ((p2 - p1).Length - DifficultyManager.HitObjectRadiusSolidGamefield * 1.96f) / DifficultyManager.HitObjectSizeModifier; pSprite connectingLine = new pSprite(TextureManager.Load(OsuTexture.connectionline), FieldTypes.GamefieldSprites, OriginTypes.Centre, firstObject.Sprites[0].Clocking, (p2 + p1) / 2, SpriteManager.drawOrderBwd(firstObject.EndTime - 15), false, Color4.White); //a small hack to allow for texel boundaries to be the correct colour. connectingLine.DrawLeft++; connectingLine.DrawWidth -= 2; connectingLine.ExactCoordinates = false; connectingLine.Scale = new Vector2(length / 2 * (1 / GameBase.SpriteToBaseRatio), 1); connectingLine.Rotation = (float)Math.Atan2(p2.Y - p1.Y, p2.X - p1.X); int startTime = (useEnd && h1 is Slider) ? ((Slider)h1).snakingEnd : h1.StartTime - DifficultyManager.PreEmpt; startTime = Math.Max(startTime, h2.StartTime - DifficultyManager.PreEmpt); connectingLine.Transform(new TransformationF(TransformationType.Fade, 0, 1, startTime, startTime + DifficultyManager.FadeIn)); foreach (Transformation t in (h1.EndTime < h2.EndTime ? h1.Sprites[0].Transformations : h2.Sprites[0].Transformations)) { if (t is TransformationF tf && tf.EndFloat == 0) { connectingLine.Transform(t); } } h2.Sprites.Add(connectingLine); connectingLine.TagNumeric = HitObject.DIMMABLE_TAG; h1.connectedObject = h2; h2.connectedObject = h1; h1.connectionSprite = connectingLine; h2.connectionSprite = connectingLine; return(connectingLine); }