private void createTicks() { if (TickDistance == 0) { return; } var length = Curve.Distance; var tickDistance = Math.Min(TickDistance, length); var repeatDuration = length / Velocity; var minDistanceFromEnd = Velocity * 0.01; AddNested(new Fruit { Samples = Samples, ComboColour = ComboColour, StartTime = StartTime, X = X }); for (var repeat = 0; repeat < RepeatCount; repeat++) { var repeatStartTime = StartTime + repeat * repeatDuration; var reversed = repeat % 2 == 1; for (var d = tickDistance; d <= length; d += tickDistance) { if (d > length - minDistanceFromEnd) { break; } var timeProgress = d / length; var distanceProgress = reversed ? 1 - timeProgress : timeProgress; var lastTickTime = repeatStartTime + timeProgress * repeatDuration; AddNested(new Droplet { StartTime = lastTickTime, ComboColour = ComboColour, X = Curve.PositionAt(distanceProgress).X / CatchPlayfield.BASE_WIDTH, Samples = new List <SampleInfo>(Samples.Select(s => new SampleInfo { Bank = s.Bank, Name = @"slidertick", Volume = s.Volume })) }); } double tinyTickInterval = tickDistance / length * repeatDuration; while (tinyTickInterval > 100) { tinyTickInterval /= 2; } for (double t = 0; t < repeatDuration; t += tinyTickInterval) { double progress = reversed ? 1 - t / repeatDuration : t / repeatDuration; AddNested(new TinyDroplet { StartTime = repeatStartTime + t, ComboColour = ComboColour, X = Curve.PositionAt(progress).X / CatchPlayfield.BASE_WIDTH, Samples = new List <SampleInfo>(Samples.Select(s => new SampleInfo { Bank = s.Bank, Name = @"slidertick", Volume = s.Volume })) }); } AddNested(new Fruit { Samples = Samples, ComboColour = ComboColour, StartTime = repeatStartTime + repeatDuration, X = Curve.PositionAt(reversed ? 0 : 1).X / CatchPlayfield.BASE_WIDTH }); } }
public Vector2 PositionAt(double progress) => Curve.PositionAt(ProgressAt(progress));
protected override IEnumerable <CytusHitObject> ConvertHitObject(HitObject original, IBeatmap beatmap) { if (!(original is IHasXPosition)) { throw new Exception($"This hitobject of type {original.GetType().Name} is not a {nameof(IHasXPosition)}!"); } double time = original.StartTime; float x = ((IHasXPosition)original).X; float y = beatmap.GetScanPosition(original.StartTime, Constants.BeatsPerScan); // we have to determine if this is a slider or normal hitobject // TODO: check for IHasRepeats if (original is IHasCurve ihc) { CytusSliderTick lastTick; double endTime = ihc.EndTime; var tp = beatmap.ControlPointInfo.TimingPointAt(time); double tickInterval = tp.BeatLength / (int)tp.TimeSignature; SliderCurve curve = ihc.Curve ?? new SliderCurve { ControlPoints = ihc.ControlPoints, CurveType = ihc.CurveType, Distance = ihc.Distance, Offset = Vector2.Zero }; var end = lastTick = new CytusSliderEnd(endTime, x + curve.PositionAt(1).X, beatmap.GetScanPosition(endTime, Constants.BeatsPerScan)) { Samples = original.Samples, SampleControlPoint = original.SampleControlPoint }; var ticks = new List <CytusSliderTick>(); for (double i = endTime - tickInterval; i >= time + tickInterval / 2; i -= tickInterval) { ticks.Add(lastTick = new CytusSliderTick(i, x + curve.PositionAt((i - time) / (endTime - time)).X, beatmap.GetScanPosition(i, Constants.BeatsPerScan), lastTick) { Samples = original.Samples, SampleControlPoint = original.SampleControlPoint }); } var start = new CytusSliderHead(original.StartTime, x, y, lastTick) { Samples = original.Samples, SampleControlPoint = original.SampleControlPoint }; yield return(start); foreach (var tick in ticks) { yield return(tick); } yield return(end); } else { // This is a normal note yield return(new CytusNote(time, x, y) { Samples = original.Samples, SampleControlPoint = original.SampleControlPoint }); } }