// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. using System; using System.Collections.Generic; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Scoring; using osuTK; using osuTK.Graphics; namespace osu.Game.Rulesets.Catch.Objects.Drawable { public abstract class PalpableCatchHitObject : DrawableCatchHitObject where TObject : CatchHitObject { public override bool CanBePlated => true; protected Container ScaleContainer; protected PalpableCatchHitObject(TObject hitObject) : base(hitObject) { Origin = Anchor.Centre; Size = new Vector2(CatchHitObject.OBJECT_RADIUS * 2); Masking = false; } [BackgroundDependencyLoader] private void load() { AddRangeInternal(new Framework.Graphics.Drawable[] { ScaleContainer = new Container { RelativeSizeAxes = Axes.Both, Origin = Anchor.Centre, Anchor = Anchor.Centre, } }); ScaleContainer.Scale = new Vector2(HitObject.Scale); } protected override void UpdateComboColour(Color4 proposedColour, IReadOnlyList comboColours) { // ignore the incoming combo colour as we use a custom lookup AccentColour.Value = comboColours[(HitObject.IndexInBeatmap + 1) % comboColours.Count]; } } public abstract class DrawableCatchHitObject : DrawableCatchHitObject where TObject : CatchHitObject { public new TObject HitObject; protected DrawableCatchHitObject(TObject hitObject) : base(hitObject) { HitObject = hitObject; Anchor = Anchor.BottomLeft; } } public abstract class DrawableCatchHitObject : DrawableHitObject { public virtual bool CanBePlated => false; public virtual bool StaysOnPlate => CanBePlated; public float DisplayRadius => DrawSize.X / 2 * Scale.X * HitObject.Scale; protected DrawableCatchHitObject(CatchHitObject hitObject) : base(hitObject) { RelativePositionAxes = Axes.X; X = hitObject.X; } public Func CheckPosition; public bool IsOnPlate; public override bool RemoveWhenNotAlive => IsOnPlate; protected override void CheckForResult(bool userTriggered, double timeOffset) { if (CheckPosition == null) return; if (timeOffset >= 0 && Result != null) ApplyResult(r => r.Type = CheckPosition.Invoke(HitObject) ? HitResult.Perfect : HitResult.Miss); } protected sealed override double InitialLifetimeOffset => HitObject.TimePreempt; protected override void UpdateInitialTransforms() => this.FadeInFromZero(200); protected override void UpdateStateTransforms(ArmedState state) { var endTime = HitObject.GetEndTime(); using (BeginAbsoluteSequence(endTime, true)) { switch (state) { case ArmedState.Miss: this.FadeOut(250).RotateTo(Rotation * 2, 250, Easing.Out); break; case ArmedState.Hit: this.FadeOut(); break; } } } } }