private static List <SliderPartCherry> generateSliderBody(HitObject obj, IHasCurve curve, bool isKiai, int index) { var objPosition = (obj as IHasPosition)?.Position ?? Vector2.Zero; var comboData = obj as IHasCombo; List <SliderPartCherry> hitObjects = new List <SliderPartCherry>(); var bodyCherriesCount = Math.Min(curve.Distance * (curve.RepeatCount + 1) / 10, max_visuals_per_slider_span * (curve.RepeatCount + 1)); for (int i = 0; i < bodyCherriesCount; i++) { var progress = (float)i / bodyCherriesCount; var position = curve.CurvePositionAt(progress) + objPosition; position *= new Vector2(1, 0.5f); if (positionIsValid(position)) { hitObjects.Add(new SliderPartCherry { StartTime = obj.StartTime + curve.Duration * progress, Position = position, NewCombo = comboData?.NewCombo ?? false, ComboOffset = comboData?.ComboOffset ?? 0, IndexInBeatmap = index, IsKiai = isKiai, }); } } return(hitObjects); }
private static List <TouhouHitObject> generateDefaultSlider(HitObject obj, IBeatmap beatmap, IHasCurve curve, double spanDuration, bool isKiai, int index) { List <TouhouHitObject> hitObjects = new List <TouhouHitObject>(); var objPosition = (obj as IHasPosition)?.Position ?? Vector2.Zero; var comboData = obj as IHasCombo; var difficulty = beatmap.BeatmapInfo.BaseDifficulty; var controlPointInfo = beatmap.ControlPointInfo; TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(obj.StartTime); DifficultyControlPoint difficultyPoint = controlPointInfo.DifficultyPointAt(obj.StartTime); double scoringDistance = 100 * difficulty.SliderMultiplier * difficultyPoint.SpeedMultiplier; var velocity = scoringDistance / timingPoint.BeatLength; var tickDistance = scoringDistance / difficulty.SliderTickRate; double legacyLastTickOffset = (obj as IHasLegacyLastTickOffset)?.LegacyLastTickOffset ?? 0; foreach (var e in SliderEventGenerator.Generate(obj.StartTime, spanDuration, velocity, tickDistance, curve.Path.Distance, curve.RepeatCount + 1, legacyLastTickOffset)) { var sliderEventPosition = (curve.CurvePositionAt(e.PathProgress / (curve.RepeatCount + 1)) + objPosition) * new Vector2(1, 0.5f); switch (e.Type) { case SliderEventType.Head: hitObjects.Add(new SoundHitObject { StartTime = obj.StartTime, Samples = obj.Samples }); break; case SliderEventType.Tick: if (positionIsValid(sliderEventPosition)) { hitObjects.Add(new TickCherry { Angle = 180, StartTime = e.Time, Position = sliderEventPosition, NewCombo = comboData?.NewCombo ?? false, ComboOffset = comboData?.ComboOffset ?? 0, IndexInBeatmap = index, IsKiai = isKiai }); } hitObjects.Add(new SoundHitObject { StartTime = e.Time, Samples = getTickSamples(obj.Samples) }); break; case SliderEventType.Repeat: if (positionIsValid(sliderEventPosition)) { hitObjects.AddRange(generateTriangularExplosion( e.Time, 20, sliderEventPosition, comboData, isKiai, index, MathExtensions.GetRandomTimedAngleOffset(e.Time))); } hitObjects.Add(new SoundHitObject { StartTime = e.Time, Samples = obj.Samples }); break; case SliderEventType.Tail: if (positionIsValid(sliderEventPosition)) { hitObjects.AddRange(generateExplosion( e.Time, Math.Clamp((int)curve.Distance / 15, 5, 20), sliderEventPosition, comboData, isKiai, index)); } hitObjects.Add(new SoundHitObject { StartTime = curve.EndTime, Samples = obj.Samples }); break; } } hitObjects.AddRange(generateSliderBody(obj, curve, isKiai, index)); return(hitObjects); }