// Copyright (c) 2007-2017 ppy Pty Ltd . // 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.Game.Rulesets.Objects.Drawables; using OpenTK; namespace osu.Game.Rulesets.Timing.Drawables { /// /// A container for hit objects which applies applies the speed changes defined by the and /// properties to its to affect the scroll speed. /// public abstract class DrawableTimingSection : Container { public readonly TimingSection TimingSection; protected override Container Content => content; private Container content; private readonly Axes scrollingAxes; /// /// Creates a new . /// /// The encapsulated timing section that provides the speed changes. /// The axes through which this drawable timing section scrolls through. protected DrawableTimingSection(TimingSection timingSection, Axes scrollingAxes) { this.scrollingAxes = scrollingAxes; TimingSection = timingSection; } [BackgroundDependencyLoader] private void load() { AddInternal(content = CreateHitObjectCollection()); content.RelativeChildOffset = new Vector2((scrollingAxes & Axes.X) > 0 ? (float)TimingSection.Time : 0, (scrollingAxes & Axes.Y) > 0 ? (float)TimingSection.Time : 0); } public override Axes RelativeSizeAxes { get { return Axes.Both; } set { throw new InvalidOperationException($"{nameof(DrawableTimingSection)} must always be relatively-sized."); } } protected override void Update() { var parent = Parent as TimingSectionCollection; if (parent == null) return; float speedAdjustedSize = (float)(1000 / TimingSection.BeatLength / TimingSection.SpeedMultiplier); // The application of speed changes happens by modifying our size while maintaining the parent's relative child size as our own // By doing this the scroll speed of the hit objects is changed by a factor of Size / RelativeChildSize Size = new Vector2((scrollingAxes & Axes.X) > 0 ? speedAdjustedSize : 1, (scrollingAxes & Axes.Y) > 0 ? speedAdjustedSize : 1); RelativeChildSize = new Vector2((scrollingAxes & Axes.X) > 0 ? (float)parent.TimeSpan : 1, (scrollingAxes & Axes.Y) > 0 ? (float)parent.TimeSpan : 1); } /// /// Whether this timing change can contain a hit object. This is true if the hit object occurs after this timing change with respect to time. /// public bool CanContain(DrawableHitObject hitObject) => TimingSection.Time <= hitObject.HitObject.StartTime; /// /// Creates the container which handles the movement of a collection of hit objects. /// /// The hit object collection. protected abstract HitObjectCollection CreateHitObjectCollection(); } }