mirror of
https://github.com/osukey/osukey.git
synced 2025-08-04 23:24:04 +09:00
Merge branch 'master' into update-branch
This commit is contained in:
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Beatmaps;
|
||||
@ -11,7 +11,7 @@ using osu.Game.Rulesets.Objects;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Beatmaps
|
||||
{
|
||||
internal class CatchBeatmapConverter : BeatmapConverter<CatchHitObject>
|
||||
public class CatchBeatmapConverter : BeatmapConverter<CatchHitObject>
|
||||
{
|
||||
protected override IEnumerable<Type> ValidConversionTypes { get; } = new[] { typeof(IHasXPosition) };
|
||||
|
||||
@ -20,6 +20,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
|
||||
var curveData = obj as IHasCurve;
|
||||
var positionData = obj as IHasXPosition;
|
||||
var comboData = obj as IHasCombo;
|
||||
var endTime = obj as IHasEndTime;
|
||||
|
||||
if (positionData == null)
|
||||
yield break;
|
||||
@ -42,6 +43,19 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
|
||||
yield break;
|
||||
}
|
||||
|
||||
if (endTime != null)
|
||||
{
|
||||
yield return new BananaShower
|
||||
{
|
||||
StartTime = obj.StartTime,
|
||||
Samples = obj.Samples,
|
||||
Duration = endTime.Duration,
|
||||
NewCombo = comboData?.NewCombo ?? false
|
||||
};
|
||||
|
||||
yield break;
|
||||
}
|
||||
|
||||
yield return new Fruit
|
||||
{
|
||||
StartTime = obj.StartTime,
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
@ -12,14 +12,14 @@ using OpenTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Beatmaps
|
||||
{
|
||||
internal class CatchBeatmapProcessor : BeatmapProcessor<CatchHitObject>
|
||||
public class CatchBeatmapProcessor : BeatmapProcessor<CatchHitObject>
|
||||
{
|
||||
public override void PostProcess(Beatmap<CatchHitObject> beatmap)
|
||||
{
|
||||
if (beatmap.ComboColors.Count == 0)
|
||||
return;
|
||||
|
||||
int comboIndex = 0;
|
||||
int index = 0;
|
||||
int colourIndex = 0;
|
||||
|
||||
CatchHitObject lastObj = null;
|
||||
@ -31,12 +31,10 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
|
||||
if (obj.NewCombo)
|
||||
{
|
||||
if (lastObj != null) lastObj.LastInCombo = true;
|
||||
|
||||
comboIndex = 0;
|
||||
colourIndex = (colourIndex + 1) % beatmap.ComboColors.Count;
|
||||
}
|
||||
|
||||
obj.ComboIndex = comboIndex++;
|
||||
obj.IndexInBeatmap = index++;
|
||||
obj.ComboColour = beatmap.ComboColors[colourIndex];
|
||||
|
||||
lastObj = obj;
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Beatmaps;
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System.ComponentModel;
|
||||
@ -22,6 +22,6 @@ namespace osu.Game.Rulesets.Catch
|
||||
[Description("Move right")]
|
||||
MoveRight,
|
||||
[Description("Engage dash")]
|
||||
Dash
|
||||
Dash,
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Beatmaps;
|
||||
@ -80,7 +80,7 @@ namespace osu.Game.Rulesets.Catch
|
||||
{
|
||||
Mods = new Mod[]
|
||||
{
|
||||
new ModAutoplay(),
|
||||
new CatchModAutoplay(),
|
||||
new ModCinema(),
|
||||
},
|
||||
},
|
||||
@ -101,7 +101,7 @@ namespace osu.Game.Rulesets.Catch
|
||||
|
||||
public override int LegacyID => 2;
|
||||
|
||||
public CatchRuleset(RulesetInfo rulesetInfo)
|
||||
public CatchRuleset(RulesetInfo rulesetInfo = null)
|
||||
: base(rulesetInfo)
|
||||
{
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
|
@ -1,69 +0,0 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Rulesets.Mods;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Mods
|
||||
{
|
||||
public class CatchModNoFail : ModNoFail
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public class CatchModEasy : ModEasy
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public class CatchModHidden : ModHidden
|
||||
{
|
||||
public override string Description => @"Play with fading notes for a slight score advantage.";
|
||||
public override double ScoreMultiplier => 1.06;
|
||||
}
|
||||
|
||||
public class CatchModHardRock : ModHardRock
|
||||
{
|
||||
public override double ScoreMultiplier => 1.12;
|
||||
public override bool Ranked => true;
|
||||
}
|
||||
|
||||
public class CatchModSuddenDeath : ModSuddenDeath
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public class CatchModDaycore : ModDaycore
|
||||
{
|
||||
public override double ScoreMultiplier => 0.5;
|
||||
}
|
||||
|
||||
public class CatchModDoubleTime : ModDoubleTime
|
||||
{
|
||||
public override double ScoreMultiplier => 1.06;
|
||||
}
|
||||
|
||||
public class CatchModRelax : ModRelax
|
||||
{
|
||||
public override string Description => @"Use the mouse to control the catcher.";
|
||||
}
|
||||
|
||||
public class CatchModHalfTime : ModHalfTime
|
||||
{
|
||||
public override double ScoreMultiplier => 0.5;
|
||||
}
|
||||
|
||||
public class CatchModNightcore : ModNightcore
|
||||
{
|
||||
public override double ScoreMultiplier => 1.06;
|
||||
}
|
||||
|
||||
public class CatchModFlashlight : ModFlashlight
|
||||
{
|
||||
public override double ScoreMultiplier => 1.12;
|
||||
}
|
||||
|
||||
public class CatchModPerfect : ModPerfect
|
||||
{
|
||||
|
||||
}
|
||||
}
|
24
osu.Game.Rulesets.Catch/Mods/CatchModAutoplay.cs
Normal file
24
osu.Game.Rulesets.Catch/Mods/CatchModAutoplay.cs
Normal file
@ -0,0 +1,24 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Catch.Objects;
|
||||
using osu.Game.Rulesets.Catch.Replays;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Users;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Mods
|
||||
{
|
||||
public class CatchModAutoplay : ModAutoplay<CatchHitObject>
|
||||
{
|
||||
protected override Score CreateReplayScore(Beatmap<CatchHitObject> beatmap)
|
||||
{
|
||||
return new Score
|
||||
{
|
||||
User = new User { Username = "osu!salad!" },
|
||||
Replay = new CatchAutoGenerator(beatmap).Generate(),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
12
osu.Game.Rulesets.Catch/Mods/CatchModDaycore.cs
Normal file
12
osu.Game.Rulesets.Catch/Mods/CatchModDaycore.cs
Normal file
@ -0,0 +1,12 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Rulesets.Mods;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Mods
|
||||
{
|
||||
public class CatchModDaycore : ModDaycore
|
||||
{
|
||||
public override double ScoreMultiplier => 0.5;
|
||||
}
|
||||
}
|
12
osu.Game.Rulesets.Catch/Mods/CatchModDoubleTime.cs
Normal file
12
osu.Game.Rulesets.Catch/Mods/CatchModDoubleTime.cs
Normal file
@ -0,0 +1,12 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Rulesets.Mods;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Mods
|
||||
{
|
||||
public class CatchModDoubleTime : ModDoubleTime
|
||||
{
|
||||
public override double ScoreMultiplier => 1.06;
|
||||
}
|
||||
}
|
11
osu.Game.Rulesets.Catch/Mods/CatchModEasy.cs
Normal file
11
osu.Game.Rulesets.Catch/Mods/CatchModEasy.cs
Normal file
@ -0,0 +1,11 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Rulesets.Mods;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Mods
|
||||
{
|
||||
public class CatchModEasy : ModEasy
|
||||
{
|
||||
}
|
||||
}
|
12
osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs
Normal file
12
osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs
Normal file
@ -0,0 +1,12 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Rulesets.Mods;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Mods
|
||||
{
|
||||
public class CatchModFlashlight : ModFlashlight
|
||||
{
|
||||
public override double ScoreMultiplier => 1.12;
|
||||
}
|
||||
}
|
12
osu.Game.Rulesets.Catch/Mods/CatchModHalfTime.cs
Normal file
12
osu.Game.Rulesets.Catch/Mods/CatchModHalfTime.cs
Normal file
@ -0,0 +1,12 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Rulesets.Mods;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Mods
|
||||
{
|
||||
public class CatchModHalfTime : ModHalfTime
|
||||
{
|
||||
public override double ScoreMultiplier => 0.5;
|
||||
}
|
||||
}
|
13
osu.Game.Rulesets.Catch/Mods/CatchModHardRock.cs
Normal file
13
osu.Game.Rulesets.Catch/Mods/CatchModHardRock.cs
Normal file
@ -0,0 +1,13 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Rulesets.Mods;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Mods
|
||||
{
|
||||
public class CatchModHardRock : ModHardRock
|
||||
{
|
||||
public override double ScoreMultiplier => 1.12;
|
||||
public override bool Ranked => true;
|
||||
}
|
||||
}
|
13
osu.Game.Rulesets.Catch/Mods/CatchModHidden.cs
Normal file
13
osu.Game.Rulesets.Catch/Mods/CatchModHidden.cs
Normal file
@ -0,0 +1,13 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Rulesets.Mods;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Mods
|
||||
{
|
||||
public class CatchModHidden : ModHidden
|
||||
{
|
||||
public override string Description => @"Play with fading notes for a slight score advantage.";
|
||||
public override double ScoreMultiplier => 1.06;
|
||||
}
|
||||
}
|
12
osu.Game.Rulesets.Catch/Mods/CatchModNightcore.cs
Normal file
12
osu.Game.Rulesets.Catch/Mods/CatchModNightcore.cs
Normal file
@ -0,0 +1,12 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Rulesets.Mods;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Mods
|
||||
{
|
||||
public class CatchModNightcore : ModNightcore
|
||||
{
|
||||
public override double ScoreMultiplier => 1.06;
|
||||
}
|
||||
}
|
11
osu.Game.Rulesets.Catch/Mods/CatchModNoFail.cs
Normal file
11
osu.Game.Rulesets.Catch/Mods/CatchModNoFail.cs
Normal file
@ -0,0 +1,11 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Rulesets.Mods;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Mods
|
||||
{
|
||||
public class CatchModNoFail : ModNoFail
|
||||
{
|
||||
}
|
||||
}
|
11
osu.Game.Rulesets.Catch/Mods/CatchModPerfect.cs
Normal file
11
osu.Game.Rulesets.Catch/Mods/CatchModPerfect.cs
Normal file
@ -0,0 +1,11 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Rulesets.Mods;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Mods
|
||||
{
|
||||
public class CatchModPerfect : ModPerfect
|
||||
{
|
||||
}
|
||||
}
|
12
osu.Game.Rulesets.Catch/Mods/CatchModRelax.cs
Normal file
12
osu.Game.Rulesets.Catch/Mods/CatchModRelax.cs
Normal file
@ -0,0 +1,12 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Rulesets.Mods;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Mods
|
||||
{
|
||||
public class CatchModRelax : ModRelax
|
||||
{
|
||||
public override string Description => @"Use the mouse to control the catcher.";
|
||||
}
|
||||
}
|
11
osu.Game.Rulesets.Catch/Mods/CatchModSuddenDeath.cs
Normal file
11
osu.Game.Rulesets.Catch/Mods/CatchModSuddenDeath.cs
Normal file
@ -0,0 +1,11 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Rulesets.Mods;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Mods
|
||||
{
|
||||
public class CatchModSuddenDeath : ModSuddenDeath
|
||||
{
|
||||
}
|
||||
}
|
63
osu.Game.Rulesets.Catch/Objects/BananaShower.cs
Normal file
63
osu.Game.Rulesets.Catch/Objects/BananaShower.cs
Normal file
@ -0,0 +1,63 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using OpenTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Objects
|
||||
{
|
||||
public class BananaShower : CatchHitObject, IHasEndTime
|
||||
{
|
||||
public override FruitVisualRepresentation VisualRepresentation => FruitVisualRepresentation.Banana;
|
||||
|
||||
public override bool LastInCombo => true;
|
||||
|
||||
protected override void CreateNestedHitObjects()
|
||||
{
|
||||
base.CreateNestedHitObjects();
|
||||
createBananas();
|
||||
}
|
||||
|
||||
private void createBananas()
|
||||
{
|
||||
double spacing = Duration;
|
||||
while (spacing > 100)
|
||||
spacing /= 2;
|
||||
|
||||
if (spacing <= 0)
|
||||
return;
|
||||
|
||||
for (double i = StartTime; i <= EndTime; i += spacing)
|
||||
AddNested(new Banana
|
||||
{
|
||||
Samples = Samples,
|
||||
ComboColour = getNextComboColour(),
|
||||
StartTime = i,
|
||||
X = RNG.NextSingle()
|
||||
});
|
||||
}
|
||||
|
||||
private Color4 getNextComboColour()
|
||||
{
|
||||
switch (RNG.Next(0, 3))
|
||||
{
|
||||
default:
|
||||
return new Color4(255, 240, 0, 255);
|
||||
case 1:
|
||||
return new Color4(255, 192, 0, 255);
|
||||
case 2:
|
||||
return new Color4(214, 221, 28, 255);
|
||||
}
|
||||
}
|
||||
|
||||
public double EndTime => StartTime + Duration;
|
||||
|
||||
public double Duration { get; set; }
|
||||
|
||||
public class Banana : Fruit
|
||||
{
|
||||
public override FruitVisualRepresentation VisualRepresentation => FruitVisualRepresentation.Banana;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Beatmaps;
|
||||
@ -15,8 +15,11 @@ namespace osu.Game.Rulesets.Catch.Objects
|
||||
|
||||
public float X { get; set; }
|
||||
|
||||
public Color4 ComboColour { get; set; } = Color4.Gray;
|
||||
public int ComboIndex { get; set; }
|
||||
public Color4 ComboColour { get; set; }
|
||||
|
||||
public int IndexInBeatmap { get; set; }
|
||||
|
||||
public virtual FruitVisualRepresentation VisualRepresentation => (FruitVisualRepresentation)(IndexInBeatmap % 4);
|
||||
|
||||
public virtual bool NewCombo { get; set; }
|
||||
|
||||
@ -44,4 +47,13 @@ namespace osu.Game.Rulesets.Catch.Objects
|
||||
Scale = 1.0f - 0.7f * (difficulty.CircleSize - 5) / 5;
|
||||
}
|
||||
}
|
||||
|
||||
public enum FruitVisualRepresentation
|
||||
{
|
||||
Pear,
|
||||
Grape,
|
||||
Raspberry,
|
||||
Pineapple,
|
||||
Banana // banananananannaanana
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,44 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// 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 osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
{
|
||||
public class DrawableBananaShower : DrawableCatchHitObject<BananaShower>
|
||||
{
|
||||
private readonly Container bananaContainer;
|
||||
|
||||
public DrawableBananaShower(BananaShower s, Func<CatchHitObject, DrawableHitObject<CatchHitObject>> getVisualRepresentation = null)
|
||||
: base(s)
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
||||
Origin = Anchor.BottomLeft;
|
||||
X = 0;
|
||||
|
||||
Child = bananaContainer = new Container { RelativeSizeAxes = Axes.Both };
|
||||
|
||||
foreach (var b in s.NestedHitObjects.Cast<BananaShower.Banana>())
|
||||
AddNested(getVisualRepresentation?.Invoke(b));
|
||||
}
|
||||
|
||||
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
|
||||
{
|
||||
if (timeOffset >= 0)
|
||||
AddJudgement(new Judgement { Result = NestedHitObjects.Cast<DrawableCatchHitObject>().Any(n => n.Judgements.Any(j => j.IsHit)) ? HitResult.Perfect : HitResult.Miss });
|
||||
}
|
||||
|
||||
protected override void AddNested(DrawableHitObject h)
|
||||
{
|
||||
((DrawableCatchHitObject)h).CheckPosition = o => CheckPosition?.Invoke(o) ?? false;
|
||||
bananaContainer.Add(h);
|
||||
base.AddNested(h);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,15 +1,28 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
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;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
{
|
||||
public abstract class PalpableCatchHitObject<TObject> : DrawableCatchHitObject<TObject>
|
||||
where TObject : CatchHitObject
|
||||
{
|
||||
public override bool CanBePlated => true;
|
||||
|
||||
protected PalpableCatchHitObject(TObject hitObject)
|
||||
: base(hitObject)
|
||||
{
|
||||
Scale = new Vector2(HitObject.Scale);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class DrawableCatchHitObject<TObject> : DrawableCatchHitObject
|
||||
where TObject : CatchHitObject
|
||||
{
|
||||
@ -19,27 +32,29 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
: base(hitObject)
|
||||
{
|
||||
HitObject = hitObject;
|
||||
|
||||
Scale = new Vector2(HitObject.Scale);
|
||||
Anchor = Anchor.BottomLeft;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class DrawableCatchHitObject : DrawableScrollingHitObject<CatchHitObject>
|
||||
public abstract class DrawableCatchHitObject : DrawableHitObject<CatchHitObject>
|
||||
{
|
||||
public virtual bool CanBePlated => false;
|
||||
|
||||
protected DrawableCatchHitObject(CatchHitObject hitObject)
|
||||
: base(hitObject)
|
||||
{
|
||||
RelativePositionAxes = Axes.Both;
|
||||
RelativePositionAxes = Axes.X;
|
||||
X = hitObject.X;
|
||||
Y = (float)HitObject.StartTime;
|
||||
}
|
||||
|
||||
public Func<CatchHitObject, bool> CheckPosition;
|
||||
|
||||
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
|
||||
{
|
||||
if (timeOffset > 0)
|
||||
AddJudgement(new Judgement { Result = CheckPosition?.Invoke(HitObject) ?? false ? HitResult.Perfect : HitResult.Miss });
|
||||
if (CheckPosition == null) return;
|
||||
|
||||
if (timeOffset >= 0)
|
||||
AddJudgement(new Judgement { Result = CheckPosition.Invoke(HitObject) ? HitResult.Perfect : HitResult.Miss });
|
||||
}
|
||||
|
||||
private const float preempt = 1000;
|
||||
@ -47,17 +62,21 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
protected override void UpdateState(ArmedState state)
|
||||
{
|
||||
using (BeginAbsoluteSequence(HitObject.StartTime - preempt))
|
||||
{
|
||||
// animation
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
@ -8,15 +8,13 @@ using OpenTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
{
|
||||
public class DrawableDroplet : DrawableCatchHitObject<Droplet>
|
||||
public class DrawableDroplet : PalpableCatchHitObject<Droplet>
|
||||
{
|
||||
public DrawableDroplet(Droplet h)
|
||||
: base(h)
|
||||
{
|
||||
Origin = Anchor.Centre;
|
||||
|
||||
Size = new Vector2(Pulp.PULP_SIZE);
|
||||
|
||||
Size = new Vector2((float)CatchHitObject.OBJECT_RADIUS) / 4;
|
||||
AccentColour = h.ComboColour;
|
||||
Masking = false;
|
||||
}
|
||||
@ -27,7 +25,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
Child = new Pulp
|
||||
{
|
||||
AccentColour = AccentColour,
|
||||
Scale = new Vector2(0.8f),
|
||||
Size = Size
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,12 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Game.Rulesets.Catch.Objects.Drawable.Pieces;
|
||||
using OpenTK;
|
||||
@ -11,14 +14,16 @@ using OpenTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
{
|
||||
public class DrawableFruit : DrawableCatchHitObject<Fruit>
|
||||
public class DrawableFruit : PalpableCatchHitObject<Fruit>
|
||||
{
|
||||
private Circle border;
|
||||
|
||||
public DrawableFruit(Fruit h)
|
||||
: base(h)
|
||||
{
|
||||
Origin = Anchor.Centre;
|
||||
|
||||
Size = new Vector2(Pulp.PULP_SIZE * 2.2f, Pulp.PULP_SIZE * 2.8f);
|
||||
Size = new Vector2((float)CatchHitObject.OBJECT_RADIUS);
|
||||
AccentColour = HitObject.ComboColour;
|
||||
Masking = false;
|
||||
|
||||
@ -28,48 +33,34 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
Children = new Framework.Graphics.Drawable[]
|
||||
Children = new[]
|
||||
{
|
||||
//todo: share this more
|
||||
new BufferedContainer
|
||||
createPulp(HitObject.VisualRepresentation),
|
||||
border = new Circle
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
CacheDrawnFrameBuffer = true,
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Hollow = !HitObject.HyperDash,
|
||||
Type = EdgeEffectType.Glow,
|
||||
Radius = 4,
|
||||
Colour = HitObject.HyperDash ? Color4.Red : AccentColour.Darken(1).Opacity(0.6f)
|
||||
},
|
||||
Size = new Vector2(Height * 1.5f),
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
BorderColour = Color4.White,
|
||||
BorderThickness = 4f,
|
||||
Children = new Framework.Graphics.Drawable[]
|
||||
{
|
||||
new Pulp
|
||||
new Box
|
||||
{
|
||||
RelativePositionAxes = Axes.Both,
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
AccentColour = AccentColour,
|
||||
Scale = new Vector2(0.6f),
|
||||
},
|
||||
new Pulp
|
||||
{
|
||||
RelativePositionAxes = Axes.Both,
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
AccentColour = AccentColour,
|
||||
Y = -0.08f
|
||||
},
|
||||
new Pulp
|
||||
{
|
||||
RelativePositionAxes = Axes.Both,
|
||||
Anchor = Anchor.CentreRight,
|
||||
Origin = Anchor.CentreRight,
|
||||
AccentColour = AccentColour,
|
||||
Y = -0.08f
|
||||
},
|
||||
new Pulp
|
||||
{
|
||||
RelativePositionAxes = Axes.Both,
|
||||
Anchor = Anchor.BottomCentre,
|
||||
Origin = Anchor.BottomCentre,
|
||||
AccentColour = AccentColour,
|
||||
},
|
||||
AlwaysPresent = true,
|
||||
Colour = AccentColour,
|
||||
Alpha = 0,
|
||||
RelativeSizeAxes = Axes.Both
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
if (HitObject.HyperDash)
|
||||
@ -82,9 +73,205 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
AccentColour = Color4.Red,
|
||||
Blending = BlendingMode.Additive,
|
||||
Alpha = 0.5f,
|
||||
Scale = new Vector2(2)
|
||||
Scale = new Vector2(1.333f)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private Framework.Graphics.Drawable createPulp(FruitVisualRepresentation representation)
|
||||
{
|
||||
const float large_pulp_3 = 13f;
|
||||
const float distance_from_centre_3 = 0.23f;
|
||||
|
||||
const float large_pulp_4 = large_pulp_3 * 0.925f;
|
||||
const float distance_from_centre_4 = distance_from_centre_3 / 0.925f;
|
||||
|
||||
const float small_pulp = large_pulp_3 / 2;
|
||||
|
||||
Vector2 positionAt(float angle, float distance) => new Vector2(
|
||||
distance * (float)Math.Sin(angle * Math.PI / 180),
|
||||
distance * (float)Math.Cos(angle * Math.PI / 180));
|
||||
|
||||
switch (representation)
|
||||
{
|
||||
default:
|
||||
return new Container();
|
||||
case FruitVisualRepresentation.Raspberry:
|
||||
return new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new Framework.Graphics.Drawable[]
|
||||
{
|
||||
new Pulp
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.BottomCentre,
|
||||
AccentColour = AccentColour,
|
||||
Size = new Vector2(small_pulp),
|
||||
Y = 0.05f,
|
||||
},
|
||||
new Pulp
|
||||
{
|
||||
AccentColour = AccentColour,
|
||||
Size = new Vector2(large_pulp_4),
|
||||
Position = positionAt(0, distance_from_centre_4),
|
||||
},
|
||||
new Pulp
|
||||
{
|
||||
AccentColour = AccentColour,
|
||||
Size = new Vector2(large_pulp_4),
|
||||
Position = positionAt(90, distance_from_centre_4),
|
||||
},
|
||||
new Pulp
|
||||
{
|
||||
AccentColour = AccentColour,
|
||||
Size = new Vector2(large_pulp_4),
|
||||
Position = positionAt(180, distance_from_centre_4),
|
||||
},
|
||||
new Pulp
|
||||
{
|
||||
Size = new Vector2(large_pulp_4),
|
||||
AccentColour = AccentColour,
|
||||
Position = positionAt(270, distance_from_centre_4),
|
||||
},
|
||||
}
|
||||
};
|
||||
case FruitVisualRepresentation.Pineapple:
|
||||
return new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new Framework.Graphics.Drawable[]
|
||||
{
|
||||
new Pulp
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.BottomCentre,
|
||||
AccentColour = AccentColour,
|
||||
Size = new Vector2(small_pulp),
|
||||
Y = 0.1f,
|
||||
},
|
||||
new Pulp
|
||||
{
|
||||
AccentColour = AccentColour,
|
||||
Size = new Vector2(large_pulp_4),
|
||||
Position = positionAt(45, distance_from_centre_4),
|
||||
},
|
||||
new Pulp
|
||||
{
|
||||
AccentColour = AccentColour,
|
||||
Size = new Vector2(large_pulp_4),
|
||||
Position = positionAt(135, distance_from_centre_4),
|
||||
},
|
||||
new Pulp
|
||||
{
|
||||
AccentColour = AccentColour,
|
||||
Size = new Vector2(large_pulp_4),
|
||||
Position = positionAt(225, distance_from_centre_4),
|
||||
},
|
||||
new Pulp
|
||||
{
|
||||
Size = new Vector2(large_pulp_4),
|
||||
AccentColour = AccentColour,
|
||||
Position = positionAt(315, distance_from_centre_4),
|
||||
},
|
||||
}
|
||||
};
|
||||
case FruitVisualRepresentation.Pear:
|
||||
return new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new Framework.Graphics.Drawable[]
|
||||
{
|
||||
new Pulp
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
AccentColour = AccentColour,
|
||||
Size = new Vector2(small_pulp),
|
||||
Y = -0.1f,
|
||||
},
|
||||
new Pulp
|
||||
{
|
||||
AccentColour = AccentColour,
|
||||
Size = new Vector2(large_pulp_3),
|
||||
Position = positionAt(60, distance_from_centre_3),
|
||||
},
|
||||
new Pulp
|
||||
{
|
||||
AccentColour = AccentColour,
|
||||
Size = new Vector2(large_pulp_3),
|
||||
Position = positionAt(180, distance_from_centre_3),
|
||||
},
|
||||
new Pulp
|
||||
{
|
||||
Size = new Vector2(large_pulp_3),
|
||||
AccentColour = AccentColour,
|
||||
Position = positionAt(300, distance_from_centre_3),
|
||||
},
|
||||
}
|
||||
};
|
||||
case FruitVisualRepresentation.Grape:
|
||||
return new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new Framework.Graphics.Drawable[]
|
||||
{
|
||||
new Pulp
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
AccentColour = AccentColour,
|
||||
Size = new Vector2(small_pulp),
|
||||
},
|
||||
new Pulp
|
||||
{
|
||||
AccentColour = AccentColour,
|
||||
Size = new Vector2(large_pulp_3),
|
||||
Position = positionAt(0, distance_from_centre_3),
|
||||
},
|
||||
new Pulp
|
||||
{
|
||||
AccentColour = AccentColour,
|
||||
Size = new Vector2(large_pulp_3),
|
||||
Position = positionAt(120, distance_from_centre_3),
|
||||
},
|
||||
new Pulp
|
||||
{
|
||||
Size = new Vector2(large_pulp_3),
|
||||
AccentColour = AccentColour,
|
||||
Position = positionAt(240, distance_from_centre_3),
|
||||
},
|
||||
}
|
||||
};
|
||||
case FruitVisualRepresentation.Banana:
|
||||
return new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new Framework.Graphics.Drawable[]
|
||||
{
|
||||
new Pulp
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
AccentColour = AccentColour,
|
||||
Size = new Vector2(small_pulp),
|
||||
Y = -0.15f
|
||||
},
|
||||
new Pulp
|
||||
{
|
||||
AccentColour = AccentColour,
|
||||
Size = new Vector2(large_pulp_4 * 1.2f, large_pulp_4 * 3),
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
border.Alpha = (float)MathHelper.Clamp((HitObject.StartTime - Time.Current) / 500, 0, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// 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
|
||||
@ -13,41 +13,28 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
{
|
||||
private readonly Container dropletContainer;
|
||||
|
||||
public DrawableJuiceStream(JuiceStream s) : base(s)
|
||||
public DrawableJuiceStream(JuiceStream s, Func<CatchHitObject, DrawableHitObject<CatchHitObject>> getVisualRepresentation = null)
|
||||
: base(s)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
Height = (float)HitObject.Duration;
|
||||
Origin = Anchor.BottomLeft;
|
||||
X = 0;
|
||||
|
||||
Child = dropletContainer = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
RelativeChildOffset = new Vector2(0, (float)HitObject.StartTime),
|
||||
RelativeChildSize = new Vector2(1, (float)HitObject.Duration)
|
||||
};
|
||||
Child = dropletContainer = new Container { RelativeSizeAxes = Axes.Both, };
|
||||
|
||||
foreach (CatchHitObject tick in s.NestedHitObjects.OfType<CatchHitObject>())
|
||||
{
|
||||
TinyDroplet tiny = tick as TinyDroplet;
|
||||
if (tiny != null)
|
||||
{
|
||||
AddNested(new DrawableDroplet(tiny) { Scale = new Vector2(0.5f) });
|
||||
continue;
|
||||
}
|
||||
|
||||
Droplet droplet = tick as Droplet;
|
||||
if (droplet != null)
|
||||
AddNested(new DrawableDroplet(droplet));
|
||||
|
||||
Fruit fruit = tick as Fruit;
|
||||
if (fruit != null)
|
||||
AddNested(new DrawableFruit(fruit));
|
||||
}
|
||||
foreach (var o in s.NestedHitObjects.Cast<CatchHitObject>())
|
||||
AddNested(getVisualRepresentation?.Invoke(o));
|
||||
}
|
||||
|
||||
protected override void AddNested(DrawableHitObject<CatchHitObject> h)
|
||||
protected override bool ProvidesJudgement => false;
|
||||
|
||||
protected override void AddNested(DrawableHitObject h)
|
||||
{
|
||||
((DrawableCatchHitObject)h).CheckPosition = o => CheckPosition?.Invoke(o) ?? false;
|
||||
var catchObject = (DrawableCatchHitObject)h;
|
||||
|
||||
catchObject.CheckPosition = o => CheckPosition?.Invoke(o) ?? false;
|
||||
catchObject.AccentColour = HitObject.ComboColour;
|
||||
|
||||
dropletContainer.Add(h);
|
||||
base.AddNested(h);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
@ -6,18 +6,17 @@ using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Graphics;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Objects.Drawable.Pieces
|
||||
{
|
||||
public class Pulp : Circle, IHasAccentColour
|
||||
{
|
||||
public const float PULP_SIZE = (float)CatchHitObject.OBJECT_RADIUS / 2.2f;
|
||||
|
||||
public Pulp()
|
||||
{
|
||||
Size = new Vector2(PULP_SIZE);
|
||||
RelativePositionAxes = Axes.Both;
|
||||
Anchor = Anchor.Centre;
|
||||
Origin = Anchor.Centre;
|
||||
|
||||
Blending = BlendingMode.Additive;
|
||||
Colour = Color4.White.Opacity(0.9f);
|
||||
@ -34,8 +33,8 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable.Pieces
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Type = EdgeEffectType.Glow,
|
||||
Radius = 5,
|
||||
Colour = accentColour.Lighten(100),
|
||||
Radius = 8,
|
||||
Colour = accentColour.Darken(0.2f).Opacity(0.75f)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Objects
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Objects
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
@ -21,9 +21,7 @@ namespace osu.Game.Rulesets.Catch.Objects
|
||||
/// </summary>
|
||||
private const float base_scoring_distance = 100;
|
||||
|
||||
public readonly SliderCurve Curve = new SliderCurve();
|
||||
|
||||
public int RepeatCount { get; set; } = 1;
|
||||
public int RepeatCount { get; set; }
|
||||
|
||||
public double Velocity;
|
||||
public double TickDistance;
|
||||
@ -55,7 +53,7 @@ namespace osu.Game.Rulesets.Catch.Objects
|
||||
|
||||
var length = Curve.Distance;
|
||||
var tickDistance = Math.Min(TickDistance, length);
|
||||
var repeatDuration = length / Velocity;
|
||||
var spanDuration = length / Velocity;
|
||||
|
||||
var minDistanceFromEnd = Velocity * 0.01;
|
||||
|
||||
@ -67,10 +65,10 @@ namespace osu.Game.Rulesets.Catch.Objects
|
||||
X = X
|
||||
});
|
||||
|
||||
for (var repeat = 0; repeat < RepeatCount; repeat++)
|
||||
for (var span = 0; span < this.SpanCount(); span++)
|
||||
{
|
||||
var repeatStartTime = StartTime + repeat * repeatDuration;
|
||||
var reversed = repeat % 2 == 1;
|
||||
var spanStartTime = StartTime + span * spanDuration;
|
||||
var reversed = span % 2 == 1;
|
||||
|
||||
for (var d = tickDistance; d <= length; d += tickDistance)
|
||||
{
|
||||
@ -80,7 +78,7 @@ namespace osu.Game.Rulesets.Catch.Objects
|
||||
var timeProgress = d / length;
|
||||
var distanceProgress = reversed ? 1 - timeProgress : timeProgress;
|
||||
|
||||
var lastTickTime = repeatStartTime + timeProgress * repeatDuration;
|
||||
var lastTickTime = spanStartTime + timeProgress * spanDuration;
|
||||
AddNested(new Droplet
|
||||
{
|
||||
StartTime = lastTickTime,
|
||||
@ -95,17 +93,17 @@ namespace osu.Game.Rulesets.Catch.Objects
|
||||
});
|
||||
}
|
||||
|
||||
double tinyTickInterval = tickDistance / length * repeatDuration;
|
||||
double tinyTickInterval = tickDistance / length * spanDuration;
|
||||
while (tinyTickInterval > 100)
|
||||
tinyTickInterval /= 2;
|
||||
|
||||
for (double t = 0; t < repeatDuration; t += tinyTickInterval)
|
||||
for (double t = 0; t < spanDuration; t += tinyTickInterval)
|
||||
{
|
||||
double progress = reversed ? 1 - t / repeatDuration : t / repeatDuration;
|
||||
double progress = reversed ? 1 - t / spanDuration : t / spanDuration;
|
||||
|
||||
AddNested(new TinyDroplet
|
||||
{
|
||||
StartTime = repeatStartTime + t,
|
||||
StartTime = spanStartTime + t,
|
||||
ComboColour = ComboColour,
|
||||
X = Curve.PositionAt(progress).X / CatchPlayfield.BASE_WIDTH,
|
||||
Samples = new List<SampleInfo>(Samples.Select(s => new SampleInfo
|
||||
@ -121,17 +119,15 @@ namespace osu.Game.Rulesets.Catch.Objects
|
||||
{
|
||||
Samples = Samples,
|
||||
ComboColour = ComboColour,
|
||||
StartTime = repeatStartTime + repeatDuration,
|
||||
StartTime = spanStartTime + spanDuration,
|
||||
X = Curve.PositionAt(reversed ? 0 : 1).X / CatchPlayfield.BASE_WIDTH
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public double EndTime => StartTime + this.SpanCount() * Curve.Distance / Velocity;
|
||||
|
||||
public double EndTime => StartTime + RepeatCount * Curve.Distance / Velocity;
|
||||
|
||||
public float EndX => Curve.PositionAt(ProgressAt(1)).X / CatchPlayfield.BASE_WIDTH;
|
||||
public float EndX => Curve.PositionAt(this.ProgressAt(1)).X / CatchPlayfield.BASE_WIDTH;
|
||||
|
||||
public double Duration => EndTime - StartTime;
|
||||
|
||||
@ -141,6 +137,8 @@ namespace osu.Game.Rulesets.Catch.Objects
|
||||
set { Curve.Distance = value; }
|
||||
}
|
||||
|
||||
public SliderCurve Curve { get; } = new SliderCurve();
|
||||
|
||||
public List<Vector2> ControlPoints
|
||||
{
|
||||
get { return Curve.ControlPoints; }
|
||||
@ -154,17 +152,5 @@ namespace osu.Game.Rulesets.Catch.Objects
|
||||
get { return Curve.CurveType; }
|
||||
set { Curve.CurveType = value; }
|
||||
}
|
||||
|
||||
public Vector2 PositionAt(double progress) => Curve.PositionAt(ProgressAt(progress));
|
||||
|
||||
public double ProgressAt(double progress)
|
||||
{
|
||||
double p = progress * RepeatCount % 1;
|
||||
if (RepeatAt(progress) % 2 == 1)
|
||||
p = 1 - p;
|
||||
return p;
|
||||
}
|
||||
|
||||
public int RepeatAt(double progress) => (int)(progress * RepeatCount);
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Objects
|
||||
|
120
osu.Game.Rulesets.Catch/Replays/CatchAutoGenerator.cs
Normal file
120
osu.Game.Rulesets.Catch/Replays/CatchAutoGenerator.cs
Normal file
@ -0,0 +1,120 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Catch.Objects;
|
||||
using osu.Game.Rulesets.Catch.UI;
|
||||
using osu.Game.Rulesets.Replays;
|
||||
using osu.Game.Users;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Replays
|
||||
{
|
||||
internal class CatchAutoGenerator : AutoGenerator<CatchHitObject>
|
||||
{
|
||||
public const double RELEASE_DELAY = 20;
|
||||
|
||||
public CatchAutoGenerator(Beatmap<CatchHitObject> beatmap)
|
||||
: base(beatmap)
|
||||
{
|
||||
Replay = new Replay { User = new User { Username = @"Autoplay" } };
|
||||
}
|
||||
|
||||
protected Replay Replay;
|
||||
|
||||
public override Replay Generate()
|
||||
{
|
||||
// todo: add support for HT DT
|
||||
const double dash_speed = CatcherArea.Catcher.BASE_SPEED;
|
||||
const double movement_speed = dash_speed / 2;
|
||||
float lastPosition = 0.5f;
|
||||
double lastTime = 0;
|
||||
|
||||
// Todo: Realistically this shouldn't be needed, but the first frame is skipped with the way replays are currently handled
|
||||
Replay.Frames.Add(new CatchReplayFrame(-100000, lastPosition));
|
||||
|
||||
void moveToNext(CatchHitObject h)
|
||||
{
|
||||
float positionChange = Math.Abs(lastPosition - h.X);
|
||||
double timeAvailable = h.StartTime - lastTime;
|
||||
|
||||
//So we can either make it there without a dash or not.
|
||||
double speedRequired = positionChange / timeAvailable;
|
||||
|
||||
bool dashRequired = speedRequired > movement_speed && h.StartTime != 0;
|
||||
|
||||
// todo: get correct catcher size, based on difficulty CS.
|
||||
const float catcher_width_half = CatcherArea.CATCHER_SIZE / CatchPlayfield.BASE_WIDTH * 0.3f * 0.5f;
|
||||
|
||||
if (lastPosition - catcher_width_half < h.X && lastPosition + catcher_width_half > h.X)
|
||||
{
|
||||
//we are already in the correct range.
|
||||
lastTime = h.StartTime;
|
||||
Replay.Frames.Add(new CatchReplayFrame(h.StartTime, lastPosition));
|
||||
return;
|
||||
}
|
||||
|
||||
if (h is BananaShower.Banana)
|
||||
{
|
||||
// auto bananas unrealistically warp to catch 100% combo.
|
||||
Replay.Frames.Add(new CatchReplayFrame(h.StartTime, h.X));
|
||||
}
|
||||
else if (h.HyperDash)
|
||||
{
|
||||
Replay.Frames.Add(new CatchReplayFrame(h.StartTime - timeAvailable, lastPosition, ReplayButtonState.Right1));
|
||||
Replay.Frames.Add(new CatchReplayFrame(h.StartTime, h.X));
|
||||
}
|
||||
else if (dashRequired)
|
||||
{
|
||||
//we do a movement in two parts - the dash part then the normal part...
|
||||
double timeAtNormalSpeed = positionChange / movement_speed;
|
||||
double timeWeNeedToSave = timeAtNormalSpeed - timeAvailable;
|
||||
double timeAtDashSpeed = timeWeNeedToSave / 2;
|
||||
|
||||
float midPosition = (float)Interpolation.Lerp(lastPosition, h.X, (float)timeAtDashSpeed / timeAvailable);
|
||||
|
||||
//dash movement
|
||||
Replay.Frames.Add(new CatchReplayFrame(h.StartTime - timeAvailable + 1, lastPosition, ReplayButtonState.Left1));
|
||||
Replay.Frames.Add(new CatchReplayFrame(h.StartTime - timeAvailable + timeAtDashSpeed, midPosition));
|
||||
Replay.Frames.Add(new CatchReplayFrame(h.StartTime, h.X));
|
||||
}
|
||||
else
|
||||
{
|
||||
double timeBefore = positionChange / movement_speed;
|
||||
|
||||
Replay.Frames.Add(new CatchReplayFrame(h.StartTime - timeBefore, lastPosition, ReplayButtonState.Right1));
|
||||
Replay.Frames.Add(new CatchReplayFrame(h.StartTime, h.X));
|
||||
}
|
||||
|
||||
lastTime = h.StartTime;
|
||||
lastPosition = h.X;
|
||||
}
|
||||
|
||||
foreach (var obj in Beatmap.HitObjects)
|
||||
{
|
||||
switch (obj)
|
||||
{
|
||||
case Fruit _:
|
||||
moveToNext(obj);
|
||||
break;
|
||||
}
|
||||
|
||||
foreach (var nestedObj in obj.NestedHitObjects.Cast<CatchHitObject>())
|
||||
{
|
||||
switch (nestedObj)
|
||||
{
|
||||
case BananaShower.Banana _:
|
||||
case TinyDroplet _:
|
||||
case Droplet _:
|
||||
moveToNext(nestedObj);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Replay;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Input;
|
||||
using osu.Game.Rulesets.Replays;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Replays
|
||||
{
|
||||
public class CatchFramedReplayInputHandler : FramedReplayInputHandler
|
||||
{
|
||||
public CatchFramedReplayInputHandler(Replay replay)
|
||||
: base(replay)
|
||||
{
|
||||
}
|
||||
|
||||
public override List<InputState> GetPendingStates()
|
||||
{
|
||||
if (!Position.HasValue) return new List<InputState>();
|
||||
|
||||
var action = new List<CatchAction>();
|
||||
|
||||
if (CurrentFrame.ButtonState == ReplayButtonState.Left1)
|
||||
action.Add(CatchAction.Dash);
|
||||
|
||||
if (Position.Value.X > CurrentFrame.Position.X)
|
||||
action.Add(CatchAction.MoveRight);
|
||||
else if (Position.Value.X < CurrentFrame.Position.X)
|
||||
action.Add(CatchAction.MoveLeft);
|
||||
|
||||
return new List<InputState>
|
||||
{
|
||||
new CatchReplayState
|
||||
{
|
||||
PressedActions = action,
|
||||
CatcherX = Position.Value.X
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
public class CatchReplayState : ReplayState<CatchAction>
|
||||
{
|
||||
public float? CatcherX { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
17
osu.Game.Rulesets.Catch/Replays/CatchReplayFrame.cs
Normal file
17
osu.Game.Rulesets.Catch/Replays/CatchReplayFrame.cs
Normal file
@ -0,0 +1,17 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Rulesets.Replays;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Replays
|
||||
{
|
||||
public class CatchReplayFrame : ReplayFrame
|
||||
{
|
||||
public override bool IsImportant => MouseX > 0;
|
||||
|
||||
public CatchReplayFrame(double time, float? x = null, ReplayButtonState button = ReplayButtonState.None)
|
||||
: base(time, x ?? -1, null, button)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System.Linq;
|
||||
@ -10,7 +10,7 @@ using osu.Game.Rulesets.UI;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Scoring
|
||||
{
|
||||
internal class CatchScoreProcessor : ScoreProcessor<CatchHitObject>
|
||||
public class CatchScoreProcessor : ScoreProcessor<CatchHitObject>
|
||||
{
|
||||
public CatchScoreProcessor(RulesetContainer<CatchHitObject> rulesetContainer)
|
||||
: base(rulesetContainer)
|
||||
@ -21,23 +21,21 @@ namespace osu.Game.Rulesets.Catch.Scoring
|
||||
{
|
||||
foreach (var obj in beatmap.HitObjects)
|
||||
{
|
||||
var stream = obj as JuiceStream;
|
||||
|
||||
if (stream != null)
|
||||
switch (obj)
|
||||
{
|
||||
AddJudgement(new CatchJudgement { Result = HitResult.Perfect });
|
||||
AddJudgement(new CatchJudgement { Result = HitResult.Perfect });
|
||||
|
||||
foreach (var unused in stream.NestedHitObjects.OfType<CatchHitObject>())
|
||||
case JuiceStream stream:
|
||||
foreach (var _ in stream.NestedHitObjects.Cast<CatchHitObject>())
|
||||
AddJudgement(new CatchJudgement { Result = HitResult.Perfect });
|
||||
break;
|
||||
case BananaShower shower:
|
||||
foreach (var _ in shower.NestedHitObjects.Cast<CatchHitObject>())
|
||||
AddJudgement(new CatchJudgement { Result = HitResult.Perfect });
|
||||
AddJudgement(new CatchJudgement { Result = HitResult.Perfect });
|
||||
|
||||
continue;
|
||||
break;
|
||||
case Fruit _:
|
||||
AddJudgement(new CatchJudgement { Result = HitResult.Perfect });
|
||||
break;
|
||||
}
|
||||
|
||||
var fruit = obj as Fruit;
|
||||
|
||||
if (fruit != null)
|
||||
AddJudgement(new CatchJudgement { Result = HitResult.Perfect });
|
||||
}
|
||||
|
||||
base.SimulateAutoplay(beatmap);
|
||||
|
50
osu.Game.Rulesets.Catch/Tests/TestCaseBananaShower.cs
Normal file
50
osu.Game.Rulesets.Catch/Tests/TestCaseBananaShower.cs
Normal file
@ -0,0 +1,50 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Catch.Objects;
|
||||
using osu.Game.Rulesets.Catch.Objects.Drawable;
|
||||
using osu.Game.Rulesets.Catch.UI;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
[Ignore("getting CI working")]
|
||||
public class TestCaseBananaShower : Game.Tests.Visual.TestCasePlayer
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(BananaShower),
|
||||
typeof(DrawableBananaShower),
|
||||
|
||||
typeof(CatchRuleset),
|
||||
typeof(CatchRulesetContainer),
|
||||
};
|
||||
|
||||
public TestCaseBananaShower()
|
||||
: base(new CatchRuleset())
|
||||
{
|
||||
}
|
||||
|
||||
protected override Beatmap CreateBeatmap()
|
||||
{
|
||||
var beatmap = new Beatmap
|
||||
{
|
||||
BeatmapInfo = new BeatmapInfo
|
||||
{
|
||||
BaseDifficulty = new BeatmapDifficulty
|
||||
{
|
||||
CircleSize = 6,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
beatmap.HitObjects.Add(new BananaShower { StartTime = 200, Duration = 5000, NewCombo = true });
|
||||
|
||||
return beatmap;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using NUnit.Framework;
|
||||
@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
[Ignore("getting CI working")]
|
||||
public class TestCaseCatchPlayer : Game.Tests.Visual.TestCasePlayer
|
||||
{
|
||||
public TestCaseCatchPlayer() : base(typeof(CatchRuleset))
|
||||
public TestCaseCatchPlayer() : base(new CatchRuleset())
|
||||
{
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using NUnit.Framework;
|
||||
@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
public class TestCaseCatchStacker : Game.Tests.Visual.TestCasePlayer
|
||||
{
|
||||
public TestCaseCatchStacker()
|
||||
: base(typeof(CatchRuleset))
|
||||
: base(new CatchRuleset())
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
|
104
osu.Game.Rulesets.Catch/Tests/TestCaseFruitObjects.cs
Normal file
104
osu.Game.Rulesets.Catch/Tests/TestCaseFruitObjects.cs
Normal file
@ -0,0 +1,104 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Game.Rulesets.Catch.Objects;
|
||||
using osu.Game.Rulesets.Catch.Objects.Drawable;
|
||||
using osu.Game.Rulesets.Catch.Objects.Drawable.Pieces;
|
||||
using osu.Game.Tests.Visual;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Tests
|
||||
{
|
||||
[Ignore("getting CI working")]
|
||||
public class TestCaseFruitObjects : OsuTestCase
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(CatchHitObject),
|
||||
typeof(Fruit),
|
||||
typeof(Droplet),
|
||||
typeof(DrawableCatchHitObject),
|
||||
typeof(DrawableFruit),
|
||||
typeof(DrawableDroplet),
|
||||
typeof(Pulp),
|
||||
};
|
||||
|
||||
public TestCaseFruitObjects()
|
||||
{
|
||||
Add(new GridContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Content = new[]
|
||||
{
|
||||
new Drawable[]
|
||||
{
|
||||
createDrawable(0),
|
||||
createDrawable(1),
|
||||
createDrawable(2),
|
||||
},
|
||||
new Drawable[]
|
||||
{
|
||||
createDrawable(3),
|
||||
createDrawable(4),
|
||||
createDrawable(5),
|
||||
},
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private DrawableFruit createDrawable(int index)
|
||||
{
|
||||
var fruit = new Fruit
|
||||
{
|
||||
StartTime = 1000000000000,
|
||||
IndexInBeatmap = index,
|
||||
Scale = 1.5f,
|
||||
};
|
||||
|
||||
fruit.ComboColour = colourForRrepesentation(fruit.VisualRepresentation);
|
||||
|
||||
return new DrawableFruit(fruit)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
RelativePositionAxes = Axes.Both,
|
||||
Position = Vector2.Zero,
|
||||
Alpha = 1,
|
||||
LifetimeStart = double.NegativeInfinity,
|
||||
LifetimeEnd = double.PositiveInfinity,
|
||||
};
|
||||
}
|
||||
|
||||
private Color4 colourForRrepesentation(FruitVisualRepresentation representation)
|
||||
{
|
||||
switch (representation)
|
||||
{
|
||||
default:
|
||||
case FruitVisualRepresentation.Pear:
|
||||
return new Color4(17, 136, 170, 255);
|
||||
case FruitVisualRepresentation.Grape:
|
||||
return new Color4(204, 102, 0, 255);
|
||||
case FruitVisualRepresentation.Raspberry:
|
||||
return new Color4(121, 9, 13, 255);
|
||||
case FruitVisualRepresentation.Pineapple:
|
||||
return new Color4(102, 136, 0, 255);
|
||||
case FruitVisualRepresentation.Banana:
|
||||
switch (RNG.Next(0, 3))
|
||||
{
|
||||
default:
|
||||
return new Color4(255, 240, 0, 255);
|
||||
case 1:
|
||||
return new Color4(255, 192, 0, 255);
|
||||
case 2:
|
||||
return new Color4(214, 221, 28, 255);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using NUnit.Framework;
|
||||
@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
public class TestCaseHyperdash : Game.Tests.Visual.TestCasePlayer
|
||||
{
|
||||
public TestCaseHyperdash()
|
||||
: base(typeof(CatchRuleset))
|
||||
: base(new CatchRuleset())
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using NUnit.Framework;
|
||||
@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
public class TestCasePerformancePoints : Game.Tests.Visual.TestCasePerformancePoints
|
||||
{
|
||||
public TestCasePerformancePoints()
|
||||
: base(new CatchRuleset(new RulesetInfo()))
|
||||
: base(new CatchRuleset())
|
||||
{
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,15 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using OpenTK;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Catch.Objects;
|
||||
using osu.Game.Rulesets.Catch.Objects.Drawable;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.UI.Scrolling;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.UI
|
||||
{
|
||||
@ -22,33 +22,35 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
|
||||
private readonly CatcherArea catcherArea;
|
||||
|
||||
public CatchPlayfield(BeatmapDifficulty difficulty)
|
||||
: base(Axes.Y)
|
||||
public CatchPlayfield(BeatmapDifficulty difficulty, Func<CatchHitObject, DrawableHitObject<CatchHitObject>> getVisualRepresentation)
|
||||
: base(ScrollingDirection.Down, BASE_WIDTH)
|
||||
{
|
||||
Container explodingFruitContainer;
|
||||
|
||||
Reversed.Value = true;
|
||||
|
||||
Anchor = Anchor.TopCentre;
|
||||
Origin = Anchor.TopCentre;
|
||||
|
||||
InternalChildren = new Drawable[]
|
||||
ScaledContent.Anchor = Anchor.BottomLeft;
|
||||
ScaledContent.Origin = Anchor.BottomLeft;
|
||||
|
||||
ScaledContent.AddRange(new Drawable[]
|
||||
{
|
||||
content = new Container<Drawable>
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
explodingFruitContainer = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
catcherArea = new CatcherArea(difficulty)
|
||||
{
|
||||
GetVisualRepresentation = getVisualRepresentation,
|
||||
ExplodingFruitTarget = explodingFruitContainer,
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Origin = Anchor.TopLeft,
|
||||
}
|
||||
};
|
||||
},
|
||||
content = new Container<Drawable>
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
public bool CheckIfWeCanCatch(CatchHitObject obj) => catcherArea.AttemptCatch(obj);
|
||||
@ -56,6 +58,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
public override void Add(DrawableHitObject h)
|
||||
{
|
||||
h.Depth = (float)h.HitObject.StartTime;
|
||||
h.OnJudgement += onJudgement;
|
||||
|
||||
base.Add(h);
|
||||
|
||||
@ -63,18 +66,6 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
fruit.CheckPosition = CheckIfWeCanCatch;
|
||||
}
|
||||
|
||||
public override void OnJudgement(DrawableHitObject judgedObject, Judgement judgement)
|
||||
{
|
||||
if (judgement.IsHit)
|
||||
{
|
||||
Vector2 screenPosition = judgedObject.ScreenSpaceDrawQuad.Centre;
|
||||
|
||||
// todo: don't do this
|
||||
(judgedObject.Parent as Container<DrawableHitObject>)?.Remove(judgedObject);
|
||||
(judgedObject.Parent as Container)?.Remove(judgedObject);
|
||||
|
||||
catcherArea.Add(judgedObject, screenPosition);
|
||||
}
|
||||
}
|
||||
private void onJudgement(DrawableHitObject judgedObject, Judgement judgement) => catcherArea.OnJudgement((DrawableCatchHitObject)judgedObject, judgement);
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Framework.Input;
|
||||
@ -6,10 +6,14 @@ using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Catch.Beatmaps;
|
||||
using osu.Game.Rulesets.Catch.Objects;
|
||||
using osu.Game.Rulesets.Catch.Objects.Drawable;
|
||||
using osu.Game.Rulesets.Catch.Replays;
|
||||
using osu.Game.Rulesets.Catch.Scoring;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
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
|
||||
{
|
||||
@ -22,23 +26,31 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
|
||||
public override ScoreProcessor CreateScoreProcessor() => new CatchScoreProcessor(this);
|
||||
|
||||
protected override FramedReplayInputHandler CreateReplayInputHandler(Replay replay) => new CatchFramedReplayInputHandler(replay);
|
||||
|
||||
protected override BeatmapProcessor<CatchHitObject> CreateBeatmapProcessor() => new CatchBeatmapProcessor();
|
||||
|
||||
protected override BeatmapConverter<CatchHitObject> 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);
|
||||
|
||||
protected override DrawableHitObject<CatchHitObject> GetVisualRepresentation(CatchHitObject h)
|
||||
{
|
||||
var fruit = h as Fruit;
|
||||
if (fruit != null)
|
||||
return new DrawableFruit(fruit);
|
||||
|
||||
var stream = h as JuiceStream;
|
||||
if (stream != null)
|
||||
return new DrawableJuiceStream(stream);
|
||||
switch (h)
|
||||
{
|
||||
case Fruit fruit:
|
||||
return new DrawableFruit(fruit);
|
||||
case JuiceStream stream:
|
||||
return new DrawableJuiceStream(stream, GetVisualRepresentation);
|
||||
case BananaShower 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;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
@ -12,6 +12,9 @@ using osu.Framework.Input.Bindings;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Catch.Objects;
|
||||
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 OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
@ -24,6 +27,8 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
|
||||
protected readonly Catcher MovableCatcher;
|
||||
|
||||
public Func<CatchHitObject, DrawableHitObject<CatchHitObject>> GetVisualRepresentation;
|
||||
|
||||
public Container ExplodingFruitTarget
|
||||
{
|
||||
set { MovableCatcher.ExplodingFruitTarget = value; }
|
||||
@ -39,19 +44,58 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
};
|
||||
}
|
||||
|
||||
public void Add(DrawableHitObject fruit, Vector2 absolutePosition)
|
||||
private DrawableCatchHitObject lastPlateableFruit;
|
||||
|
||||
public void OnJudgement(DrawableCatchHitObject fruit, Judgement judgement)
|
||||
{
|
||||
fruit.RelativePositionAxes = Axes.None;
|
||||
fruit.Position = new Vector2(MovableCatcher.ToLocalSpace(absolutePosition).X - MovableCatcher.DrawSize.X / 2, 0);
|
||||
if (judgement.IsHit && fruit.CanBePlated)
|
||||
{
|
||||
var caughtFruit = (DrawableCatchHitObject)GetVisualRepresentation?.Invoke(fruit.HitObject);
|
||||
|
||||
fruit.Anchor = Anchor.TopCentre;
|
||||
fruit.Origin = Anchor.BottomCentre;
|
||||
fruit.Scale *= 0.7f;
|
||||
fruit.LifetimeEnd = double.MaxValue;
|
||||
if (caughtFruit == null) return;
|
||||
|
||||
MovableCatcher.Add(fruit);
|
||||
caughtFruit.AccentColour = fruit.AccentColour;
|
||||
caughtFruit.RelativePositionAxes = Axes.None;
|
||||
caughtFruit.Position = new Vector2(MovableCatcher.ToLocalSpace(fruit.ScreenSpaceDrawQuad.Centre).X - MovableCatcher.DrawSize.X / 2, 0);
|
||||
|
||||
caughtFruit.Anchor = Anchor.TopCentre;
|
||||
caughtFruit.Origin = Anchor.Centre;
|
||||
caughtFruit.Scale *= 0.7f;
|
||||
caughtFruit.LifetimeEnd = double.MaxValue;
|
||||
|
||||
MovableCatcher.Add(caughtFruit);
|
||||
|
||||
lastPlateableFruit = caughtFruit;
|
||||
}
|
||||
|
||||
if (fruit.HitObject.LastInCombo)
|
||||
{
|
||||
if (judgement.IsHit)
|
||||
{
|
||||
// this is required to make this run after the last caught fruit runs UpdateState at least once.
|
||||
// TODO: find a better alternative
|
||||
if (lastPlateableFruit.IsLoaded)
|
||||
MovableCatcher.Explode();
|
||||
else
|
||||
lastPlateableFruit.OnLoadComplete = _ => { MovableCatcher.Explode(); };
|
||||
}
|
||||
else
|
||||
MovableCatcher.Drop();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void UpdateAfterChildren()
|
||||
{
|
||||
base.UpdateAfterChildren();
|
||||
|
||||
var state = GetContainingInputManager().CurrentState as CatchFramedReplayInputHandler.CatchReplayState;
|
||||
|
||||
if (state?.CatcherX != null)
|
||||
MovableCatcher.X = state.CatcherX.Value;
|
||||
}
|
||||
|
||||
public bool OnReleased(CatchAction action) => false;
|
||||
|
||||
public bool AttemptCatch(CatchHitObject obj) => MovableCatcher.AttemptCatch(obj);
|
||||
|
||||
public class Catcher : Container, IKeyBindingHandler<CatchAction>
|
||||
@ -84,12 +128,12 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
createCatcherSprite(),
|
||||
caughtFruit = new Container<DrawableHitObject>
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.BottomCentre,
|
||||
}
|
||||
},
|
||||
createCatcherSprite(),
|
||||
};
|
||||
}
|
||||
|
||||
@ -167,20 +211,23 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
/// <param name="fruit">The fruit that was caught.</param>
|
||||
public void Add(DrawableHitObject fruit)
|
||||
{
|
||||
float distance = fruit.DrawSize.X / 2 * fruit.Scale.X;
|
||||
float ourRadius = fruit.DrawSize.X / 2 * fruit.Scale.X;
|
||||
float theirRadius = 0;
|
||||
|
||||
while (caughtFruit.Any(f => f.LifetimeEnd == double.MaxValue && Vector2Extensions.DistanceSquared(f.Position, fruit.Position) < distance * distance))
|
||||
const float allowance = 6;
|
||||
|
||||
while (caughtFruit.Any(f =>
|
||||
f.LifetimeEnd == double.MaxValue &&
|
||||
Vector2Extensions.Distance(f.Position, fruit.Position) < (ourRadius + (theirRadius = f.DrawSize.X / 2 * f.Scale.X)) / (allowance / 2)))
|
||||
{
|
||||
fruit.X += RNG.Next(-5, 5);
|
||||
fruit.Y -= RNG.Next(0, 5);
|
||||
float diff = (ourRadius + theirRadius) / allowance;
|
||||
fruit.X += (RNG.NextSingle() - 0.5f) * 2 * diff;
|
||||
fruit.Y -= RNG.NextSingle() * diff;
|
||||
}
|
||||
|
||||
fruit.X = MathHelper.Clamp(fruit.X, -CATCHER_SIZE / 2, CATCHER_SIZE / 2);
|
||||
|
||||
caughtFruit.Add(fruit);
|
||||
|
||||
var catchObject = (CatchHitObject)fruit.HitObject;
|
||||
|
||||
if (catchObject.LastInCombo)
|
||||
explode();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -190,15 +237,15 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
/// <returns>Whether the catch is possible.</returns>
|
||||
public bool AttemptCatch(CatchHitObject fruit)
|
||||
{
|
||||
const double relative_catcher_width = CATCHER_SIZE / 2;
|
||||
double halfCatcherWidth = CATCHER_SIZE * Math.Abs(Scale.X) * 0.5f;
|
||||
|
||||
// this stuff wil disappear once we move fruit to non-relative coordinate space in the future.
|
||||
var catchObjectPosition = fruit.X * CatchPlayfield.BASE_WIDTH;
|
||||
var catcherPosition = Position.X * CatchPlayfield.BASE_WIDTH;
|
||||
|
||||
var validCatch =
|
||||
catchObjectPosition >= catcherPosition - relative_catcher_width / 2 &&
|
||||
catchObjectPosition <= catcherPosition + relative_catcher_width / 2;
|
||||
catchObjectPosition >= catcherPosition - halfCatcherWidth &&
|
||||
catchObjectPosition <= catcherPosition + halfCatcherWidth;
|
||||
|
||||
if (validCatch && fruit.HyperDash)
|
||||
{
|
||||
@ -309,7 +356,35 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
X = (float)MathHelper.Clamp(X + direction * Clock.ElapsedFrameTime * BASE_SPEED * dashModifier, 0, 1);
|
||||
}
|
||||
|
||||
private void explode()
|
||||
/// <summary>
|
||||
/// Drop any fruit off the plate.
|
||||
/// </summary>
|
||||
public void Drop()
|
||||
{
|
||||
var fruit = caughtFruit.ToArray();
|
||||
|
||||
foreach (var f in fruit)
|
||||
{
|
||||
if (ExplodingFruitTarget != null)
|
||||
{
|
||||
f.Anchor = Anchor.TopLeft;
|
||||
f.Position = caughtFruit.ToSpaceOfOtherDrawable(f.DrawPosition, ExplodingFruitTarget);
|
||||
|
||||
caughtFruit.Remove(f);
|
||||
|
||||
ExplodingFruitTarget.Add(f);
|
||||
}
|
||||
|
||||
f.MoveToY(f.Y + 75, 750, Easing.InSine);
|
||||
f.FadeOut(750);
|
||||
f.Expire();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Explode any fruit off the plate.
|
||||
/// </summary>
|
||||
public void Explode()
|
||||
{
|
||||
var fruit = caughtFruit.ToArray();
|
||||
|
||||
|
Reference in New Issue
Block a user