mirror of
https://github.com/ppy/osu.git
synced 2024-11-11 08:27:49 +08:00
Merge branch 'master' into net5.0
This commit is contained in:
commit
53da137425
@ -5,6 +5,6 @@
|
|||||||
"version": "5.0.100"
|
"version": "5.0.100"
|
||||||
},
|
},
|
||||||
"msbuild-sdks": {
|
"msbuild-sdks": {
|
||||||
"Microsoft.Build.Traversal": "2.2.3"
|
"Microsoft.Build.Traversal": "3.0.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -51,7 +51,7 @@
|
|||||||
<Reference Include="Java.Interop" />
|
<Reference Include="Java.Interop" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.1030.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.1202.0" />
|
||||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2020.1120.0" />
|
<PackageReference Include="ppy.osu.Framework.Android" Version="2020.1203.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -60,6 +60,7 @@ namespace osu.Desktop
|
|||||||
if (OperatingSystem.IsWindows())
|
if (OperatingSystem.IsWindows())
|
||||||
{
|
{
|
||||||
stableInstallPath = getStableInstallPathFromRegistry();
|
stableInstallPath = getStableInstallPathFromRegistry();
|
||||||
|
|
||||||
if (checkExists(stableInstallPath))
|
if (checkExists(stableInstallPath))
|
||||||
return stableInstallPath;
|
return stableInstallPath;
|
||||||
}
|
}
|
||||||
@ -141,7 +142,7 @@ namespace osu.Desktop
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
// SDL2 DesktopWindow
|
// SDL2 DesktopWindow
|
||||||
case DesktopWindow desktopWindow:
|
case SDL2DesktopWindow desktopWindow:
|
||||||
desktopWindow.CursorState |= CursorState.Hidden;
|
desktopWindow.CursorState |= CursorState.Hidden;
|
||||||
desktopWindow.SetIconFromStream(iconStream);
|
desktopWindow.SetIconFromStream(iconStream);
|
||||||
desktopWindow.Title = Name;
|
desktopWindow.Title = Name;
|
||||||
|
@ -22,9 +22,9 @@ namespace osu.Desktop
|
|||||||
{
|
{
|
||||||
// Back up the cwd before DesktopGameHost changes it
|
// Back up the cwd before DesktopGameHost changes it
|
||||||
var cwd = Environment.CurrentDirectory;
|
var cwd = Environment.CurrentDirectory;
|
||||||
bool useSdl = args.Contains("--sdl");
|
bool useOsuTK = args.Contains("--tk");
|
||||||
|
|
||||||
using (DesktopGameHost host = Host.GetSuitableHost(@"osu", true, useSdl: useSdl))
|
using (DesktopGameHost host = Host.GetSuitableHost(@"osu", true, useOsuTK: useOsuTK))
|
||||||
{
|
{
|
||||||
host.ExceptionThrown += handleException;
|
host.ExceptionThrown += handleException;
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.2.6" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.2.6" />
|
||||||
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
|
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
|
||||||
<PackageReference Include="DiscordRichPresence" Version="1.0.150" />
|
<PackageReference Include="DiscordRichPresence" Version="1.0.169" />
|
||||||
<!-- .NET 3.1 SDK seems to cause issues with a runtime specification. This will likely be resolved in .NET 5. -->
|
<!-- .NET 3.1 SDK seems to cause issues with a runtime specification. This will likely be resolved in .NET 5. -->
|
||||||
<PackageReference Include="System.IO.FileSystem.Primitives" Version="4.3.0" />
|
<PackageReference Include="System.IO.FileSystem.Primitives" Version="4.3.0" />
|
||||||
<PackageReference Include="System.Runtime.Handles" Version="4.3.0" />
|
<PackageReference Include="System.Runtime.Handles" Version="4.3.0" />
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.IO.Stores;
|
using osu.Framework.IO.Stores;
|
||||||
using osu.Game.Rulesets.Catch.Skinning;
|
using osu.Game.Rulesets.Catch.Skinning;
|
||||||
|
using osu.Game.Rulesets.Catch.Skinning.Legacy;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
|
|
||||||
|
@ -38,17 +38,17 @@ namespace osu.Game.Rulesets.Catch.Tests.Mods
|
|||||||
new Fruit
|
new Fruit
|
||||||
{
|
{
|
||||||
X = 0,
|
X = 0,
|
||||||
StartTime = 250
|
StartTime = 1000
|
||||||
},
|
},
|
||||||
new Fruit
|
new Fruit
|
||||||
{
|
{
|
||||||
X = CatchPlayfield.WIDTH,
|
X = CatchPlayfield.WIDTH,
|
||||||
StartTime = 500
|
StartTime = 2000
|
||||||
},
|
},
|
||||||
new JuiceStream
|
new JuiceStream
|
||||||
{
|
{
|
||||||
X = CatchPlayfield.CENTER_X,
|
X = CatchPlayfield.CENTER_X,
|
||||||
StartTime = 750,
|
StartTime = 3000,
|
||||||
Path = new SliderPath(PathType.Linear, new[] { Vector2.Zero, Vector2.UnitY * 200 })
|
Path = new SliderPath(PathType.Linear, new[] { Vector2.Zero, Vector2.UnitY * 200 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
|||||||
NewCombo = i % 8 == 0,
|
NewCombo = i % 8 == 0,
|
||||||
Samples = new List<HitSampleInfo>(new[]
|
Samples = new List<HitSampleInfo>(new[]
|
||||||
{
|
{
|
||||||
new HitSampleInfo { Bank = "normal", Name = "hitnormal", Volume = 100 }
|
new HitSampleInfo(HitSampleInfo.HIT_NORMAL, "normal", volume: 100)
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,14 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Game.Tests.Visual;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Catch.Tests
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class TestSceneCatchPlayerLegacySkin : LegacySkinPlayerTestScene
|
||||||
|
{
|
||||||
|
protected override Ruleset CreatePlayerRuleset() => new CatchRuleset();
|
||||||
|
}
|
||||||
|
}
|
@ -1,26 +1,272 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Game.Rulesets.Catch.UI;
|
using osu.Game.Rulesets.Catch.UI;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Testing;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
using osu.Game.Configuration;
|
||||||
|
using osu.Game.Rulesets.Catch.Judgements;
|
||||||
|
using osu.Game.Rulesets.Catch.Objects;
|
||||||
|
using osu.Game.Rulesets.Catch.Objects.Drawables;
|
||||||
|
using osu.Game.Rulesets.Judgements;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
using osu.Game.Tests.Visual;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Tests
|
namespace osu.Game.Rulesets.Catch.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class TestSceneCatcher : CatchSkinnableTestScene
|
public class TestSceneCatcher : OsuTestScene
|
||||||
{
|
{
|
||||||
[BackgroundDependencyLoader]
|
[Resolved]
|
||||||
private void load()
|
private OsuConfigManager config { get; set; }
|
||||||
|
|
||||||
|
private Container droppedObjectContainer;
|
||||||
|
|
||||||
|
private TestCatcher catcher;
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void SetUp() => Schedule(() =>
|
||||||
{
|
{
|
||||||
SetContents(() => new Catcher(new Container())
|
var difficulty = new BeatmapDifficulty
|
||||||
|
{
|
||||||
|
CircleSize = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
var trailContainer = new Container();
|
||||||
|
droppedObjectContainer = new Container();
|
||||||
|
catcher = new TestCatcher(trailContainer, droppedObjectContainer, difficulty);
|
||||||
|
|
||||||
|
Child = new Container
|
||||||
{
|
{
|
||||||
RelativePositionAxes = Axes.None,
|
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
trailContainer,
|
||||||
|
droppedObjectContainer,
|
||||||
|
catcher
|
||||||
|
}
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestCatcherHyperStateReverted()
|
||||||
|
{
|
||||||
|
DrawableCatchHitObject drawableObject1 = null;
|
||||||
|
DrawableCatchHitObject drawableObject2 = null;
|
||||||
|
JudgementResult result1 = null;
|
||||||
|
JudgementResult result2 = null;
|
||||||
|
AddStep("catch hyper fruit", () =>
|
||||||
|
{
|
||||||
|
drawableObject1 = createDrawableObject(new Fruit { HyperDashTarget = new Fruit { X = 100 } });
|
||||||
|
result1 = attemptCatch(drawableObject1);
|
||||||
|
});
|
||||||
|
AddStep("catch normal fruit", () =>
|
||||||
|
{
|
||||||
|
drawableObject2 = createDrawableObject(new Fruit());
|
||||||
|
result2 = attemptCatch(drawableObject2);
|
||||||
|
});
|
||||||
|
AddStep("revert second result", () =>
|
||||||
|
{
|
||||||
|
catcher.OnRevertResult(drawableObject2, result2);
|
||||||
|
});
|
||||||
|
checkHyperDash(true);
|
||||||
|
AddStep("revert first result", () =>
|
||||||
|
{
|
||||||
|
catcher.OnRevertResult(drawableObject1, result1);
|
||||||
|
});
|
||||||
|
checkHyperDash(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestCatcherAnimationStateReverted()
|
||||||
|
{
|
||||||
|
DrawableCatchHitObject drawableObject = null;
|
||||||
|
JudgementResult result = null;
|
||||||
|
AddStep("catch kiai fruit", () =>
|
||||||
|
{
|
||||||
|
drawableObject = createDrawableObject(new TestKiaiFruit());
|
||||||
|
result = attemptCatch(drawableObject);
|
||||||
|
});
|
||||||
|
checkState(CatcherAnimationState.Kiai);
|
||||||
|
AddStep("revert result", () =>
|
||||||
|
{
|
||||||
|
catcher.OnRevertResult(drawableObject, result);
|
||||||
|
});
|
||||||
|
checkState(CatcherAnimationState.Idle);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestCatcherCatchWidth()
|
||||||
|
{
|
||||||
|
var halfWidth = Catcher.CalculateCatchWidth(new BeatmapDifficulty { CircleSize = 0 }) / 2;
|
||||||
|
AddStep("catch fruit", () =>
|
||||||
|
{
|
||||||
|
attemptCatch(new Fruit { X = -halfWidth + 1 });
|
||||||
|
attemptCatch(new Fruit { X = halfWidth - 1 });
|
||||||
|
});
|
||||||
|
checkPlate(2);
|
||||||
|
AddStep("miss fruit", () =>
|
||||||
|
{
|
||||||
|
attemptCatch(new Fruit { X = -halfWidth - 1 });
|
||||||
|
attemptCatch(new Fruit { X = halfWidth + 1 });
|
||||||
|
});
|
||||||
|
checkPlate(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestFruitChangesCatcherState()
|
||||||
|
{
|
||||||
|
AddStep("miss fruit", () => attemptCatch(new Fruit { X = 100 }));
|
||||||
|
checkState(CatcherAnimationState.Fail);
|
||||||
|
AddStep("catch fruit", () => attemptCatch(new Fruit()));
|
||||||
|
checkState(CatcherAnimationState.Idle);
|
||||||
|
AddStep("catch kiai fruit", () => attemptCatch(new TestKiaiFruit()));
|
||||||
|
checkState(CatcherAnimationState.Kiai);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestNormalFruitResetsHyperDashState()
|
||||||
|
{
|
||||||
|
AddStep("catch hyper fruit", () => attemptCatch(new Fruit
|
||||||
|
{
|
||||||
|
HyperDashTarget = new Fruit { X = 100 }
|
||||||
|
}));
|
||||||
|
checkHyperDash(true);
|
||||||
|
AddStep("catch normal fruit", () => attemptCatch(new Fruit()));
|
||||||
|
checkHyperDash(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestTinyDropletMissPreservesCatcherState()
|
||||||
|
{
|
||||||
|
AddStep("catch hyper kiai fruit", () => attemptCatch(new TestKiaiFruit
|
||||||
|
{
|
||||||
|
HyperDashTarget = new Fruit { X = 100 }
|
||||||
|
}));
|
||||||
|
AddStep("catch tiny droplet", () => attemptCatch(new TinyDroplet()));
|
||||||
|
AddStep("miss tiny droplet", () => attemptCatch(new TinyDroplet { X = 100 }));
|
||||||
|
// catcher state and hyper dash state is preserved
|
||||||
|
checkState(CatcherAnimationState.Kiai);
|
||||||
|
checkHyperDash(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestBananaMissPreservesCatcherState()
|
||||||
|
{
|
||||||
|
AddStep("catch hyper kiai fruit", () => attemptCatch(new TestKiaiFruit
|
||||||
|
{
|
||||||
|
HyperDashTarget = new Fruit { X = 100 }
|
||||||
|
}));
|
||||||
|
AddStep("miss banana", () => attemptCatch(new Banana { X = 100 }));
|
||||||
|
// catcher state is preserved but hyper dash state is reset
|
||||||
|
checkState(CatcherAnimationState.Kiai);
|
||||||
|
checkHyperDash(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestCatcherStacking()
|
||||||
|
{
|
||||||
|
AddStep("catch fruit", () => attemptCatch(new Fruit()));
|
||||||
|
checkPlate(1);
|
||||||
|
AddStep("catch more fruits", () => attemptCatch(new Fruit(), 9));
|
||||||
|
checkPlate(10);
|
||||||
|
AddAssert("caught objects are stacked", () =>
|
||||||
|
catcher.CaughtObjects.All(obj => obj.Y <= 0) &&
|
||||||
|
catcher.CaughtObjects.Any(obj => obj.Y == 0) &&
|
||||||
|
catcher.CaughtObjects.Any(obj => obj.Y < -20));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestCatcherExplosionAndDropping()
|
||||||
|
{
|
||||||
|
AddStep("catch fruit", () => attemptCatch(new Fruit()));
|
||||||
|
AddStep("catch tiny droplet", () => attemptCatch(new TinyDroplet()));
|
||||||
|
AddAssert("tiny droplet is exploded", () => catcher.CaughtObjects.Count() == 1 && droppedObjectContainer.Count == 1);
|
||||||
|
AddUntilStep("wait explosion", () => !droppedObjectContainer.Any());
|
||||||
|
AddStep("catch more fruits", () => attemptCatch(new Fruit(), 9));
|
||||||
|
AddStep("explode", () => catcher.Explode());
|
||||||
|
AddAssert("fruits are exploded", () => !catcher.CaughtObjects.Any() && droppedObjectContainer.Count == 10);
|
||||||
|
AddUntilStep("wait explosion", () => !droppedObjectContainer.Any());
|
||||||
|
AddStep("catch fruits", () => attemptCatch(new Fruit(), 10));
|
||||||
|
AddStep("drop", () => catcher.Drop());
|
||||||
|
AddAssert("fruits are dropped", () => !catcher.CaughtObjects.Any() && droppedObjectContainer.Count == 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestCase(true)]
|
||||||
|
[TestCase(false)]
|
||||||
|
public void TestHitLighting(bool enabled)
|
||||||
|
{
|
||||||
|
AddStep($"{(enabled ? "enable" : "disable")} hit lighting", () => config.Set(OsuSetting.HitLighting, enabled));
|
||||||
|
AddStep("catch fruit", () => attemptCatch(new Fruit()));
|
||||||
|
AddAssert("check hit lighting", () => catcher.ChildrenOfType<HitExplosion>().Any() == enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkPlate(int count) => AddAssert($"{count} objects on the plate", () => catcher.CaughtObjects.Count() == count);
|
||||||
|
|
||||||
|
private void checkState(CatcherAnimationState state) => AddAssert($"catcher state is {state}", () => catcher.CurrentState == state);
|
||||||
|
|
||||||
|
private void checkHyperDash(bool state) => AddAssert($"catcher is {(state ? "" : "not ")}hyper dashing", () => catcher.HyperDashing == state);
|
||||||
|
|
||||||
|
private void attemptCatch(CatchHitObject hitObject, int count = 1)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < count; i++)
|
||||||
|
attemptCatch(createDrawableObject(hitObject));
|
||||||
|
}
|
||||||
|
|
||||||
|
private JudgementResult attemptCatch(DrawableCatchHitObject drawableObject)
|
||||||
|
{
|
||||||
|
drawableObject.HitObject.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||||
|
var result = new CatchJudgementResult(drawableObject.HitObject, drawableObject.HitObject.CreateJudgement())
|
||||||
|
{
|
||||||
|
Type = catcher.CanCatch(drawableObject.HitObject) ? HitResult.Great : HitResult.Miss
|
||||||
|
};
|
||||||
|
catcher.OnNewResult(drawableObject, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private DrawableCatchHitObject createDrawableObject(CatchHitObject hitObject)
|
||||||
|
{
|
||||||
|
switch (hitObject)
|
||||||
|
{
|
||||||
|
case Banana banana:
|
||||||
|
return new DrawableBanana(banana);
|
||||||
|
|
||||||
|
case Droplet droplet:
|
||||||
|
return new DrawableDroplet(droplet);
|
||||||
|
|
||||||
|
case Fruit fruit:
|
||||||
|
return new DrawableFruit(fruit);
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(hitObject));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TestCatcher : Catcher
|
||||||
|
{
|
||||||
|
public IEnumerable<DrawablePalpableCatchHitObject> CaughtObjects => this.ChildrenOfType<DrawablePalpableCatchHitObject>();
|
||||||
|
|
||||||
|
public TestCatcher(Container trailsTarget, Container droppedObjectTarget, BeatmapDifficulty difficulty)
|
||||||
|
: base(trailsTarget, droppedObjectTarget, difficulty)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TestKiaiFruit : Fruit
|
||||||
|
{
|
||||||
|
protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
||||||
|
{
|
||||||
|
controlPointInfo.Add(0, new EffectControlPoint { KiaiMode = true });
|
||||||
|
base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,18 +6,16 @@ using NUnit.Framework;
|
|||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Rulesets.Catch.Beatmaps;
|
|
||||||
using osu.Game.Rulesets.Catch.Judgements;
|
using osu.Game.Rulesets.Catch.Judgements;
|
||||||
using osu.Game.Rulesets.Catch.Objects;
|
using osu.Game.Rulesets.Catch.Objects;
|
||||||
using osu.Game.Rulesets.Catch.Objects.Drawables;
|
using osu.Game.Rulesets.Catch.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Catch.UI;
|
using osu.Game.Rulesets.Catch.UI;
|
||||||
using osu.Game.Rulesets.Judgements;
|
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Rulesets.UI;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Tests
|
namespace osu.Game.Rulesets.Catch.Tests
|
||||||
{
|
{
|
||||||
@ -29,82 +27,67 @@ namespace osu.Game.Rulesets.Catch.Tests
|
|||||||
[Resolved]
|
[Resolved]
|
||||||
private OsuConfigManager config { get; set; }
|
private OsuConfigManager config { get; set; }
|
||||||
|
|
||||||
private Catcher catcher => this.ChildrenOfType<CatcherArea>().First().MovableCatcher;
|
private Catcher catcher => this.ChildrenOfType<Catcher>().First();
|
||||||
|
|
||||||
|
private float circleSize;
|
||||||
|
|
||||||
public TestSceneCatcherArea()
|
public TestSceneCatcherArea()
|
||||||
{
|
{
|
||||||
AddSliderStep<float>("CircleSize", 0, 8, 5, createCatcher);
|
AddSliderStep<float>("circle size", 0, 8, 5, createCatcher);
|
||||||
AddToggleStep("Hyperdash", t =>
|
AddToggleStep("hyper dash", t => this.ChildrenOfType<TestCatcherArea>().ForEach(area => area.ToggleHyperDash(t)));
|
||||||
CreatedDrawables.OfType<CatchInputManager>().Select(i => i.Child)
|
|
||||||
.OfType<TestCatcherArea>().ForEach(c => c.ToggleHyperDash(t)));
|
|
||||||
|
|
||||||
AddRepeatStep("catch fruit", () => catchFruit(new TestFruit(false)
|
AddStep("catch fruit", () => attemptCatch(new Fruit()));
|
||||||
{
|
AddStep("catch fruit last in combo", () => attemptCatch(new Fruit { LastInCombo = true }));
|
||||||
X = catcher.X
|
AddStep("catch kiai fruit", () => attemptCatch(new TestSceneCatcher.TestKiaiFruit()));
|
||||||
}), 20);
|
AddStep("miss last in combo", () => attemptCatch(new Fruit { X = 100, LastInCombo = true }));
|
||||||
AddRepeatStep("catch fruit last in combo", () => catchFruit(new TestFruit(false)
|
|
||||||
{
|
|
||||||
X = catcher.X,
|
|
||||||
LastInCombo = true,
|
|
||||||
}), 20);
|
|
||||||
AddRepeatStep("catch kiai fruit", () => catchFruit(new TestFruit(true)
|
|
||||||
{
|
|
||||||
X = catcher.X
|
|
||||||
}), 20);
|
|
||||||
AddRepeatStep("miss fruit", () => catchFruit(new Fruit
|
|
||||||
{
|
|
||||||
X = catcher.X + 100,
|
|
||||||
LastInCombo = true,
|
|
||||||
}, true), 20);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase(true)]
|
private void attemptCatch(Fruit fruit)
|
||||||
[TestCase(false)]
|
|
||||||
public void TestHitLighting(bool enable)
|
|
||||||
{
|
{
|
||||||
AddStep("create catcher", () => createCatcher(5));
|
fruit.X += catcher.X;
|
||||||
|
fruit.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty
|
||||||
|
{
|
||||||
|
CircleSize = circleSize
|
||||||
|
});
|
||||||
|
|
||||||
AddStep("toggle hit lighting", () => config.Set(OsuSetting.HitLighting, enable));
|
foreach (var area in this.ChildrenOfType<CatcherArea>())
|
||||||
AddStep("catch fruit", () => catchFruit(new TestFruit(false)
|
|
||||||
{
|
|
||||||
X = catcher.X
|
|
||||||
}));
|
|
||||||
AddStep("catch fruit last in combo", () => catchFruit(new TestFruit(false)
|
|
||||||
{
|
|
||||||
X = catcher.X,
|
|
||||||
LastInCombo = true
|
|
||||||
}));
|
|
||||||
AddAssert("check hit explosion", () => catcher.ChildrenOfType<HitExplosion>().Any() == enable);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void catchFruit(Fruit fruit, bool miss = false)
|
|
||||||
{
|
|
||||||
this.ChildrenOfType<CatcherArea>().ForEach(area =>
|
|
||||||
{
|
{
|
||||||
DrawableFruit drawable = new DrawableFruit(fruit);
|
DrawableFruit drawable = new DrawableFruit(fruit);
|
||||||
area.Add(drawable);
|
area.Add(drawable);
|
||||||
|
|
||||||
Schedule(() =>
|
Schedule(() =>
|
||||||
{
|
{
|
||||||
area.AttemptCatch(fruit);
|
area.OnNewResult(drawable, new CatchJudgementResult(fruit, new CatchJudgement())
|
||||||
area.OnNewResult(drawable, new JudgementResult(fruit, new CatchJudgement()) { Type = miss ? HitResult.Miss : HitResult.Great });
|
{
|
||||||
|
Type = area.MovableCatcher.CanCatch(fruit) ? HitResult.Great : HitResult.Miss
|
||||||
|
});
|
||||||
|
|
||||||
drawable.Expire();
|
drawable.Expire();
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createCatcher(float size)
|
private void createCatcher(float size)
|
||||||
{
|
{
|
||||||
SetContents(() => new CatchInputManager(catchRuleset)
|
circleSize = size;
|
||||||
|
|
||||||
|
SetContents(() =>
|
||||||
|
{
|
||||||
|
var droppedObjectContainer = new Container();
|
||||||
|
|
||||||
|
return new CatchInputManager(catchRuleset)
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Child = new TestCatcherArea(new BeatmapDifficulty { CircleSize = size })
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
droppedObjectContainer,
|
||||||
|
new TestCatcherArea(droppedObjectContainer, new BeatmapDifficulty { CircleSize = size })
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.TopCentre,
|
Origin = Anchor.TopCentre,
|
||||||
CreateDrawableRepresentation = ((DrawableRuleset<CatchHitObject>)catchRuleset.CreateInstance().CreateDrawableRulesetWith(new CatchBeatmap())).CreateDrawableRepresentation
|
}
|
||||||
},
|
}
|
||||||
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,26 +97,13 @@ namespace osu.Game.Rulesets.Catch.Tests
|
|||||||
catchRuleset = rulesets.GetRuleset(2);
|
catchRuleset = rulesets.GetRuleset(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TestFruit : Fruit
|
|
||||||
{
|
|
||||||
public TestFruit(bool kiai)
|
|
||||||
{
|
|
||||||
var kiaiCpi = new ControlPointInfo();
|
|
||||||
kiaiCpi.Add(0, new EffectControlPoint { KiaiMode = kiai });
|
|
||||||
|
|
||||||
ApplyDefaultsToSelf(kiaiCpi, new BeatmapDifficulty());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class TestCatcherArea : CatcherArea
|
private class TestCatcherArea : CatcherArea
|
||||||
{
|
{
|
||||||
public TestCatcherArea(BeatmapDifficulty beatmapDifficulty)
|
public TestCatcherArea(Container droppedObjectContainer, BeatmapDifficulty beatmapDifficulty)
|
||||||
: base(beatmapDifficulty)
|
: base(droppedObjectContainer, beatmapDifficulty)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public new Catcher MovableCatcher => base.MovableCatcher;
|
|
||||||
|
|
||||||
public void ToggleHyperDash(bool status) => MovableCatcher.SetHyperDashState(status ? 2 : 1);
|
public void ToggleHyperDash(bool status) => MovableCatcher.SetHyperDashState(status ? 2 : 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -136,7 +136,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
|||||||
if (juice.NestedHitObjects.Last() is CatchHitObject tail)
|
if (juice.NestedHitObjects.Last() is CatchHitObject tail)
|
||||||
tail.LastInCombo = true; // usually the (Catch)BeatmapProcessor would do this for us when necessary
|
tail.LastInCombo = true; // usually the (Catch)BeatmapProcessor would do this for us when necessary
|
||||||
|
|
||||||
addToPlayfield(new DrawableJuiceStream(juice, drawableRuleset.CreateDrawableRepresentation));
|
addToPlayfield(new DrawableJuiceStream(juice));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void spawnBananas(bool hit = false)
|
private void spawnBananas(bool hit = false)
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System;
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Timing;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Rulesets.Catch.Objects;
|
using osu.Game.Rulesets.Catch.Objects;
|
||||||
using osu.Game.Rulesets.Catch.Objects.Drawables;
|
using osu.Game.Rulesets.Catch.Objects.Drawables;
|
||||||
using osuTK;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Tests
|
namespace osu.Game.Rulesets.Catch.Tests
|
||||||
{
|
{
|
||||||
@ -17,53 +19,69 @@ namespace osu.Game.Rulesets.Catch.Tests
|
|||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
|
||||||
foreach (FruitVisualRepresentation rep in Enum.GetValues(typeof(FruitVisualRepresentation)))
|
AddStep("show pear", () => SetContents(() => createDrawableFruit(0)));
|
||||||
AddStep($"show {rep}", () => SetContents(() => createDrawableFruit(rep)));
|
AddStep("show grape", () => SetContents(() => createDrawableFruit(1)));
|
||||||
|
AddStep("show pineapple / apple", () => SetContents(() => createDrawableFruit(2)));
|
||||||
|
AddStep("show raspberry / orange", () => SetContents(() => createDrawableFruit(3)));
|
||||||
|
|
||||||
|
AddStep("show banana", () => SetContents(createDrawableBanana));
|
||||||
|
|
||||||
AddStep("show droplet", () => SetContents(() => createDrawableDroplet()));
|
AddStep("show droplet", () => SetContents(() => createDrawableDroplet()));
|
||||||
AddStep("show tiny droplet", () => SetContents(createDrawableTinyDroplet));
|
AddStep("show tiny droplet", () => SetContents(createDrawableTinyDroplet));
|
||||||
|
|
||||||
foreach (FruitVisualRepresentation rep in Enum.GetValues(typeof(FruitVisualRepresentation)))
|
AddStep("show hyperdash pear", () => SetContents(() => createDrawableFruit(0, true)));
|
||||||
AddStep($"show hyperdash {rep}", () => SetContents(() => createDrawableFruit(rep, true)));
|
AddStep("show hyperdash grape", () => SetContents(() => createDrawableFruit(1, true)));
|
||||||
|
AddStep("show hyperdash pineapple / apple", () => SetContents(() => createDrawableFruit(2, true)));
|
||||||
|
AddStep("show hyperdash raspberry / orange", () => SetContents(() => createDrawableFruit(3, true)));
|
||||||
|
|
||||||
AddStep("show hyperdash droplet", () => SetContents(() => createDrawableDroplet(true)));
|
AddStep("show hyperdash droplet", () => SetContents(() => createDrawableDroplet(true)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Drawable createDrawableFruit(FruitVisualRepresentation rep, bool hyperdash = false) =>
|
private Drawable createDrawableFruit(int indexInBeatmap, bool hyperdash = false) =>
|
||||||
setProperties(new DrawableFruit(new TestCatchFruit(rep)), hyperdash);
|
new TestDrawableCatchHitObjectSpecimen(new DrawableFruit(new Fruit
|
||||||
|
|
||||||
private Drawable createDrawableDroplet(bool hyperdash = false) => setProperties(new DrawableDroplet(new Droplet()), hyperdash);
|
|
||||||
|
|
||||||
private Drawable createDrawableTinyDroplet() => setProperties(new DrawableTinyDroplet(new TinyDroplet()));
|
|
||||||
|
|
||||||
private DrawableCatchHitObject setProperties(DrawableCatchHitObject d, bool hyperdash = false)
|
|
||||||
{
|
{
|
||||||
var hitObject = d.HitObject;
|
IndexInBeatmap = indexInBeatmap,
|
||||||
hitObject.StartTime = 1000000000000;
|
HyperDashBindable = { Value = hyperdash }
|
||||||
hitObject.Scale = 1.5f;
|
}));
|
||||||
|
|
||||||
if (hyperdash)
|
private Drawable createDrawableBanana() =>
|
||||||
hitObject.HyperDashTarget = new Banana();
|
new TestDrawableCatchHitObjectSpecimen(new DrawableBanana(new Banana()));
|
||||||
|
|
||||||
|
private Drawable createDrawableDroplet(bool hyperdash = false) =>
|
||||||
|
new TestDrawableCatchHitObjectSpecimen(new DrawableDroplet(new Droplet
|
||||||
|
{
|
||||||
|
HyperDashBindable = { Value = hyperdash }
|
||||||
|
}));
|
||||||
|
|
||||||
|
private Drawable createDrawableTinyDroplet() => new TestDrawableCatchHitObjectSpecimen(new DrawableTinyDroplet(new TinyDroplet()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TestDrawableCatchHitObjectSpecimen : CompositeDrawable
|
||||||
|
{
|
||||||
|
public readonly ManualClock ManualClock;
|
||||||
|
|
||||||
|
public TestDrawableCatchHitObjectSpecimen(DrawableCatchHitObject d)
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both;
|
||||||
|
Anchor = Anchor.Centre;
|
||||||
|
Origin = Anchor.Centre;
|
||||||
|
|
||||||
|
ManualClock = new ManualClock();
|
||||||
|
Clock = new FramedClock(ManualClock);
|
||||||
|
|
||||||
|
var hitObject = d.HitObject;
|
||||||
|
hitObject.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||||
|
hitObject.Scale = 1.5f;
|
||||||
|
hitObject.StartTime = 500;
|
||||||
|
|
||||||
d.Anchor = Anchor.Centre;
|
d.Anchor = Anchor.Centre;
|
||||||
d.RelativePositionAxes = Axes.None;
|
|
||||||
d.Position = Vector2.Zero;
|
|
||||||
d.HitObjectApplied += _ =>
|
d.HitObjectApplied += _ =>
|
||||||
{
|
{
|
||||||
d.LifetimeStart = double.NegativeInfinity;
|
d.LifetimeStart = double.NegativeInfinity;
|
||||||
d.LifetimeEnd = double.PositiveInfinity;
|
d.LifetimeEnd = double.PositiveInfinity;
|
||||||
};
|
};
|
||||||
return d;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class TestCatchFruit : Fruit
|
InternalChild = d;
|
||||||
{
|
|
||||||
public TestCatchFruit(FruitVisualRepresentation rep)
|
|
||||||
{
|
|
||||||
VisualRepresentation = rep;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override FruitVisualRepresentation VisualRepresentation { get; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
96
osu.Game.Rulesets.Catch.Tests/TestSceneFruitRandomness.cs
Normal file
96
osu.Game.Rulesets.Catch.Tests/TestSceneFruitRandomness.cs
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Game.Rulesets.Catch.Objects;
|
||||||
|
using osu.Game.Rulesets.Catch.Objects.Drawables;
|
||||||
|
using osu.Game.Tests.Visual;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Catch.Tests
|
||||||
|
{
|
||||||
|
public class TestSceneFruitRandomness : OsuTestScene
|
||||||
|
{
|
||||||
|
private readonly TestDrawableFruit drawableFruit;
|
||||||
|
private readonly TestDrawableBanana drawableBanana;
|
||||||
|
|
||||||
|
public TestSceneFruitRandomness()
|
||||||
|
{
|
||||||
|
drawableFruit = new TestDrawableFruit(new Fruit());
|
||||||
|
drawableBanana = new TestDrawableBanana(new Banana());
|
||||||
|
|
||||||
|
Add(new TestDrawableCatchHitObjectSpecimen(drawableFruit) { X = -200 });
|
||||||
|
Add(new TestDrawableCatchHitObjectSpecimen(drawableBanana));
|
||||||
|
|
||||||
|
AddSliderStep("start time", 500, 600, 0, x =>
|
||||||
|
{
|
||||||
|
drawableFruit.HitObject.StartTime = drawableBanana.HitObject.StartTime = x;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestFruitRandomness()
|
||||||
|
{
|
||||||
|
// Use values such that the banana colour changes (2/3 of the integers are okay)
|
||||||
|
const int initial_start_time = 500;
|
||||||
|
const int another_start_time = 501;
|
||||||
|
|
||||||
|
float fruitRotation = 0;
|
||||||
|
float bananaRotation = 0;
|
||||||
|
float bananaScale = 0;
|
||||||
|
Color4 bananaColour = new Color4();
|
||||||
|
|
||||||
|
AddStep("Initialize start time", () =>
|
||||||
|
{
|
||||||
|
drawableFruit.HitObject.StartTime = drawableBanana.HitObject.StartTime = initial_start_time;
|
||||||
|
|
||||||
|
fruitRotation = drawableFruit.InnerRotation;
|
||||||
|
bananaRotation = drawableBanana.InnerRotation;
|
||||||
|
bananaScale = drawableBanana.InnerScale;
|
||||||
|
bananaColour = drawableBanana.AccentColour.Value;
|
||||||
|
});
|
||||||
|
|
||||||
|
AddStep("change start time", () =>
|
||||||
|
{
|
||||||
|
drawableFruit.HitObject.StartTime = drawableBanana.HitObject.StartTime = another_start_time;
|
||||||
|
});
|
||||||
|
|
||||||
|
AddAssert("fruit rotation is changed", () => drawableFruit.InnerRotation != fruitRotation);
|
||||||
|
AddAssert("banana rotation is changed", () => drawableBanana.InnerRotation != bananaRotation);
|
||||||
|
AddAssert("banana scale is changed", () => drawableBanana.InnerScale != bananaScale);
|
||||||
|
AddAssert("banana colour is changed", () => drawableBanana.AccentColour.Value != bananaColour);
|
||||||
|
|
||||||
|
AddStep("reset start time", () =>
|
||||||
|
{
|
||||||
|
drawableFruit.HitObject.StartTime = drawableBanana.HitObject.StartTime = initial_start_time;
|
||||||
|
});
|
||||||
|
|
||||||
|
AddAssert("rotation and scale restored", () =>
|
||||||
|
drawableFruit.InnerRotation == fruitRotation &&
|
||||||
|
drawableBanana.InnerRotation == bananaRotation &&
|
||||||
|
drawableBanana.InnerScale == bananaScale &&
|
||||||
|
drawableBanana.AccentColour.Value == bananaColour);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TestDrawableFruit : DrawableFruit
|
||||||
|
{
|
||||||
|
public float InnerRotation => ScaleContainer.Rotation;
|
||||||
|
|
||||||
|
public TestDrawableFruit(Fruit h)
|
||||||
|
: base(h)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TestDrawableBanana : DrawableBanana
|
||||||
|
{
|
||||||
|
public float InnerRotation => ScaleContainer.Rotation;
|
||||||
|
public float InnerScale => ScaleContainer.Scale.X;
|
||||||
|
|
||||||
|
public TestDrawableBanana(Banana h)
|
||||||
|
: base(h)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
32
osu.Game.Rulesets.Catch.Tests/TestSceneFruitVisualChange.cs
Normal file
32
osu.Game.Rulesets.Catch.Tests/TestSceneFruitVisualChange.cs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Game.Rulesets.Catch.Objects;
|
||||||
|
using osu.Game.Rulesets.Catch.Objects.Drawables;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Catch.Tests
|
||||||
|
{
|
||||||
|
public class TestSceneFruitVisualChange : TestSceneFruitObjects
|
||||||
|
{
|
||||||
|
private readonly Bindable<int> indexInBeatmap = new Bindable<int>();
|
||||||
|
private readonly Bindable<bool> hyperDash = new Bindable<bool>();
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
AddStep("fruit changes visual and hyper", () => SetContents(() => new TestDrawableCatchHitObjectSpecimen(new DrawableFruit(new Fruit
|
||||||
|
{
|
||||||
|
IndexInBeatmapBindable = { BindTarget = indexInBeatmap },
|
||||||
|
HyperDashBindable = { BindTarget = hyperDash },
|
||||||
|
}))));
|
||||||
|
|
||||||
|
AddStep("droplet changes hyper", () => SetContents(() => new TestDrawableCatchHitObjectSpecimen(new DrawableDroplet(new Droplet
|
||||||
|
{
|
||||||
|
HyperDashBindable = { BindTarget = hyperDash },
|
||||||
|
}))));
|
||||||
|
|
||||||
|
Scheduler.AddDelayed(() => indexInBeatmap.Value++, 250, true);
|
||||||
|
Scheduler.AddDelayed(() => hyperDash.Value = !hyperDash.Value, 1000, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -13,6 +13,7 @@ using osu.Game.Beatmaps.ControlPoints;
|
|||||||
using osu.Game.Rulesets.Catch.Objects;
|
using osu.Game.Rulesets.Catch.Objects;
|
||||||
using osu.Game.Rulesets.Catch.Objects.Drawables;
|
using osu.Game.Rulesets.Catch.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Catch.Skinning;
|
using osu.Game.Rulesets.Catch.Skinning;
|
||||||
|
using osu.Game.Rulesets.Catch.Skinning.Legacy;
|
||||||
using osu.Game.Rulesets.Catch.UI;
|
using osu.Game.Rulesets.Catch.UI;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
using osu.Game.Tests.Visual;
|
using osu.Game.Tests.Visual;
|
||||||
@ -117,7 +118,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
|||||||
|
|
||||||
AddStep("create hyper-dashing catcher", () =>
|
AddStep("create hyper-dashing catcher", () =>
|
||||||
{
|
{
|
||||||
Child = setupSkinHierarchy(catcherArea = new CatcherArea
|
Child = setupSkinHierarchy(catcherArea = new CatcherArea(new Container())
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<Import Project="..\osu.TestProject.props" />
|
<Import Project="..\osu.TestProject.props" />
|
||||||
<ItemGroup Label="Package References">
|
<ItemGroup Label="Package References">
|
||||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.0" />
|
||||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
||||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||||
|
@ -5,11 +5,11 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Catch.MathUtils;
|
||||||
using osu.Game.Rulesets.Catch.Objects;
|
using osu.Game.Rulesets.Catch.Objects;
|
||||||
using osu.Game.Rulesets.Catch.UI;
|
using osu.Game.Rulesets.Catch.UI;
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
|
||||||
using osu.Game.Rulesets.Catch.MathUtils;
|
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Beatmaps
|
namespace osu.Game.Rulesets.Catch.Beatmaps
|
||||||
{
|
{
|
||||||
@ -192,24 +192,24 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
|
|||||||
|
|
||||||
private static void initialiseHyperDash(IBeatmap beatmap)
|
private static void initialiseHyperDash(IBeatmap beatmap)
|
||||||
{
|
{
|
||||||
List<CatchHitObject> objectWithDroplets = new List<CatchHitObject>();
|
List<PalpableCatchHitObject> palpableObjects = new List<PalpableCatchHitObject>();
|
||||||
|
|
||||||
foreach (var currentObject in beatmap.HitObjects)
|
foreach (var currentObject in beatmap.HitObjects)
|
||||||
{
|
{
|
||||||
if (currentObject is Fruit fruitObject)
|
if (currentObject is Fruit fruitObject)
|
||||||
objectWithDroplets.Add(fruitObject);
|
palpableObjects.Add(fruitObject);
|
||||||
|
|
||||||
if (currentObject is JuiceStream)
|
if (currentObject is JuiceStream)
|
||||||
{
|
{
|
||||||
foreach (var currentJuiceElement in currentObject.NestedHitObjects)
|
foreach (var juice in currentObject.NestedHitObjects)
|
||||||
{
|
{
|
||||||
if (!(currentJuiceElement is TinyDroplet))
|
if (juice is PalpableCatchHitObject palpableObject && !(juice is TinyDroplet))
|
||||||
objectWithDroplets.Add((CatchHitObject)currentJuiceElement);
|
palpableObjects.Add(palpableObject);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
objectWithDroplets.Sort((h1, h2) => h1.StartTime.CompareTo(h2.StartTime));
|
palpableObjects.Sort((h1, h2) => h1.StartTime.CompareTo(h2.StartTime));
|
||||||
|
|
||||||
double halfCatcherWidth = Catcher.CalculateCatchWidth(beatmap.BeatmapInfo.BaseDifficulty) / 2;
|
double halfCatcherWidth = Catcher.CalculateCatchWidth(beatmap.BeatmapInfo.BaseDifficulty) / 2;
|
||||||
|
|
||||||
@ -221,10 +221,10 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
|
|||||||
int lastDirection = 0;
|
int lastDirection = 0;
|
||||||
double lastExcess = halfCatcherWidth;
|
double lastExcess = halfCatcherWidth;
|
||||||
|
|
||||||
for (int i = 0; i < objectWithDroplets.Count - 1; i++)
|
for (int i = 0; i < palpableObjects.Count - 1; i++)
|
||||||
{
|
{
|
||||||
CatchHitObject currentObject = objectWithDroplets[i];
|
var currentObject = palpableObjects[i];
|
||||||
CatchHitObject nextObject = objectWithDroplets[i + 1];
|
var nextObject = palpableObjects[i + 1];
|
||||||
|
|
||||||
// Reset variables in-case values have changed (e.g. after applying HR)
|
// Reset variables in-case values have changed (e.g. after applying HR)
|
||||||
currentObject.HyperDashTarget = null;
|
currentObject.HyperDashTarget = null;
|
||||||
|
@ -21,7 +21,7 @@ using osu.Game.Rulesets.Difficulty;
|
|||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
using System;
|
using System;
|
||||||
using osu.Game.Rulesets.Catch.Skinning;
|
using osu.Game.Rulesets.Catch.Skinning.Legacy;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch
|
namespace osu.Game.Rulesets.Catch
|
||||||
|
@ -5,11 +5,8 @@ namespace osu.Game.Rulesets.Catch
|
|||||||
{
|
{
|
||||||
public enum CatchSkinComponents
|
public enum CatchSkinComponents
|
||||||
{
|
{
|
||||||
FruitBananas,
|
Fruit,
|
||||||
FruitApple,
|
Banana,
|
||||||
FruitGrapes,
|
|
||||||
FruitOrange,
|
|
||||||
FruitPear,
|
|
||||||
Droplet,
|
Droplet,
|
||||||
CatcherIdle,
|
CatcherIdle,
|
||||||
CatcherFail,
|
CatcherFail,
|
||||||
|
@ -12,9 +12,9 @@ namespace osu.Game.Rulesets.Catch.Difficulty.Preprocessing
|
|||||||
{
|
{
|
||||||
private const float normalized_hitobject_radius = 41.0f;
|
private const float normalized_hitobject_radius = 41.0f;
|
||||||
|
|
||||||
public new CatchHitObject BaseObject => (CatchHitObject)base.BaseObject;
|
public new PalpableCatchHitObject BaseObject => (PalpableCatchHitObject)base.BaseObject;
|
||||||
|
|
||||||
public new CatchHitObject LastObject => (CatchHitObject)base.LastObject;
|
public new PalpableCatchHitObject LastObject => (PalpableCatchHitObject)base.LastObject;
|
||||||
|
|
||||||
public readonly float NormalizedPosition;
|
public readonly float NormalizedPosition;
|
||||||
public readonly float LastNormalizedPosition;
|
public readonly float LastNormalizedPosition;
|
||||||
|
28
osu.Game.Rulesets.Catch/Judgements/CatchJudgementResult.cs
Normal file
28
osu.Game.Rulesets.Catch/Judgements/CatchJudgementResult.cs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using osu.Game.Rulesets.Catch.UI;
|
||||||
|
using osu.Game.Rulesets.Judgements;
|
||||||
|
using osu.Game.Rulesets.Objects;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Catch.Judgements
|
||||||
|
{
|
||||||
|
public class CatchJudgementResult : JudgementResult
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The catcher animation state prior to this judgement.
|
||||||
|
/// </summary>
|
||||||
|
public CatcherAnimationState CatcherAnimationState;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the catcher was hyper dashing prior to this judgement.
|
||||||
|
/// </summary>
|
||||||
|
public bool CatcherHyperDash;
|
||||||
|
|
||||||
|
public CatchJudgementResult([NotNull] HitObject hitObject, [NotNull] Judgement judgement)
|
||||||
|
: base(hitObject, judgement)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -5,7 +5,7 @@ using osu.Game.Rulesets.Mods;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Mods
|
namespace osu.Game.Rulesets.Catch.Mods
|
||||||
{
|
{
|
||||||
public class CatchModEasy : ModEasy
|
public class CatchModEasy : ModEasyWithExtraLives
|
||||||
{
|
{
|
||||||
public override string Description => @"Larger fruits, more forgiving HP drain, less accuracy required, and three lives!";
|
public override string Description => @"Larger fruits, more forgiving HP drain, less accuracy required, and three lives!";
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,26 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
using osu.Game.Rulesets.Catch.Judgements;
|
using osu.Game.Rulesets.Catch.Judgements;
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
|
using osu.Game.Utils;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Objects
|
namespace osu.Game.Rulesets.Catch.Objects
|
||||||
{
|
{
|
||||||
public class Banana : Fruit
|
public class Banana : PalpableCatchHitObject, IHasComboInformation
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Index of banana in current shower.
|
/// Index of banana in current shower.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int BananaIndex;
|
public int BananaIndex;
|
||||||
|
|
||||||
public override FruitVisualRepresentation VisualRepresentation => FruitVisualRepresentation.Banana;
|
|
||||||
|
|
||||||
public override Judgement CreateJudgement() => new CatchBananaJudgement();
|
public override Judgement CreateJudgement() => new CatchBananaJudgement();
|
||||||
|
|
||||||
private static readonly List<HitSampleInfo> samples = new List<HitSampleInfo> { new BananaHitSampleInfo() };
|
private static readonly List<HitSampleInfo> samples = new List<HitSampleInfo> { new BananaHitSampleInfo() };
|
||||||
@ -26,11 +30,45 @@ namespace osu.Game.Rulesets.Catch.Objects
|
|||||||
Samples = samples;
|
Samples = samples;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class BananaHitSampleInfo : HitSampleInfo
|
// override any external colour changes with banananana
|
||||||
{
|
Color4 IHasComboInformation.GetComboColour(IReadOnlyList<Color4> comboColours) => getBananaColour();
|
||||||
private static string[] lookupNames { get; } = { "metronomelow", "catch-banana" };
|
|
||||||
|
|
||||||
public override IEnumerable<string> LookupNames => lookupNames;
|
private Color4 getBananaColour()
|
||||||
|
{
|
||||||
|
switch (StatelessRNG.NextInt(3, RandomSeed))
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class BananaHitSampleInfo : HitSampleInfo, IEquatable<BananaHitSampleInfo>
|
||||||
|
{
|
||||||
|
private static readonly string[] lookup_names = { "Gameplay/metronomelow", "Gameplay/catch-banana" };
|
||||||
|
|
||||||
|
public override IEnumerable<string> LookupNames => lookup_names;
|
||||||
|
|
||||||
|
public BananaHitSampleInfo(int volume = 0)
|
||||||
|
: base(string.Empty, volume: volume)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed override HitSampleInfo With(Optional<string> newName = default, Optional<string?> newBank = default, Optional<string?> newSuffix = default, Optional<int> newVolume = default)
|
||||||
|
=> new BananaHitSampleInfo(newVolume.GetOr(Volume));
|
||||||
|
|
||||||
|
public bool Equals(BananaHitSampleInfo? other)
|
||||||
|
=> other != null;
|
||||||
|
|
||||||
|
public override bool Equals(object? obj)
|
||||||
|
=> obj is BananaHitSampleInfo other && Equals(other);
|
||||||
|
|
||||||
|
public override int GetHashCode() => lookup_names.GetHashCode();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,8 +9,6 @@ namespace osu.Game.Rulesets.Catch.Objects
|
|||||||
{
|
{
|
||||||
public class BananaShower : CatchHitObject, IHasDuration
|
public class BananaShower : CatchHitObject, IHasDuration
|
||||||
{
|
{
|
||||||
public override FruitVisualRepresentation VisualRepresentation => FruitVisualRepresentation.Banana;
|
|
||||||
|
|
||||||
public override bool LastInCombo => true;
|
public override bool LastInCombo => true;
|
||||||
|
|
||||||
public override Judgement CreateJudgement() => new IgnoreJudgement();
|
public override Judgement CreateJudgement() => new IgnoreJudgement();
|
||||||
|
@ -16,32 +16,47 @@ namespace osu.Game.Rulesets.Catch.Objects
|
|||||||
{
|
{
|
||||||
public const float OBJECT_RADIUS = 64;
|
public const float OBJECT_RADIUS = 64;
|
||||||
|
|
||||||
private float x;
|
// This value is after XOffset applied.
|
||||||
|
public readonly Bindable<float> XBindable = new Bindable<float>();
|
||||||
|
|
||||||
|
// This value is before XOffset applied.
|
||||||
|
private float originalX;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The horizontal position of the fruit between 0 and <see cref="CatchPlayfield.WIDTH"/>.
|
/// The horizontal position of the fruit between 0 and <see cref="CatchPlayfield.WIDTH"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public float X
|
public float X
|
||||||
{
|
{
|
||||||
get => x + XOffset;
|
// TODO: I don't like this asymmetry.
|
||||||
set => x = value;
|
get => XBindable.Value;
|
||||||
|
// originalX is set by `XBindable.BindValueChanged`
|
||||||
|
set => XBindable.Value = value + xOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
private float xOffset;
|
||||||
/// Whether this object can be placed on the catcher's plate.
|
|
||||||
/// </summary>
|
|
||||||
public virtual bool CanBePlated => false;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A random offset applied to <see cref="X"/>, set by the <see cref="CatchBeatmapProcessor"/>.
|
/// A random offset applied to <see cref="X"/>, set by the <see cref="CatchBeatmapProcessor"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal float XOffset { get; set; }
|
internal float XOffset
|
||||||
|
{
|
||||||
|
get => xOffset;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
xOffset = value;
|
||||||
|
XBindable.Value = originalX + xOffset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public double TimePreempt = 1000;
|
public double TimePreempt = 1000;
|
||||||
|
|
||||||
public int IndexInBeatmap { get; set; }
|
public readonly Bindable<int> IndexInBeatmapBindable = new Bindable<int>();
|
||||||
|
|
||||||
public virtual FruitVisualRepresentation VisualRepresentation => (FruitVisualRepresentation)(IndexInBeatmap % 4);
|
public int IndexInBeatmap
|
||||||
|
{
|
||||||
|
get => IndexInBeatmapBindable.Value;
|
||||||
|
set => IndexInBeatmapBindable.Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
public virtual bool NewCombo { get; set; }
|
public virtual bool NewCombo { get; set; }
|
||||||
|
|
||||||
@ -63,13 +78,6 @@ namespace osu.Game.Rulesets.Catch.Objects
|
|||||||
set => ComboIndexBindable.Value = value;
|
set => ComboIndexBindable.Value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Difference between the distance to the next object
|
|
||||||
/// and the distance that would have triggered a hyper dash.
|
|
||||||
/// A value close to 0 indicates a difficult jump (for difficulty calculation).
|
|
||||||
/// </summary>
|
|
||||||
public float DistanceToHyperDash { get; set; }
|
|
||||||
|
|
||||||
public Bindable<bool> LastInComboBindable { get; } = new Bindable<bool>();
|
public Bindable<bool> LastInComboBindable { get; } = new Bindable<bool>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -81,17 +89,19 @@ namespace osu.Game.Rulesets.Catch.Objects
|
|||||||
set => LastInComboBindable.Value = value;
|
set => LastInComboBindable.Value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public float Scale { get; set; } = 1;
|
public readonly Bindable<float> ScaleBindable = new Bindable<float>(1);
|
||||||
|
|
||||||
|
public float Scale
|
||||||
|
{
|
||||||
|
get => ScaleBindable.Value;
|
||||||
|
set => ScaleBindable.Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether this fruit can initiate a hyperdash.
|
/// The seed value used for visual randomness such as fruit rotation.
|
||||||
|
/// The value is <see cref="HitObject.StartTime"/> truncated to an integer.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool HyperDash => HyperDashTarget != null;
|
public int RandomSeed => (int)StartTime;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The target fruit if we are to initiate a hyperdash.
|
|
||||||
/// </summary>
|
|
||||||
public CatchHitObject HyperDashTarget;
|
|
||||||
|
|
||||||
protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
||||||
{
|
{
|
||||||
@ -103,22 +113,10 @@ namespace osu.Game.Rulesets.Catch.Objects
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected override HitWindows CreateHitWindows() => HitWindows.Empty;
|
protected override HitWindows CreateHitWindows() => HitWindows.Empty;
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
protected CatchHitObject()
|
||||||
/// Represents a single object that can be caught by the catcher.
|
|
||||||
/// </summary>
|
|
||||||
public abstract class PalpableCatchHitObject : CatchHitObject
|
|
||||||
{
|
{
|
||||||
public override bool CanBePlated => true;
|
XBindable.BindValueChanged(x => originalX = x.NewValue - xOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum FruitVisualRepresentation
|
|
||||||
{
|
|
||||||
Pear,
|
|
||||||
Grape,
|
|
||||||
Pineapple,
|
|
||||||
Raspberry,
|
|
||||||
Banana // banananananannaanana
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,31 +0,0 @@
|
|||||||
// 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.
|
|
||||||
|
|
||||||
using osu.Framework.Graphics;
|
|
||||||
using osu.Game.Rulesets.Catch.Objects.Drawables.Pieces;
|
|
||||||
using osuTK;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Objects.Drawables
|
|
||||||
{
|
|
||||||
public class BananaPiece : PulpFormation
|
|
||||||
{
|
|
||||||
public BananaPiece()
|
|
||||||
{
|
|
||||||
InternalChildren = new Drawable[]
|
|
||||||
{
|
|
||||||
new Pulp
|
|
||||||
{
|
|
||||||
AccentColour = { BindTarget = AccentColour },
|
|
||||||
Size = new Vector2(SMALL_PULP),
|
|
||||||
Y = -0.3f
|
|
||||||
},
|
|
||||||
new Pulp
|
|
||||||
{
|
|
||||||
AccentColour = { BindTarget = AccentColour },
|
|
||||||
Size = new Vector2(LARGE_PULP_4 * 0.8f, LARGE_PULP_4 * 2.5f),
|
|
||||||
Y = 0.05f,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,26 +1,40 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using JetBrains.Annotations;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Utils;
|
using osu.Game.Rulesets.Catch.Skinning.Default;
|
||||||
using osuTK.Graphics;
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Objects.Drawables
|
namespace osu.Game.Rulesets.Catch.Objects.Drawables
|
||||||
{
|
{
|
||||||
public class DrawableBanana : DrawableFruit
|
public class DrawableBanana : DrawablePalpableCatchHitObject
|
||||||
{
|
{
|
||||||
public DrawableBanana(Banana h)
|
public DrawableBanana()
|
||||||
|
: this(null)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public DrawableBanana([CanBeNull] Banana h)
|
||||||
: base(h)
|
: base(h)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
private Color4? colour;
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
protected override Color4 GetComboColour(IReadOnlyList<Color4> comboColours)
|
|
||||||
{
|
{
|
||||||
// override any external colour changes with banananana
|
ScaleContainer.Child = new SkinnableDrawable(
|
||||||
return colour ??= getBananaColour();
|
new CatchSkinComponent(CatchSkinComponents.Banana),
|
||||||
|
_ => new BananaPiece());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
// start time affects the random seed which is used to determine the banana colour
|
||||||
|
StartTimeBindable.BindValueChanged(_ => UpdateComboColour());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void UpdateInitialTransforms()
|
protected override void UpdateInitialTransforms()
|
||||||
@ -30,14 +44,14 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
|
|||||||
const float end_scale = 0.6f;
|
const float end_scale = 0.6f;
|
||||||
const float random_scale_range = 1.6f;
|
const float random_scale_range = 1.6f;
|
||||||
|
|
||||||
ScaleContainer.ScaleTo(HitObject.Scale * (end_scale + random_scale_range * RNG.NextSingle()))
|
ScaleContainer.ScaleTo(HitObject.Scale * (end_scale + random_scale_range * RandomSingle(3)))
|
||||||
.Then().ScaleTo(HitObject.Scale * end_scale, HitObject.TimePreempt);
|
.Then().ScaleTo(HitObject.Scale * end_scale, HitObject.TimePreempt);
|
||||||
|
|
||||||
ScaleContainer.RotateTo(getRandomAngle())
|
ScaleContainer.RotateTo(getRandomAngle(1))
|
||||||
.Then()
|
.Then()
|
||||||
.RotateTo(getRandomAngle(), HitObject.TimePreempt);
|
.RotateTo(getRandomAngle(2), HitObject.TimePreempt);
|
||||||
|
|
||||||
float getRandomAngle() => 180 * (RNG.NextSingle() * 2 - 1);
|
float getRandomAngle(int series) => 180 * (RandomSingle(series) * 2 - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void PlaySamples()
|
public override void PlaySamples()
|
||||||
@ -46,20 +60,5 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
|
|||||||
if (Samples != null)
|
if (Samples != null)
|
||||||
Samples.Frequency.Value = 0.77f + ((Banana)HitObject).BananaIndex * 0.006f;
|
Samples.Frequency.Value = 0.77f + ((Banana)HitObject).BananaIndex * 0.006f;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Color4 getBananaColour()
|
|
||||||
{
|
|
||||||
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,26 +1,27 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System;
|
using JetBrains.Annotations;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Game.Rulesets.Objects;
|
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Objects.Drawables
|
namespace osu.Game.Rulesets.Catch.Objects.Drawables
|
||||||
{
|
{
|
||||||
public class DrawableBananaShower : DrawableCatchHitObject<BananaShower>
|
public class DrawableBananaShower : DrawableCatchHitObject
|
||||||
{
|
{
|
||||||
private readonly Func<CatchHitObject, DrawableHitObject<CatchHitObject>> createDrawableRepresentation;
|
|
||||||
private readonly Container bananaContainer;
|
private readonly Container bananaContainer;
|
||||||
|
|
||||||
public DrawableBananaShower(BananaShower s, Func<CatchHitObject, DrawableHitObject<CatchHitObject>> createDrawableRepresentation = null)
|
public DrawableBananaShower()
|
||||||
|
: this(null)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public DrawableBananaShower([CanBeNull] BananaShower s)
|
||||||
: base(s)
|
: base(s)
|
||||||
{
|
{
|
||||||
this.createDrawableRepresentation = createDrawableRepresentation;
|
|
||||||
RelativeSizeAxes = Axes.X;
|
RelativeSizeAxes = Axes.X;
|
||||||
Origin = Anchor.BottomLeft;
|
Origin = Anchor.BottomLeft;
|
||||||
X = 0;
|
|
||||||
|
|
||||||
AddInternal(bananaContainer = new Container { RelativeSizeAxes = Axes.Both });
|
AddInternal(bananaContainer = new Container { RelativeSizeAxes = Axes.Both });
|
||||||
}
|
}
|
||||||
@ -34,18 +35,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
|
|||||||
protected override void ClearNestedHitObjects()
|
protected override void ClearNestedHitObjects()
|
||||||
{
|
{
|
||||||
base.ClearNestedHitObjects();
|
base.ClearNestedHitObjects();
|
||||||
bananaContainer.Clear();
|
bananaContainer.Clear(false);
|
||||||
}
|
|
||||||
|
|
||||||
protected override DrawableHitObject CreateNestedHitObject(HitObject hitObject)
|
|
||||||
{
|
|
||||||
switch (hitObject)
|
|
||||||
{
|
|
||||||
case Banana banana:
|
|
||||||
return createDrawableRepresentation?.Invoke(banana)?.With(o => ((DrawableCatchHitObject)o).CheckPosition = p => CheckPosition?.Invoke(p) ?? false);
|
|
||||||
}
|
|
||||||
|
|
||||||
return base.CreateNestedHitObject(hitObject);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,77 +2,50 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using JetBrains.Annotations;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Game.Rulesets.Catch.Judgements;
|
||||||
using osu.Game.Rulesets.Catch.UI;
|
using osu.Game.Rulesets.Catch.UI;
|
||||||
|
using osu.Game.Rulesets.Judgements;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osuTK;
|
using osu.Game.Utils;
|
||||||
using osuTK.Graphics;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Objects.Drawables
|
namespace osu.Game.Rulesets.Catch.Objects.Drawables
|
||||||
{
|
{
|
||||||
public abstract class PalpableDrawableCatchHitObject<TObject> : DrawableCatchHitObject<TObject>
|
|
||||||
where TObject : PalpableCatchHitObject
|
|
||||||
{
|
|
||||||
protected Container ScaleContainer { get; private set; }
|
|
||||||
|
|
||||||
protected PalpableDrawableCatchHitObject(TObject hitObject)
|
|
||||||
: base(hitObject)
|
|
||||||
{
|
|
||||||
Origin = Anchor.Centre;
|
|
||||||
Size = new Vector2(CatchHitObject.OBJECT_RADIUS * 2);
|
|
||||||
Masking = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load()
|
|
||||||
{
|
|
||||||
AddRangeInternal(new Drawable[]
|
|
||||||
{
|
|
||||||
ScaleContainer = new Container
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
ScaleContainer.Scale = new Vector2(HitObject.Scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override Color4 GetComboColour(IReadOnlyList<Color4> comboColours) =>
|
|
||||||
comboColours[(HitObject.IndexInBeatmap + 1) % comboColours.Count];
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract class DrawableCatchHitObject<TObject> : DrawableCatchHitObject
|
|
||||||
where TObject : CatchHitObject
|
|
||||||
{
|
|
||||||
public new TObject HitObject;
|
|
||||||
|
|
||||||
protected DrawableCatchHitObject(TObject hitObject)
|
|
||||||
: base(hitObject)
|
|
||||||
{
|
|
||||||
HitObject = hitObject;
|
|
||||||
Anchor = Anchor.BottomLeft;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract class DrawableCatchHitObject : DrawableHitObject<CatchHitObject>
|
public abstract class DrawableCatchHitObject : DrawableHitObject<CatchHitObject>
|
||||||
{
|
{
|
||||||
|
public readonly Bindable<float> XBindable = new Bindable<float>();
|
||||||
|
|
||||||
protected override double InitialLifetimeOffset => HitObject.TimePreempt;
|
protected override double InitialLifetimeOffset => HitObject.TimePreempt;
|
||||||
|
|
||||||
public virtual bool StaysOnPlate => HitObject.CanBePlated;
|
|
||||||
|
|
||||||
public float DisplayRadius => DrawSize.X / 2 * Scale.X * HitObject.Scale;
|
|
||||||
|
|
||||||
protected override float SamplePlaybackPosition => HitObject.X / CatchPlayfield.WIDTH;
|
protected override float SamplePlaybackPosition => HitObject.X / CatchPlayfield.WIDTH;
|
||||||
|
|
||||||
protected DrawableCatchHitObject(CatchHitObject hitObject)
|
public int RandomSeed => HitObject?.RandomSeed ?? 0;
|
||||||
|
|
||||||
|
protected DrawableCatchHitObject([CanBeNull] CatchHitObject hitObject)
|
||||||
: base(hitObject)
|
: base(hitObject)
|
||||||
{
|
{
|
||||||
X = hitObject.X;
|
Anchor = Anchor.BottomLeft;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get a random number in range [0,1) based on seed <see cref="RandomSeed"/>.
|
||||||
|
/// </summary>
|
||||||
|
public float RandomSingle(int series) => StatelessRNG.NextSingle(RandomSeed, series);
|
||||||
|
|
||||||
|
protected override void OnApply()
|
||||||
|
{
|
||||||
|
base.OnApply();
|
||||||
|
|
||||||
|
XBindable.BindTo(HitObject.XBindable);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnFree()
|
||||||
|
{
|
||||||
|
base.OnFree();
|
||||||
|
|
||||||
|
XBindable.UnbindFrom(HitObject.XBindable);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Func<CatchHitObject, bool> CheckPosition;
|
public Func<CatchHitObject, bool> CheckPosition;
|
||||||
@ -81,6 +54,8 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
|
|||||||
|
|
||||||
public override bool RemoveWhenNotAlive => IsOnPlate;
|
public override bool RemoveWhenNotAlive => IsOnPlate;
|
||||||
|
|
||||||
|
protected override JudgementResult CreateResult(Judgement judgement) => new CatchJudgementResult(HitObject, judgement);
|
||||||
|
|
||||||
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||||
{
|
{
|
||||||
if (CheckPosition == null) return;
|
if (CheckPosition == null) return;
|
||||||
|
@ -1,18 +1,24 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using JetBrains.Annotations;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Utils;
|
using osu.Game.Rulesets.Catch.Skinning.Default;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Objects.Drawables
|
namespace osu.Game.Rulesets.Catch.Objects.Drawables
|
||||||
{
|
{
|
||||||
public class DrawableDroplet : PalpableDrawableCatchHitObject<Droplet>
|
public class DrawableDroplet : DrawablePalpableCatchHitObject
|
||||||
{
|
{
|
||||||
public override bool StaysOnPlate => false;
|
public override bool StaysOnPlate => false;
|
||||||
|
|
||||||
public DrawableDroplet(Droplet h)
|
public DrawableDroplet()
|
||||||
|
: this(null)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public DrawableDroplet([CanBeNull] CatchHitObject h)
|
||||||
: base(h)
|
: base(h)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -20,7 +26,9 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
ScaleContainer.Child = new SkinnableDrawable(new CatchSkinComponent(CatchSkinComponents.Droplet), _ => new DropletPiece());
|
ScaleContainer.Child = new SkinnableDrawable(
|
||||||
|
new CatchSkinComponent(CatchSkinComponents.Droplet),
|
||||||
|
_ => new DropletPiece());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void UpdateInitialTransforms()
|
protected override void UpdateInitialTransforms()
|
||||||
@ -28,7 +36,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
|
|||||||
base.UpdateInitialTransforms();
|
base.UpdateInitialTransforms();
|
||||||
|
|
||||||
// roughly matches osu-stable
|
// roughly matches osu-stable
|
||||||
float startRotation = RNG.NextSingle() * 20;
|
float startRotation = RandomSingle(1) * 20;
|
||||||
double duration = HitObject.TimePreempt + 2000;
|
double duration = HitObject.TimePreempt + 2000;
|
||||||
|
|
||||||
ScaleContainer.RotateTo(startRotation).RotateTo(startRotation + 720, duration);
|
ScaleContainer.RotateTo(startRotation).RotateTo(startRotation + 720, duration);
|
||||||
|
@ -1,16 +1,25 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System;
|
using JetBrains.Annotations;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Utils;
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Game.Rulesets.Catch.Skinning.Default;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Objects.Drawables
|
namespace osu.Game.Rulesets.Catch.Objects.Drawables
|
||||||
{
|
{
|
||||||
public class DrawableFruit : PalpableDrawableCatchHitObject<Fruit>
|
public class DrawableFruit : DrawablePalpableCatchHitObject
|
||||||
{
|
{
|
||||||
public DrawableFruit(Fruit h)
|
public readonly Bindable<FruitVisualRepresentation> VisualRepresentation = new Bindable<FruitVisualRepresentation>();
|
||||||
|
|
||||||
|
public DrawableFruit()
|
||||||
|
: this(null)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public DrawableFruit([CanBeNull] Fruit h)
|
||||||
: base(h)
|
: base(h)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -18,34 +27,29 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
|
IndexInBeatmap.BindValueChanged(change =>
|
||||||
|
{
|
||||||
|
VisualRepresentation.Value = (FruitVisualRepresentation)(change.NewValue % 4);
|
||||||
|
}, true);
|
||||||
|
|
||||||
ScaleContainer.Child = new SkinnableDrawable(
|
ScaleContainer.Child = new SkinnableDrawable(
|
||||||
new CatchSkinComponent(getComponent(HitObject.VisualRepresentation)), _ => new FruitPiece());
|
new CatchSkinComponent(CatchSkinComponents.Fruit),
|
||||||
|
_ => new FruitPiece());
|
||||||
ScaleContainer.Rotation = (float)(RNG.NextDouble() - 0.5f) * 40;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private CatchSkinComponents getComponent(FruitVisualRepresentation hitObjectVisualRepresentation)
|
protected override void UpdateInitialTransforms()
|
||||||
{
|
{
|
||||||
switch (hitObjectVisualRepresentation)
|
base.UpdateInitialTransforms();
|
||||||
|
|
||||||
|
ScaleContainer.RotateTo((RandomSingle(1) - 0.5f) * 40);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum FruitVisualRepresentation
|
||||||
{
|
{
|
||||||
case FruitVisualRepresentation.Pear:
|
Pear,
|
||||||
return CatchSkinComponents.FruitPear;
|
Grape,
|
||||||
|
Pineapple,
|
||||||
case FruitVisualRepresentation.Grape:
|
Raspberry,
|
||||||
return CatchSkinComponents.FruitGrapes;
|
|
||||||
|
|
||||||
case FruitVisualRepresentation.Pineapple:
|
|
||||||
return CatchSkinComponents.FruitApple;
|
|
||||||
|
|
||||||
case FruitVisualRepresentation.Raspberry:
|
|
||||||
return CatchSkinComponents.FruitOrange;
|
|
||||||
|
|
||||||
case FruitVisualRepresentation.Banana:
|
|
||||||
return CatchSkinComponents.FruitBananas;
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw new ArgumentOutOfRangeException(nameof(hitObjectVisualRepresentation), hitObjectVisualRepresentation, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,37 +1,33 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System;
|
using JetBrains.Annotations;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Game.Rulesets.Objects;
|
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osuTK;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Objects.Drawables
|
namespace osu.Game.Rulesets.Catch.Objects.Drawables
|
||||||
{
|
{
|
||||||
public class DrawableJuiceStream : DrawableCatchHitObject<JuiceStream>
|
public class DrawableJuiceStream : DrawableCatchHitObject
|
||||||
{
|
{
|
||||||
private readonly Func<CatchHitObject, DrawableHitObject<CatchHitObject>> createDrawableRepresentation;
|
|
||||||
private readonly Container dropletContainer;
|
private readonly Container dropletContainer;
|
||||||
|
|
||||||
public override Vector2 OriginPosition => base.OriginPosition - new Vector2(0, CatchHitObject.OBJECT_RADIUS);
|
public DrawableJuiceStream()
|
||||||
|
: this(null)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
public DrawableJuiceStream(JuiceStream s, Func<CatchHitObject, DrawableHitObject<CatchHitObject>> createDrawableRepresentation = null)
|
public DrawableJuiceStream([CanBeNull] JuiceStream s)
|
||||||
: base(s)
|
: base(s)
|
||||||
{
|
{
|
||||||
this.createDrawableRepresentation = createDrawableRepresentation;
|
|
||||||
RelativeSizeAxes = Axes.X;
|
RelativeSizeAxes = Axes.X;
|
||||||
Origin = Anchor.BottomLeft;
|
Origin = Anchor.BottomLeft;
|
||||||
X = 0;
|
|
||||||
|
|
||||||
AddInternal(dropletContainer = new Container { RelativeSizeAxes = Axes.Both, });
|
AddInternal(dropletContainer = new Container { RelativeSizeAxes = Axes.Both, });
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void AddNestedHitObject(DrawableHitObject hitObject)
|
protected override void AddNestedHitObject(DrawableHitObject hitObject)
|
||||||
{
|
{
|
||||||
hitObject.Origin = Anchor.BottomCentre;
|
|
||||||
|
|
||||||
base.AddNestedHitObject(hitObject);
|
base.AddNestedHitObject(hitObject);
|
||||||
dropletContainer.Add(hitObject);
|
dropletContainer.Add(hitObject);
|
||||||
}
|
}
|
||||||
@ -39,19 +35,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
|
|||||||
protected override void ClearNestedHitObjects()
|
protected override void ClearNestedHitObjects()
|
||||||
{
|
{
|
||||||
base.ClearNestedHitObjects();
|
base.ClearNestedHitObjects();
|
||||||
dropletContainer.Clear();
|
dropletContainer.Clear(false);
|
||||||
}
|
|
||||||
|
|
||||||
protected override DrawableHitObject CreateNestedHitObject(HitObject hitObject)
|
|
||||||
{
|
|
||||||
switch (hitObject)
|
|
||||||
{
|
|
||||||
case CatchHitObject catchObject:
|
|
||||||
return createDrawableRepresentation?.Invoke(catchObject)?.With(o =>
|
|
||||||
((DrawableCatchHitObject)o).CheckPosition = p => CheckPosition?.Invoke(p) ?? false);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new ArgumentException($"{nameof(hitObject)} must be of type {nameof(CatchHitObject)}.");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,85 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Catch.Objects.Drawables
|
||||||
|
{
|
||||||
|
public abstract class DrawablePalpableCatchHitObject : DrawableCatchHitObject
|
||||||
|
{
|
||||||
|
public new PalpableCatchHitObject HitObject => (PalpableCatchHitObject)base.HitObject;
|
||||||
|
|
||||||
|
public readonly Bindable<bool> HyperDash = new Bindable<bool>();
|
||||||
|
|
||||||
|
public readonly Bindable<float> ScaleBindable = new Bindable<float>(1);
|
||||||
|
|
||||||
|
public readonly Bindable<int> IndexInBeatmap = new Bindable<int>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The multiplicative factor applied to <see cref="ScaleContainer"/> scale relative to <see cref="HitObject"/> scale.
|
||||||
|
/// </summary>
|
||||||
|
protected virtual float ScaleFactor => 1;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether this hit object should stay on the catcher plate when the object is caught by the catcher.
|
||||||
|
/// </summary>
|
||||||
|
public virtual bool StaysOnPlate => true;
|
||||||
|
|
||||||
|
public float DisplayRadius => CatchHitObject.OBJECT_RADIUS * HitObject.Scale * ScaleFactor;
|
||||||
|
|
||||||
|
protected readonly Container ScaleContainer;
|
||||||
|
|
||||||
|
protected DrawablePalpableCatchHitObject([CanBeNull] CatchHitObject h)
|
||||||
|
: base(h)
|
||||||
|
{
|
||||||
|
Origin = Anchor.Centre;
|
||||||
|
Size = new Vector2(CatchHitObject.OBJECT_RADIUS * 2);
|
||||||
|
|
||||||
|
AddInternal(ScaleContainer = new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
XBindable.BindValueChanged(x =>
|
||||||
|
{
|
||||||
|
if (!IsOnPlate) X = x.NewValue;
|
||||||
|
}, true);
|
||||||
|
|
||||||
|
ScaleBindable.BindValueChanged(scale =>
|
||||||
|
{
|
||||||
|
ScaleContainer.Scale = new Vector2(scale.NewValue * ScaleFactor);
|
||||||
|
}, true);
|
||||||
|
|
||||||
|
IndexInBeatmap.BindValueChanged(_ => UpdateComboColour());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnApply()
|
||||||
|
{
|
||||||
|
base.OnApply();
|
||||||
|
|
||||||
|
HyperDash.BindTo(HitObject.HyperDashBindable);
|
||||||
|
ScaleBindable.BindTo(HitObject.ScaleBindable);
|
||||||
|
IndexInBeatmap.BindTo(HitObject.IndexInBeatmapBindable);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnFree()
|
||||||
|
{
|
||||||
|
HyperDash.UnbindFrom(HitObject.HyperDashBindable);
|
||||||
|
ScaleBindable.UnbindFrom(HitObject.ScaleBindable);
|
||||||
|
IndexInBeatmap.UnbindFrom(HitObject.IndexInBeatmapBindable);
|
||||||
|
|
||||||
|
base.OnFree();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,21 +1,22 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using osu.Framework.Allocation;
|
using JetBrains.Annotations;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Objects.Drawables
|
namespace osu.Game.Rulesets.Catch.Objects.Drawables
|
||||||
{
|
{
|
||||||
public class DrawableTinyDroplet : DrawableDroplet
|
public class DrawableTinyDroplet : DrawableDroplet
|
||||||
{
|
{
|
||||||
public DrawableTinyDroplet(TinyDroplet h)
|
protected override float ScaleFactor => base.ScaleFactor / 2;
|
||||||
: base(h)
|
|
||||||
|
public DrawableTinyDroplet()
|
||||||
|
: this(null)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
public DrawableTinyDroplet([CanBeNull] TinyDroplet h)
|
||||||
private void load()
|
: base(h)
|
||||||
{
|
{
|
||||||
ScaleContainer.Scale /= 2;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,69 +0,0 @@
|
|||||||
// 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.
|
|
||||||
|
|
||||||
using osu.Framework.Allocation;
|
|
||||||
using osu.Framework.Graphics;
|
|
||||||
using osu.Framework.Graphics.Containers;
|
|
||||||
using osu.Framework.Graphics.Shapes;
|
|
||||||
using osu.Game.Rulesets.Catch.Objects.Drawables.Pieces;
|
|
||||||
using osu.Game.Rulesets.Catch.UI;
|
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
|
||||||
using osuTK;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Objects.Drawables
|
|
||||||
{
|
|
||||||
public class DropletPiece : CompositeDrawable
|
|
||||||
{
|
|
||||||
public DropletPiece()
|
|
||||||
{
|
|
||||||
Size = new Vector2(CatchHitObject.OBJECT_RADIUS / 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load(DrawableHitObject drawableObject)
|
|
||||||
{
|
|
||||||
DrawableCatchHitObject drawableCatchObject = (DrawableCatchHitObject)drawableObject;
|
|
||||||
var hitObject = drawableCatchObject.HitObject;
|
|
||||||
|
|
||||||
InternalChild = new Pulp
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
AccentColour = { BindTarget = drawableObject.AccentColour }
|
|
||||||
};
|
|
||||||
|
|
||||||
if (hitObject.HyperDash)
|
|
||||||
{
|
|
||||||
AddInternal(new Container
|
|
||||||
{
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Size = new Vector2(2f),
|
|
||||||
Depth = 1,
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
new Circle
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
BorderColour = Catcher.DEFAULT_HYPER_DASH_COLOUR,
|
|
||||||
BorderThickness = 6,
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
new Box
|
|
||||||
{
|
|
||||||
AlwaysPresent = true,
|
|
||||||
Alpha = 0.3f,
|
|
||||||
Blending = BlendingParameters.Additive,
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Colour = Catcher.DEFAULT_HYPER_DASH_COLOUR,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,111 +0,0 @@
|
|||||||
// 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.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using osu.Framework.Allocation;
|
|
||||||
using osu.Framework.Graphics;
|
|
||||||
using osu.Framework.Graphics.Containers;
|
|
||||||
using osu.Framework.Graphics.Shapes;
|
|
||||||
using osu.Game.Rulesets.Catch.UI;
|
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
|
||||||
using osuTK.Graphics;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Objects.Drawables
|
|
||||||
{
|
|
||||||
internal class FruitPiece : CompositeDrawable
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Because we're adding a border around the fruit, we need to scale down some.
|
|
||||||
/// </summary>
|
|
||||||
public const float RADIUS_ADJUST = 1.1f;
|
|
||||||
|
|
||||||
private Circle border;
|
|
||||||
private CatchHitObject hitObject;
|
|
||||||
|
|
||||||
public FruitPiece()
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both;
|
|
||||||
}
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load(DrawableHitObject drawableObject)
|
|
||||||
{
|
|
||||||
DrawableCatchHitObject drawableCatchObject = (DrawableCatchHitObject)drawableObject;
|
|
||||||
hitObject = drawableCatchObject.HitObject;
|
|
||||||
|
|
||||||
AddRangeInternal(new[]
|
|
||||||
{
|
|
||||||
getFruitFor(drawableCatchObject.HitObject.VisualRepresentation),
|
|
||||||
border = new Circle
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
BorderColour = Color4.White,
|
|
||||||
BorderThickness = 6f * RADIUS_ADJUST,
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
new Box
|
|
||||||
{
|
|
||||||
AlwaysPresent = true,
|
|
||||||
Alpha = 0,
|
|
||||||
RelativeSizeAxes = Axes.Both
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (hitObject.HyperDash)
|
|
||||||
{
|
|
||||||
AddInternal(new Circle
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
BorderColour = Catcher.DEFAULT_HYPER_DASH_COLOUR,
|
|
||||||
BorderThickness = 12f * RADIUS_ADJUST,
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
new Box
|
|
||||||
{
|
|
||||||
AlwaysPresent = true,
|
|
||||||
Alpha = 0.3f,
|
|
||||||
Blending = BlendingParameters.Additive,
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Colour = Catcher.DEFAULT_HYPER_DASH_COLOUR,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Update()
|
|
||||||
{
|
|
||||||
base.Update();
|
|
||||||
border.Alpha = (float)Math.Clamp((hitObject.StartTime - Time.Current) / 500, 0, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Drawable getFruitFor(FruitVisualRepresentation representation)
|
|
||||||
{
|
|
||||||
switch (representation)
|
|
||||||
{
|
|
||||||
case FruitVisualRepresentation.Pear:
|
|
||||||
return new PearPiece();
|
|
||||||
|
|
||||||
case FruitVisualRepresentation.Grape:
|
|
||||||
return new GrapePiece();
|
|
||||||
|
|
||||||
case FruitVisualRepresentation.Pineapple:
|
|
||||||
return new PineapplePiece();
|
|
||||||
|
|
||||||
case FruitVisualRepresentation.Banana:
|
|
||||||
return new BananaPiece();
|
|
||||||
|
|
||||||
case FruitVisualRepresentation.Raspberry:
|
|
||||||
return new RaspberryPiece();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Empty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,43 +0,0 @@
|
|||||||
// 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.
|
|
||||||
|
|
||||||
using osu.Framework.Graphics;
|
|
||||||
using osu.Game.Rulesets.Catch.Objects.Drawables.Pieces;
|
|
||||||
using osuTK;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Objects.Drawables
|
|
||||||
{
|
|
||||||
public class GrapePiece : PulpFormation
|
|
||||||
{
|
|
||||||
public GrapePiece()
|
|
||||||
{
|
|
||||||
InternalChildren = new Drawable[]
|
|
||||||
{
|
|
||||||
new Pulp
|
|
||||||
{
|
|
||||||
AccentColour = { BindTarget = AccentColour },
|
|
||||||
Size = new Vector2(SMALL_PULP),
|
|
||||||
Y = -0.25f,
|
|
||||||
},
|
|
||||||
new Pulp
|
|
||||||
{
|
|
||||||
AccentColour = { BindTarget = AccentColour },
|
|
||||||
Size = new Vector2(LARGE_PULP_3),
|
|
||||||
Position = PositionAt(0, DISTANCE_FROM_CENTRE_3),
|
|
||||||
},
|
|
||||||
new Pulp
|
|
||||||
{
|
|
||||||
AccentColour = { BindTarget = AccentColour },
|
|
||||||
Size = new Vector2(LARGE_PULP_3),
|
|
||||||
Position = PositionAt(120, DISTANCE_FROM_CENTRE_3),
|
|
||||||
},
|
|
||||||
new Pulp
|
|
||||||
{
|
|
||||||
Size = new Vector2(LARGE_PULP_3),
|
|
||||||
AccentColour = { BindTarget = AccentColour },
|
|
||||||
Position = PositionAt(240, DISTANCE_FROM_CENTRE_3),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,43 +0,0 @@
|
|||||||
// 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.
|
|
||||||
|
|
||||||
using osu.Framework.Graphics;
|
|
||||||
using osu.Game.Rulesets.Catch.Objects.Drawables.Pieces;
|
|
||||||
using osuTK;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Objects.Drawables
|
|
||||||
{
|
|
||||||
public class PearPiece : PulpFormation
|
|
||||||
{
|
|
||||||
public PearPiece()
|
|
||||||
{
|
|
||||||
InternalChildren = new Drawable[]
|
|
||||||
{
|
|
||||||
new Pulp
|
|
||||||
{
|
|
||||||
AccentColour = { BindTarget = AccentColour },
|
|
||||||
Size = new Vector2(SMALL_PULP),
|
|
||||||
Y = -0.33f,
|
|
||||||
},
|
|
||||||
new Pulp
|
|
||||||
{
|
|
||||||
AccentColour = { BindTarget = AccentColour },
|
|
||||||
Size = new Vector2(LARGE_PULP_3),
|
|
||||||
Position = PositionAt(60, DISTANCE_FROM_CENTRE_3),
|
|
||||||
},
|
|
||||||
new Pulp
|
|
||||||
{
|
|
||||||
AccentColour = { BindTarget = AccentColour },
|
|
||||||
Size = new Vector2(LARGE_PULP_3),
|
|
||||||
Position = PositionAt(180, DISTANCE_FROM_CENTRE_3),
|
|
||||||
},
|
|
||||||
new Pulp
|
|
||||||
{
|
|
||||||
Size = new Vector2(LARGE_PULP_3),
|
|
||||||
AccentColour = { BindTarget = AccentColour },
|
|
||||||
Position = PositionAt(300, DISTANCE_FROM_CENTRE_3),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,49 +0,0 @@
|
|||||||
// 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.
|
|
||||||
|
|
||||||
using osu.Framework.Graphics;
|
|
||||||
using osu.Game.Rulesets.Catch.Objects.Drawables.Pieces;
|
|
||||||
using osuTK;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Objects.Drawables
|
|
||||||
{
|
|
||||||
public class PineapplePiece : PulpFormation
|
|
||||||
{
|
|
||||||
public PineapplePiece()
|
|
||||||
{
|
|
||||||
InternalChildren = new Drawable[]
|
|
||||||
{
|
|
||||||
new Pulp
|
|
||||||
{
|
|
||||||
AccentColour = { BindTarget = AccentColour },
|
|
||||||
Size = new Vector2(SMALL_PULP),
|
|
||||||
Y = -0.3f,
|
|
||||||
},
|
|
||||||
new Pulp
|
|
||||||
{
|
|
||||||
AccentColour = { BindTarget = AccentColour },
|
|
||||||
Size = new Vector2(LARGE_PULP_4),
|
|
||||||
Position = PositionAt(45, DISTANCE_FROM_CENTRE_4),
|
|
||||||
},
|
|
||||||
new Pulp
|
|
||||||
{
|
|
||||||
AccentColour = { BindTarget = AccentColour },
|
|
||||||
Size = new Vector2(LARGE_PULP_4),
|
|
||||||
Position = PositionAt(135, DISTANCE_FROM_CENTRE_4),
|
|
||||||
},
|
|
||||||
new Pulp
|
|
||||||
{
|
|
||||||
AccentColour = { BindTarget = AccentColour },
|
|
||||||
Size = new Vector2(LARGE_PULP_4),
|
|
||||||
Position = PositionAt(225, DISTANCE_FROM_CENTRE_4),
|
|
||||||
},
|
|
||||||
new Pulp
|
|
||||||
{
|
|
||||||
Size = new Vector2(LARGE_PULP_4),
|
|
||||||
AccentColour = { BindTarget = AccentColour },
|
|
||||||
Position = PositionAt(315, DISTANCE_FROM_CENTRE_4),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,49 +0,0 @@
|
|||||||
// 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.
|
|
||||||
|
|
||||||
using osu.Framework.Graphics;
|
|
||||||
using osu.Game.Rulesets.Catch.Objects.Drawables.Pieces;
|
|
||||||
using osuTK;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Objects.Drawables
|
|
||||||
{
|
|
||||||
public class RaspberryPiece : PulpFormation
|
|
||||||
{
|
|
||||||
public RaspberryPiece()
|
|
||||||
{
|
|
||||||
InternalChildren = new Drawable[]
|
|
||||||
{
|
|
||||||
new Pulp
|
|
||||||
{
|
|
||||||
AccentColour = { BindTarget = AccentColour },
|
|
||||||
Size = new Vector2(SMALL_PULP),
|
|
||||||
Y = -0.34f,
|
|
||||||
},
|
|
||||||
new Pulp
|
|
||||||
{
|
|
||||||
AccentColour = { BindTarget = AccentColour },
|
|
||||||
Size = new Vector2(LARGE_PULP_4),
|
|
||||||
Position = PositionAt(0, DISTANCE_FROM_CENTRE_4),
|
|
||||||
},
|
|
||||||
new Pulp
|
|
||||||
{
|
|
||||||
AccentColour = { BindTarget = AccentColour },
|
|
||||||
Size = new Vector2(LARGE_PULP_4),
|
|
||||||
Position = PositionAt(90, DISTANCE_FROM_CENTRE_4),
|
|
||||||
},
|
|
||||||
new Pulp
|
|
||||||
{
|
|
||||||
AccentColour = { BindTarget = AccentColour },
|
|
||||||
Size = new Vector2(LARGE_PULP_4),
|
|
||||||
Position = PositionAt(180, DISTANCE_FROM_CENTRE_4),
|
|
||||||
},
|
|
||||||
new Pulp
|
|
||||||
{
|
|
||||||
Size = new Vector2(LARGE_PULP_4),
|
|
||||||
AccentColour = { BindTarget = AccentColour },
|
|
||||||
Position = PositionAt(270, DISTANCE_FROM_CENTRE_4),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -50,12 +50,7 @@ namespace osu.Game.Rulesets.Catch.Objects
|
|||||||
{
|
{
|
||||||
base.CreateNestedHitObjects(cancellationToken);
|
base.CreateNestedHitObjects(cancellationToken);
|
||||||
|
|
||||||
var dropletSamples = Samples.Select(s => new HitSampleInfo
|
var dropletSamples = Samples.Select(s => s.With(@"slidertick")).ToList();
|
||||||
{
|
|
||||||
Bank = s.Bank,
|
|
||||||
Name = @"slidertick",
|
|
||||||
Volume = s.Volume
|
|
||||||
}).ToList();
|
|
||||||
|
|
||||||
int nodeIndex = 0;
|
int nodeIndex = 0;
|
||||||
SliderEventDescriptor? lastEvent = null;
|
SliderEventDescriptor? lastEvent = null;
|
||||||
|
48
osu.Game.Rulesets.Catch/Objects/PalpableCatchHitObject.cs
Normal file
48
osu.Game.Rulesets.Catch/Objects/PalpableCatchHitObject.cs
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Catch.Objects
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a single object that can be caught by the catcher.
|
||||||
|
/// This includes normal fruits, droplets, and bananas but excludes objects that act only as a container of nested hit objects.
|
||||||
|
/// </summary>
|
||||||
|
public abstract class PalpableCatchHitObject : CatchHitObject, IHasComboInformation
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Difference between the distance to the next object
|
||||||
|
/// and the distance that would have triggered a hyper dash.
|
||||||
|
/// A value close to 0 indicates a difficult jump (for difficulty calculation).
|
||||||
|
/// </summary>
|
||||||
|
public float DistanceToHyperDash { get; set; }
|
||||||
|
|
||||||
|
public readonly Bindable<bool> HyperDashBindable = new Bindable<bool>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether this fruit can initiate a hyperdash.
|
||||||
|
/// </summary>
|
||||||
|
public bool HyperDash => HyperDashBindable.Value;
|
||||||
|
|
||||||
|
private CatchHitObject hyperDashTarget;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The target fruit if we are to initiate a hyperdash.
|
||||||
|
/// </summary>
|
||||||
|
public CatchHitObject HyperDashTarget
|
||||||
|
{
|
||||||
|
get => hyperDashTarget;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
hyperDashTarget = value;
|
||||||
|
HyperDashBindable.Value = value != null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Color4 IHasComboInformation.GetComboColour(IReadOnlyList<Color4> comboColours) => comboColours[(IndexInBeatmap + 1) % comboColours.Count];
|
||||||
|
}
|
||||||
|
}
|
@ -40,7 +40,7 @@ namespace osu.Game.Rulesets.Catch.Replays
|
|||||||
float lastPosition = CatchPlayfield.CENTER_X;
|
float lastPosition = CatchPlayfield.CENTER_X;
|
||||||
double lastTime = 0;
|
double lastTime = 0;
|
||||||
|
|
||||||
void moveToNext(CatchHitObject h)
|
void moveToNext(PalpableCatchHitObject h)
|
||||||
{
|
{
|
||||||
float positionChange = Math.Abs(lastPosition - h.X);
|
float positionChange = Math.Abs(lastPosition - h.X);
|
||||||
double timeAvailable = h.StartTime - lastTime;
|
double timeAvailable = h.StartTime - lastTime;
|
||||||
@ -101,23 +101,16 @@ namespace osu.Game.Rulesets.Catch.Replays
|
|||||||
|
|
||||||
foreach (var obj in Beatmap.HitObjects)
|
foreach (var obj in Beatmap.HitObjects)
|
||||||
{
|
{
|
||||||
switch (obj)
|
if (obj is PalpableCatchHitObject palpableObject)
|
||||||
{
|
{
|
||||||
case Fruit _:
|
moveToNext(palpableObject);
|
||||||
moveToNext(obj);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var nestedObj in obj.NestedHitObjects.Cast<CatchHitObject>())
|
foreach (var nestedObj in obj.NestedHitObjects.Cast<CatchHitObject>())
|
||||||
{
|
{
|
||||||
switch (nestedObj)
|
if (nestedObj is PalpableCatchHitObject palpableNestedObject)
|
||||||
{
|
{
|
||||||
case Banana _:
|
moveToNext(palpableNestedObject);
|
||||||
case TinyDroplet _:
|
|
||||||
case Droplet _:
|
|
||||||
case Fruit _:
|
|
||||||
moveToNext(nestedObj);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
26
osu.Game.Rulesets.Catch/Skinning/Default/BananaPiece.cs
Normal file
26
osu.Game.Rulesets.Catch/Skinning/Default/BananaPiece.cs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Catch.Skinning.Default
|
||||||
|
{
|
||||||
|
public class BananaPiece : CatchHitObjectPiece
|
||||||
|
{
|
||||||
|
protected override BorderPiece BorderPiece { get; }
|
||||||
|
|
||||||
|
public BananaPiece()
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both;
|
||||||
|
|
||||||
|
InternalChildren = new Drawable[]
|
||||||
|
{
|
||||||
|
new BananaPulpFormation
|
||||||
|
{
|
||||||
|
AccentColour = { BindTarget = AccentColour },
|
||||||
|
},
|
||||||
|
BorderPiece = new BorderPiece(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Catch.Skinning.Default
|
||||||
|
{
|
||||||
|
public class BananaPulpFormation : PulpFormation
|
||||||
|
{
|
||||||
|
public BananaPulpFormation()
|
||||||
|
{
|
||||||
|
AddPulp(new Vector2(0, -0.3f), new Vector2(SMALL_PULP));
|
||||||
|
AddPulp(new Vector2(0, 0.05f), new Vector2(LARGE_PULP_4 * 0.8f, LARGE_PULP_4 * 2.5f));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
32
osu.Game.Rulesets.Catch/Skinning/Default/BorderPiece.cs
Normal file
32
osu.Game.Rulesets.Catch/Skinning/Default/BorderPiece.cs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Game.Rulesets.Catch.Objects;
|
||||||
|
using osuTK;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Catch.Skinning.Default
|
||||||
|
{
|
||||||
|
public class BorderPiece : Circle
|
||||||
|
{
|
||||||
|
public BorderPiece()
|
||||||
|
{
|
||||||
|
Size = new Vector2(CatchHitObject.OBJECT_RADIUS * 2);
|
||||||
|
Anchor = Anchor.Centre;
|
||||||
|
Origin = Anchor.Centre;
|
||||||
|
BorderColour = Color4.White;
|
||||||
|
BorderThickness = 6f * FruitPiece.RADIUS_ADJUST;
|
||||||
|
|
||||||
|
// Border is drawn only when there is a child drawable.
|
||||||
|
Child = new Box
|
||||||
|
{
|
||||||
|
AlwaysPresent = true,
|
||||||
|
Alpha = 0,
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,61 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Game.Rulesets.Catch.Objects.Drawables;
|
||||||
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Catch.Skinning.Default
|
||||||
|
{
|
||||||
|
public abstract class CatchHitObjectPiece : CompositeDrawable
|
||||||
|
{
|
||||||
|
public readonly Bindable<Color4> AccentColour = new Bindable<Color4>();
|
||||||
|
public readonly Bindable<bool> HyperDash = new Bindable<bool>();
|
||||||
|
|
||||||
|
[Resolved(canBeNull: true)]
|
||||||
|
[CanBeNull]
|
||||||
|
protected DrawableHitObject DrawableHitObject { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A part of this piece that will be faded out while falling in the playfield.
|
||||||
|
/// </summary>
|
||||||
|
[CanBeNull]
|
||||||
|
protected virtual BorderPiece BorderPiece => null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A part of this piece that will be only visible when <see cref="HyperDash"/> is true.
|
||||||
|
/// </summary>
|
||||||
|
[CanBeNull]
|
||||||
|
protected virtual HyperBorderPiece HyperBorderPiece => null;
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
var hitObject = (DrawablePalpableCatchHitObject)DrawableHitObject;
|
||||||
|
|
||||||
|
if (hitObject != null)
|
||||||
|
{
|
||||||
|
AccentColour.BindTo(hitObject.AccentColour);
|
||||||
|
HyperDash.BindTo(hitObject.HyperDash);
|
||||||
|
}
|
||||||
|
|
||||||
|
HyperDash.BindValueChanged(hyper =>
|
||||||
|
{
|
||||||
|
if (HyperBorderPiece != null)
|
||||||
|
HyperBorderPiece.Alpha = hyper.NewValue ? 1 : 0;
|
||||||
|
}, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Update()
|
||||||
|
{
|
||||||
|
if (BorderPiece != null && DrawableHitObject?.HitObject != null)
|
||||||
|
BorderPiece.Alpha = (float)Math.Clamp((DrawableHitObject.HitObject.StartTime - Time.Current) / 500, 0, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
29
osu.Game.Rulesets.Catch/Skinning/Default/DropletPiece.cs
Normal file
29
osu.Game.Rulesets.Catch/Skinning/Default/DropletPiece.cs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Game.Rulesets.Catch.Objects;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Catch.Skinning.Default
|
||||||
|
{
|
||||||
|
public class DropletPiece : CatchHitObjectPiece
|
||||||
|
{
|
||||||
|
protected override HyperBorderPiece HyperBorderPiece { get; }
|
||||||
|
|
||||||
|
public DropletPiece()
|
||||||
|
{
|
||||||
|
Size = new Vector2(CatchHitObject.OBJECT_RADIUS / 2);
|
||||||
|
|
||||||
|
InternalChildren = new Drawable[]
|
||||||
|
{
|
||||||
|
new Pulp
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
AccentColour = { BindTarget = AccentColour }
|
||||||
|
},
|
||||||
|
HyperBorderPiece = new HyperDropletBorderPiece()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
48
osu.Game.Rulesets.Catch/Skinning/Default/FruitPiece.cs
Normal file
48
osu.Game.Rulesets.Catch/Skinning/Default/FruitPiece.cs
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Game.Rulesets.Catch.Objects.Drawables;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Catch.Skinning.Default
|
||||||
|
{
|
||||||
|
internal class FruitPiece : CatchHitObjectPiece
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Because we're adding a border around the fruit, we need to scale down some.
|
||||||
|
/// </summary>
|
||||||
|
public const float RADIUS_ADJUST = 1.1f;
|
||||||
|
|
||||||
|
public readonly Bindable<FruitVisualRepresentation> VisualRepresentation = new Bindable<FruitVisualRepresentation>();
|
||||||
|
|
||||||
|
protected override BorderPiece BorderPiece { get; }
|
||||||
|
protected override HyperBorderPiece HyperBorderPiece { get; }
|
||||||
|
|
||||||
|
public FruitPiece()
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both;
|
||||||
|
|
||||||
|
InternalChildren = new Drawable[]
|
||||||
|
{
|
||||||
|
new FruitPulpFormation
|
||||||
|
{
|
||||||
|
AccentColour = { BindTarget = AccentColour },
|
||||||
|
VisualRepresentation = { BindTarget = VisualRepresentation }
|
||||||
|
},
|
||||||
|
BorderPiece = new BorderPiece(),
|
||||||
|
HyperBorderPiece = new HyperBorderPiece()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
var fruit = (DrawableFruit)DrawableHitObject;
|
||||||
|
|
||||||
|
if (fruit != null)
|
||||||
|
VisualRepresentation.BindTo(fruit.VisualRepresentation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,59 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Game.Rulesets.Catch.Objects.Drawables;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Catch.Skinning.Default
|
||||||
|
{
|
||||||
|
public class FruitPulpFormation : PulpFormation
|
||||||
|
{
|
||||||
|
public readonly Bindable<FruitVisualRepresentation> VisualRepresentation = new Bindable<FruitVisualRepresentation>();
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
VisualRepresentation.BindValueChanged(setFormation, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setFormation(ValueChangedEvent<FruitVisualRepresentation> visualRepresentation)
|
||||||
|
{
|
||||||
|
Clear();
|
||||||
|
|
||||||
|
switch (visualRepresentation.NewValue)
|
||||||
|
{
|
||||||
|
case FruitVisualRepresentation.Pear:
|
||||||
|
AddPulp(new Vector2(0, -0.33f), new Vector2(SMALL_PULP));
|
||||||
|
AddPulp(PositionAt(60, DISTANCE_FROM_CENTRE_3), new Vector2(LARGE_PULP_3));
|
||||||
|
AddPulp(PositionAt(180, DISTANCE_FROM_CENTRE_3), new Vector2(LARGE_PULP_3));
|
||||||
|
AddPulp(PositionAt(300, DISTANCE_FROM_CENTRE_3), new Vector2(LARGE_PULP_3));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FruitVisualRepresentation.Grape:
|
||||||
|
AddPulp(new Vector2(0, -0.25f), new Vector2(SMALL_PULP));
|
||||||
|
AddPulp(PositionAt(0, DISTANCE_FROM_CENTRE_3), new Vector2(LARGE_PULP_3));
|
||||||
|
AddPulp(PositionAt(120, DISTANCE_FROM_CENTRE_3), new Vector2(LARGE_PULP_3));
|
||||||
|
AddPulp(PositionAt(240, DISTANCE_FROM_CENTRE_3), new Vector2(LARGE_PULP_3));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FruitVisualRepresentation.Pineapple:
|
||||||
|
AddPulp(new Vector2(0, -0.3f), new Vector2(SMALL_PULP));
|
||||||
|
AddPulp(PositionAt(45, DISTANCE_FROM_CENTRE_4), new Vector2(LARGE_PULP_4));
|
||||||
|
AddPulp(PositionAt(135, DISTANCE_FROM_CENTRE_4), new Vector2(LARGE_PULP_4));
|
||||||
|
AddPulp(PositionAt(225, DISTANCE_FROM_CENTRE_4), new Vector2(LARGE_PULP_4));
|
||||||
|
AddPulp(PositionAt(315, DISTANCE_FROM_CENTRE_4), new Vector2(LARGE_PULP_4));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FruitVisualRepresentation.Raspberry:
|
||||||
|
AddPulp(new Vector2(0, -0.34f), new Vector2(SMALL_PULP));
|
||||||
|
AddPulp(PositionAt(0, DISTANCE_FROM_CENTRE_4), new Vector2(LARGE_PULP_4));
|
||||||
|
AddPulp(PositionAt(90, DISTANCE_FROM_CENTRE_4), new Vector2(LARGE_PULP_4));
|
||||||
|
AddPulp(PositionAt(180, DISTANCE_FROM_CENTRE_4), new Vector2(LARGE_PULP_4));
|
||||||
|
AddPulp(PositionAt(270, DISTANCE_FROM_CENTRE_4), new Vector2(LARGE_PULP_4));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
22
osu.Game.Rulesets.Catch/Skinning/Default/HyperBorderPiece.cs
Normal file
22
osu.Game.Rulesets.Catch/Skinning/Default/HyperBorderPiece.cs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Game.Rulesets.Catch.UI;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Catch.Skinning.Default
|
||||||
|
{
|
||||||
|
public class HyperBorderPiece : BorderPiece
|
||||||
|
{
|
||||||
|
public HyperBorderPiece()
|
||||||
|
{
|
||||||
|
BorderColour = Catcher.DEFAULT_HYPER_DASH_COLOUR;
|
||||||
|
BorderThickness = 12f * FruitPiece.RADIUS_ADJUST;
|
||||||
|
|
||||||
|
Child.Alpha = 0.3f;
|
||||||
|
Child.Blending = BlendingParameters.Additive;
|
||||||
|
Child.Colour = Catcher.DEFAULT_HYPER_DASH_COLOUR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Catch.Skinning.Default
|
||||||
|
{
|
||||||
|
public class HyperDropletBorderPiece : HyperBorderPiece
|
||||||
|
{
|
||||||
|
public HyperDropletBorderPiece()
|
||||||
|
{
|
||||||
|
Size /= 2;
|
||||||
|
BorderThickness = 6f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -8,10 +8,12 @@ using osu.Framework.Graphics.Effects;
|
|||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Objects.Drawables.Pieces
|
namespace osu.Game.Rulesets.Catch.Skinning.Default
|
||||||
{
|
{
|
||||||
public class Pulp : Circle
|
public class Pulp : Circle
|
||||||
{
|
{
|
||||||
|
public readonly Bindable<Color4> AccentColour = new Bindable<Color4>();
|
||||||
|
|
||||||
public Pulp()
|
public Pulp()
|
||||||
{
|
{
|
||||||
RelativePositionAxes = Axes.Both;
|
RelativePositionAxes = Axes.Both;
|
||||||
@ -22,8 +24,6 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables.Pieces
|
|||||||
Colour = Color4.White.Opacity(0.9f);
|
Colour = Color4.White.Opacity(0.9f);
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly Bindable<Color4> AccentColour = new Bindable<Color4>();
|
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
@ -2,19 +2,17 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using osu.Framework.Allocation;
|
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Objects.Drawables
|
namespace osu.Game.Rulesets.Catch.Skinning.Default
|
||||||
{
|
{
|
||||||
public abstract class PulpFormation : CompositeDrawable
|
public abstract class PulpFormation : CompositeDrawable
|
||||||
{
|
{
|
||||||
protected readonly IBindable<Color4> AccentColour = new Bindable<Color4>();
|
public readonly Bindable<Color4> AccentColour = new Bindable<Color4>();
|
||||||
|
|
||||||
protected const float LARGE_PULP_3 = 16f * FruitPiece.RADIUS_ADJUST;
|
protected const float LARGE_PULP_3 = 16f * FruitPiece.RADIUS_ADJUST;
|
||||||
protected const float DISTANCE_FROM_CENTRE_3 = 0.15f;
|
protected const float DISTANCE_FROM_CENTRE_3 = 0.15f;
|
||||||
@ -24,6 +22,8 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
|
|||||||
|
|
||||||
protected const float SMALL_PULP = LARGE_PULP_3 / 2;
|
protected const float SMALL_PULP = LARGE_PULP_3 / 2;
|
||||||
|
|
||||||
|
private int pulpsInUse;
|
||||||
|
|
||||||
protected PulpFormation()
|
protected PulpFormation()
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both;
|
RelativeSizeAxes = Axes.Both;
|
||||||
@ -33,11 +33,24 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
|
|||||||
distance * MathF.Sin(angle * MathF.PI / 180),
|
distance * MathF.Sin(angle * MathF.PI / 180),
|
||||||
distance * MathF.Cos(angle * MathF.PI / 180));
|
distance * MathF.Cos(angle * MathF.PI / 180));
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
protected void Clear()
|
||||||
private void load(DrawableHitObject drawableObject)
|
|
||||||
{
|
{
|
||||||
DrawableCatchHitObject drawableCatchObject = (DrawableCatchHitObject)drawableObject;
|
for (int i = 0; i < pulpsInUse; i++)
|
||||||
AccentColour.BindTo(drawableCatchObject.AccentColour);
|
InternalChildren[i].Alpha = 0;
|
||||||
|
pulpsInUse = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void AddPulp(Vector2 position, Vector2 size)
|
||||||
|
{
|
||||||
|
if (pulpsInUse == InternalChildren.Count)
|
||||||
|
AddInternal(new Pulp { AccentColour = { BindTarget = AccentColour } });
|
||||||
|
|
||||||
|
var pulp = InternalChildren[pulpsInUse];
|
||||||
|
pulp.Position = position;
|
||||||
|
pulp.Size = size;
|
||||||
|
pulp.Alpha = 1;
|
||||||
|
|
||||||
|
pulpsInUse++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,15 +1,13 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using Humanizer;
|
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
using osuTK;
|
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
using static osu.Game.Skinning.LegacySkinConfiguration;
|
using static osu.Game.Skinning.LegacySkinConfiguration;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Skinning
|
namespace osu.Game.Rulesets.Catch.Skinning.Legacy
|
||||||
{
|
{
|
||||||
public class CatchLegacySkinTransformer : LegacySkinTransformer
|
public class CatchLegacySkinTransformer : LegacySkinTransformer
|
||||||
{
|
{
|
||||||
@ -40,20 +38,21 @@ namespace osu.Game.Rulesets.Catch.Skinning
|
|||||||
|
|
||||||
switch (catchSkinComponent.Component)
|
switch (catchSkinComponent.Component)
|
||||||
{
|
{
|
||||||
case CatchSkinComponents.FruitApple:
|
case CatchSkinComponents.Fruit:
|
||||||
case CatchSkinComponents.FruitBananas:
|
if (GetTexture("fruit-pear") != null)
|
||||||
case CatchSkinComponents.FruitOrange:
|
return new LegacyFruitPiece();
|
||||||
case CatchSkinComponents.FruitGrapes:
|
|
||||||
case CatchSkinComponents.FruitPear:
|
break;
|
||||||
var lookupName = catchSkinComponent.Component.ToString().Kebaberize();
|
|
||||||
if (GetTexture(lookupName) != null)
|
case CatchSkinComponents.Banana:
|
||||||
return new LegacyFruitPiece(lookupName);
|
if (GetTexture("fruit-bananas") != null)
|
||||||
|
return new LegacyBananaPiece();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CatchSkinComponents.Droplet:
|
case CatchSkinComponents.Droplet:
|
||||||
if (GetTexture("fruit-drop") != null)
|
if (GetTexture("fruit-drop") != null)
|
||||||
return new LegacyFruitPiece("fruit-drop") { Scale = new Vector2(0.8f) };
|
return new LegacyDropletPiece();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
@ -9,7 +9,7 @@ using osuTK;
|
|||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
using static osu.Game.Skinning.LegacySkinConfiguration;
|
using static osu.Game.Skinning.LegacySkinConfiguration;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Skinning
|
namespace osu.Game.Rulesets.Catch.Skinning.Legacy
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A combo counter implementation that visually behaves almost similar to stable's osu!catch combo counter.
|
/// A combo counter implementation that visually behaves almost similar to stable's osu!catch combo counter.
|
47
osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyFruitPiece.cs
Normal file
47
osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyFruitPiece.cs
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Game.Rulesets.Catch.Objects.Drawables;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Catch.Skinning.Legacy
|
||||||
|
{
|
||||||
|
internal class LegacyFruitPiece : LegacyCatchHitObjectPiece
|
||||||
|
{
|
||||||
|
public readonly Bindable<FruitVisualRepresentation> VisualRepresentation = new Bindable<FruitVisualRepresentation>();
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
var fruit = (DrawableFruit)DrawableHitObject;
|
||||||
|
|
||||||
|
if (fruit != null)
|
||||||
|
VisualRepresentation.BindTo(fruit.VisualRepresentation);
|
||||||
|
|
||||||
|
VisualRepresentation.BindValueChanged(visual => setTexture(visual.NewValue), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setTexture(FruitVisualRepresentation visualRepresentation)
|
||||||
|
{
|
||||||
|
switch (visualRepresentation)
|
||||||
|
{
|
||||||
|
case FruitVisualRepresentation.Pear:
|
||||||
|
SetTexture(Skin.GetTexture("fruit-pear"), Skin.GetTexture("fruit-pear-overlay"));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FruitVisualRepresentation.Grape:
|
||||||
|
SetTexture(Skin.GetTexture("fruit-grapes"), Skin.GetTexture("fruit-grapes-overlay"));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FruitVisualRepresentation.Pineapple:
|
||||||
|
SetTexture(Skin.GetTexture("fruit-apple"), Skin.GetTexture("fruit-apple-overlay"));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FruitVisualRepresentation.Raspberry:
|
||||||
|
SetTexture(Skin.GetTexture("fruit-orange"), Skin.GetTexture("fruit-orange-overlay"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
20
osu.Game.Rulesets.Catch/Skinning/LegacyBananaPiece.cs
Normal file
20
osu.Game.Rulesets.Catch/Skinning/LegacyBananaPiece.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
using osu.Framework.Graphics.Textures;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Catch.Skinning
|
||||||
|
{
|
||||||
|
public class LegacyBananaPiece : LegacyCatchHitObjectPiece
|
||||||
|
{
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
Texture texture = Skin.GetTexture("fruit-bananas");
|
||||||
|
Texture overlayTexture = Skin.GetTexture("fruit-bananas-overlay");
|
||||||
|
|
||||||
|
SetTexture(texture, overlayTexture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,98 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Pooling;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Framework.Graphics.Textures;
|
||||||
|
using osu.Game.Rulesets.Catch.Objects.Drawables;
|
||||||
|
using osu.Game.Rulesets.Catch.UI;
|
||||||
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
|
using osu.Game.Skinning;
|
||||||
|
using osuTK;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Catch.Skinning
|
||||||
|
{
|
||||||
|
public abstract class LegacyCatchHitObjectPiece : PoolableDrawable
|
||||||
|
{
|
||||||
|
public readonly Bindable<Color4> AccentColour = new Bindable<Color4>();
|
||||||
|
public readonly Bindable<bool> HyperDash = new Bindable<bool>();
|
||||||
|
|
||||||
|
private readonly Sprite colouredSprite;
|
||||||
|
private readonly Sprite overlaySprite;
|
||||||
|
private readonly Sprite hyperSprite;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
protected ISkinSource Skin { get; private set; }
|
||||||
|
|
||||||
|
[Resolved(canBeNull: true)]
|
||||||
|
[CanBeNull]
|
||||||
|
protected DrawableHitObject DrawableHitObject { get; private set; }
|
||||||
|
|
||||||
|
protected LegacyCatchHitObjectPiece()
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both;
|
||||||
|
|
||||||
|
InternalChildren = new Drawable[]
|
||||||
|
{
|
||||||
|
colouredSprite = new Sprite
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
},
|
||||||
|
overlaySprite = new Sprite
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
},
|
||||||
|
hyperSprite = new Sprite
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Blending = BlendingParameters.Additive,
|
||||||
|
Depth = 1,
|
||||||
|
Alpha = 0,
|
||||||
|
Scale = new Vector2(1.2f),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
var hitObject = (DrawablePalpableCatchHitObject)DrawableHitObject;
|
||||||
|
|
||||||
|
if (hitObject != null)
|
||||||
|
{
|
||||||
|
AccentColour.BindTo(hitObject.AccentColour);
|
||||||
|
HyperDash.BindTo(hitObject.HyperDash);
|
||||||
|
}
|
||||||
|
|
||||||
|
hyperSprite.Colour = Skin.GetConfig<CatchSkinColour, Color4>(CatchSkinColour.HyperDashFruit)?.Value ??
|
||||||
|
Skin.GetConfig<CatchSkinColour, Color4>(CatchSkinColour.HyperDash)?.Value ??
|
||||||
|
Catcher.DEFAULT_HYPER_DASH_COLOUR;
|
||||||
|
|
||||||
|
AccentColour.BindValueChanged(colour =>
|
||||||
|
{
|
||||||
|
colouredSprite.Colour = LegacyColourCompatibility.DisallowZeroAlpha(colour.NewValue);
|
||||||
|
}, true);
|
||||||
|
|
||||||
|
HyperDash.BindValueChanged(hyper =>
|
||||||
|
{
|
||||||
|
hyperSprite.Alpha = hyper.NewValue ? 0.7f : 0;
|
||||||
|
}, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void SetTexture(Texture texture, Texture overlayTexture)
|
||||||
|
{
|
||||||
|
colouredSprite.Texture = texture;
|
||||||
|
overlaySprite.Texture = overlayTexture;
|
||||||
|
hyperSprite.Texture = texture;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
26
osu.Game.Rulesets.Catch/Skinning/LegacyDropletPiece.cs
Normal file
26
osu.Game.Rulesets.Catch/Skinning/LegacyDropletPiece.cs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
using osu.Framework.Graphics.Textures;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Catch.Skinning
|
||||||
|
{
|
||||||
|
public class LegacyDropletPiece : LegacyCatchHitObjectPiece
|
||||||
|
{
|
||||||
|
public LegacyDropletPiece()
|
||||||
|
{
|
||||||
|
Scale = new Vector2(0.8f);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
Texture texture = Skin.GetTexture("fruit-drop");
|
||||||
|
Texture overlayTexture = Skin.GetTexture("fruit-drop-overlay");
|
||||||
|
|
||||||
|
SetTexture(texture, overlayTexture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,81 +0,0 @@
|
|||||||
// 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.
|
|
||||||
|
|
||||||
using osu.Framework.Allocation;
|
|
||||||
using osu.Framework.Bindables;
|
|
||||||
using osu.Framework.Graphics;
|
|
||||||
using osu.Framework.Graphics.Containers;
|
|
||||||
using osu.Framework.Graphics.Sprites;
|
|
||||||
using osu.Game.Rulesets.Catch.Objects.Drawables;
|
|
||||||
using osu.Game.Rulesets.Catch.UI;
|
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
|
||||||
using osu.Game.Skinning;
|
|
||||||
using osuTK;
|
|
||||||
using osuTK.Graphics;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Skinning
|
|
||||||
{
|
|
||||||
internal class LegacyFruitPiece : CompositeDrawable
|
|
||||||
{
|
|
||||||
private readonly string lookupName;
|
|
||||||
|
|
||||||
private readonly IBindable<Color4> accentColour = new Bindable<Color4>();
|
|
||||||
private Sprite colouredSprite;
|
|
||||||
|
|
||||||
public LegacyFruitPiece(string lookupName)
|
|
||||||
{
|
|
||||||
this.lookupName = lookupName;
|
|
||||||
RelativeSizeAxes = Axes.Both;
|
|
||||||
}
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load(DrawableHitObject drawableObject, ISkinSource skin)
|
|
||||||
{
|
|
||||||
DrawableCatchHitObject drawableCatchObject = (DrawableCatchHitObject)drawableObject;
|
|
||||||
|
|
||||||
accentColour.BindTo(drawableCatchObject.AccentColour);
|
|
||||||
|
|
||||||
InternalChildren = new Drawable[]
|
|
||||||
{
|
|
||||||
colouredSprite = new Sprite
|
|
||||||
{
|
|
||||||
Texture = skin.GetTexture(lookupName),
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
},
|
|
||||||
new Sprite
|
|
||||||
{
|
|
||||||
Texture = skin.GetTexture($"{lookupName}-overlay"),
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
if (drawableCatchObject.HitObject.HyperDash)
|
|
||||||
{
|
|
||||||
var hyperDash = new Sprite
|
|
||||||
{
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
Blending = BlendingParameters.Additive,
|
|
||||||
Depth = 1,
|
|
||||||
Alpha = 0.7f,
|
|
||||||
Scale = new Vector2(1.2f),
|
|
||||||
Texture = skin.GetTexture(lookupName),
|
|
||||||
Colour = skin.GetConfig<CatchSkinColour, Color4>(CatchSkinColour.HyperDashFruit)?.Value ??
|
|
||||||
skin.GetConfig<CatchSkinColour, Color4>(CatchSkinColour.HyperDash)?.Value ??
|
|
||||||
Catcher.DEFAULT_HYPER_DASH_COLOUR,
|
|
||||||
};
|
|
||||||
|
|
||||||
AddInternal(hyperDash);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void LoadComplete()
|
|
||||||
{
|
|
||||||
base.LoadComplete();
|
|
||||||
|
|
||||||
accentColour.BindValueChanged(colour => colouredSprite.Colour = LegacyColourCompatibility.DisallowZeroAlpha(colour.NewValue), true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,6 +2,7 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
@ -35,41 +36,53 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
|
|
||||||
public CatchPlayfield(BeatmapDifficulty difficulty, Func<CatchHitObject, DrawableHitObject<CatchHitObject>> createDrawableRepresentation)
|
public CatchPlayfield(BeatmapDifficulty difficulty, Func<CatchHitObject, DrawableHitObject<CatchHitObject>> createDrawableRepresentation)
|
||||||
{
|
{
|
||||||
var explodingFruitContainer = new Container
|
var droppedObjectContainer = new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
};
|
};
|
||||||
|
|
||||||
CatcherArea = new CatcherArea(difficulty)
|
CatcherArea = new CatcherArea(droppedObjectContainer, difficulty)
|
||||||
{
|
{
|
||||||
CreateDrawableRepresentation = createDrawableRepresentation,
|
|
||||||
ExplodingFruitTarget = explodingFruitContainer,
|
|
||||||
Anchor = Anchor.BottomLeft,
|
Anchor = Anchor.BottomLeft,
|
||||||
Origin = Anchor.TopLeft,
|
Origin = Anchor.TopLeft,
|
||||||
};
|
};
|
||||||
|
|
||||||
InternalChildren = new[]
|
InternalChildren = new[]
|
||||||
{
|
{
|
||||||
explodingFruitContainer,
|
droppedObjectContainer,
|
||||||
CatcherArea.MovableCatcher.CreateProxiedContent(),
|
CatcherArea.MovableCatcher.CreateProxiedContent(),
|
||||||
HitObjectContainer,
|
HitObjectContainer,
|
||||||
CatcherArea,
|
CatcherArea,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool CheckIfWeCanCatch(CatchHitObject obj) => CatcherArea.AttemptCatch(obj);
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
public override void Add(DrawableHitObject h)
|
|
||||||
{
|
{
|
||||||
h.OnNewResult += onNewResult;
|
RegisterPool<Droplet, DrawableDroplet>(50);
|
||||||
h.OnRevertResult += onRevertResult;
|
RegisterPool<TinyDroplet, DrawableTinyDroplet>(50);
|
||||||
|
RegisterPool<Fruit, DrawableFruit>(100);
|
||||||
base.Add(h);
|
RegisterPool<Banana, DrawableBanana>(100);
|
||||||
|
RegisterPool<JuiceStream, DrawableJuiceStream>(10);
|
||||||
var fruit = (DrawableCatchHitObject)h;
|
RegisterPool<BananaShower, DrawableBananaShower>(2);
|
||||||
fruit.CheckPosition = CheckIfWeCanCatch;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
// these subscriptions need to be done post constructor to ensure externally bound components have a chance to populate required fields (ScoreProcessor / ComboAtJudgement in this case).
|
||||||
|
NewResult += onNewResult;
|
||||||
|
RevertResult += onRevertResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnNewDrawableHitObject(DrawableHitObject d)
|
||||||
|
{
|
||||||
|
((DrawableCatchHitObject)d).CheckPosition = checkIfWeCanCatch;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool checkIfWeCanCatch(CatchHitObject obj) => CatcherArea.MovableCatcher.CanCatch(obj);
|
||||||
|
|
||||||
private void onNewResult(DrawableHitObject judgedObject, JudgementResult result)
|
private void onNewResult(DrawableHitObject judgedObject, JudgementResult result)
|
||||||
=> CatcherArea.OnNewResult((DrawableCatchHitObject)judgedObject, result);
|
=> CatcherArea.OnNewResult((DrawableCatchHitObject)judgedObject, result);
|
||||||
|
|
||||||
|
@ -9,14 +9,16 @@ using osu.Framework.Bindables;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Animations;
|
using osu.Framework.Graphics.Animations;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Pooling;
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
using osu.Framework.Utils;
|
using osu.Framework.Utils;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
|
using osu.Game.Rulesets.Catch.Judgements;
|
||||||
using osu.Game.Rulesets.Catch.Objects;
|
using osu.Game.Rulesets.Catch.Objects;
|
||||||
using osu.Game.Rulesets.Catch.Objects.Drawables;
|
using osu.Game.Rulesets.Catch.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Catch.Skinning;
|
using osu.Game.Rulesets.Catch.Skinning;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Judgements;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
@ -46,19 +48,15 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public const double BASE_SPEED = 1.0;
|
public const double BASE_SPEED = 1.0;
|
||||||
|
|
||||||
public Container ExplodingFruitTarget;
|
|
||||||
|
|
||||||
private Container<DrawableHitObject> caughtFruitContainer { get; } = new Container<DrawableHitObject>
|
|
||||||
{
|
|
||||||
Anchor = Anchor.TopCentre,
|
|
||||||
Origin = Anchor.BottomCentre,
|
|
||||||
};
|
|
||||||
|
|
||||||
[NotNull]
|
[NotNull]
|
||||||
private readonly Container trailsTarget;
|
private readonly Container trailsTarget;
|
||||||
|
|
||||||
private CatcherTrailDisplay trails;
|
private CatcherTrailDisplay trails;
|
||||||
|
|
||||||
|
private readonly Container droppedObjectTarget;
|
||||||
|
|
||||||
|
private readonly Container<DrawablePalpableCatchHitObject> caughtFruitContainer;
|
||||||
|
|
||||||
public CatcherAnimationState CurrentState { get; private set; }
|
public CatcherAnimationState CurrentState { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -91,9 +89,9 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly float catchWidth;
|
private readonly float catchWidth;
|
||||||
|
|
||||||
private CatcherSprite catcherIdle;
|
private readonly CatcherSprite catcherIdle;
|
||||||
private CatcherSprite catcherKiai;
|
private readonly CatcherSprite catcherKiai;
|
||||||
private CatcherSprite catcherFail;
|
private readonly CatcherSprite catcherFail;
|
||||||
|
|
||||||
private CatcherSprite currentCatcher;
|
private CatcherSprite currentCatcher;
|
||||||
|
|
||||||
@ -107,9 +105,13 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
private float hyperDashTargetPosition;
|
private float hyperDashTargetPosition;
|
||||||
private Bindable<bool> hitLighting;
|
private Bindable<bool> hitLighting;
|
||||||
|
|
||||||
public Catcher([NotNull] Container trailsTarget, BeatmapDifficulty difficulty = null)
|
private readonly DrawablePool<HitExplosion> hitExplosionPool;
|
||||||
|
private readonly Container<HitExplosion> hitExplosionContainer;
|
||||||
|
|
||||||
|
public Catcher([NotNull] Container trailsTarget, [NotNull] Container droppedObjectTarget, BeatmapDifficulty difficulty = null)
|
||||||
{
|
{
|
||||||
this.trailsTarget = trailsTarget;
|
this.trailsTarget = trailsTarget;
|
||||||
|
this.droppedObjectTarget = droppedObjectTarget;
|
||||||
|
|
||||||
Origin = Anchor.TopCentre;
|
Origin = Anchor.TopCentre;
|
||||||
|
|
||||||
@ -118,16 +120,15 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
Scale = calculateScale(difficulty);
|
Scale = calculateScale(difficulty);
|
||||||
|
|
||||||
catchWidth = CalculateCatchWidth(Scale);
|
catchWidth = CalculateCatchWidth(Scale);
|
||||||
}
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load(OsuConfigManager config)
|
|
||||||
{
|
|
||||||
hitLighting = config.GetBindable<bool>(OsuSetting.HitLighting);
|
|
||||||
|
|
||||||
InternalChildren = new Drawable[]
|
InternalChildren = new Drawable[]
|
||||||
{
|
{
|
||||||
caughtFruitContainer,
|
hitExplosionPool = new DrawablePool<HitExplosion>(10),
|
||||||
|
caughtFruitContainer = new Container<DrawablePalpableCatchHitObject>
|
||||||
|
{
|
||||||
|
Anchor = Anchor.TopCentre,
|
||||||
|
Origin = Anchor.BottomCentre,
|
||||||
|
},
|
||||||
catcherIdle = new CatcherSprite(CatcherAnimationState.Idle)
|
catcherIdle = new CatcherSprite(CatcherAnimationState.Idle)
|
||||||
{
|
{
|
||||||
Anchor = Anchor.TopCentre,
|
Anchor = Anchor.TopCentre,
|
||||||
@ -142,9 +143,19 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
{
|
{
|
||||||
Anchor = Anchor.TopCentre,
|
Anchor = Anchor.TopCentre,
|
||||||
Alpha = 0,
|
Alpha = 0,
|
||||||
}
|
},
|
||||||
|
hitExplosionContainer = new Container<HitExplosion>
|
||||||
|
{
|
||||||
|
Anchor = Anchor.TopCentre,
|
||||||
|
Origin = Anchor.BottomCentre,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuConfigManager config)
|
||||||
|
{
|
||||||
|
hitLighting = config.GetBindable<bool>(OsuSetting.HitLighting);
|
||||||
trails = new CatcherTrailDisplay(this);
|
trails = new CatcherTrailDisplay(this);
|
||||||
|
|
||||||
updateCatcher();
|
updateCatcher();
|
||||||
@ -166,65 +177,26 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Calculates the scale of the catcher based off the provided beatmap difficulty.
|
/// Calculates the scale of the catcher based off the provided beatmap difficulty.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private static Vector2 calculateScale(BeatmapDifficulty difficulty)
|
private static Vector2 calculateScale(BeatmapDifficulty difficulty) => new Vector2(1.0f - 0.7f * (difficulty.CircleSize - 5) / 5);
|
||||||
=> new Vector2(1.0f - 0.7f * (difficulty.CircleSize - 5) / 5);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Calculates the width of the area used for attempting catches in gameplay.
|
/// Calculates the width of the area used for attempting catches in gameplay.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="scale">The scale of the catcher.</param>
|
/// <param name="scale">The scale of the catcher.</param>
|
||||||
internal static float CalculateCatchWidth(Vector2 scale)
|
internal static float CalculateCatchWidth(Vector2 scale) => CatcherArea.CATCHER_SIZE * Math.Abs(scale.X) * ALLOWED_CATCH_RANGE;
|
||||||
=> CatcherArea.CATCHER_SIZE * Math.Abs(scale.X) * ALLOWED_CATCH_RANGE;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Calculates the width of the area used for attempting catches in gameplay.
|
/// Calculates the width of the area used for attempting catches in gameplay.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="difficulty">The beatmap difficulty.</param>
|
/// <param name="difficulty">The beatmap difficulty.</param>
|
||||||
internal static float CalculateCatchWidth(BeatmapDifficulty difficulty)
|
internal static float CalculateCatchWidth(BeatmapDifficulty difficulty) => CalculateCatchWidth(calculateScale(difficulty));
|
||||||
=> CalculateCatchWidth(calculateScale(difficulty));
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Add a caught fruit to the catcher's stack.
|
/// Determine if this catcher can catch a <see cref="CatchHitObject"/> in the current position.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="fruit">The fruit that was caught.</param>
|
public bool CanCatch(CatchHitObject hitObject)
|
||||||
public void PlaceOnPlate(DrawableCatchHitObject fruit)
|
|
||||||
{
|
{
|
||||||
var ourRadius = fruit.DisplayRadius;
|
if (!(hitObject is PalpableCatchHitObject fruit))
|
||||||
float theirRadius = 0;
|
|
||||||
|
|
||||||
const float allowance = 10;
|
|
||||||
|
|
||||||
while (caughtFruitContainer.Any(f =>
|
|
||||||
f.LifetimeEnd == double.MaxValue &&
|
|
||||||
Vector2Extensions.Distance(f.Position, fruit.Position) < (ourRadius + (theirRadius = f.DrawSize.X / 2 * f.Scale.X)) / (allowance / 2)))
|
|
||||||
{
|
|
||||||
var diff = (ourRadius + theirRadius) / allowance;
|
|
||||||
fruit.X += (RNG.NextSingle() - 0.5f) * diff * 2;
|
|
||||||
fruit.Y -= RNG.NextSingle() * diff;
|
|
||||||
}
|
|
||||||
|
|
||||||
fruit.X = Math.Clamp(fruit.X, -CatcherArea.CATCHER_SIZE / 2, CatcherArea.CATCHER_SIZE / 2);
|
|
||||||
|
|
||||||
caughtFruitContainer.Add(fruit);
|
|
||||||
|
|
||||||
if (hitLighting.Value)
|
|
||||||
{
|
|
||||||
AddInternal(new HitExplosion(fruit)
|
|
||||||
{
|
|
||||||
X = fruit.X,
|
|
||||||
Scale = new Vector2(fruit.HitObject.Scale)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Let the catcher attempt to catch a fruit.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="fruit">The fruit to catch.</param>
|
|
||||||
/// <returns>Whether the catch is possible.</returns>
|
|
||||||
public bool AttemptCatch(CatchHitObject fruit)
|
|
||||||
{
|
|
||||||
if (!fruit.CanBePlated)
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var halfCatchWidth = catchWidth * 0.5f;
|
var halfCatchWidth = catchWidth * 0.5f;
|
||||||
@ -233,18 +205,29 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
var catchObjectPosition = fruit.X;
|
var catchObjectPosition = fruit.X;
|
||||||
var catcherPosition = Position.X;
|
var catcherPosition = Position.X;
|
||||||
|
|
||||||
var validCatch =
|
return catchObjectPosition >= catcherPosition - halfCatchWidth &&
|
||||||
catchObjectPosition >= catcherPosition - halfCatchWidth &&
|
|
||||||
catchObjectPosition <= catcherPosition + halfCatchWidth;
|
catchObjectPosition <= catcherPosition + halfCatchWidth;
|
||||||
|
}
|
||||||
|
|
||||||
// only update hyperdash state if we are not catching a tiny droplet.
|
public void OnNewResult(DrawableCatchHitObject drawableObject, JudgementResult result)
|
||||||
if (fruit is TinyDroplet) return validCatch;
|
|
||||||
|
|
||||||
if (validCatch && fruit.HyperDash)
|
|
||||||
{
|
{
|
||||||
var target = fruit.HyperDashTarget;
|
var catchResult = (CatchJudgementResult)result;
|
||||||
var timeDifference = target.StartTime - fruit.StartTime;
|
catchResult.CatcherAnimationState = CurrentState;
|
||||||
double positionDifference = target.X - catcherPosition;
|
catchResult.CatcherHyperDash = HyperDashing;
|
||||||
|
|
||||||
|
if (!(drawableObject.HitObject is PalpableCatchHitObject hitObject)) return;
|
||||||
|
|
||||||
|
if (result.IsHit)
|
||||||
|
placeCaughtObject(hitObject);
|
||||||
|
|
||||||
|
// droplet doesn't affect the catcher state
|
||||||
|
if (hitObject is TinyDroplet) return;
|
||||||
|
|
||||||
|
if (result.IsHit && hitObject.HyperDash)
|
||||||
|
{
|
||||||
|
var target = hitObject.HyperDashTarget;
|
||||||
|
var timeDifference = target.StartTime - hitObject.StartTime;
|
||||||
|
double positionDifference = target.X - X;
|
||||||
var velocity = positionDifference / Math.Max(1.0, timeDifference - 1000.0 / 60.0);
|
var velocity = positionDifference / Math.Max(1.0, timeDifference - 1000.0 / 60.0);
|
||||||
|
|
||||||
SetHyperDashState(Math.Abs(velocity), target.X);
|
SetHyperDashState(Math.Abs(velocity), target.X);
|
||||||
@ -252,12 +235,30 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
else
|
else
|
||||||
SetHyperDashState();
|
SetHyperDashState();
|
||||||
|
|
||||||
if (validCatch)
|
if (result.IsHit)
|
||||||
updateState(fruit.Kiai ? CatcherAnimationState.Kiai : CatcherAnimationState.Idle);
|
updateState(hitObject.Kiai ? CatcherAnimationState.Kiai : CatcherAnimationState.Idle);
|
||||||
else if (!(fruit is Banana))
|
else if (!(hitObject is Banana))
|
||||||
updateState(CatcherAnimationState.Fail);
|
updateState(CatcherAnimationState.Fail);
|
||||||
|
}
|
||||||
|
|
||||||
return validCatch;
|
public void OnRevertResult(DrawableCatchHitObject drawableObject, JudgementResult result)
|
||||||
|
{
|
||||||
|
var catchResult = (CatchJudgementResult)result;
|
||||||
|
|
||||||
|
if (CurrentState != catchResult.CatcherAnimationState)
|
||||||
|
updateState(catchResult.CatcherAnimationState);
|
||||||
|
|
||||||
|
if (HyperDashing != catchResult.CatcherHyperDash)
|
||||||
|
{
|
||||||
|
if (catchResult.CatcherHyperDash)
|
||||||
|
SetHyperDashState(2);
|
||||||
|
else
|
||||||
|
SetHyperDashState();
|
||||||
|
}
|
||||||
|
|
||||||
|
caughtFruitContainer.RemoveAll(d => d.HitObject == drawableObject.HitObject);
|
||||||
|
droppedObjectTarget.RemoveAll(d => (d as DrawableCatchHitObject)?.HitObject == drawableObject.HitObject);
|
||||||
|
hitExplosionContainer.RemoveAll(d => d.HitObject == drawableObject.HitObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -291,23 +292,16 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void runHyperDashStateTransition(bool hyperDashing)
|
public void UpdatePosition(float position)
|
||||||
{
|
{
|
||||||
updateTrailVisibility();
|
position = Math.Clamp(position, 0, CatchPlayfield.WIDTH);
|
||||||
|
|
||||||
if (hyperDashing)
|
if (position == X)
|
||||||
{
|
return;
|
||||||
this.FadeColour(hyperDashColour, HYPER_DASH_TRANSITION_DURATION, Easing.OutQuint);
|
|
||||||
this.FadeTo(0.2f, HYPER_DASH_TRANSITION_DURATION, Easing.OutQuint);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this.FadeColour(Color4.White, HYPER_DASH_TRANSITION_DURATION, Easing.OutQuint);
|
|
||||||
this.FadeTo(1f, HYPER_DASH_TRANSITION_DURATION, Easing.OutQuint);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateTrailVisibility() => trails.DisplayTrail = Dashing || HyperDashing;
|
Scale = new Vector2(Math.Abs(Scale.X) * (position > X ? 1 : -1), Scale.Y);
|
||||||
|
X = position;
|
||||||
|
}
|
||||||
|
|
||||||
public bool OnPressed(CatchAction action)
|
public bool OnPressed(CatchAction action)
|
||||||
{
|
{
|
||||||
@ -347,55 +341,33 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdatePosition(float position)
|
|
||||||
{
|
|
||||||
position = Math.Clamp(position, 0, CatchPlayfield.WIDTH);
|
|
||||||
|
|
||||||
if (position == X)
|
|
||||||
return;
|
|
||||||
|
|
||||||
Scale = new Vector2(Math.Abs(Scale.X) * (position > X ? 1 : -1), Scale.Y);
|
|
||||||
X = position;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Drop any fruit off the plate.
|
/// Drop any fruit off the plate.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Drop()
|
public void Drop() => clearPlate(DroppedObjectAnimation.Drop);
|
||||||
{
|
|
||||||
foreach (var f in caughtFruitContainer.ToArray())
|
|
||||||
Drop(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Explode any fruit off the plate.
|
/// Explode all fruit off the plate.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Explode()
|
public void Explode() => clearPlate(DroppedObjectAnimation.Explode);
|
||||||
|
|
||||||
|
private void runHyperDashStateTransition(bool hyperDashing)
|
||||||
{
|
{
|
||||||
foreach (var f in caughtFruitContainer.ToArray())
|
updateTrailVisibility();
|
||||||
Explode(f);
|
|
||||||
|
if (hyperDashing)
|
||||||
|
{
|
||||||
|
this.FadeColour(hyperDashColour, HYPER_DASH_TRANSITION_DURATION, Easing.OutQuint);
|
||||||
|
this.FadeTo(0.2f, HYPER_DASH_TRANSITION_DURATION, Easing.OutQuint);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.FadeColour(Color4.White, HYPER_DASH_TRANSITION_DURATION, Easing.OutQuint);
|
||||||
|
this.FadeTo(1f, HYPER_DASH_TRANSITION_DURATION, Easing.OutQuint);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Drop(DrawableHitObject fruit)
|
private void updateTrailVisibility() => trails.DisplayTrail = Dashing || HyperDashing;
|
||||||
{
|
|
||||||
removeFromPlateWithTransform(fruit, f =>
|
|
||||||
{
|
|
||||||
f.MoveToY(f.Y + 75, 750, Easing.InSine);
|
|
||||||
f.FadeOut(750);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Explode(DrawableHitObject fruit)
|
|
||||||
{
|
|
||||||
var originalX = fruit.X * Scale.X;
|
|
||||||
|
|
||||||
removeFromPlateWithTransform(fruit, f =>
|
|
||||||
{
|
|
||||||
f.MoveToY(f.Y - 50, 250, Easing.OutSine).Then().MoveToY(f.Y + 50, 500, Easing.InSine);
|
|
||||||
f.MoveToX(f.X + originalX * 6, 1000);
|
|
||||||
f.FadeOut(750);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void SkinChanged(ISkinSource skin, bool allowFallback)
|
protected override void SkinChanged(ISkinSource skin, bool allowFallback)
|
||||||
{
|
{
|
||||||
@ -469,33 +441,144 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
updateCatcher();
|
updateCatcher();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeFromPlateWithTransform(DrawableHitObject fruit, Action<DrawableHitObject> action)
|
private void placeCaughtObject(PalpableCatchHitObject source)
|
||||||
{
|
{
|
||||||
if (ExplodingFruitTarget != null)
|
var caughtObject = createCaughtObject(source);
|
||||||
{
|
|
||||||
fruit.Anchor = Anchor.TopLeft;
|
|
||||||
fruit.Position = caughtFruitContainer.ToSpaceOfOtherDrawable(fruit.DrawPosition, ExplodingFruitTarget);
|
|
||||||
|
|
||||||
if (!caughtFruitContainer.Remove(fruit))
|
if (caughtObject == null) return;
|
||||||
// we may have already been removed by a previous operation (due to the weird OnLoadComplete scheduling).
|
|
||||||
// this avoids a crash on potentially attempting to Add a fruit to ExplodingFruitTarget twice.
|
|
||||||
return;
|
|
||||||
|
|
||||||
ExplodingFruitTarget.Add(fruit);
|
caughtObject.RelativePositionAxes = Axes.None;
|
||||||
|
caughtObject.X = source.X - X;
|
||||||
|
caughtObject.IsOnPlate = true;
|
||||||
|
|
||||||
|
caughtObject.Anchor = Anchor.TopCentre;
|
||||||
|
caughtObject.Origin = Anchor.Centre;
|
||||||
|
caughtObject.Scale *= 0.5f;
|
||||||
|
caughtObject.LifetimeStart = source.StartTime;
|
||||||
|
caughtObject.LifetimeEnd = double.MaxValue;
|
||||||
|
|
||||||
|
adjustPositionInStack(caughtObject);
|
||||||
|
|
||||||
|
caughtFruitContainer.Add(caughtObject);
|
||||||
|
|
||||||
|
addLighting(caughtObject);
|
||||||
|
|
||||||
|
if (!caughtObject.StaysOnPlate)
|
||||||
|
removeFromPlate(caughtObject, DroppedObjectAnimation.Explode);
|
||||||
}
|
}
|
||||||
|
|
||||||
var actionTime = Clock.CurrentTime;
|
private void adjustPositionInStack(DrawablePalpableCatchHitObject caughtObject)
|
||||||
|
|
||||||
fruit.ApplyCustomUpdateState += onFruitOnApplyCustomUpdateState;
|
|
||||||
onFruitOnApplyCustomUpdateState(fruit, fruit.State.Value);
|
|
||||||
|
|
||||||
void onFruitOnApplyCustomUpdateState(DrawableHitObject o, ArmedState state)
|
|
||||||
{
|
{
|
||||||
using (fruit.BeginAbsoluteSequence(actionTime))
|
const float radius_div_2 = CatchHitObject.OBJECT_RADIUS / 2;
|
||||||
action(fruit);
|
const float allowance = 10;
|
||||||
|
|
||||||
fruit.Expire();
|
float caughtObjectRadius = caughtObject.DisplayRadius;
|
||||||
|
|
||||||
|
while (caughtFruitContainer.Any(f => Vector2Extensions.Distance(f.Position, caughtObject.Position) < (caughtObjectRadius + radius_div_2) / (allowance / 2)))
|
||||||
|
{
|
||||||
|
float diff = (caughtObjectRadius + radius_div_2) / allowance;
|
||||||
|
|
||||||
|
caughtObject.X += (RNG.NextSingle() - 0.5f) * diff * 2;
|
||||||
|
caughtObject.Y -= RNG.NextSingle() * diff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
caughtObject.X = Math.Clamp(caughtObject.X, -CatcherArea.CATCHER_SIZE / 2, CatcherArea.CATCHER_SIZE / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addLighting(DrawablePalpableCatchHitObject caughtObject)
|
||||||
|
{
|
||||||
|
if (!hitLighting.Value) return;
|
||||||
|
|
||||||
|
HitExplosion hitExplosion = hitExplosionPool.Get();
|
||||||
|
hitExplosion.HitObject = caughtObject.HitObject;
|
||||||
|
hitExplosion.X = caughtObject.X;
|
||||||
|
hitExplosion.Scale = new Vector2(caughtObject.HitObject.Scale);
|
||||||
|
hitExplosion.ObjectColour = caughtObject.AccentColour.Value;
|
||||||
|
hitExplosionContainer.Add(hitExplosion);
|
||||||
|
}
|
||||||
|
|
||||||
|
private DrawablePalpableCatchHitObject createCaughtObject(PalpableCatchHitObject source)
|
||||||
|
{
|
||||||
|
switch (source)
|
||||||
|
{
|
||||||
|
case Banana banana:
|
||||||
|
return new DrawableBanana(banana);
|
||||||
|
|
||||||
|
case Fruit fruit:
|
||||||
|
return new DrawableFruit(fruit);
|
||||||
|
|
||||||
|
case TinyDroplet tiny:
|
||||||
|
return new DrawableTinyDroplet(tiny);
|
||||||
|
|
||||||
|
case Droplet droplet:
|
||||||
|
return new DrawableDroplet(droplet);
|
||||||
|
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clearPlate(DroppedObjectAnimation animation)
|
||||||
|
{
|
||||||
|
var caughtObjects = caughtFruitContainer.Children.ToArray();
|
||||||
|
caughtFruitContainer.Clear(false);
|
||||||
|
|
||||||
|
droppedObjectTarget.AddRange(caughtObjects);
|
||||||
|
|
||||||
|
foreach (var caughtObject in caughtObjects)
|
||||||
|
drop(caughtObject, animation);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeFromPlate(DrawablePalpableCatchHitObject caughtObject, DroppedObjectAnimation animation)
|
||||||
|
{
|
||||||
|
if (!caughtFruitContainer.Remove(caughtObject))
|
||||||
|
throw new InvalidOperationException("Can only drop a caught object on the plate");
|
||||||
|
|
||||||
|
droppedObjectTarget.Add(caughtObject);
|
||||||
|
|
||||||
|
drop(caughtObject, animation);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void drop(DrawablePalpableCatchHitObject d, DroppedObjectAnimation animation)
|
||||||
|
{
|
||||||
|
var originalX = d.X * Scale.X;
|
||||||
|
var startTime = Clock.CurrentTime;
|
||||||
|
|
||||||
|
d.Anchor = Anchor.TopLeft;
|
||||||
|
d.Position = caughtFruitContainer.ToSpaceOfOtherDrawable(d.DrawPosition, droppedObjectTarget);
|
||||||
|
|
||||||
|
// we cannot just apply the transforms because DHO clears transforms when state is updated
|
||||||
|
d.ApplyCustomUpdateState += (o, state) => animate(o, animation, originalX, startTime);
|
||||||
|
if (d.IsLoaded)
|
||||||
|
animate(d, animation, originalX, startTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void animate(Drawable d, DroppedObjectAnimation animation, float originalX, double startTime)
|
||||||
|
{
|
||||||
|
using (d.BeginAbsoluteSequence(startTime))
|
||||||
|
{
|
||||||
|
switch (animation)
|
||||||
|
{
|
||||||
|
case DroppedObjectAnimation.Drop:
|
||||||
|
d.MoveToY(d.Y + 75, 750, Easing.InSine);
|
||||||
|
d.FadeOut(750);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DroppedObjectAnimation.Explode:
|
||||||
|
d.MoveToY(d.Y - 50, 250, Easing.OutSine).Then().MoveToY(d.Y + 50, 500, Easing.InSine);
|
||||||
|
d.MoveToX(d.X + originalX * 6, 1000);
|
||||||
|
d.FadeOut(750);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
d.Expire();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum DroppedObjectAnimation
|
||||||
|
{
|
||||||
|
Drop,
|
||||||
|
Explode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,13 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System;
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Catch.Judgements;
|
using osu.Game.Rulesets.Catch.Judgements;
|
||||||
using osu.Game.Rulesets.Catch.Objects;
|
|
||||||
using osu.Game.Rulesets.Catch.Objects.Drawables;
|
using osu.Game.Rulesets.Catch.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Catch.Replays;
|
using osu.Game.Rulesets.Catch.Replays;
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
@ -21,19 +18,10 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
{
|
{
|
||||||
public const float CATCHER_SIZE = 106.75f;
|
public const float CATCHER_SIZE = 106.75f;
|
||||||
|
|
||||||
public Func<CatchHitObject, DrawableHitObject<CatchHitObject>> CreateDrawableRepresentation;
|
|
||||||
|
|
||||||
public readonly Catcher MovableCatcher;
|
public readonly Catcher MovableCatcher;
|
||||||
private readonly CatchComboDisplay comboDisplay;
|
private readonly CatchComboDisplay comboDisplay;
|
||||||
|
|
||||||
public Container ExplodingFruitTarget
|
public CatcherArea(Container droppedObjectContainer, BeatmapDifficulty difficulty = null)
|
||||||
{
|
|
||||||
set => MovableCatcher.ExplodingFruitTarget = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private DrawableCatchHitObject lastPlateableFruit;
|
|
||||||
|
|
||||||
public CatcherArea(BeatmapDifficulty difficulty = null)
|
|
||||||
{
|
{
|
||||||
Size = new Vector2(CatchPlayfield.WIDTH, CATCHER_SIZE);
|
Size = new Vector2(CatchPlayfield.WIDTH, CATCHER_SIZE);
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
@ -47,73 +35,32 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
Margin = new MarginPadding { Bottom = 350f },
|
Margin = new MarginPadding { Bottom = 350f },
|
||||||
X = CatchPlayfield.CENTER_X
|
X = CatchPlayfield.CENTER_X
|
||||||
},
|
},
|
||||||
MovableCatcher = new Catcher(this, difficulty) { X = CatchPlayfield.CENTER_X },
|
MovableCatcher = new Catcher(this, droppedObjectContainer, difficulty) { X = CatchPlayfield.CENTER_X },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnNewResult(DrawableCatchHitObject fruit, JudgementResult result)
|
public void OnNewResult(DrawableCatchHitObject hitObject, JudgementResult result)
|
||||||
{
|
{
|
||||||
|
MovableCatcher.OnNewResult(hitObject, result);
|
||||||
|
|
||||||
if (!result.Type.IsScorable())
|
if (!result.Type.IsScorable())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
void runAfterLoaded(Action action)
|
if (hitObject.HitObject.LastInCombo)
|
||||||
{
|
|
||||||
if (lastPlateableFruit == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// 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)
|
|
||||||
action();
|
|
||||||
else
|
|
||||||
lastPlateableFruit.OnLoadComplete += _ => action();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result.IsHit && fruit.HitObject.CanBePlated)
|
|
||||||
{
|
|
||||||
// create a new (cloned) fruit to stay on the plate. the original is faded out immediately.
|
|
||||||
var caughtFruit = (DrawableCatchHitObject)CreateDrawableRepresentation?.Invoke(fruit.HitObject);
|
|
||||||
|
|
||||||
if (caughtFruit == null) return;
|
|
||||||
|
|
||||||
caughtFruit.RelativePositionAxes = Axes.None;
|
|
||||||
caughtFruit.Position = new Vector2(MovableCatcher.ToLocalSpace(fruit.ScreenSpaceDrawQuad.Centre).X - MovableCatcher.DrawSize.X / 2, 0);
|
|
||||||
caughtFruit.IsOnPlate = true;
|
|
||||||
|
|
||||||
caughtFruit.Anchor = Anchor.TopCentre;
|
|
||||||
caughtFruit.Origin = Anchor.Centre;
|
|
||||||
caughtFruit.Scale *= 0.5f;
|
|
||||||
caughtFruit.LifetimeStart = caughtFruit.HitObject.StartTime;
|
|
||||||
caughtFruit.LifetimeEnd = double.MaxValue;
|
|
||||||
|
|
||||||
MovableCatcher.PlaceOnPlate(caughtFruit);
|
|
||||||
lastPlateableFruit = caughtFruit;
|
|
||||||
|
|
||||||
if (!fruit.StaysOnPlate)
|
|
||||||
runAfterLoaded(() => MovableCatcher.Explode(caughtFruit));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fruit.HitObject.LastInCombo)
|
|
||||||
{
|
{
|
||||||
if (result.Judgement is CatchJudgement catchJudgement && catchJudgement.ShouldExplodeFor(result))
|
if (result.Judgement is CatchJudgement catchJudgement && catchJudgement.ShouldExplodeFor(result))
|
||||||
runAfterLoaded(() => MovableCatcher.Explode());
|
MovableCatcher.Explode();
|
||||||
else
|
else
|
||||||
MovableCatcher.Drop();
|
MovableCatcher.Drop();
|
||||||
}
|
}
|
||||||
|
|
||||||
comboDisplay.OnNewResult(fruit, result);
|
comboDisplay.OnNewResult(hitObject, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnRevertResult(DrawableCatchHitObject fruit, JudgementResult result)
|
public void OnRevertResult(DrawableCatchHitObject hitObject, JudgementResult result)
|
||||||
=> comboDisplay.OnRevertResult(fruit, result);
|
|
||||||
|
|
||||||
public void OnReleased(CatchAction action)
|
|
||||||
{
|
{
|
||||||
}
|
comboDisplay.OnRevertResult(hitObject, result);
|
||||||
|
MovableCatcher.OnRevertResult(hitObject, result);
|
||||||
public bool AttemptCatch(CatchHitObject obj)
|
|
||||||
{
|
|
||||||
return MovableCatcher.AttemptCatch(obj);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void UpdateAfterChildren()
|
protected override void UpdateAfterChildren()
|
||||||
|
@ -6,6 +6,7 @@ using JetBrains.Annotations;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Animations;
|
using osu.Framework.Graphics.Animations;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Pooling;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
@ -20,6 +21,8 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
{
|
{
|
||||||
private readonly Catcher catcher;
|
private readonly Catcher catcher;
|
||||||
|
|
||||||
|
private readonly DrawablePool<CatcherTrailSprite> trailPool;
|
||||||
|
|
||||||
private readonly Container<CatcherTrailSprite> dashTrails;
|
private readonly Container<CatcherTrailSprite> dashTrails;
|
||||||
private readonly Container<CatcherTrailSprite> hyperDashTrails;
|
private readonly Container<CatcherTrailSprite> hyperDashTrails;
|
||||||
private readonly Container<CatcherTrailSprite> endGlowSprites;
|
private readonly Container<CatcherTrailSprite> endGlowSprites;
|
||||||
@ -80,8 +83,9 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
|
|
||||||
RelativeSizeAxes = Axes.Both;
|
RelativeSizeAxes = Axes.Both;
|
||||||
|
|
||||||
InternalChildren = new[]
|
InternalChildren = new Drawable[]
|
||||||
{
|
{
|
||||||
|
trailPool = new DrawablePool<CatcherTrailSprite>(30),
|
||||||
dashTrails = new Container<CatcherTrailSprite> { RelativeSizeAxes = Axes.Both },
|
dashTrails = new Container<CatcherTrailSprite> { RelativeSizeAxes = Axes.Both },
|
||||||
hyperDashTrails = new Container<CatcherTrailSprite> { RelativeSizeAxes = Axes.Both, Colour = Catcher.DEFAULT_HYPER_DASH_COLOUR },
|
hyperDashTrails = new Container<CatcherTrailSprite> { RelativeSizeAxes = Axes.Both, Colour = Catcher.DEFAULT_HYPER_DASH_COLOUR },
|
||||||
endGlowSprites = new Container<CatcherTrailSprite> { RelativeSizeAxes = Axes.Both, Colour = Catcher.DEFAULT_HYPER_DASH_COLOUR },
|
endGlowSprites = new Container<CatcherTrailSprite> { RelativeSizeAxes = Axes.Both, Colour = Catcher.DEFAULT_HYPER_DASH_COLOUR },
|
||||||
@ -118,14 +122,14 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
{
|
{
|
||||||
var texture = (catcher.CurrentDrawableCatcher as TextureAnimation)?.CurrentFrame ?? ((Sprite)catcher.CurrentDrawableCatcher).Texture;
|
var texture = (catcher.CurrentDrawableCatcher as TextureAnimation)?.CurrentFrame ?? ((Sprite)catcher.CurrentDrawableCatcher).Texture;
|
||||||
|
|
||||||
var sprite = new CatcherTrailSprite(texture)
|
CatcherTrailSprite sprite = trailPool.Get();
|
||||||
{
|
|
||||||
Anchor = catcher.Anchor,
|
sprite.Texture = texture;
|
||||||
Scale = catcher.Scale,
|
sprite.Anchor = catcher.Anchor;
|
||||||
Blending = BlendingParameters.Additive,
|
sprite.Scale = catcher.Scale;
|
||||||
RelativePositionAxes = catcher.RelativePositionAxes,
|
sprite.Blending = BlendingParameters.Additive;
|
||||||
Position = catcher.Position
|
sprite.RelativePositionAxes = catcher.RelativePositionAxes;
|
||||||
};
|
sprite.Position = catcher.Position;
|
||||||
|
|
||||||
target.Add(sprite);
|
target.Add(sprite);
|
||||||
|
|
||||||
|
@ -1,22 +1,40 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Pooling;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.UI
|
namespace osu.Game.Rulesets.Catch.UI
|
||||||
{
|
{
|
||||||
public class CatcherTrailSprite : Sprite
|
public class CatcherTrailSprite : PoolableDrawable
|
||||||
{
|
{
|
||||||
public CatcherTrailSprite(Texture texture)
|
public Texture Texture
|
||||||
{
|
{
|
||||||
Texture = texture;
|
set => sprite.Texture = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly Sprite sprite;
|
||||||
|
|
||||||
|
public CatcherTrailSprite()
|
||||||
|
{
|
||||||
|
InternalChild = sprite = new Sprite
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both
|
||||||
|
};
|
||||||
|
|
||||||
Size = new Vector2(CatcherArea.CATCHER_SIZE);
|
Size = new Vector2(CatcherArea.CATCHER_SIZE);
|
||||||
|
|
||||||
// Sets the origin roughly to the centre of the catcher's plate to allow for correct scaling.
|
// Sets the origin roughly to the centre of the catcher's plate to allow for correct scaling.
|
||||||
OriginPosition = new Vector2(0.5f, 0.06f) * CatcherArea.CATCHER_SIZE;
|
OriginPosition = new Vector2(0.5f, 0.06f) * CatcherArea.CATCHER_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void FreeAfterUse()
|
||||||
|
{
|
||||||
|
ClearTransforms();
|
||||||
|
base.FreeAfterUse();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@ using osu.Game.Configuration;
|
|||||||
using osu.Game.Input.Handlers;
|
using osu.Game.Input.Handlers;
|
||||||
using osu.Game.Replays;
|
using osu.Game.Replays;
|
||||||
using osu.Game.Rulesets.Catch.Objects;
|
using osu.Game.Rulesets.Catch.Objects;
|
||||||
using osu.Game.Rulesets.Catch.Objects.Drawables;
|
|
||||||
using osu.Game.Rulesets.Catch.Replays;
|
using osu.Game.Rulesets.Catch.Replays;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
@ -40,30 +39,6 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
|
|
||||||
protected override PassThroughInputManager CreateInputManager() => new CatchInputManager(Ruleset.RulesetInfo);
|
protected override PassThroughInputManager CreateInputManager() => new CatchInputManager(Ruleset.RulesetInfo);
|
||||||
|
|
||||||
public override DrawableHitObject<CatchHitObject> CreateDrawableRepresentation(CatchHitObject h)
|
public override DrawableHitObject<CatchHitObject> CreateDrawableRepresentation(CatchHitObject h) => null;
|
||||||
{
|
|
||||||
switch (h)
|
|
||||||
{
|
|
||||||
case Banana banana:
|
|
||||||
return new DrawableBanana(banana);
|
|
||||||
|
|
||||||
case Fruit fruit:
|
|
||||||
return new DrawableFruit(fruit);
|
|
||||||
|
|
||||||
case JuiceStream stream:
|
|
||||||
return new DrawableJuiceStream(stream, CreateDrawableRepresentation);
|
|
||||||
|
|
||||||
case BananaShower shower:
|
|
||||||
return new DrawableBananaShower(shower, CreateDrawableRepresentation);
|
|
||||||
|
|
||||||
case TinyDroplet tiny:
|
|
||||||
return new DrawableTinyDroplet(tiny);
|
|
||||||
|
|
||||||
case Droplet droplet:
|
|
||||||
return new DrawableDroplet(droplet);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,35 +5,45 @@ using osu.Framework.Extensions.Color4Extensions;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Effects;
|
using osu.Framework.Graphics.Effects;
|
||||||
|
using osu.Framework.Graphics.Pooling;
|
||||||
using osu.Framework.Utils;
|
using osu.Framework.Utils;
|
||||||
using osu.Game.Rulesets.Catch.Objects.Drawables;
|
using osu.Game.Rulesets.Catch.Objects;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.UI
|
namespace osu.Game.Rulesets.Catch.UI
|
||||||
{
|
{
|
||||||
public class HitExplosion : CompositeDrawable
|
public class HitExplosion : PoolableDrawable
|
||||||
{
|
{
|
||||||
private readonly CircularContainer largeFaint;
|
private Color4 objectColour;
|
||||||
|
public CatchHitObject HitObject;
|
||||||
|
|
||||||
public HitExplosion(DrawableCatchHitObject fruit)
|
public Color4 ObjectColour
|
||||||
|
{
|
||||||
|
get => objectColour;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (objectColour == value) return;
|
||||||
|
|
||||||
|
objectColour = value;
|
||||||
|
onColourChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly CircularContainer largeFaint;
|
||||||
|
private readonly CircularContainer smallFaint;
|
||||||
|
private readonly CircularContainer directionalGlow1;
|
||||||
|
private readonly CircularContainer directionalGlow2;
|
||||||
|
|
||||||
|
public HitExplosion()
|
||||||
{
|
{
|
||||||
Size = new Vector2(20);
|
Size = new Vector2(20);
|
||||||
Anchor = Anchor.TopCentre;
|
Anchor = Anchor.TopCentre;
|
||||||
Origin = Anchor.BottomCentre;
|
Origin = Anchor.BottomCentre;
|
||||||
|
|
||||||
Color4 objectColour = fruit.AccentColour.Value;
|
|
||||||
|
|
||||||
// scale roughly in-line with visual appearance of notes
|
// scale roughly in-line with visual appearance of notes
|
||||||
|
|
||||||
const float angle_variangle = 15; // should be less than 45
|
|
||||||
|
|
||||||
const float roundness = 100;
|
|
||||||
|
|
||||||
const float initial_height = 10;
|
const float initial_height = 10;
|
||||||
|
|
||||||
var colour = Interpolation.ValueAt(0.4f, objectColour, Color4.White, 0, 1);
|
|
||||||
|
|
||||||
InternalChildren = new Drawable[]
|
InternalChildren = new Drawable[]
|
||||||
{
|
{
|
||||||
largeFaint = new CircularContainer
|
largeFaint = new CircularContainer
|
||||||
@ -42,81 +52,84 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Masking = true,
|
Masking = true,
|
||||||
// we want our size to be very small so the glow dominates it.
|
|
||||||
Size = new Vector2(0.8f),
|
|
||||||
Blending = BlendingParameters.Additive,
|
Blending = BlendingParameters.Additive,
|
||||||
EdgeEffect = new EdgeEffectParameters
|
},
|
||||||
|
smallFaint = new CircularContainer
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Masking = true,
|
||||||
|
Blending = BlendingParameters.Additive,
|
||||||
|
},
|
||||||
|
directionalGlow1 = new CircularContainer
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Masking = true,
|
||||||
|
Size = new Vector2(0.01f, initial_height),
|
||||||
|
Blending = BlendingParameters.Additive,
|
||||||
|
},
|
||||||
|
directionalGlow2 = new CircularContainer
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Masking = true,
|
||||||
|
Size = new Vector2(0.01f, initial_height),
|
||||||
|
Blending = BlendingParameters.Additive,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void PrepareForUse()
|
||||||
|
{
|
||||||
|
base.PrepareForUse();
|
||||||
|
|
||||||
|
const double duration = 400;
|
||||||
|
|
||||||
|
// we want our size to be very small so the glow dominates it.
|
||||||
|
largeFaint.Size = new Vector2(0.8f);
|
||||||
|
largeFaint
|
||||||
|
.ResizeTo(largeFaint.Size * new Vector2(5, 1), duration, Easing.OutQuint)
|
||||||
|
.FadeOut(duration * 2);
|
||||||
|
|
||||||
|
const float angle_variangle = 15; // should be less than 45
|
||||||
|
directionalGlow1.Rotation = RNG.NextSingle(-angle_variangle, angle_variangle);
|
||||||
|
directionalGlow2.Rotation = RNG.NextSingle(-angle_variangle, angle_variangle);
|
||||||
|
|
||||||
|
this.FadeInFromZero(50).Then().FadeOut(duration, Easing.Out);
|
||||||
|
Expire(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onColourChanged()
|
||||||
|
{
|
||||||
|
const float roundness = 100;
|
||||||
|
|
||||||
|
largeFaint.EdgeEffect = new EdgeEffectParameters
|
||||||
{
|
{
|
||||||
Type = EdgeEffectType.Glow,
|
Type = EdgeEffectType.Glow,
|
||||||
Colour = Interpolation.ValueAt(0.1f, objectColour, Color4.White, 0, 1).Opacity(0.3f),
|
Colour = Interpolation.ValueAt(0.1f, objectColour, Color4.White, 0, 1).Opacity(0.3f),
|
||||||
Roundness = 160,
|
Roundness = 160,
|
||||||
Radius = 200,
|
Radius = 200,
|
||||||
},
|
};
|
||||||
},
|
|
||||||
new CircularContainer
|
smallFaint.EdgeEffect = new EdgeEffectParameters
|
||||||
{
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Masking = true,
|
|
||||||
Blending = BlendingParameters.Additive,
|
|
||||||
EdgeEffect = new EdgeEffectParameters
|
|
||||||
{
|
{
|
||||||
Type = EdgeEffectType.Glow,
|
Type = EdgeEffectType.Glow,
|
||||||
Colour = Interpolation.ValueAt(0.6f, objectColour, Color4.White, 0, 1),
|
Colour = Interpolation.ValueAt(0.6f, objectColour, Color4.White, 0, 1),
|
||||||
Roundness = 20,
|
Roundness = 20,
|
||||||
Radius = 50,
|
Radius = 50,
|
||||||
},
|
|
||||||
},
|
|
||||||
new CircularContainer
|
|
||||||
{
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Masking = true,
|
|
||||||
Size = new Vector2(0.01f, initial_height),
|
|
||||||
Blending = BlendingParameters.Additive,
|
|
||||||
Rotation = RNG.NextSingle(-angle_variangle, angle_variangle),
|
|
||||||
EdgeEffect = new EdgeEffectParameters
|
|
||||||
{
|
|
||||||
Type = EdgeEffectType.Glow,
|
|
||||||
Colour = colour,
|
|
||||||
Roundness = roundness,
|
|
||||||
Radius = 40,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
new CircularContainer
|
|
||||||
{
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Masking = true,
|
|
||||||
Size = new Vector2(0.01f, initial_height),
|
|
||||||
Blending = BlendingParameters.Additive,
|
|
||||||
Rotation = RNG.NextSingle(-angle_variangle, angle_variangle),
|
|
||||||
EdgeEffect = new EdgeEffectParameters
|
|
||||||
{
|
|
||||||
Type = EdgeEffectType.Glow,
|
|
||||||
Colour = colour,
|
|
||||||
Roundness = roundness,
|
|
||||||
Radius = 40,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
protected override void LoadComplete()
|
directionalGlow1.EdgeEffect = directionalGlow2.EdgeEffect = new EdgeEffectParameters
|
||||||
{
|
{
|
||||||
base.LoadComplete();
|
Type = EdgeEffectType.Glow,
|
||||||
|
Colour = Interpolation.ValueAt(0.4f, objectColour, Color4.White, 0, 1),
|
||||||
const double duration = 400;
|
Roundness = roundness,
|
||||||
|
Radius = 40,
|
||||||
largeFaint
|
};
|
||||||
.ResizeTo(largeFaint.Size * new Vector2(5, 1), duration, Easing.OutQuint)
|
|
||||||
.FadeOut(duration * 2);
|
|
||||||
|
|
||||||
this.FadeInFromZero(50).Then().FadeOut(duration, Easing.Out);
|
|
||||||
Expire(true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,6 +96,11 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor
|
|||||||
throw new System.NotImplementedException();
|
throw new System.NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override SnapResult SnapScreenSpacePositionToValidPosition(Vector2 screenSpacePosition)
|
||||||
|
{
|
||||||
|
throw new System.NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
public override float GetBeatSnapDistanceAt(double referenceTime)
|
public override float GetBeatSnapDistanceAt(double referenceTime)
|
||||||
{
|
{
|
||||||
throw new System.NotImplementedException();
|
throw new System.NotImplementedException();
|
||||||
|
@ -15,7 +15,7 @@ using osu.Game.Rulesets.Mania.Edit;
|
|||||||
using osu.Game.Rulesets.Mania.Edit.Blueprints;
|
using osu.Game.Rulesets.Mania.Edit.Blueprints;
|
||||||
using osu.Game.Rulesets.Mania.Objects;
|
using osu.Game.Rulesets.Mania.Objects;
|
||||||
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
|
using osu.Game.Rulesets.Mania.Skinning.Default;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.UI.Scrolling;
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
using osu.Game.Screens.Edit;
|
using osu.Game.Screens.Edit;
|
||||||
|
@ -24,7 +24,10 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning
|
|||||||
if (hitWindows.IsHitResultAllowed(result))
|
if (hitWindows.IsHitResultAllowed(result))
|
||||||
{
|
{
|
||||||
AddStep("Show " + result.GetDescription(), () => SetContents(() =>
|
AddStep("Show " + result.GetDescription(), () => SetContents(() =>
|
||||||
new DrawableManiaJudgement(new JudgementResult(new HitObject(), new Judgement()) { Type = result }, null)
|
new DrawableManiaJudgement(new JudgementResult(new HitObject { StartTime = Time.Current }, new Judgement())
|
||||||
|
{
|
||||||
|
Type = result
|
||||||
|
}, null)
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
|
@ -10,7 +10,7 @@ using osu.Framework.Graphics.Containers;
|
|||||||
using osu.Framework.Graphics.Pooling;
|
using osu.Framework.Graphics.Pooling;
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
using osu.Game.Rulesets.Mania.Judgements;
|
using osu.Game.Rulesets.Mania.Judgements;
|
||||||
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
|
using osu.Game.Rulesets.Mania.Skinning.Default;
|
||||||
using osu.Game.Rulesets.Mania.UI;
|
using osu.Game.Rulesets.Mania.UI;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<Import Project="..\osu.TestProject.props" />
|
<Import Project="..\osu.TestProject.props" />
|
||||||
<ItemGroup Label="Package References">
|
<ItemGroup Label="Package References">
|
||||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.0" />
|
||||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
||||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
|
using osu.Game.Rulesets.Mania.Skinning.Default;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Edit.Blueprints.Components
|
namespace osu.Game.Rulesets.Mania.Edit.Blueprints.Components
|
||||||
{
|
{
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
|
using osu.Game.Rulesets.Mania.Skinning.Default;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Edit.Blueprints.Components
|
namespace osu.Game.Rulesets.Mania.Edit.Blueprints.Components
|
||||||
{
|
{
|
||||||
|
@ -78,9 +78,9 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
|
|||||||
|
|
||||||
private double originalStartTime;
|
private double originalStartTime;
|
||||||
|
|
||||||
public override void UpdatePosition(SnapResult result)
|
public override void UpdateTimeAndPosition(SnapResult result)
|
||||||
{
|
{
|
||||||
base.UpdatePosition(result);
|
base.UpdateTimeAndPosition(result);
|
||||||
|
|
||||||
if (PlacementActive)
|
if (PlacementActive)
|
||||||
{
|
{
|
||||||
|
@ -48,9 +48,9 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void UpdatePosition(SnapResult result)
|
public override void UpdateTimeAndPosition(SnapResult result)
|
||||||
{
|
{
|
||||||
base.UpdatePosition(result);
|
base.UpdateTimeAndPosition(result);
|
||||||
|
|
||||||
if (!PlacementActive)
|
if (!PlacementActive)
|
||||||
Column = result.Playfield as Column;
|
Column = result.Playfield as Column;
|
||||||
|
@ -22,9 +22,9 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
|
|||||||
InternalChild = piece = new EditNotePiece { Origin = Anchor.Centre };
|
InternalChild = piece = new EditNotePiece { Origin = Anchor.Centre };
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void UpdatePosition(SnapResult result)
|
public override void UpdateTimeAndPosition(SnapResult result)
|
||||||
{
|
{
|
||||||
base.UpdatePosition(result);
|
base.UpdateTimeAndPosition(result);
|
||||||
|
|
||||||
if (result.Playfield != null)
|
if (result.Playfield != null)
|
||||||
{
|
{
|
||||||
|
@ -9,7 +9,7 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
|
using osu.Game.Rulesets.Mania.Skinning.Default;
|
||||||
using osu.Game.Rulesets.Mania.UI;
|
using osu.Game.Rulesets.Mania.UI;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
|
@ -26,7 +26,7 @@ using osu.Game.Rulesets.Mania.Configuration;
|
|||||||
using osu.Game.Rulesets.Mania.Difficulty;
|
using osu.Game.Rulesets.Mania.Difficulty;
|
||||||
using osu.Game.Rulesets.Mania.Edit;
|
using osu.Game.Rulesets.Mania.Edit;
|
||||||
using osu.Game.Rulesets.Mania.Scoring;
|
using osu.Game.Rulesets.Mania.Scoring;
|
||||||
using osu.Game.Rulesets.Mania.Skinning;
|
using osu.Game.Rulesets.Mania.Skinning.Legacy;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
|
@ -5,7 +5,7 @@ using osu.Game.Rulesets.Mods;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Mods
|
namespace osu.Game.Rulesets.Mania.Mods
|
||||||
{
|
{
|
||||||
public class ManiaModEasy : ModEasy
|
public class ManiaModEasy : ModEasyWithExtraLives
|
||||||
{
|
{
|
||||||
public override string Description => @"More forgiving HP drain, less accuracy required, and three lives!";
|
public override string Description => @"More forgiving HP drain, less accuracy required, and three lives!";
|
||||||
}
|
}
|
||||||
|
@ -4,9 +4,9 @@
|
|||||||
using System;
|
using System;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
|
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
|
using osu.Game.Rulesets.Mania.Skinning.Default;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
@ -30,6 +30,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
|
|
||||||
public void UpdateResult() => base.UpdateResult(true);
|
public void UpdateResult() => base.UpdateResult(true);
|
||||||
|
|
||||||
|
protected override double MaximumJudgementOffset => base.MaximumJudgementOffset * release_window_lenience;
|
||||||
|
|
||||||
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||||
{
|
{
|
||||||
Debug.Assert(HitObject.HitWindows != null);
|
Debug.Assert(HitObject.HitWindows != null);
|
||||||
|
@ -5,7 +5,7 @@ using System.Diagnostics;
|
|||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
|
using osu.Game.Rulesets.Mania.Skinning.Default;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Rulesets.UI.Scrolling;
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
|
@ -5,16 +5,17 @@ using System;
|
|||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osuTK.Graphics;
|
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Effects;
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Layout;
|
using osu.Framework.Layout;
|
||||||
|
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
|
namespace osu.Game.Rulesets.Mania.Skinning.Default
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents length-wise portion of a hold note.
|
/// Represents length-wise portion of a hold note.
|
@ -4,7 +4,6 @@
|
|||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osuTK.Graphics;
|
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
@ -12,8 +11,9 @@ using osu.Framework.Graphics.Effects;
|
|||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.UI.Scrolling;
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
|
namespace osu.Game.Rulesets.Mania.Skinning.Default
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents the static hit markers of notes.
|
/// Represents the static hit markers of notes.
|
@ -1,7 +1,7 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
|
namespace osu.Game.Rulesets.Mania.Skinning.Default
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Interface for mania hold note bodies.
|
/// Interface for mania hold note bodies.
|
@ -9,7 +9,7 @@ using osu.Game.Rulesets.Mania.UI;
|
|||||||
using osu.Game.Rulesets.UI.Scrolling;
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Skinning
|
namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
||||||
{
|
{
|
||||||
public class HitTargetInsetContainer : Container
|
public class HitTargetInsetContainer : Container
|
||||||
{
|
{
|
@ -14,7 +14,7 @@ using osu.Game.Rulesets.UI.Scrolling;
|
|||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Skinning
|
namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
||||||
{
|
{
|
||||||
public class LegacyBodyPiece : LegacyManiaColumnElement
|
public class LegacyBodyPiece : LegacyManiaColumnElement
|
||||||
{
|
{
|
@ -12,7 +12,7 @@ using osu.Game.Skinning;
|
|||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Skinning
|
namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
||||||
{
|
{
|
||||||
public class LegacyColumnBackground : LegacyManiaColumnElement, IKeyBindingHandler<ManiaAction>
|
public class LegacyColumnBackground : LegacyManiaColumnElement, IKeyBindingHandler<ManiaAction>
|
||||||
{
|
{
|
@ -13,7 +13,7 @@ using osu.Game.Rulesets.UI.Scrolling;
|
|||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Skinning
|
namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
||||||
{
|
{
|
||||||
public class LegacyHitExplosion : LegacyManiaColumnElement, IHitExplosion
|
public class LegacyHitExplosion : LegacyManiaColumnElement, IHitExplosion
|
||||||
{
|
{
|
@ -12,7 +12,7 @@ using osu.Game.Skinning;
|
|||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Skinning
|
namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
||||||
{
|
{
|
||||||
public class LegacyHitTarget : CompositeDrawable
|
public class LegacyHitTarget : CompositeDrawable
|
||||||
{
|
{
|
@ -4,7 +4,7 @@
|
|||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Skinning
|
namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
||||||
{
|
{
|
||||||
public class LegacyHoldNoteHeadPiece : LegacyNotePiece
|
public class LegacyHoldNoteHeadPiece : LegacyNotePiece
|
||||||
{
|
{
|
@ -6,7 +6,7 @@ using osu.Framework.Graphics.Textures;
|
|||||||
using osu.Game.Rulesets.UI.Scrolling;
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Skinning
|
namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
||||||
{
|
{
|
||||||
public class LegacyHoldNoteTailPiece : LegacyNotePiece
|
public class LegacyHoldNoteTailPiece : LegacyNotePiece
|
||||||
{
|
{
|
@ -12,7 +12,7 @@ using osu.Game.Rulesets.UI.Scrolling;
|
|||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Skinning
|
namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
||||||
{
|
{
|
||||||
public class LegacyKeyArea : LegacyManiaColumnElement, IKeyBindingHandler<ManiaAction>
|
public class LegacyKeyArea : LegacyManiaColumnElement, IKeyBindingHandler<ManiaAction>
|
||||||
{
|
{
|
@ -8,7 +8,7 @@ using osu.Game.Rulesets.Mania.Beatmaps;
|
|||||||
using osu.Game.Rulesets.Mania.UI;
|
using osu.Game.Rulesets.Mania.UI;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Skinning
|
namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A <see cref="CompositeDrawable"/> which is placed somewhere within a <see cref="Column"/>.
|
/// A <see cref="CompositeDrawable"/> which is placed somewhere within a <see cref="Column"/>.
|
@ -12,7 +12,7 @@ using osu.Game.Rulesets.UI.Scrolling;
|
|||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Skinning
|
namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
||||||
{
|
{
|
||||||
public class LegacyNotePiece : LegacyManiaColumnElement
|
public class LegacyNotePiece : LegacyManiaColumnElement
|
||||||
{
|
{
|
@ -12,7 +12,7 @@ using osu.Game.Skinning;
|
|||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Skinning
|
namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
||||||
{
|
{
|
||||||
public class LegacyStageBackground : CompositeDrawable
|
public class LegacyStageBackground : CompositeDrawable
|
||||||
{
|
{
|
@ -9,7 +9,7 @@ using osu.Game.Rulesets.UI.Scrolling;
|
|||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Skinning
|
namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
||||||
{
|
{
|
||||||
public class LegacyStageForeground : CompositeDrawable
|
public class LegacyStageForeground : CompositeDrawable
|
||||||
{
|
{
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user