mirror of
https://github.com/osukey/osukey.git
synced 2025-07-01 08:20:00 +09:00
Split out scrolling algorithm
This commit is contained in:
@ -1,19 +1,17 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Caching;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Lists;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Timing;
|
||||
using osu.Game.Rulesets.UI.Scrolling.Algorithms;
|
||||
|
||||
namespace osu.Game.Rulesets.UI.Scrolling
|
||||
{
|
||||
public class ScrollingHitObjectContainer : Playfield.HitObjectContainer
|
||||
public abstract class ScrollingHitObjectContainer : HitObjectContainer
|
||||
{
|
||||
public readonly BindableDouble TimeRange = new BindableDouble
|
||||
{
|
||||
@ -21,22 +19,32 @@ namespace osu.Game.Rulesets.UI.Scrolling
|
||||
MaxValue = double.MaxValue
|
||||
};
|
||||
|
||||
protected readonly SortedList<MultiplierControlPoint> ControlPoints = new SortedList<MultiplierControlPoint>();
|
||||
|
||||
private readonly ScrollingDirection direction;
|
||||
|
||||
private Cached positionCache = new Cached();
|
||||
private Cached initialStateCache = new Cached();
|
||||
|
||||
public ScrollingHitObjectContainer(ScrollingDirection direction)
|
||||
protected ScrollingHitObjectContainer(ScrollingDirection direction)
|
||||
{
|
||||
this.direction = direction;
|
||||
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
|
||||
TimeRange.ValueChanged += v => positionCache.Invalidate();
|
||||
TimeRange.ValueChanged += v => initialStateCache.Invalidate();
|
||||
}
|
||||
|
||||
private IScrollingAlgorithm scrollingAlgorithm;
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
scrollingAlgorithm = CreateScrollingAlgorithm();
|
||||
}
|
||||
|
||||
public override void Add(DrawableHitObject hitObject)
|
||||
{
|
||||
positionCache.Invalidate();
|
||||
initialStateCache.Invalidate();
|
||||
base.Add(hitObject);
|
||||
}
|
||||
|
||||
@ -44,69 +52,42 @@ namespace osu.Game.Rulesets.UI.Scrolling
|
||||
{
|
||||
var result = base.Remove(hitObject);
|
||||
if (result)
|
||||
positionCache.Invalidate();
|
||||
initialStateCache.Invalidate();
|
||||
return result;
|
||||
}
|
||||
|
||||
private readonly SortedList<MultiplierControlPoint> controlPoints = new SortedList<MultiplierControlPoint>();
|
||||
|
||||
public void AddControlPoint(MultiplierControlPoint controlPoint)
|
||||
{
|
||||
controlPoints.Add(controlPoint);
|
||||
positionCache.Invalidate();
|
||||
ControlPoints.Add(controlPoint);
|
||||
initialStateCache.Invalidate();
|
||||
}
|
||||
|
||||
public bool RemoveControlPoint(MultiplierControlPoint controlPoint)
|
||||
{
|
||||
var result = controlPoints.Remove(controlPoint);
|
||||
var result = ControlPoints.Remove(controlPoint);
|
||||
if (result)
|
||||
positionCache.Invalidate();
|
||||
initialStateCache.Invalidate();
|
||||
return result;
|
||||
}
|
||||
|
||||
public override bool Invalidate(Invalidation invalidation = Invalidation.All, Drawable source = null, bool shallPropagate = true)
|
||||
{
|
||||
if ((invalidation & (Invalidation.RequiredParentSizeToFit | Invalidation.DrawInfo)) > 0)
|
||||
positionCache.Invalidate();
|
||||
initialStateCache.Invalidate();
|
||||
|
||||
return base.Invalidate(invalidation, source, shallPropagate);
|
||||
}
|
||||
|
||||
private readonly Dictionary<DrawableHitObject, double> hitObjectPositions = new Dictionary<DrawableHitObject, double>();
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
if (positionCache.IsValid)
|
||||
if (initialStateCache.IsValid)
|
||||
return;
|
||||
|
||||
foreach (var obj in Objects)
|
||||
{
|
||||
var startPosition = hitObjectPositions[obj] = positionAt(obj.HitObject.StartTime);
|
||||
scrollingAlgorithm.ComputeInitialStates(Objects, direction, TimeRange, DrawSize);
|
||||
|
||||
obj.LifetimeStart = obj.HitObject.StartTime - TimeRange - 1000;
|
||||
obj.LifetimeEnd = ((obj.HitObject as IHasEndTime)?.EndTime ?? obj.HitObject.StartTime) + TimeRange + 1000;
|
||||
|
||||
if (!(obj.HitObject is IHasEndTime endTime))
|
||||
continue;
|
||||
|
||||
var length = positionAt(endTime.EndTime) - startPosition;
|
||||
|
||||
switch (direction)
|
||||
{
|
||||
case ScrollingDirection.Up:
|
||||
case ScrollingDirection.Down:
|
||||
obj.Height = (float)(length * DrawHeight);
|
||||
break;
|
||||
case ScrollingDirection.Left:
|
||||
case ScrollingDirection.Right:
|
||||
obj.Width = (float)(length * DrawWidth);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
positionCache.Validate();
|
||||
initialStateCache.Validate();
|
||||
}
|
||||
|
||||
protected override void UpdateAfterChildrenLife()
|
||||
@ -116,48 +97,12 @@ namespace osu.Game.Rulesets.UI.Scrolling
|
||||
// We need to calculate this as soon as possible after lifetimes so that hitobjects
|
||||
// get the final say in their positions
|
||||
|
||||
var timelinePosition = positionAt(Time.Current);
|
||||
|
||||
foreach (var obj in AliveObjects)
|
||||
{
|
||||
var finalPosition = hitObjectPositions[obj] - timelinePosition;
|
||||
|
||||
switch (direction)
|
||||
{
|
||||
case ScrollingDirection.Up:
|
||||
obj.Y = (float)(finalPosition * DrawHeight);
|
||||
break;
|
||||
case ScrollingDirection.Down:
|
||||
obj.Y = (float)(-finalPosition * DrawHeight);
|
||||
break;
|
||||
case ScrollingDirection.Left:
|
||||
obj.X = (float)(finalPosition * DrawWidth);
|
||||
break;
|
||||
case ScrollingDirection.Right:
|
||||
obj.X = (float)(-finalPosition * DrawWidth);
|
||||
break;
|
||||
}
|
||||
}
|
||||
scrollingAlgorithm.ComputePositions(AliveObjects, direction, Time.Current, TimeRange, DrawSize);
|
||||
}
|
||||
|
||||
private double positionAt(double time)
|
||||
{
|
||||
double length = 0;
|
||||
for (int i = 0; i < controlPoints.Count; i++)
|
||||
{
|
||||
var current = controlPoints[i];
|
||||
var next = i < controlPoints.Count - 1 ? controlPoints[i + 1] : null;
|
||||
|
||||
if (i > 0 && current.StartTime > time)
|
||||
continue;
|
||||
|
||||
// Duration of the current control point
|
||||
var currentDuration = (next?.StartTime ?? double.PositiveInfinity) - current.StartTime;
|
||||
|
||||
length += Math.Min(currentDuration, time - current.StartTime) * current.Multiplier / TimeRange;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
/// <summary>
|
||||
/// Creates the algorithm that will process the positions of the <see cref="DrawableHitObject"/>s.
|
||||
/// </summary>
|
||||
protected abstract IScrollingAlgorithm CreateScrollingAlgorithm();
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user