diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableBananaShower.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableBananaShower.cs index b5d9163a50..72aeddee56 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableBananaShower.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableBananaShower.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; using System.Linq; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -12,7 +13,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable { private readonly Container bananaContainer; - public DrawableBananaShower(BananaShower s) + public DrawableBananaShower(BananaShower s, Func> getVisualRepresentation = null) : base(s) { RelativeSizeAxes = Axes.X; @@ -22,7 +23,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable Child = bananaContainer = new Container { RelativeSizeAxes = Axes.Both }; foreach (var b in s.NestedHitObjects.Cast()) - AddNested(new DrawableFruit(b)); + AddNested(getVisualRepresentation?.Invoke(b)); } protected override void AddNested(DrawableHitObject h) diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs index 554fb1323e..8871e26101 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs @@ -5,6 +5,7 @@ using System; using osu.Framework.Graphics; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Objects.Types; using OpenTK; using osu.Game.Rulesets.Scoring; @@ -13,6 +14,8 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable public abstract class PalpableCatchHitObject : DrawableCatchHitObject where TObject : CatchHitObject { + public override bool CanBePlated => true; + protected PalpableCatchHitObject(TObject hitObject) : base(hitObject) { @@ -36,6 +39,8 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable public abstract class DrawableCatchHitObject : DrawableHitObject { + public virtual bool CanBePlated => false; + protected DrawableCatchHitObject(CatchHitObject hitObject) : base(hitObject) { @@ -47,8 +52,10 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable protected override void CheckForJudgements(bool userTriggered, double timeOffset) { + if (CheckPosition == null) return; + if (timeOffset > 0) - AddJudgement(new Judgement { Result = CheckPosition?.Invoke(HitObject) ?? false ? HitResult.Perfect : HitResult.Miss }); + AddJudgement(new Judgement { Result = (bool)CheckPosition?.Invoke(HitObject) ? HitResult.Perfect : HitResult.Miss }); } private const float preempt = 1000; @@ -61,12 +68,19 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable this.FadeIn(200); } - switch (state) + var endTime = (HitObject as IHasEndTime)?.EndTime ?? HitObject.StartTime; + + using (BeginAbsoluteSequence(endTime, true)) { - case ArmedState.Miss: - using (BeginAbsoluteSequence(HitObject.StartTime, true)) - this.FadeOut(250).RotateTo(Rotation * 2, 250, Easing.Out); - break; + switch (state) + { + case ArmedState.Miss: + this.FadeOut(250).RotateTo(Rotation * 2, 250, Easing.Out).Expire(); + break; + case ArmedState.Hit: + this.FadeOut().Expire(); + break; + } } } } diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableJuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableJuiceStream.cs index e66999229c..c8b15aec61 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableJuiceStream.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableJuiceStream.cs @@ -1,9 +1,10 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; +using System.Linq; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using OpenTK; using osu.Game.Rulesets.Objects.Drawables; namespace osu.Game.Rulesets.Catch.Objects.Drawable @@ -12,7 +13,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable { private readonly Container dropletContainer; - public DrawableJuiceStream(JuiceStream s) + public DrawableJuiceStream(JuiceStream s, Func> getVisualRepresentation = null) : base(s) { RelativeSizeAxes = Axes.Both; @@ -21,21 +22,8 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable Child = dropletContainer = new Container { RelativeSizeAxes = Axes.Both, }; - foreach (var tick in s.NestedHitObjects) - { - switch (tick) - { - case TinyDroplet tiny: - AddNested(new DrawableDroplet(tiny) { Scale = new Vector2(0.5f) }); - break; - case Droplet droplet: - AddNested(new DrawableDroplet(droplet)); - break; - case Fruit fruit: - AddNested(new DrawableFruit(fruit)); - break; - } - } + foreach (var o in s.NestedHitObjects.Cast()) + AddNested(getVisualRepresentation?.Invoke(o)); } protected override void AddNested(DrawableHitObject h) diff --git a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs index b1c83f5964..188af58e6a 100644 --- a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs +++ b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs @@ -125,10 +125,8 @@ namespace osu.Game.Rulesets.Catch.Objects X = Curve.PositionAt(reversed ? 0 : 1).X / CatchPlayfield.BASE_WIDTH }); } - } - public double EndTime => StartTime + RepeatCount * Curve.Distance / Velocity; public float EndX => Curve.PositionAt(ProgressAt(1)).X / CatchPlayfield.BASE_WIDTH; diff --git a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs index 7fdabd46c2..8ea30a2899 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Beatmaps; @@ -21,7 +22,7 @@ namespace osu.Game.Rulesets.Catch.UI private readonly CatcherArea catcherArea; - public CatchPlayfield(BeatmapDifficulty difficulty) + public CatchPlayfield(BeatmapDifficulty difficulty, Func> getVisualRepresentation) : base(ScrollingDirection.Down, BASE_WIDTH) { Container explodingFruitContainer; @@ -44,6 +45,7 @@ namespace osu.Game.Rulesets.Catch.UI }, catcherArea = new CatcherArea(difficulty) { + GetVisualRepresentation = getVisualRepresentation, ExplodingFruitTarget = explodingFruitContainer, Anchor = Anchor.BottomLeft, Origin = Anchor.TopLeft, diff --git a/osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs b/osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs index ae0fe8189e..956a524121 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs @@ -13,6 +13,7 @@ using osu.Game.Rulesets.Replays; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI.Scrolling; +using OpenTK; namespace osu.Game.Rulesets.Catch.UI { @@ -31,7 +32,7 @@ namespace osu.Game.Rulesets.Catch.UI protected override BeatmapConverter CreateBeatmapConverter() => new CatchBeatmapConverter(); - protected override Playfield CreatePlayfield() => new CatchPlayfield(Beatmap.BeatmapInfo.BaseDifficulty); + protected override Playfield CreatePlayfield() => new CatchPlayfield(Beatmap.BeatmapInfo.BaseDifficulty, GetVisualRepresentation); public override PassThroughInputManager CreateInputManager() => new CatchInputManager(Ruleset.RulesetInfo); @@ -42,9 +43,13 @@ namespace osu.Game.Rulesets.Catch.UI case Fruit fruit: return new DrawableFruit(fruit); case JuiceStream stream: - return new DrawableJuiceStream(stream); + return new DrawableJuiceStream(stream, GetVisualRepresentation); case BananaShower banana: - return new DrawableBananaShower(banana); + return new DrawableBananaShower(banana, GetVisualRepresentation); + case TinyDroplet tiny: + return new DrawableDroplet(tiny) { Scale = new Vector2(0.5f) }; + case Droplet droplet: + return new DrawableDroplet(droplet); } return null; diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs index 1837086d9c..6d0c3589e8 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs @@ -16,7 +16,6 @@ using osu.Game.Rulesets.Catch.Objects.Drawable; using osu.Game.Rulesets.Catch.Replays; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects.Drawables; -using osu.Game.Rulesets.UI; using OpenTK; using OpenTK.Graphics; @@ -28,6 +27,8 @@ namespace osu.Game.Rulesets.Catch.UI protected readonly Catcher MovableCatcher; + public Func> GetVisualRepresentation; + public Container ExplodingFruitTarget { set { MovableCatcher.ExplodingFruitTarget = value; } @@ -45,23 +46,24 @@ namespace osu.Game.Rulesets.Catch.UI public void OnJudgement(DrawableCatchHitObject fruit, Judgement judgement) { - if (judgement.IsHit) + if (judgement.IsHit && fruit.CanBePlated) { - var screenSpacePosition = fruit.ScreenSpaceDrawQuad.Centre; + var caughtFruit = (DrawableCatchHitObject)GetVisualRepresentation?.Invoke(fruit.HitObject); - // todo: make this less ugly, somehow. - (fruit.Parent as HitObjectContainer)?.Remove(fruit); - (fruit.Parent as Container)?.Remove(fruit); + if (caughtFruit != null) + { + caughtFruit.State.Value = ArmedState.Idle; + caughtFruit.AccentColour = fruit.AccentColour; + caughtFruit.RelativePositionAxes = Axes.None; + caughtFruit.Position = new Vector2(MovableCatcher.ToLocalSpace(fruit.ScreenSpaceDrawQuad.Centre).X - MovableCatcher.DrawSize.X / 2, 0); - fruit.RelativePositionAxes = Axes.None; - fruit.Position = new Vector2(MovableCatcher.ToLocalSpace(screenSpacePosition).X - MovableCatcher.DrawSize.X / 2, 0); + caughtFruit.Anchor = Anchor.TopCentre; + caughtFruit.Origin = Anchor.Centre; + caughtFruit.Scale *= 0.7f; + caughtFruit.LifetimeEnd = double.MaxValue; + } - fruit.Anchor = Anchor.TopCentre; - fruit.Origin = Anchor.Centre; - fruit.Scale *= 0.7f; - fruit.LifetimeEnd = double.MaxValue; - - MovableCatcher.Add(fruit); + MovableCatcher.Add(caughtFruit); } if (fruit.HitObject.LastInCombo)