1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-14 17:57:38 +08:00
osu-lazer/osu.Game/Rulesets/Objects/HitObject.cs

150 lines
5.3 KiB
C#
Raw Normal View History

// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
2018-04-13 17:19:50 +08:00
using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
2018-04-13 17:19:50 +08:00
using Newtonsoft.Json;
using osu.Framework.Bindables;
2018-04-13 17:19:50 +08:00
using osu.Game.Audio;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Judgements;
2018-04-13 17:19:50 +08:00
using osu.Game.Rulesets.Objects.Types;
2019-09-06 14:24:00 +08:00
using osu.Game.Rulesets.Scoring;
2018-04-13 17:19:50 +08:00
namespace osu.Game.Rulesets.Objects
{
/// <summary>
/// A HitObject describes an object in a Beatmap.
/// <para>
/// HitObjects may contain more properties for which you should be checking through the IHas* types.
/// </para>
/// </summary>
public class HitObject
{
/// <summary>
/// A small adjustment to the start time of control points to account for rounding/precision errors.
/// </summary>
private const double control_point_leniency = 1;
public readonly Bindable<double> StartTimeBindable = new Bindable<double>();
2018-04-13 17:19:50 +08:00
/// <summary>
/// The time at which the HitObject starts.
/// </summary>
public virtual double StartTime
{
get => StartTimeBindable.Value;
set => StartTimeBindable.Value = value;
}
2018-04-13 17:19:50 +08:00
2019-06-30 20:58:30 +08:00
private List<HitSampleInfo> samples;
2018-04-13 17:19:50 +08:00
/// <summary>
/// The samples to be played when this hit object is hit.
/// <para>
/// In the case of <see cref="IHasRepeats"/> types, this is the sample of the curve body
/// and can be treated as the default samples for the hit object.
/// </para>
/// </summary>
2019-06-30 20:58:30 +08:00
public List<HitSampleInfo> Samples
2018-04-13 17:19:50 +08:00
{
2019-06-30 20:58:30 +08:00
get => samples ?? (samples = new List<HitSampleInfo>());
2018-04-13 17:19:50 +08:00
set => samples = value;
}
[JsonIgnore]
public SampleControlPoint SampleControlPoint;
/// <summary>
/// Whether this <see cref="HitObject"/> is in Kiai time.
/// </summary>
[JsonIgnore]
public bool Kiai { get; private set; }
/// <summary>
/// The hit windows for this <see cref="HitObject"/>.
/// </summary>
public HitWindows HitWindows { get; set; }
2018-04-13 17:19:50 +08:00
2018-11-05 11:15:45 +08:00
private readonly List<HitObject> nestedHitObjects = new List<HitObject>();
2018-04-13 17:19:50 +08:00
[JsonIgnore]
2018-10-10 12:03:18 +08:00
public IReadOnlyList<HitObject> NestedHitObjects => nestedHitObjects;
2018-04-13 17:19:50 +08:00
public HitObject()
{
StartTimeBindable.ValueChanged += time =>
{
double offset = time.NewValue - time.OldValue;
foreach (var nested in NestedHitObjects)
nested.StartTime += offset;
};
}
2018-04-13 17:19:50 +08:00
/// <summary>
/// Applies default values to this HitObject.
/// </summary>
/// <param name="controlPointInfo">The control points.</param>
/// <param name="difficulty">The difficulty settings to use.</param>
public void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
{
ApplyDefaultsToSelf(controlPointInfo, difficulty);
// This is done here since ApplyDefaultsToSelf may be used to determine the end time
SampleControlPoint = controlPointInfo.SamplePointAt(((this as IHasEndTime)?.EndTime ?? StartTime) + control_point_leniency);
2018-10-10 12:03:18 +08:00
nestedHitObjects.Clear();
2018-04-13 17:19:50 +08:00
CreateNestedHitObjects();
if (this is IHasComboInformation hasCombo)
{
foreach (var n in NestedHitObjects.OfType<IHasComboInformation>())
{
n.ComboIndexBindable.BindTo(hasCombo.ComboIndexBindable);
n.IndexInCurrentComboBindable.BindTo(hasCombo.IndexInCurrentComboBindable);
}
}
2018-11-05 11:15:45 +08:00
nestedHitObjects.Sort((h1, h2) => h1.StartTime.CompareTo(h2.StartTime));
2018-10-10 13:58:29 +08:00
foreach (var h in nestedHitObjects)
2018-10-10 12:03:18 +08:00
h.ApplyDefaults(controlPointInfo, difficulty);
2018-04-13 17:19:50 +08:00
}
protected virtual void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
{
Kiai = controlPointInfo.EffectPointAt(StartTime + control_point_leniency).KiaiMode;
2018-04-13 17:19:50 +08:00
if (HitWindows == null)
HitWindows = CreateHitWindows();
HitWindows?.SetDifficulty(difficulty.OverallDifficulty);
2018-04-13 17:19:50 +08:00
}
protected virtual void CreateNestedHitObjects()
{
}
2018-10-10 12:03:18 +08:00
protected void AddNested(HitObject hitObject) => nestedHitObjects.Add(hitObject);
/// <summary>
/// Creates the <see cref="Judgement"/> that represents the scoring information for this <see cref="HitObject"/>.
/// May be null.
/// </summary>
2018-08-06 10:50:18 +08:00
public virtual Judgement CreateJudgement() => null;
/// <summary>
/// Creates the <see cref="HitWindows"/> for this <see cref="HitObject"/>.
2019-09-02 16:15:36 +08:00
/// This can be null to indicate that the <see cref="HitObject"/> has no <see cref="HitWindows"/> and timing errors should not be displayed to the user.
/// <para>
2019-04-25 16:36:17 +08:00
/// This will only be invoked if <see cref="HitWindows"/> hasn't been set externally (e.g. from a <see cref="BeatmapConverter{T}"/>.
/// </para>
/// </summary>
2019-10-09 18:08:31 +08:00
[NotNull]
protected virtual HitWindows CreateHitWindows() => new HitWindows();
2018-04-13 17:19:50 +08:00
}
}