예제 #1
0
        protected override IEnumerable <DifficultyHitObject> CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate)
        {
            float halfCatchWidth;

            using (var catcher = new CatcherArea.Catcher(beatmap.BeatmapInfo.BaseDifficulty))
            {
                halfCatchWidth = catcher.CatchWidth * 0.5f;

                // We're only using 80% of the catcher's width to simulate imperfect gameplay, reduced further at circle sizes above 5.5
                halfCatchWidth *= Math.Min(1.075f - (0.05f * beatmap.BeatmapInfo.BaseDifficulty.CircleSize), 0.8f);
            }

            CatchHitObject lastObject = null;

            // In 2B beatmaps, it is possible that a normal Fruit is placed in the middle of a JuiceStream.
            foreach (var hitObject in beatmap.HitObjects
                     .SelectMany(obj => obj is JuiceStream stream ? stream.NestedHitObjects : new[] { obj })
                     .Cast <CatchHitObject>()
                     .OrderBy(x => x.StartTime))
            {
                // We want to only consider fruits that contribute to the combo.
                if (hitObject is BananaShower || hitObject is TinyDroplet)
                {
                    continue;
                }

                if (lastObject != null)
                {
                    yield return(new CatchDifficultyHitObject(hitObject, lastObject, clockRate, halfCatchWidth));
                }

                lastObject = hitObject;
            }
        }
예제 #2
0
        public CatchDifficultyCalculator(Ruleset ruleset, WorkingBeatmap beatmap)
            : base(ruleset, beatmap)
        {
            var catcher = new CatcherArea.Catcher(beatmap.BeatmapInfo.BaseDifficulty);

            halfCatchWidth = catcher.CatchWidth * 0.5f;

            // We're only using 80% of the catcher's width to simulate imperfect gameplay.
            halfCatchWidth *= 0.8f;
        }
예제 #3
0
        protected override DifficultyAttributes Calculate(IBeatmap beatmap, Mod[] mods, double timeRate)
        {
            if (!beatmap.HitObjects.Any())
            {
                return(new CatchDifficultyAttributes(mods, 0));
            }

            var   catcher        = new CatcherArea.Catcher(beatmap.BeatmapInfo.BaseDifficulty);
            float halfCatchWidth = catcher.CatchWidth * 0.5f;

            var difficultyHitObjects = new List <CatchDifficultyHitObject>();

            foreach (var hitObject in beatmap.HitObjects)
            {
                switch (hitObject)
                {
                // We want to only consider fruits that contribute to the combo. Droplets are addressed as accuracy and spinners are not relevant for "skill" calculations.
                case Fruit fruit:
                    difficultyHitObjects.Add(new CatchDifficultyHitObject(fruit, halfCatchWidth));
                    break;

                case JuiceStream _:
                    difficultyHitObjects.AddRange(hitObject.NestedHitObjects.OfType <CatchHitObject>().Where(o => !(o is TinyDroplet)).Select(o => new CatchDifficultyHitObject(o, halfCatchWidth)));
                    break;
                }
            }

            difficultyHitObjects.Sort((a, b) => a.BaseHitObject.StartTime.CompareTo(b.BaseHitObject.StartTime));

            if (!calculateStrainValues(difficultyHitObjects, timeRate))
            {
                return(new CatchDifficultyAttributes(mods, 0));
            }

            // this is the same as osu!, so there's potential to share the implementation... maybe
            double preempt    = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450) / timeRate;
            double starRating = Math.Sqrt(calculateDifficulty(difficultyHitObjects, timeRate)) * star_scaling_factor;

            return(new CatchDifficultyAttributes(mods, starRating)
            {
                ApproachRate = preempt > 1200.0 ? -(preempt - 1800.0) / 120.0 : -(preempt - 1200.0) / 150.0 + 5.0,
                MaxCombo = difficultyHitObjects.Count
            });
        }
예제 #4
0
        protected override IEnumerable <DifficultyHitObject> CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate)
        {
            float halfCatchWidth;

            using (var catcher = new CatcherArea.Catcher(beatmap.BeatmapInfo.BaseDifficulty))
            {
                halfCatchWidth = catcher.CatchWidth * 0.5f;

                halfCatchWidth *= 0.8f; // We're only using 80% of the catcher's width to simulate imperfect gameplay.
            }

            CatchHitObject lastObject = null;

            foreach (var hitObject in beatmap.HitObjects.OfType <CatchHitObject>())
            {
                if (lastObject == null)
                {
                    lastObject = hitObject;
                    continue;
                }

                switch (hitObject)
                {
                // We want to only consider fruits that contribute to the combo. Droplets are addressed as accuracy and spinners are not relevant for "skill" calculations.
                case Fruit fruit:
                    yield return(new CatchDifficultyHitObject(fruit, lastObject, clockRate, halfCatchWidth));

                    lastObject = hitObject;
                    break;

                case JuiceStream _:
                    foreach (var nested in hitObject.NestedHitObjects.OfType <CatchHitObject>().Where(o => !(o is TinyDroplet)))
                    {
                        yield return(new CatchDifficultyHitObject(nested, lastObject, clockRate, halfCatchWidth));

                        lastObject = nested;
                    }

                    break;
                }
            }
        }
예제 #5
0
 public MouseInputHelper(CatchPlayfield playfield)
 {
     catcher          = playfield.CatcherArea.MovableCatcher;
     RelativeSizeAxes = Axes.Both;
 }