mirror of
https://github.com/ppy/osu.git
synced 2024-11-11 11:07:52 +08:00
Merge branch 'master' into import-screen
This commit is contained in:
commit
26fa010fed
@ -1,7 +1,7 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="osu! SDL" type="DotNetProject" factoryName=".NET Project" folderName="osu!" activateToolWindowBeforeRun="false">
|
||||
<configuration default="false" name="osu! (legacy osuTK)" type="DotNetProject" factoryName=".NET Project" folderName="osu!" activateToolWindowBeforeRun="false">
|
||||
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Desktop/bin/Debug/netcoreapp3.1/osu!.dll" />
|
||||
<option name="PROGRAM_PARAMETERS" value="--sdl" />
|
||||
<option name="PROGRAM_PARAMETERS" value="--tk" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Desktop/bin/Debug/netcoreapp3.1" />
|
||||
<option name="PASS_PARENT_ENVS" value="1" />
|
||||
<option name="USE_EXTERNAL_CONSOLE" value="0" />
|
@ -52,6 +52,6 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.1202.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2020.1203.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2020.1214.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
@ -29,7 +29,7 @@
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.2.6" />
|
||||
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
|
||||
<PackageReference Include="DiscordRichPresence" Version="1.0.166" />
|
||||
<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. -->
|
||||
<PackageReference Include="System.IO.FileSystem.Primitives" Version="4.3.0" />
|
||||
<PackageReference Include="System.Runtime.Handles" Version="4.3.0" />
|
||||
|
@ -84,7 +84,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
|
||||
public float Position
|
||||
{
|
||||
get => HitObject?.X ?? position;
|
||||
get => HitObject?.EffectiveX ?? position;
|
||||
set => position = value;
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.IO.Stores;
|
||||
using osu.Game.Rulesets.Catch.Skinning;
|
||||
using osu.Game.Rulesets.Catch.Skinning.Legacy;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK.Graphics;
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
// 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 System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
@ -12,8 +13,12 @@ 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.Skinning;
|
||||
using osu.Game.Tests.Visual;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Tests
|
||||
@ -24,7 +29,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
[Resolved]
|
||||
private OsuConfigManager config { get; set; }
|
||||
|
||||
private Container droppedObjectContainer;
|
||||
private Container<CaughtObject> droppedObjectContainer;
|
||||
|
||||
private TestCatcher catcher;
|
||||
|
||||
@ -37,7 +42,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
};
|
||||
|
||||
var trailContainer = new Container();
|
||||
droppedObjectContainer = new Container();
|
||||
droppedObjectContainer = new Container<CaughtObject>();
|
||||
catcher = new TestCatcher(trailContainer, droppedObjectContainer, difficulty);
|
||||
|
||||
Child = new Container
|
||||
@ -52,6 +57,50 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
};
|
||||
});
|
||||
|
||||
[Test]
|
||||
public void TestCatcherHyperStateReverted()
|
||||
{
|
||||
DrawableCatchHitObject drawableObject1 = null;
|
||||
DrawableCatchHitObject drawableObject2 = null;
|
||||
JudgementResult result1 = null;
|
||||
JudgementResult result2 = null;
|
||||
AddStep("catch hyper fruit", () =>
|
||||
{
|
||||
attemptCatch(new Fruit { HyperDashTarget = new Fruit { X = 100 } }, out drawableObject1, out result1);
|
||||
});
|
||||
AddStep("catch normal fruit", () =>
|
||||
{
|
||||
attemptCatch(new Fruit(), out drawableObject2, out result2);
|
||||
});
|
||||
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", () =>
|
||||
{
|
||||
attemptCatch(new TestKiaiFruit(), out drawableObject, out result);
|
||||
});
|
||||
checkState(CatcherAnimationState.Kiai);
|
||||
AddStep("revert result", () =>
|
||||
{
|
||||
catcher.OnRevertResult(drawableObject, result);
|
||||
});
|
||||
checkState(CatcherAnimationState.Idle);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCatcherCatchWidth()
|
||||
{
|
||||
@ -149,13 +198,22 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
AddAssert("fruits are dropped", () => !catcher.CaughtObjects.Any() && droppedObjectContainer.Count == 10);
|
||||
}
|
||||
|
||||
[TestCase(true)]
|
||||
[TestCase(false)]
|
||||
public void TestHitLighting(bool enabled)
|
||||
[Test]
|
||||
public void TestHitLightingColour()
|
||||
{
|
||||
AddStep($"{(enabled ? "enable" : "disable")} hit lighting", () => config.Set(OsuSetting.HitLighting, enabled));
|
||||
var fruitColour = SkinConfiguration.DefaultComboColours[1];
|
||||
AddStep("enable hit lighting", () => config.Set(OsuSetting.HitLighting, true));
|
||||
AddStep("catch fruit", () => attemptCatch(new Fruit()));
|
||||
AddAssert("check hit lighting", () => catcher.ChildrenOfType<HitExplosion>().Any() == enabled);
|
||||
AddAssert("correct hit lighting colour", () =>
|
||||
catcher.ChildrenOfType<HitExplosion>().First()?.ObjectColour == fruitColour);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestHitLightingDisabled()
|
||||
{
|
||||
AddStep("disable hit lighting", () => config.Set(OsuSetting.HitLighting, false));
|
||||
AddStep("catch fruit", () => attemptCatch(new Fruit()));
|
||||
AddAssert("no hit lighting", () => !catcher.ChildrenOfType<HitExplosion>().Any());
|
||||
}
|
||||
|
||||
private void checkPlate(int count) => AddAssert($"{count} objects on the plate", () => catcher.CaughtObjects.Count() == count);
|
||||
@ -166,17 +224,60 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
|
||||
private void attemptCatch(CatchHitObject hitObject, int count = 1)
|
||||
{
|
||||
hitObject.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
catcher.AttemptCatch(hitObject);
|
||||
attemptCatch(hitObject, out _, out _);
|
||||
}
|
||||
|
||||
private void attemptCatch(CatchHitObject hitObject, out DrawableCatchHitObject drawableObject, out JudgementResult result)
|
||||
{
|
||||
hitObject.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||
drawableObject = createDrawableObject(hitObject);
|
||||
result = createResult(hitObject);
|
||||
applyResult(drawableObject, result);
|
||||
}
|
||||
|
||||
private void applyResult(DrawableCatchHitObject drawableObject, JudgementResult result)
|
||||
{
|
||||
// Load DHO to set colour of hit explosion correctly
|
||||
Add(drawableObject);
|
||||
drawableObject.OnLoadComplete += _ =>
|
||||
{
|
||||
catcher.OnNewResult(drawableObject, result);
|
||||
drawableObject.Expire();
|
||||
};
|
||||
}
|
||||
|
||||
private JudgementResult createResult(CatchHitObject hitObject)
|
||||
{
|
||||
return new CatchJudgementResult(hitObject, hitObject.CreateJudgement())
|
||||
{
|
||||
Type = catcher.CanCatch(hitObject) ? HitResult.Great : HitResult.Miss
|
||||
};
|
||||
}
|
||||
|
||||
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 IEnumerable<CaughtObject> CaughtObjects => this.ChildrenOfType<CaughtObject>();
|
||||
|
||||
public TestCatcher(Container trailsTarget, Container droppedObjectTarget, BeatmapDifficulty difficulty)
|
||||
public TestCatcher(Container trailsTarget, Container<CaughtObject> droppedObjectTarget, BeatmapDifficulty difficulty)
|
||||
: base(trailsTarget, droppedObjectTarget, difficulty)
|
||||
{
|
||||
}
|
||||
|
@ -15,7 +15,6 @@ using osu.Game.Rulesets.Catch.Judgements;
|
||||
using osu.Game.Rulesets.Catch.Objects;
|
||||
using osu.Game.Rulesets.Catch.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Catch.UI;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Tests
|
||||
@ -45,7 +44,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
|
||||
private void attemptCatch(Fruit fruit)
|
||||
{
|
||||
fruit.X += catcher.X;
|
||||
fruit.X = fruit.OriginalX + catcher.X;
|
||||
fruit.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty
|
||||
{
|
||||
CircleSize = circleSize
|
||||
@ -58,10 +57,9 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
|
||||
Schedule(() =>
|
||||
{
|
||||
bool caught = area.AttemptCatch(fruit);
|
||||
area.OnNewResult(drawable, new JudgementResult(fruit, new CatchJudgement())
|
||||
area.OnNewResult(drawable, new CatchJudgementResult(fruit, new CatchJudgement())
|
||||
{
|
||||
Type = caught ? HitResult.Great : HitResult.Miss
|
||||
Type = area.MovableCatcher.CanCatch(fruit) ? HitResult.Great : HitResult.Miss
|
||||
});
|
||||
|
||||
drawable.Expire();
|
||||
@ -75,7 +73,10 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
|
||||
SetContents(() =>
|
||||
{
|
||||
var droppedObjectContainer = new Container();
|
||||
var droppedObjectContainer = new Container<CaughtObject>
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both
|
||||
};
|
||||
|
||||
return new CatchInputManager(catchRuleset)
|
||||
{
|
||||
@ -101,7 +102,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
|
||||
private class TestCatcherArea : CatcherArea
|
||||
{
|
||||
public TestCatcherArea(Container droppedObjectContainer, BeatmapDifficulty beatmapDifficulty)
|
||||
public TestCatcherArea(Container<CaughtObject> droppedObjectContainer, BeatmapDifficulty beatmapDifficulty)
|
||||
: base(droppedObjectContainer, beatmapDifficulty)
|
||||
{
|
||||
}
|
||||
|
@ -5,19 +5,20 @@ using NUnit.Framework;
|
||||
using osu.Game.Rulesets.Catch.Objects;
|
||||
using osu.Game.Rulesets.Catch.Objects.Drawables;
|
||||
using osu.Game.Tests.Visual;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Tests
|
||||
{
|
||||
public class TestSceneFruitRandomness : OsuTestScene
|
||||
{
|
||||
private readonly TestDrawableFruit drawableFruit;
|
||||
private readonly TestDrawableBanana drawableBanana;
|
||||
private readonly DrawableFruit drawableFruit;
|
||||
private readonly DrawableBanana drawableBanana;
|
||||
|
||||
public TestSceneFruitRandomness()
|
||||
{
|
||||
drawableFruit = new TestDrawableFruit(new Fruit());
|
||||
drawableBanana = new TestDrawableBanana(new Banana());
|
||||
drawableFruit = new DrawableFruit(new Fruit());
|
||||
drawableBanana = new DrawableBanana(new Banana());
|
||||
|
||||
Add(new TestDrawableCatchHitObjectSpecimen(drawableFruit) { X = -200 });
|
||||
Add(new TestDrawableCatchHitObjectSpecimen(drawableBanana));
|
||||
@ -37,16 +38,16 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
|
||||
float fruitRotation = 0;
|
||||
float bananaRotation = 0;
|
||||
float bananaScale = 0;
|
||||
Vector2 bananaSize = new Vector2();
|
||||
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;
|
||||
fruitRotation = drawableFruit.DisplayRotation;
|
||||
bananaRotation = drawableBanana.DisplayRotation;
|
||||
bananaSize = drawableBanana.DisplaySize;
|
||||
bananaColour = drawableBanana.AccentColour.Value;
|
||||
});
|
||||
|
||||
@ -55,9 +56,9 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
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("fruit rotation is changed", () => drawableFruit.DisplayRotation != fruitRotation);
|
||||
AddAssert("banana rotation is changed", () => drawableBanana.DisplayRotation != bananaRotation);
|
||||
AddAssert("banana size is changed", () => drawableBanana.DisplaySize != bananaSize);
|
||||
AddAssert("banana colour is changed", () => drawableBanana.AccentColour.Value != bananaColour);
|
||||
|
||||
AddStep("reset start time", () =>
|
||||
@ -65,32 +66,11 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
drawableFruit.HitObject.StartTime = drawableBanana.HitObject.StartTime = initial_start_time;
|
||||
});
|
||||
|
||||
AddAssert("rotation and scale restored", () =>
|
||||
drawableFruit.InnerRotation == fruitRotation &&
|
||||
drawableBanana.InnerRotation == bananaRotation &&
|
||||
drawableBanana.InnerScale == bananaScale &&
|
||||
AddAssert("rotation and size restored", () =>
|
||||
drawableFruit.DisplayRotation == fruitRotation &&
|
||||
drawableBanana.DisplayRotation == bananaRotation &&
|
||||
drawableBanana.DisplaySize == bananaSize &&
|
||||
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)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Rulesets.Catch.Objects;
|
||||
using osu.Game.Rulesets.Catch.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Catch.Skinning;
|
||||
using osu.Game.Rulesets.Catch.Skinning.Legacy;
|
||||
using osu.Game.Rulesets.Catch.UI;
|
||||
using osu.Game.Skinning;
|
||||
using osu.Game.Tests.Visual;
|
||||
@ -117,7 +118,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
|
||||
AddStep("create hyper-dashing catcher", () =>
|
||||
{
|
||||
Child = setupSkinHierarchy(catcherArea = new CatcherArea(new Container())
|
||||
Child = setupSkinHierarchy(catcherArea = new CatcherArea(new Container<CaughtObject>())
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
|
@ -75,7 +75,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
|
||||
|
||||
case JuiceStream juiceStream:
|
||||
// Todo: BUG!! Stable used the last control point as the final position of the path, but it should use the computed path instead.
|
||||
lastPosition = juiceStream.X + juiceStream.Path.ControlPoints[^1].Position.Value.X;
|
||||
lastPosition = juiceStream.OriginalX + juiceStream.Path.ControlPoints[^1].Position.Value.X;
|
||||
|
||||
// Todo: BUG!! Stable attempted to use the end time of the stream, but referenced it too early in execution and used the start time instead.
|
||||
lastStartTime = juiceStream.StartTime;
|
||||
@ -86,7 +86,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
|
||||
catchObject.XOffset = 0;
|
||||
|
||||
if (catchObject is TinyDroplet)
|
||||
catchObject.XOffset = Math.Clamp(rng.Next(-20, 20), -catchObject.X, CatchPlayfield.WIDTH - catchObject.X);
|
||||
catchObject.XOffset = Math.Clamp(rng.Next(-20, 20), -catchObject.OriginalX, CatchPlayfield.WIDTH - catchObject.OriginalX);
|
||||
else if (catchObject is Droplet)
|
||||
rng.Next(); // osu!stable retrieved a random droplet rotation
|
||||
}
|
||||
@ -100,7 +100,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
|
||||
|
||||
private static void applyHardRockOffset(CatchHitObject hitObject, ref float? lastPosition, ref double lastStartTime, FastRandom rng)
|
||||
{
|
||||
float offsetPosition = hitObject.X;
|
||||
float offsetPosition = hitObject.OriginalX;
|
||||
double startTime = hitObject.StartTime;
|
||||
|
||||
if (lastPosition == null)
|
||||
@ -126,7 +126,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
|
||||
if (positionDiff == 0)
|
||||
{
|
||||
applyRandomOffset(ref offsetPosition, timeDiff / 4d, rng);
|
||||
hitObject.XOffset = offsetPosition - hitObject.X;
|
||||
hitObject.XOffset = offsetPosition - hitObject.OriginalX;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -134,7 +134,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
|
||||
if (Math.Abs(positionDiff) < timeDiff / 3)
|
||||
applyOffset(ref offsetPosition, positionDiff);
|
||||
|
||||
hitObject.XOffset = offsetPosition - hitObject.X;
|
||||
hitObject.XOffset = offsetPosition - hitObject.OriginalX;
|
||||
|
||||
lastPosition = offsetPosition;
|
||||
lastStartTime = startTime;
|
||||
@ -230,9 +230,9 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
|
||||
currentObject.HyperDashTarget = null;
|
||||
currentObject.DistanceToHyperDash = 0;
|
||||
|
||||
int thisDirection = nextObject.X > currentObject.X ? 1 : -1;
|
||||
int thisDirection = nextObject.EffectiveX > currentObject.EffectiveX ? 1 : -1;
|
||||
double timeToNext = nextObject.StartTime - currentObject.StartTime - 1000f / 60f / 4; // 1/4th of a frame of grace time, taken from osu-stable
|
||||
double distanceToNext = Math.Abs(nextObject.X - currentObject.X) - (lastDirection == thisDirection ? lastExcess : halfCatcherWidth);
|
||||
double distanceToNext = Math.Abs(nextObject.EffectiveX - currentObject.EffectiveX) - (lastDirection == thisDirection ? lastExcess : halfCatcherWidth);
|
||||
float distanceToHyper = (float)(timeToNext * Catcher.BASE_SPEED - distanceToNext);
|
||||
|
||||
if (distanceToHyper < 0)
|
||||
|
@ -21,7 +21,7 @@ using osu.Game.Rulesets.Difficulty;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Scoring;
|
||||
using System;
|
||||
using osu.Game.Rulesets.Catch.Skinning;
|
||||
using osu.Game.Rulesets.Catch.Skinning.Legacy;
|
||||
using osu.Game.Skinning;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch
|
||||
|
@ -5,11 +5,8 @@ namespace osu.Game.Rulesets.Catch
|
||||
{
|
||||
public enum CatchSkinComponents
|
||||
{
|
||||
FruitBananas,
|
||||
FruitApple,
|
||||
FruitGrapes,
|
||||
FruitOrange,
|
||||
FruitPear,
|
||||
Fruit,
|
||||
Banana,
|
||||
Droplet,
|
||||
CatcherIdle,
|
||||
CatcherFail,
|
||||
|
@ -32,8 +32,8 @@ namespace osu.Game.Rulesets.Catch.Difficulty.Preprocessing
|
||||
// We will scale everything by this factor, so we can assume a uniform CircleSize among beatmaps.
|
||||
var scalingFactor = normalized_hitobject_radius / halfCatcherWidth;
|
||||
|
||||
NormalizedPosition = BaseObject.X * scalingFactor;
|
||||
LastNormalizedPosition = LastObject.X * scalingFactor;
|
||||
NormalizedPosition = BaseObject.EffectiveX * scalingFactor;
|
||||
LastNormalizedPosition = LastObject.EffectiveX * scalingFactor;
|
||||
|
||||
// Every strain interval is hard capped at the equivalent of 375 BPM streaming speed as a safety measure
|
||||
StrainTime = Math.Max(40, DeltaTime);
|
||||
|
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)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
@ -14,7 +14,7 @@ using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Objects
|
||||
{
|
||||
public class Banana : Fruit, IHasComboInformation
|
||||
public class Banana : PalpableCatchHitObject, IHasComboInformation
|
||||
{
|
||||
/// <summary>
|
||||
/// Index of banana in current shower.
|
||||
|
@ -4,7 +4,6 @@
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Rulesets.Catch.Beatmaps;
|
||||
using osu.Game.Rulesets.Catch.UI;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
@ -16,38 +15,46 @@ namespace osu.Game.Rulesets.Catch.Objects
|
||||
{
|
||||
public const float OBJECT_RADIUS = 64;
|
||||
|
||||
// This value is after XOffset applied.
|
||||
public readonly Bindable<float> XBindable = new Bindable<float>();
|
||||
|
||||
// This value is before XOffset applied.
|
||||
private float originalX;
|
||||
public readonly Bindable<float> OriginalXBindable = new Bindable<float>();
|
||||
|
||||
/// <summary>
|
||||
/// The horizontal position of the fruit between 0 and <see cref="CatchPlayfield.WIDTH"/>.
|
||||
/// The horizontal position of the hit object between 0 and <see cref="CatchPlayfield.WIDTH"/>.
|
||||
/// </summary>
|
||||
public float X
|
||||
{
|
||||
// TODO: I don't like this asymmetry.
|
||||
get => XBindable.Value;
|
||||
// originalX is set by `XBindable.BindValueChanged`
|
||||
set => XBindable.Value = value + xOffset;
|
||||
set => OriginalXBindable.Value = value;
|
||||
}
|
||||
|
||||
private float xOffset;
|
||||
float IHasXPosition.X => OriginalXBindable.Value;
|
||||
|
||||
public readonly Bindable<float> XOffsetBindable = new Bindable<float>();
|
||||
|
||||
/// <summary>
|
||||
/// A random offset applied to <see cref="X"/>, set by the <see cref="CatchBeatmapProcessor"/>.
|
||||
/// A random offset applied to the horizontal position, set by the beatmap processing.
|
||||
/// </summary>
|
||||
internal float XOffset
|
||||
public float XOffset
|
||||
{
|
||||
get => xOffset;
|
||||
set
|
||||
{
|
||||
xOffset = value;
|
||||
XBindable.Value = originalX + xOffset;
|
||||
}
|
||||
set => XOffsetBindable.Value = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The horizontal position of the hit object between 0 and <see cref="CatchPlayfield.WIDTH"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is the original <see cref="X"/> value specified in the beatmap, not affected by the beatmap processing.
|
||||
/// Use <see cref="EffectiveX"/> for a gameplay.
|
||||
/// </remarks>
|
||||
public float OriginalX => OriginalXBindable.Value;
|
||||
|
||||
/// <summary>
|
||||
/// The effective horizontal position of the hit object between 0 and <see cref="CatchPlayfield.WIDTH"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is the original <see cref="X"/> value plus the offset applied by the beatmap processing.
|
||||
/// Use <see cref="OriginalX"/> if a value not affected by the offset is desired.
|
||||
/// </remarks>
|
||||
public float EffectiveX => OriginalXBindable.Value + XOffsetBindable.Value;
|
||||
|
||||
public double TimePreempt = 1000;
|
||||
|
||||
public readonly Bindable<int> IndexInBeatmapBindable = new Bindable<int>();
|
||||
@ -113,10 +120,5 @@ namespace osu.Game.Rulesets.Catch.Objects
|
||||
}
|
||||
|
||||
protected override HitWindows CreateHitWindows() => HitWindows.Empty;
|
||||
|
||||
protected CatchHitObject()
|
||||
{
|
||||
XBindable.BindValueChanged(x => originalX = x.NewValue - xOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
18
osu.Game.Rulesets.Catch/Objects/Drawables/CaughtBanana.cs
Normal file
18
osu.Game.Rulesets.Catch/Objects/Drawables/CaughtBanana.cs
Normal file
@ -0,0 +1,18 @@
|
||||
// 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.Game.Rulesets.Catch.Skinning.Default;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Objects.Drawables
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a <see cref="Banana"/> caught by the catcher.
|
||||
/// </summary>
|
||||
public class CaughtBanana : CaughtObject
|
||||
{
|
||||
public CaughtBanana()
|
||||
: base(CatchSkinComponents.Banana, _ => new BananaPiece())
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
20
osu.Game.Rulesets.Catch/Objects/Drawables/CaughtDroplet.cs
Normal file
20
osu.Game.Rulesets.Catch/Objects/Drawables/CaughtDroplet.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.Game.Rulesets.Catch.Skinning.Default;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Objects.Drawables
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a <see cref="Droplet"/> caught by the catcher.
|
||||
/// </summary>
|
||||
public class CaughtDroplet : CaughtObject
|
||||
{
|
||||
public override bool StaysOnPlate => false;
|
||||
|
||||
public CaughtDroplet()
|
||||
: base(CatchSkinComponents.Droplet, _ => new DropletPiece())
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
29
osu.Game.Rulesets.Catch/Objects/Drawables/CaughtFruit.cs
Normal file
29
osu.Game.Rulesets.Catch/Objects/Drawables/CaughtFruit.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.Bindables;
|
||||
using osu.Game.Rulesets.Catch.Skinning.Default;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Objects.Drawables
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a <see cref="Fruit"/> caught by the catcher.
|
||||
/// </summary>
|
||||
public class CaughtFruit : CaughtObject, IHasFruitState
|
||||
{
|
||||
public Bindable<FruitVisualRepresentation> VisualRepresentation { get; } = new Bindable<FruitVisualRepresentation>();
|
||||
|
||||
public CaughtFruit()
|
||||
: base(CatchSkinComponents.Fruit, _ => new FruitPiece())
|
||||
{
|
||||
}
|
||||
|
||||
public override void CopyStateFrom(IHasCatchObjectState objectState)
|
||||
{
|
||||
base.CopyStateFrom(objectState);
|
||||
|
||||
var fruitState = (IHasFruitState)objectState;
|
||||
VisualRepresentation.Value = fruitState.VisualRepresentation.Value;
|
||||
}
|
||||
}
|
||||
}
|
64
osu.Game.Rulesets.Catch/Objects/Drawables/CaughtObject.cs
Normal file
64
osu.Game.Rulesets.Catch/Objects/Drawables/CaughtObject.cs
Normal file
@ -0,0 +1,64 @@
|
||||
// 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.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Objects.Drawables
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a <see cref="PalpableCatchHitObject"/> caught by the catcher.
|
||||
/// </summary>
|
||||
[Cached(typeof(IHasCatchObjectState))]
|
||||
public abstract class CaughtObject : SkinnableDrawable, IHasCatchObjectState
|
||||
{
|
||||
public PalpableCatchHitObject HitObject { get; private set; }
|
||||
public Bindable<Color4> AccentColour { get; } = new Bindable<Color4>();
|
||||
public Bindable<bool> HyperDash { get; } = new Bindable<bool>();
|
||||
|
||||
public Vector2 DisplaySize => Size * Scale;
|
||||
|
||||
public float DisplayRotation => Rotation;
|
||||
|
||||
/// <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 override bool RemoveWhenNotAlive => true;
|
||||
|
||||
protected CaughtObject(CatchSkinComponents skinComponent, Func<ISkinComponent, Drawable> defaultImplementation)
|
||||
: base(new CatchSkinComponent(skinComponent), defaultImplementation)
|
||||
{
|
||||
Origin = Anchor.Centre;
|
||||
|
||||
RelativeSizeAxes = Axes.None;
|
||||
Size = new Vector2(CatchHitObject.OBJECT_RADIUS * 2);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies the hit object visual state from another <see cref="IHasCatchObjectState"/> object.
|
||||
/// </summary>
|
||||
public virtual void CopyStateFrom(IHasCatchObjectState objectState)
|
||||
{
|
||||
HitObject = objectState.HitObject;
|
||||
Scale = Vector2.Divide(objectState.DisplaySize, Size);
|
||||
Rotation = objectState.DisplayRotation;
|
||||
AccentColour.Value = objectState.AccentColour.Value;
|
||||
HyperDash.Value = objectState.HyperDash.Value;
|
||||
}
|
||||
|
||||
protected override void FreeAfterUse()
|
||||
{
|
||||
ClearTransforms();
|
||||
Alpha = 1;
|
||||
|
||||
base.FreeAfterUse();
|
||||
}
|
||||
}
|
||||
}
|
@ -2,14 +2,15 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using JetBrains.Annotations;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Catch.Skinning.Default;
|
||||
using osu.Game.Skinning;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Objects.Drawables
|
||||
{
|
||||
public class DrawableBanana : DrawableFruit
|
||||
public class DrawableBanana : DrawablePalpableCatchHitObject
|
||||
{
|
||||
protected override FruitVisualRepresentation GetVisualRepresentation(int indexInBeatmap) => FruitVisualRepresentation.Banana;
|
||||
|
||||
public DrawableBanana()
|
||||
: this(null)
|
||||
{
|
||||
@ -20,6 +21,14 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
|
||||
{
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
ScalingContainer.Child = new SkinnableDrawable(
|
||||
new CatchSkinComponent(CatchSkinComponents.Banana),
|
||||
_ => new BananaPiece());
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
@ -35,12 +44,12 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
|
||||
const float end_scale = 0.6f;
|
||||
const float random_scale_range = 1.6f;
|
||||
|
||||
ScaleContainer.ScaleTo(HitObject.Scale * (end_scale + random_scale_range * RandomSingle(3)))
|
||||
.Then().ScaleTo(HitObject.Scale * end_scale, HitObject.TimePreempt);
|
||||
ScalingContainer.ScaleTo(HitObject.Scale * (end_scale + random_scale_range * RandomSingle(3)))
|
||||
.Then().ScaleTo(HitObject.Scale * end_scale, HitObject.TimePreempt);
|
||||
|
||||
ScaleContainer.RotateTo(getRandomAngle(1))
|
||||
.Then()
|
||||
.RotateTo(getRandomAngle(2), HitObject.TimePreempt);
|
||||
ScalingContainer.RotateTo(getRandomAngle(1))
|
||||
.Then()
|
||||
.RotateTo(getRandomAngle(2), HitObject.TimePreempt);
|
||||
|
||||
float getRandomAngle(int series) => 180 * (RandomSingle(series) * 2 - 1);
|
||||
}
|
||||
|
@ -5,7 +5,9 @@ using System;
|
||||
using JetBrains.Annotations;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Catch.Judgements;
|
||||
using osu.Game.Rulesets.Catch.UI;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Utils;
|
||||
|
||||
@ -13,11 +15,12 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
|
||||
{
|
||||
public abstract class DrawableCatchHitObject : DrawableHitObject<CatchHitObject>
|
||||
{
|
||||
public readonly Bindable<float> XBindable = new Bindable<float>();
|
||||
public readonly Bindable<float> OriginalXBindable = new Bindable<float>();
|
||||
public readonly Bindable<float> XOffsetBindable = new Bindable<float>();
|
||||
|
||||
protected override double InitialLifetimeOffset => HitObject.TimePreempt;
|
||||
|
||||
protected override float SamplePlaybackPosition => HitObject.X / CatchPlayfield.WIDTH;
|
||||
protected override float SamplePlaybackPosition => HitObject.EffectiveX / CatchPlayfield.WIDTH;
|
||||
|
||||
public int RandomSeed => HitObject?.RandomSeed ?? 0;
|
||||
|
||||
@ -36,21 +39,21 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
|
||||
{
|
||||
base.OnApply();
|
||||
|
||||
XBindable.BindTo(HitObject.XBindable);
|
||||
OriginalXBindable.BindTo(HitObject.OriginalXBindable);
|
||||
XOffsetBindable.BindTo(HitObject.XOffsetBindable);
|
||||
}
|
||||
|
||||
protected override void OnFree()
|
||||
{
|
||||
base.OnFree();
|
||||
|
||||
XBindable.UnbindFrom(HitObject.XBindable);
|
||||
OriginalXBindable.UnbindFrom(HitObject.OriginalXBindable);
|
||||
XOffsetBindable.UnbindFrom(HitObject.XOffsetBindable);
|
||||
}
|
||||
|
||||
public Func<CatchHitObject, bool> CheckPosition;
|
||||
|
||||
public bool IsOnPlate;
|
||||
|
||||
public override bool RemoveWhenNotAlive => IsOnPlate;
|
||||
protected override JudgementResult CreateResult(Judgement judgement) => new CatchJudgementResult(HitObject, judgement);
|
||||
|
||||
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||
{
|
||||
|
@ -4,15 +4,13 @@
|
||||
using JetBrains.Annotations;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Catch.Objects.Drawables.Pieces;
|
||||
using osu.Game.Rulesets.Catch.Skinning.Default;
|
||||
using osu.Game.Skinning;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Objects.Drawables
|
||||
{
|
||||
public class DrawableDroplet : DrawablePalpableCatchHitObject
|
||||
{
|
||||
public override bool StaysOnPlate => false;
|
||||
|
||||
public DrawableDroplet()
|
||||
: this(null)
|
||||
{
|
||||
@ -26,17 +24,9 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
HyperDash.BindValueChanged(_ => updatePiece(), true);
|
||||
}
|
||||
|
||||
private void updatePiece()
|
||||
{
|
||||
ScaleContainer.Child = new SkinnableDrawable(
|
||||
ScalingContainer.Child = new SkinnableDrawable(
|
||||
new CatchSkinComponent(CatchSkinComponents.Droplet),
|
||||
_ => new DropletPiece
|
||||
{
|
||||
HyperDash = { BindTarget = HyperDash }
|
||||
});
|
||||
_ => new DropletPiece());
|
||||
}
|
||||
|
||||
protected override void UpdateInitialTransforms()
|
||||
@ -47,7 +37,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
|
||||
float startRotation = RandomSingle(1) * 20;
|
||||
double duration = HitObject.TimePreempt + 2000;
|
||||
|
||||
ScaleContainer.RotateTo(startRotation).RotateTo(startRotation + 720, duration);
|
||||
ScalingContainer.RotateTo(startRotation).RotateTo(startRotation + 720, duration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,21 +1,18 @@
|
||||
// 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;
|
||||
using osu.Game.Rulesets.Catch.Objects.Drawables.Pieces;
|
||||
using osu.Game.Rulesets.Catch.Skinning.Default;
|
||||
using osu.Game.Skinning;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Objects.Drawables
|
||||
{
|
||||
public class DrawableFruit : DrawablePalpableCatchHitObject
|
||||
public class DrawableFruit : DrawablePalpableCatchHitObject, IHasFruitState
|
||||
{
|
||||
public readonly Bindable<FruitVisualRepresentation> VisualRepresentation = new Bindable<FruitVisualRepresentation>();
|
||||
|
||||
protected virtual FruitVisualRepresentation GetVisualRepresentation(int indexInBeatmap) => (FruitVisualRepresentation)(indexInBeatmap % 4);
|
||||
public Bindable<FruitVisualRepresentation> VisualRepresentation { get; } = new Bindable<FruitVisualRepresentation>();
|
||||
|
||||
public DrawableFruit()
|
||||
: this(null)
|
||||
@ -32,53 +29,19 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
|
||||
{
|
||||
IndexInBeatmap.BindValueChanged(change =>
|
||||
{
|
||||
VisualRepresentation.Value = GetVisualRepresentation(change.NewValue);
|
||||
VisualRepresentation.Value = (FruitVisualRepresentation)(change.NewValue % 4);
|
||||
}, true);
|
||||
|
||||
VisualRepresentation.BindValueChanged(_ => updatePiece());
|
||||
HyperDash.BindValueChanged(_ => updatePiece(), true);
|
||||
ScalingContainer.Child = new SkinnableDrawable(
|
||||
new CatchSkinComponent(CatchSkinComponents.Fruit),
|
||||
_ => new FruitPiece());
|
||||
}
|
||||
|
||||
protected override void UpdateInitialTransforms()
|
||||
{
|
||||
base.UpdateInitialTransforms();
|
||||
|
||||
ScaleContainer.RotateTo((RandomSingle(1) - 0.5f) * 40);
|
||||
}
|
||||
|
||||
private void updatePiece()
|
||||
{
|
||||
ScaleContainer.Child = new SkinnableDrawable(
|
||||
new CatchSkinComponent(getComponent(VisualRepresentation.Value)),
|
||||
_ => new FruitPiece
|
||||
{
|
||||
VisualRepresentation = { BindTarget = VisualRepresentation },
|
||||
HyperDash = { BindTarget = HyperDash },
|
||||
});
|
||||
}
|
||||
|
||||
private CatchSkinComponents getComponent(FruitVisualRepresentation hitObjectVisualRepresentation)
|
||||
{
|
||||
switch (hitObjectVisualRepresentation)
|
||||
{
|
||||
case FruitVisualRepresentation.Pear:
|
||||
return CatchSkinComponents.FruitPear;
|
||||
|
||||
case FruitVisualRepresentation.Grape:
|
||||
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);
|
||||
}
|
||||
ScalingContainer.RotateTo((RandomSingle(1) - 0.5f) * 40);
|
||||
}
|
||||
}
|
||||
|
||||
@ -88,6 +51,5 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
|
||||
Grape,
|
||||
Pineapple,
|
||||
Raspberry,
|
||||
Banana // banananananannaanana
|
||||
}
|
||||
}
|
||||
|
@ -7,32 +7,36 @@ using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Objects.Drawables
|
||||
{
|
||||
public abstract class DrawablePalpableCatchHitObject : DrawableCatchHitObject
|
||||
[Cached(typeof(IHasCatchObjectState))]
|
||||
public abstract class DrawablePalpableCatchHitObject : DrawableCatchHitObject, IHasCatchObjectState
|
||||
{
|
||||
public new PalpableCatchHitObject HitObject => (PalpableCatchHitObject)base.HitObject;
|
||||
|
||||
public readonly Bindable<bool> HyperDash = new Bindable<bool>();
|
||||
Bindable<Color4> IHasCatchObjectState.AccentColour => AccentColour;
|
||||
|
||||
public readonly Bindable<float> ScaleBindable = new Bindable<float>(1);
|
||||
public Bindable<bool> HyperDash { get; } = new Bindable<bool>();
|
||||
|
||||
public readonly Bindable<int> IndexInBeatmap = new Bindable<int>();
|
||||
public Bindable<float> ScaleBindable { get; } = new Bindable<float>(1);
|
||||
|
||||
public Bindable<int> IndexInBeatmap { get; } = new Bindable<int>();
|
||||
|
||||
/// <summary>
|
||||
/// The multiplicative factor applied to <see cref="ScaleContainer"/> scale relative to <see cref="HitObject"/> scale.
|
||||
/// The multiplicative factor applied to <see cref="Drawable.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.
|
||||
/// The container internal transforms (such as scaling based on the circle size) are applied to.
|
||||
/// </summary>
|
||||
public virtual bool StaysOnPlate => true;
|
||||
protected readonly Container ScalingContainer;
|
||||
|
||||
public float DisplayRadius => CatchHitObject.OBJECT_RADIUS * HitObject.Scale * ScaleFactor;
|
||||
public Vector2 DisplaySize => ScalingContainer.Size * ScalingContainer.Scale;
|
||||
|
||||
protected readonly Container ScaleContainer;
|
||||
public float DisplayRotation => ScalingContainer.Rotation;
|
||||
|
||||
protected DrawablePalpableCatchHitObject([CanBeNull] CatchHitObject h)
|
||||
: base(h)
|
||||
@ -40,30 +44,34 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
|
||||
Origin = Anchor.Centre;
|
||||
Size = new Vector2(CatchHitObject.OBJECT_RADIUS * 2);
|
||||
|
||||
AddInternal(ScaleContainer = new Container
|
||||
AddInternal(ScalingContainer = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Size = new Vector2(CatchHitObject.OBJECT_RADIUS * 2)
|
||||
});
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
XBindable.BindValueChanged(x =>
|
||||
{
|
||||
if (!IsOnPlate) X = x.NewValue;
|
||||
}, true);
|
||||
OriginalXBindable.BindValueChanged(updateXPosition);
|
||||
XOffsetBindable.BindValueChanged(updateXPosition, true);
|
||||
|
||||
ScaleBindable.BindValueChanged(scale =>
|
||||
{
|
||||
ScaleContainer.Scale = new Vector2(scale.NewValue * ScaleFactor);
|
||||
ScalingContainer.Scale = new Vector2(scale.NewValue * ScaleFactor);
|
||||
Size = DisplaySize;
|
||||
}, true);
|
||||
|
||||
IndexInBeatmap.BindValueChanged(_ => UpdateComboColour());
|
||||
}
|
||||
|
||||
private void updateXPosition(ValueChangedEvent<float> _)
|
||||
{
|
||||
X = OriginalXBindable.Value + XOffsetBindable.Value;
|
||||
}
|
||||
|
||||
protected override void OnApply()
|
||||
{
|
||||
base.OnApply();
|
||||
|
@ -0,0 +1,25 @@
|
||||
// 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 osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Objects.Drawables
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a visual state of a <see cref="PalpableCatchHitObject"/>.
|
||||
/// </summary>
|
||||
public interface IHasCatchObjectState
|
||||
{
|
||||
PalpableCatchHitObject HitObject { get; }
|
||||
|
||||
Bindable<Color4> AccentColour { get; }
|
||||
|
||||
Bindable<bool> HyperDash { get; }
|
||||
|
||||
Vector2 DisplaySize { get; }
|
||||
|
||||
float DisplayRotation { get; }
|
||||
}
|
||||
}
|
15
osu.Game.Rulesets.Catch/Objects/Drawables/IHasFruitState.cs
Normal file
15
osu.Game.Rulesets.Catch/Objects/Drawables/IHasFruitState.cs
Normal file
@ -0,0 +1,15 @@
|
||||
// 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;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Objects.Drawables
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a visual state of a <see cref="Fruit"/>.
|
||||
/// </summary>
|
||||
public interface IHasFruitState : IHasCatchObjectState
|
||||
{
|
||||
Bindable<FruitVisualRepresentation> VisualRepresentation { get; }
|
||||
}
|
||||
}
|
@ -1,30 +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 osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Objects.Drawables.Pieces
|
||||
{
|
||||
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,37 +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.Game.Rulesets.Objects.Drawables;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Objects.Drawables.Pieces
|
||||
{
|
||||
public class DropletPiece : CompositeDrawable
|
||||
{
|
||||
public readonly Bindable<bool> HyperDash = new Bindable<bool>();
|
||||
|
||||
public DropletPiece()
|
||||
{
|
||||
Size = new Vector2(CatchHitObject.OBJECT_RADIUS / 2);
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(DrawableHitObject drawableObject)
|
||||
{
|
||||
InternalChild = new Pulp
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
AccentColour = { BindTarget = drawableObject.AccentColour }
|
||||
};
|
||||
|
||||
if (HyperDash.Value)
|
||||
{
|
||||
AddInternal(new HyperDropletBorderPiece());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,79 +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 JetBrains.Annotations;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Objects.Drawables.Pieces
|
||||
{
|
||||
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;
|
||||
|
||||
public readonly Bindable<FruitVisualRepresentation> VisualRepresentation = new Bindable<FruitVisualRepresentation>();
|
||||
public readonly Bindable<bool> HyperDash = new Bindable<bool>();
|
||||
|
||||
[CanBeNull]
|
||||
private DrawableCatchHitObject drawableHitObject;
|
||||
|
||||
[CanBeNull]
|
||||
private BorderPiece borderPiece;
|
||||
|
||||
public FruitPiece()
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader(permitNulls: true)]
|
||||
private void load([CanBeNull] DrawableHitObject drawable)
|
||||
{
|
||||
drawableHitObject = (DrawableCatchHitObject)drawable;
|
||||
|
||||
AddInternal(getFruitFor(VisualRepresentation.Value));
|
||||
|
||||
// if it is not part of a DHO, the border is always invisible.
|
||||
if (drawableHitObject != null)
|
||||
AddInternal(borderPiece = new BorderPiece());
|
||||
|
||||
if (HyperDash.Value)
|
||||
AddInternal(new HyperBorderPiece());
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
if (borderPiece != null && drawableHitObject?.HitObject != null)
|
||||
borderPiece.Alpha = (float)Math.Clamp((drawableHitObject.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,42 +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 osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Objects.Drawables.Pieces
|
||||
{
|
||||
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,42 +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 osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Objects.Drawables.Pieces
|
||||
{
|
||||
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,48 +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 osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Objects.Drawables.Pieces
|
||||
{
|
||||
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,48 +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 osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Objects.Drawables.Pieces
|
||||
{
|
||||
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),
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -75,7 +75,7 @@ namespace osu.Game.Rulesets.Catch.Objects
|
||||
AddNested(new TinyDroplet
|
||||
{
|
||||
StartTime = t + lastEvent.Value.Time,
|
||||
X = X + Path.PositionAt(
|
||||
X = OriginalX + Path.PositionAt(
|
||||
lastEvent.Value.PathProgress + (t / sinceLastTick) * (e.PathProgress - lastEvent.Value.PathProgress)).X,
|
||||
});
|
||||
}
|
||||
@ -93,7 +93,7 @@ namespace osu.Game.Rulesets.Catch.Objects
|
||||
{
|
||||
Samples = dropletSamples,
|
||||
StartTime = e.Time,
|
||||
X = X + Path.PositionAt(e.PathProgress).X,
|
||||
X = OriginalX + Path.PositionAt(e.PathProgress).X,
|
||||
});
|
||||
break;
|
||||
|
||||
@ -104,14 +104,14 @@ namespace osu.Game.Rulesets.Catch.Objects
|
||||
{
|
||||
Samples = this.GetNodeSamples(nodeIndex++),
|
||||
StartTime = e.Time,
|
||||
X = X + Path.PositionAt(e.PathProgress).X,
|
||||
X = OriginalX + Path.PositionAt(e.PathProgress).X,
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public float EndX => X + this.CurvePositionAt(1).X;
|
||||
public float EndX => OriginalX + this.CurvePositionAt(1).X;
|
||||
|
||||
public double Duration
|
||||
{
|
||||
|
@ -42,7 +42,7 @@ namespace osu.Game.Rulesets.Catch.Replays
|
||||
|
||||
void moveToNext(PalpableCatchHitObject h)
|
||||
{
|
||||
float positionChange = Math.Abs(lastPosition - h.X);
|
||||
float positionChange = Math.Abs(lastPosition - h.EffectiveX);
|
||||
double timeAvailable = h.StartTime - lastTime;
|
||||
|
||||
// So we can either make it there without a dash or not.
|
||||
@ -56,7 +56,7 @@ namespace osu.Game.Rulesets.Catch.Replays
|
||||
// todo: get correct catcher size, based on difficulty CS.
|
||||
const float catcher_width_half = CatcherArea.CATCHER_SIZE * 0.3f * 0.5f;
|
||||
|
||||
if (lastPosition - catcher_width_half < h.X && lastPosition + catcher_width_half > h.X)
|
||||
if (lastPosition - catcher_width_half < h.EffectiveX && lastPosition + catcher_width_half > h.EffectiveX)
|
||||
{
|
||||
// we are already in the correct range.
|
||||
lastTime = h.StartTime;
|
||||
@ -66,12 +66,12 @@ namespace osu.Game.Rulesets.Catch.Replays
|
||||
|
||||
if (impossibleJump)
|
||||
{
|
||||
addFrame(h.StartTime, h.X);
|
||||
addFrame(h.StartTime, h.EffectiveX);
|
||||
}
|
||||
else if (h.HyperDash)
|
||||
{
|
||||
addFrame(h.StartTime - timeAvailable, lastPosition);
|
||||
addFrame(h.StartTime, h.X);
|
||||
addFrame(h.StartTime, h.EffectiveX);
|
||||
}
|
||||
else if (dashRequired)
|
||||
{
|
||||
@ -80,23 +80,23 @@ namespace osu.Game.Rulesets.Catch.Replays
|
||||
double timeWeNeedToSave = timeAtNormalSpeed - timeAvailable;
|
||||
double timeAtDashSpeed = timeWeNeedToSave / 2;
|
||||
|
||||
float midPosition = (float)Interpolation.Lerp(lastPosition, h.X, (float)timeAtDashSpeed / timeAvailable);
|
||||
float midPosition = (float)Interpolation.Lerp(lastPosition, h.EffectiveX, (float)timeAtDashSpeed / timeAvailable);
|
||||
|
||||
// dash movement
|
||||
addFrame(h.StartTime - timeAvailable + 1, lastPosition, true);
|
||||
addFrame(h.StartTime - timeAvailable + timeAtDashSpeed, midPosition);
|
||||
addFrame(h.StartTime, h.X);
|
||||
addFrame(h.StartTime, h.EffectiveX);
|
||||
}
|
||||
else
|
||||
{
|
||||
double timeBefore = positionChange / movement_speed;
|
||||
|
||||
addFrame(h.StartTime - timeBefore, lastPosition);
|
||||
addFrame(h.StartTime, h.X);
|
||||
addFrame(h.StartTime, h.EffectiveX);
|
||||
}
|
||||
|
||||
lastTime = h.StartTime;
|
||||
lastPosition = h.X;
|
||||
lastPosition = h.EffectiveX;
|
||||
}
|
||||
|
||||
foreach (var obj in Beatmap.HitObjects)
|
||||
|
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));
|
||||
}
|
||||
}
|
||||
}
|
@ -3,10 +3,11 @@
|
||||
|
||||
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.Objects.Drawables.Pieces
|
||||
namespace osu.Game.Rulesets.Catch.Skinning.Default
|
||||
{
|
||||
public class BorderPiece : Circle
|
||||
{
|
@ -0,0 +1,54 @@
|
||||
// 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 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]
|
||||
protected IHasCatchObjectState ObjectState { 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();
|
||||
|
||||
AccentColour.BindTo(ObjectState.AccentColour);
|
||||
HyperDash.BindTo(ObjectState.HyperDash);
|
||||
|
||||
HyperDash.BindValueChanged(hyper =>
|
||||
{
|
||||
if (HyperBorderPiece != null)
|
||||
HyperBorderPiece.Alpha = hyper.NewValue ? 1 : 0;
|
||||
}, true);
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
if (BorderPiece != null)
|
||||
BorderPiece.Alpha = (float)Math.Clamp((ObjectState.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()
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
46
osu.Game.Rulesets.Catch/Skinning/Default/FruitPiece.cs
Normal file
46
osu.Game.Rulesets.Catch/Skinning/Default/FruitPiece.cs
Normal file
@ -0,0 +1,46 @@
|
||||
// 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 fruitState = (IHasFruitState)ObjectState;
|
||||
VisualRepresentation.BindTo(fruitState.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -4,7 +4,7 @@
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Catch.UI;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Objects.Drawables.Pieces
|
||||
namespace osu.Game.Rulesets.Catch.Skinning.Default
|
||||
{
|
||||
public class HyperBorderPiece : BorderPiece
|
||||
{
|
@ -1,7 +1,7 @@
|
||||
// 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.Objects.Drawables.Pieces
|
||||
namespace osu.Game.Rulesets.Catch.Skinning.Default
|
||||
{
|
||||
public class HyperDropletBorderPiece : HyperBorderPiece
|
||||
{
|
@ -8,10 +8,12 @@ using osu.Framework.Graphics.Effects;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Objects.Drawables.Pieces
|
||||
namespace osu.Game.Rulesets.Catch.Skinning.Default
|
||||
{
|
||||
public class Pulp : Circle
|
||||
{
|
||||
public readonly Bindable<Color4> AccentColour = new Bindable<Color4>();
|
||||
|
||||
public Pulp()
|
||||
{
|
||||
RelativePositionAxes = Axes.Both;
|
||||
@ -22,8 +24,6 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables.Pieces
|
||||
Colour = Color4.White.Opacity(0.9f);
|
||||
}
|
||||
|
||||
public readonly Bindable<Color4> AccentColour = new Bindable<Color4>();
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
@ -2,19 +2,17 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Objects.Drawables.Pieces
|
||||
namespace osu.Game.Rulesets.Catch.Skinning.Default
|
||||
{
|
||||
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 DISTANCE_FROM_CENTRE_3 = 0.15f;
|
||||
@ -24,6 +22,8 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables.Pieces
|
||||
|
||||
protected const float SMALL_PULP = LARGE_PULP_3 / 2;
|
||||
|
||||
private int pulpsInUse;
|
||||
|
||||
protected PulpFormation()
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
@ -33,11 +33,24 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables.Pieces
|
||||
distance * MathF.Sin(angle * MathF.PI / 180),
|
||||
distance * MathF.Cos(angle * MathF.PI / 180));
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(DrawableHitObject drawableObject)
|
||||
protected void Clear()
|
||||
{
|
||||
DrawableCatchHitObject drawableCatchObject = (DrawableCatchHitObject)drawableObject;
|
||||
AccentColour.BindTo(drawableCatchObject.AccentColour);
|
||||
for (int i = 0; i < pulpsInUse; i++)
|
||||
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.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using Humanizer;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
using static osu.Game.Skinning.LegacySkinConfiguration;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Skinning
|
||||
namespace osu.Game.Rulesets.Catch.Skinning.Legacy
|
||||
{
|
||||
public class CatchLegacySkinTransformer : LegacySkinTransformer
|
||||
{
|
||||
@ -40,20 +38,21 @@ namespace osu.Game.Rulesets.Catch.Skinning
|
||||
|
||||
switch (catchSkinComponent.Component)
|
||||
{
|
||||
case CatchSkinComponents.FruitApple:
|
||||
case CatchSkinComponents.FruitBananas:
|
||||
case CatchSkinComponents.FruitOrange:
|
||||
case CatchSkinComponents.FruitGrapes:
|
||||
case CatchSkinComponents.FruitPear:
|
||||
var lookupName = catchSkinComponent.Component.ToString().Kebaberize();
|
||||
if (GetTexture(lookupName) != null)
|
||||
return new LegacyFruitPiece(lookupName);
|
||||
case CatchSkinComponents.Fruit:
|
||||
if (GetTexture("fruit-pear") != null)
|
||||
return new LegacyFruitPiece();
|
||||
|
||||
break;
|
||||
|
||||
case CatchSkinComponents.Banana:
|
||||
if (GetTexture("fruit-bananas") != null)
|
||||
return new LegacyBananaPiece();
|
||||
|
||||
break;
|
||||
|
||||
case CatchSkinComponents.Droplet:
|
||||
if (GetTexture("fruit-drop") != null)
|
||||
return new LegacyFruitPiece("fruit-drop") { Scale = new Vector2(0.8f) };
|
||||
return new LegacyDropletPiece();
|
||||
|
||||
break;
|
||||
|
@ -9,7 +9,7 @@ using osuTK;
|
||||
using osuTK.Graphics;
|
||||
using static osu.Game.Skinning.LegacySkinConfiguration;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Skinning
|
||||
namespace osu.Game.Rulesets.Catch.Skinning.Legacy
|
||||
{
|
||||
/// <summary>
|
||||
/// A combo counter implementation that visually behaves almost similar to stable's osu!catch combo counter.
|
45
osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyFruitPiece.cs
Normal file
45
osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyFruitPiece.cs
Normal file
@ -0,0 +1,45 @@
|
||||
// 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 fruitState = (IHasFruitState)ObjectState;
|
||||
VisualRepresentation.BindTo(fruitState.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,90 @@
|
||||
// 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.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.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]
|
||||
protected IHasCatchObjectState ObjectState { 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();
|
||||
|
||||
AccentColour.BindTo(ObjectState.AccentColour);
|
||||
HyperDash.BindTo(ObjectState.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,83 +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 Bindable<Color4> accentColour = new Bindable<Color4>();
|
||||
private readonly Bindable<bool> hyperDash = new Bindable<bool>();
|
||||
private Sprite colouredSprite;
|
||||
|
||||
public LegacyFruitPiece(string lookupName)
|
||||
{
|
||||
this.lookupName = lookupName;
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(DrawableHitObject drawableObject, ISkinSource skin)
|
||||
{
|
||||
var drawableCatchObject = (DrawablePalpableCatchHitObject)drawableObject;
|
||||
|
||||
accentColour.BindTo(drawableCatchObject.AccentColour);
|
||||
hyperDash.BindTo(drawableCatchObject.HyperDash);
|
||||
|
||||
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 (hyperDash.Value)
|
||||
{
|
||||
var hyperDashOverlay = 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(hyperDashOverlay);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
accentColour.BindValueChanged(colour => colouredSprite.Colour = LegacyColourCompatibility.DisallowZeroAlpha(colour.NewValue), true);
|
||||
}
|
||||
}
|
||||
}
|
@ -36,7 +36,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
|
||||
public CatchPlayfield(BeatmapDifficulty difficulty, Func<CatchHitObject, DrawableHitObject<CatchHitObject>> createDrawableRepresentation)
|
||||
{
|
||||
var droppedObjectContainer = new Container
|
||||
var droppedObjectContainer = new Container<CaughtObject>
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
};
|
||||
@ -81,7 +81,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
((DrawableCatchHitObject)d).CheckPosition = checkIfWeCanCatch;
|
||||
}
|
||||
|
||||
private bool checkIfWeCanCatch(CatchHitObject obj) => CatcherArea.AttemptCatch(obj);
|
||||
private bool checkIfWeCanCatch(CatchHitObject obj) => CatcherArea.MovableCatcher.CanCatch(obj);
|
||||
|
||||
private void onNewResult(DrawableHitObject judgedObject, JudgementResult result)
|
||||
=> CatcherArea.OnNewResult((DrawableCatchHitObject)judgedObject, result);
|
||||
|
@ -14,9 +14,11 @@ using osu.Framework.Input.Bindings;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Beatmaps;
|
||||
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.Catch.Skinning;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
@ -51,9 +53,15 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
|
||||
private CatcherTrailDisplay trails;
|
||||
|
||||
private readonly Container droppedObjectTarget;
|
||||
/// <summary>
|
||||
/// Contains caught objects on the plate.
|
||||
/// </summary>
|
||||
private readonly Container<CaughtObject> caughtObjectContainer;
|
||||
|
||||
private readonly Container<DrawablePalpableCatchHitObject> caughtFruitContainer;
|
||||
/// <summary>
|
||||
/// Contains objects dropped from the plate.
|
||||
/// </summary>
|
||||
private readonly Container<CaughtObject> droppedObjectTarget;
|
||||
|
||||
public CatcherAnimationState CurrentState { get; private set; }
|
||||
|
||||
@ -106,7 +114,11 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
private readonly DrawablePool<HitExplosion> hitExplosionPool;
|
||||
private readonly Container<HitExplosion> hitExplosionContainer;
|
||||
|
||||
public Catcher([NotNull] Container trailsTarget, [NotNull] Container droppedObjectTarget, BeatmapDifficulty difficulty = null)
|
||||
private readonly DrawablePool<CaughtFruit> caughtFruitPool;
|
||||
private readonly DrawablePool<CaughtBanana> caughtBananaPool;
|
||||
private readonly DrawablePool<CaughtDroplet> caughtDropletPool;
|
||||
|
||||
public Catcher([NotNull] Container trailsTarget, [NotNull] Container<CaughtObject> droppedObjectTarget, BeatmapDifficulty difficulty = null)
|
||||
{
|
||||
this.trailsTarget = trailsTarget;
|
||||
this.droppedObjectTarget = droppedObjectTarget;
|
||||
@ -122,7 +134,11 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
hitExplosionPool = new DrawablePool<HitExplosion>(10),
|
||||
caughtFruitContainer = new Container<DrawablePalpableCatchHitObject>
|
||||
caughtFruitPool = new DrawablePool<CaughtFruit>(50),
|
||||
caughtBananaPool = new DrawablePool<CaughtBanana>(100),
|
||||
// less capacity is needed compared to fruit because droplet is not stacked
|
||||
caughtDropletPool = new DrawablePool<CaughtDroplet>(25),
|
||||
caughtObjectContainer = new Container<CaughtObject>
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.BottomCentre,
|
||||
@ -170,7 +186,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
/// <summary>
|
||||
/// Creates proxied content to be displayed beneath hitobjects.
|
||||
/// </summary>
|
||||
public Drawable CreateProxiedContent() => caughtFruitContainer.CreateProxy();
|
||||
public Drawable CreateProxiedContent() => caughtObjectContainer.CreateProxy();
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the scale of the catcher based off the provided beatmap difficulty.
|
||||
@ -190,11 +206,9 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
internal static float CalculateCatchWidth(BeatmapDifficulty difficulty) => CalculateCatchWidth(calculateScale(difficulty));
|
||||
|
||||
/// <summary>
|
||||
/// Let the catcher attempt to catch a fruit.
|
||||
/// Determine if this catcher can catch a <see cref="CatchHitObject"/> in the current position.
|
||||
/// </summary>
|
||||
/// <param name="hitObject">The fruit to catch.</param>
|
||||
/// <returns>Whether the catch is possible.</returns>
|
||||
public bool AttemptCatch(CatchHitObject hitObject)
|
||||
public bool CanCatch(CatchHitObject hitObject)
|
||||
{
|
||||
if (!(hitObject is PalpableCatchHitObject fruit))
|
||||
return false;
|
||||
@ -202,37 +216,72 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
var halfCatchWidth = catchWidth * 0.5f;
|
||||
|
||||
// this stuff wil disappear once we move fruit to non-relative coordinate space in the future.
|
||||
var catchObjectPosition = fruit.X;
|
||||
var catchObjectPosition = fruit.EffectiveX;
|
||||
var catcherPosition = Position.X;
|
||||
|
||||
var validCatch =
|
||||
catchObjectPosition >= catcherPosition - halfCatchWidth &&
|
||||
catchObjectPosition <= catcherPosition + halfCatchWidth;
|
||||
return catchObjectPosition >= catcherPosition - halfCatchWidth &&
|
||||
catchObjectPosition <= catcherPosition + halfCatchWidth;
|
||||
}
|
||||
|
||||
if (validCatch)
|
||||
placeCaughtObject(fruit);
|
||||
public void OnNewResult(DrawableCatchHitObject drawableObject, JudgementResult result)
|
||||
{
|
||||
var catchResult = (CatchJudgementResult)result;
|
||||
catchResult.CatcherAnimationState = CurrentState;
|
||||
catchResult.CatcherHyperDash = HyperDashing;
|
||||
|
||||
if (!(drawableObject is DrawablePalpableCatchHitObject palpableObject)) return;
|
||||
|
||||
var hitObject = palpableObject.HitObject;
|
||||
|
||||
if (result.IsHit)
|
||||
{
|
||||
var positionInStack = computePositionInStack(new Vector2(palpableObject.X - X, 0), palpableObject.DisplaySize.X / 2);
|
||||
|
||||
placeCaughtObject(palpableObject, positionInStack);
|
||||
|
||||
if (hitLighting.Value)
|
||||
addLighting(hitObject, positionInStack.X, drawableObject.AccentColour.Value);
|
||||
}
|
||||
|
||||
// droplet doesn't affect the catcher state
|
||||
if (fruit is TinyDroplet) return validCatch;
|
||||
if (hitObject is TinyDroplet) return;
|
||||
|
||||
if (validCatch && fruit.HyperDash)
|
||||
if (result.IsHit && hitObject.HyperDash)
|
||||
{
|
||||
var target = fruit.HyperDashTarget;
|
||||
var timeDifference = target.StartTime - fruit.StartTime;
|
||||
double positionDifference = target.X - catcherPosition;
|
||||
var target = hitObject.HyperDashTarget;
|
||||
var timeDifference = target.StartTime - hitObject.StartTime;
|
||||
double positionDifference = target.EffectiveX - X;
|
||||
var velocity = positionDifference / Math.Max(1.0, timeDifference - 1000.0 / 60.0);
|
||||
|
||||
SetHyperDashState(Math.Abs(velocity), target.X);
|
||||
SetHyperDashState(Math.Abs(velocity), target.EffectiveX);
|
||||
}
|
||||
else
|
||||
SetHyperDashState();
|
||||
|
||||
if (validCatch)
|
||||
updateState(fruit.Kiai ? CatcherAnimationState.Kiai : CatcherAnimationState.Idle);
|
||||
else if (!(fruit is Banana))
|
||||
if (result.IsHit)
|
||||
updateState(hitObject.Kiai ? CatcherAnimationState.Kiai : CatcherAnimationState.Idle);
|
||||
else if (!(hitObject is Banana))
|
||||
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();
|
||||
}
|
||||
|
||||
caughtObjectContainer.RemoveAll(d => d.HitObject == drawableObject.HitObject);
|
||||
droppedObjectTarget.RemoveAll(d => d.HitObject == drawableObject.HitObject);
|
||||
hitExplosionContainer.RemoveAll(d => d.HitObject == drawableObject.HitObject);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -415,137 +464,121 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
updateCatcher();
|
||||
}
|
||||
|
||||
private void placeCaughtObject(PalpableCatchHitObject source)
|
||||
private void placeCaughtObject(DrawablePalpableCatchHitObject drawableObject, Vector2 position)
|
||||
{
|
||||
var caughtObject = createCaughtObject(source);
|
||||
var caughtObject = getCaughtObject(drawableObject.HitObject);
|
||||
|
||||
if (caughtObject == null) return;
|
||||
|
||||
caughtObject.RelativePositionAxes = Axes.None;
|
||||
caughtObject.X = source.X - X;
|
||||
caughtObject.IsOnPlate = true;
|
||||
|
||||
caughtObject.CopyStateFrom(drawableObject);
|
||||
caughtObject.Anchor = Anchor.TopCentre;
|
||||
caughtObject.Origin = Anchor.Centre;
|
||||
caughtObject.Scale *= 0.5f;
|
||||
caughtObject.LifetimeStart = source.StartTime;
|
||||
caughtObject.LifetimeEnd = double.MaxValue;
|
||||
caughtObject.Position = position;
|
||||
caughtObject.Scale /= 2;
|
||||
|
||||
adjustPositionInStack(caughtObject);
|
||||
|
||||
caughtFruitContainer.Add(caughtObject);
|
||||
|
||||
addLighting(caughtObject);
|
||||
caughtObjectContainer.Add(caughtObject);
|
||||
|
||||
if (!caughtObject.StaysOnPlate)
|
||||
removeFromPlate(caughtObject, DroppedObjectAnimation.Explode);
|
||||
}
|
||||
|
||||
private void adjustPositionInStack(DrawablePalpableCatchHitObject caughtObject)
|
||||
private Vector2 computePositionInStack(Vector2 position, float displayRadius)
|
||||
{
|
||||
const float radius_div_2 = CatchHitObject.OBJECT_RADIUS / 2;
|
||||
const float allowance = 10;
|
||||
|
||||
float caughtObjectRadius = caughtObject.DisplayRadius;
|
||||
|
||||
while (caughtFruitContainer.Any(f => Vector2Extensions.Distance(f.Position, caughtObject.Position) < (caughtObjectRadius + radius_div_2) / (allowance / 2)))
|
||||
while (caughtObjectContainer.Any(f => Vector2Extensions.Distance(f.Position, position) < (displayRadius + radius_div_2) / (allowance / 2)))
|
||||
{
|
||||
float diff = (caughtObjectRadius + radius_div_2) / allowance;
|
||||
float diff = (displayRadius + radius_div_2) / allowance;
|
||||
|
||||
caughtObject.X += (RNG.NextSingle() - 0.5f) * diff * 2;
|
||||
caughtObject.Y -= RNG.NextSingle() * diff;
|
||||
position.X += (RNG.NextSingle() - 0.5f) * diff * 2;
|
||||
position.Y -= RNG.NextSingle() * diff;
|
||||
}
|
||||
|
||||
caughtObject.X = Math.Clamp(caughtObject.X, -CatcherArea.CATCHER_SIZE / 2, CatcherArea.CATCHER_SIZE / 2);
|
||||
position.X = Math.Clamp(position.X, -CatcherArea.CATCHER_SIZE / 2, CatcherArea.CATCHER_SIZE / 2);
|
||||
|
||||
return position;
|
||||
}
|
||||
|
||||
private void addLighting(DrawablePalpableCatchHitObject caughtObject)
|
||||
private void addLighting(CatchHitObject hitObject, float x, Color4 colour)
|
||||
{
|
||||
if (!hitLighting.Value) return;
|
||||
|
||||
HitExplosion hitExplosion = hitExplosionPool.Get();
|
||||
hitExplosion.X = caughtObject.X;
|
||||
hitExplosion.Scale = new Vector2(caughtObject.HitObject.Scale);
|
||||
hitExplosion.ObjectColour = caughtObject.AccentColour.Value;
|
||||
hitExplosion.HitObject = hitObject;
|
||||
hitExplosion.X = x;
|
||||
hitExplosion.Scale = new Vector2(hitObject.Scale);
|
||||
hitExplosion.ObjectColour = colour;
|
||||
hitExplosionContainer.Add(hitExplosion);
|
||||
}
|
||||
|
||||
private DrawablePalpableCatchHitObject createCaughtObject(PalpableCatchHitObject source)
|
||||
private CaughtObject getCaughtObject(PalpableCatchHitObject source)
|
||||
{
|
||||
switch (source)
|
||||
{
|
||||
case Banana banana:
|
||||
return new DrawableBanana(banana);
|
||||
case Fruit _:
|
||||
return caughtFruitPool.Get();
|
||||
|
||||
case Fruit fruit:
|
||||
return new DrawableFruit(fruit);
|
||||
case Banana _:
|
||||
return caughtBananaPool.Get();
|
||||
|
||||
case TinyDroplet tiny:
|
||||
return new DrawableTinyDroplet(tiny);
|
||||
|
||||
case Droplet droplet:
|
||||
return new DrawableDroplet(droplet);
|
||||
case Droplet _:
|
||||
return caughtDropletPool.Get();
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private CaughtObject getDroppedObject(CaughtObject caughtObject)
|
||||
{
|
||||
var droppedObject = getCaughtObject(caughtObject.HitObject);
|
||||
|
||||
droppedObject.CopyStateFrom(caughtObject);
|
||||
droppedObject.Anchor = Anchor.TopLeft;
|
||||
droppedObject.Position = caughtObjectContainer.ToSpaceOfOtherDrawable(caughtObject.DrawPosition, droppedObjectTarget);
|
||||
|
||||
return droppedObject;
|
||||
}
|
||||
|
||||
private void clearPlate(DroppedObjectAnimation animation)
|
||||
{
|
||||
var caughtObjects = caughtFruitContainer.Children.ToArray();
|
||||
caughtFruitContainer.Clear(false);
|
||||
var droppedObjects = caughtObjectContainer.Children.Select(getDroppedObject).ToArray();
|
||||
|
||||
droppedObjectTarget.AddRange(caughtObjects);
|
||||
caughtObjectContainer.Clear(false);
|
||||
|
||||
foreach (var caughtObject in caughtObjects)
|
||||
drop(caughtObject, animation);
|
||||
droppedObjectTarget.AddRange(droppedObjects);
|
||||
|
||||
foreach (var droppedObject in droppedObjects)
|
||||
applyDropAnimation(droppedObject, animation);
|
||||
}
|
||||
|
||||
private void removeFromPlate(DrawablePalpableCatchHitObject caughtObject, DroppedObjectAnimation animation)
|
||||
private void removeFromPlate(CaughtObject caughtObject, DroppedObjectAnimation animation)
|
||||
{
|
||||
if (!caughtFruitContainer.Remove(caughtObject))
|
||||
throw new InvalidOperationException("Can only drop a caught object on the plate");
|
||||
var droppedObject = getDroppedObject(caughtObject);
|
||||
|
||||
droppedObjectTarget.Add(caughtObject);
|
||||
caughtObjectContainer.Remove(caughtObject);
|
||||
|
||||
drop(caughtObject, animation);
|
||||
droppedObjectTarget.Add(droppedObject);
|
||||
|
||||
applyDropAnimation(droppedObject, animation);
|
||||
}
|
||||
|
||||
private void drop(DrawablePalpableCatchHitObject d, DroppedObjectAnimation animation)
|
||||
private void applyDropAnimation(Drawable 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)
|
||||
{
|
||||
switch (animation)
|
||||
{
|
||||
case DroppedObjectAnimation.Drop:
|
||||
d.MoveToY(d.Y + 75, 750, Easing.InSine);
|
||||
d.FadeOut(750);
|
||||
break;
|
||||
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();
|
||||
case DroppedObjectAnimation.Explode:
|
||||
var originalX = droppedObjectTarget.ToSpaceOfOtherDrawable(d.DrawPosition, caughtObjectContainer).X * Scale.X;
|
||||
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
|
||||
|
@ -5,7 +5,6 @@ using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Catch.Judgements;
|
||||
using osu.Game.Rulesets.Catch.Objects;
|
||||
using osu.Game.Rulesets.Catch.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Catch.Replays;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
@ -22,7 +21,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
public readonly Catcher MovableCatcher;
|
||||
private readonly CatchComboDisplay comboDisplay;
|
||||
|
||||
public CatcherArea(Container droppedObjectContainer, BeatmapDifficulty difficulty = null)
|
||||
public CatcherArea(Container<CaughtObject> droppedObjectContainer, BeatmapDifficulty difficulty = null)
|
||||
{
|
||||
Size = new Vector2(CatchPlayfield.WIDTH, CATCHER_SIZE);
|
||||
Children = new Drawable[]
|
||||
@ -42,6 +41,8 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
|
||||
public void OnNewResult(DrawableCatchHitObject hitObject, JudgementResult result)
|
||||
{
|
||||
MovableCatcher.OnNewResult(hitObject, result);
|
||||
|
||||
if (!result.Type.IsScorable())
|
||||
return;
|
||||
|
||||
@ -56,12 +57,10 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
comboDisplay.OnNewResult(hitObject, result);
|
||||
}
|
||||
|
||||
public void OnRevertResult(DrawableCatchHitObject fruit, JudgementResult result)
|
||||
=> comboDisplay.OnRevertResult(fruit, result);
|
||||
|
||||
public bool AttemptCatch(CatchHitObject obj)
|
||||
public void OnRevertResult(DrawableCatchHitObject hitObject, JudgementResult result)
|
||||
{
|
||||
return MovableCatcher.AttemptCatch(obj);
|
||||
comboDisplay.OnRevertResult(hitObject, result);
|
||||
MovableCatcher.OnRevertResult(hitObject, result);
|
||||
}
|
||||
|
||||
protected override void UpdateAfterChildren()
|
||||
|
@ -6,6 +6,7 @@ using JetBrains.Annotations;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Animations;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Pooling;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
@ -20,6 +21,8 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
{
|
||||
private readonly Catcher catcher;
|
||||
|
||||
private readonly DrawablePool<CatcherTrailSprite> trailPool;
|
||||
|
||||
private readonly Container<CatcherTrailSprite> dashTrails;
|
||||
private readonly Container<CatcherTrailSprite> hyperDashTrails;
|
||||
private readonly Container<CatcherTrailSprite> endGlowSprites;
|
||||
@ -80,8 +83,9 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
|
||||
InternalChildren = new[]
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
trailPool = new DrawablePool<CatcherTrailSprite>(30),
|
||||
dashTrails = new Container<CatcherTrailSprite> { RelativeSizeAxes = Axes.Both },
|
||||
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 },
|
||||
@ -118,14 +122,14 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
{
|
||||
var texture = (catcher.CurrentDrawableCatcher as TextureAnimation)?.CurrentFrame ?? ((Sprite)catcher.CurrentDrawableCatcher).Texture;
|
||||
|
||||
var sprite = new CatcherTrailSprite(texture)
|
||||
{
|
||||
Anchor = catcher.Anchor,
|
||||
Scale = catcher.Scale,
|
||||
Blending = BlendingParameters.Additive,
|
||||
RelativePositionAxes = catcher.RelativePositionAxes,
|
||||
Position = catcher.Position
|
||||
};
|
||||
CatcherTrailSprite sprite = trailPool.Get();
|
||||
|
||||
sprite.Texture = texture;
|
||||
sprite.Anchor = catcher.Anchor;
|
||||
sprite.Scale = catcher.Scale;
|
||||
sprite.Blending = BlendingParameters.Additive;
|
||||
sprite.RelativePositionAxes = catcher.RelativePositionAxes;
|
||||
sprite.Position = catcher.Position;
|
||||
|
||||
target.Add(sprite);
|
||||
|
||||
|
@ -1,22 +1,40 @@
|
||||
// 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.Pooling;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osuTK;
|
||||
|
||||
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);
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
protected override void FreeAfterUse()
|
||||
{
|
||||
ClearTransforms();
|
||||
base.FreeAfterUse();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Effects;
|
||||
using osu.Framework.Graphics.Pooling;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Rulesets.Catch.Objects;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
@ -15,6 +16,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
public class HitExplosion : PoolableDrawable
|
||||
{
|
||||
private Color4 objectColour;
|
||||
public CatchHitObject HitObject;
|
||||
|
||||
public Color4 ObjectColour
|
||||
{
|
||||
|
@ -15,7 +15,7 @@ using osu.Game.Rulesets.Mania.Edit;
|
||||
using osu.Game.Rulesets.Mania.Edit.Blueprints;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
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.UI.Scrolling;
|
||||
using osu.Game.Screens.Edit;
|
||||
|
@ -10,7 +10,7 @@ using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Pooling;
|
||||
using osu.Game.Rulesets.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.Objects;
|
||||
using osuTK;
|
||||
|
@ -4,7 +4,7 @@
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.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
|
||||
{
|
||||
|
@ -4,7 +4,7 @@
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
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
|
||||
{
|
||||
|
@ -9,7 +9,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
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.Mods;
|
||||
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.Edit;
|
||||
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.Skinning;
|
||||
using osu.Game.Scoring;
|
||||
|
@ -4,9 +4,9 @@
|
||||
using System;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Input.Bindings;
|
||||
using osu.Game.Rulesets.Mania.Skinning.Default;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
|
@ -5,7 +5,7 @@ using System.Diagnostics;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
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.UI.Scrolling;
|
||||
using osu.Game.Skinning;
|
||||
|
@ -5,16 +5,17 @@ using System;
|
||||
using JetBrains.Annotations;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osuTK.Graphics;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Effects;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Layout;
|
||||
using osu.Game.Rulesets.Mania.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>
|
||||
/// Represents length-wise portion of a hold note.
|
@ -4,7 +4,6 @@
|
||||
using JetBrains.Annotations;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osuTK.Graphics;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
@ -12,8 +11,9 @@ using osu.Framework.Graphics.Effects;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
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>
|
||||
/// Represents the static hit markers of notes.
|
@ -1,7 +1,7 @@
|
||||
// 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.Mania.Objects.Drawables.Pieces
|
||||
namespace osu.Game.Rulesets.Mania.Skinning.Default
|
||||
{
|
||||
/// <summary>
|
||||
/// 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.Skinning;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Skinning
|
||||
namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
||||
{
|
||||
public class HitTargetInsetContainer : Container
|
||||
{
|
@ -14,7 +14,7 @@ using osu.Game.Rulesets.UI.Scrolling;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Skinning
|
||||
namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
||||
{
|
||||
public class LegacyBodyPiece : LegacyManiaColumnElement
|
||||
{
|
@ -12,7 +12,7 @@ using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Skinning
|
||||
namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
||||
{
|
||||
public class LegacyColumnBackground : LegacyManiaColumnElement, IKeyBindingHandler<ManiaAction>
|
||||
{
|
@ -13,7 +13,7 @@ using osu.Game.Rulesets.UI.Scrolling;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Skinning
|
||||
namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
||||
{
|
||||
public class LegacyHitExplosion : LegacyManiaColumnElement, IHitExplosion
|
||||
{
|
@ -12,7 +12,7 @@ using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Skinning
|
||||
namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
||||
{
|
||||
public class LegacyHitTarget : CompositeDrawable
|
||||
{
|
@ -4,7 +4,7 @@
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Game.Skinning;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Skinning
|
||||
namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
||||
{
|
||||
public class LegacyHoldNoteHeadPiece : LegacyNotePiece
|
||||
{
|
@ -6,7 +6,7 @@ using osu.Framework.Graphics.Textures;
|
||||
using osu.Game.Rulesets.UI.Scrolling;
|
||||
using osu.Game.Skinning;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Skinning
|
||||
namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
||||
{
|
||||
public class LegacyHoldNoteTailPiece : LegacyNotePiece
|
||||
{
|
@ -12,7 +12,7 @@ using osu.Game.Rulesets.UI.Scrolling;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Skinning
|
||||
namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
||||
{
|
||||
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.Skinning;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Skinning
|
||||
namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
||||
{
|
||||
/// <summary>
|
||||
/// A <see cref="CompositeDrawable"/> which is placed somewhere within a <see cref="Column"/>.
|
@ -0,0 +1,90 @@
|
||||
// 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.Animations;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Mania.UI;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
||||
{
|
||||
public class LegacyManiaJudgementPiece : CompositeDrawable, IAnimatableJudgement
|
||||
{
|
||||
private readonly HitResult result;
|
||||
private readonly Drawable animation;
|
||||
|
||||
public LegacyManiaJudgementPiece(HitResult result, Drawable animation)
|
||||
{
|
||||
this.result = result;
|
||||
this.animation = animation;
|
||||
|
||||
Anchor = Anchor.Centre;
|
||||
Origin = Anchor.Centre;
|
||||
|
||||
AutoSizeAxes = Axes.Both;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(ISkinSource skin)
|
||||
{
|
||||
float? scorePosition = skin.GetManiaSkinConfig<float>(LegacyManiaSkinConfigurationLookups.ScorePosition)?.Value;
|
||||
|
||||
if (scorePosition != null)
|
||||
scorePosition -= Stage.HIT_TARGET_POSITION + 150;
|
||||
|
||||
Y = scorePosition ?? 0;
|
||||
|
||||
if (animation != null)
|
||||
{
|
||||
InternalChild = animation.With(d =>
|
||||
{
|
||||
d.Anchor = Anchor.Centre;
|
||||
d.Origin = Anchor.Centre;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void PlayAnimation()
|
||||
{
|
||||
if (animation == null)
|
||||
return;
|
||||
|
||||
(animation as IFramedAnimation)?.GotoFrame(0);
|
||||
|
||||
switch (result)
|
||||
{
|
||||
case HitResult.None:
|
||||
break;
|
||||
|
||||
case HitResult.Miss:
|
||||
animation.ScaleTo(1.6f);
|
||||
animation.ScaleTo(1, 100, Easing.In);
|
||||
|
||||
animation.MoveTo(Vector2.Zero);
|
||||
animation.MoveToOffset(new Vector2(0, 100), 800, Easing.InQuint);
|
||||
|
||||
animation.RotateTo(0);
|
||||
animation.RotateTo(40, 800, Easing.InQuint);
|
||||
|
||||
this.FadeOutFromOne(800);
|
||||
break;
|
||||
|
||||
default:
|
||||
animation.ScaleTo(0.8f);
|
||||
animation.ScaleTo(1, 250, Easing.OutElastic);
|
||||
|
||||
animation.Delay(50).ScaleTo(0.75f, 250);
|
||||
|
||||
this.Delay(50).FadeOut(200);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public Drawable GetAboveHitObjectsProxiedContent() => null;
|
||||
}
|
||||
}
|
@ -12,7 +12,7 @@ using osu.Game.Rulesets.UI.Scrolling;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Skinning
|
||||
namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
||||
{
|
||||
public class LegacyNotePiece : LegacyManiaColumnElement
|
||||
{
|
@ -12,7 +12,7 @@ using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Skinning
|
||||
namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
||||
{
|
||||
public class LegacyStageBackground : CompositeDrawable
|
||||
{
|
@ -9,7 +9,7 @@ using osu.Game.Rulesets.UI.Scrolling;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Skinning
|
||||
namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
||||
{
|
||||
public class LegacyStageForeground : CompositeDrawable
|
||||
{
|
@ -2,19 +2,19 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||
using osu.Game.Skinning;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using osu.Framework.Audio.Sample;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||
using osu.Game.Rulesets.Objects.Legacy;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Skinning;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Skinning
|
||||
namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
||||
{
|
||||
public class ManiaLegacySkinTransformer : LegacySkinTransformer
|
||||
{
|
||||
@ -136,7 +136,8 @@ namespace osu.Game.Rulesets.Mania.Skinning
|
||||
string filename = this.GetManiaSkinConfig<string>(hitresult_mapping[result])?.Value
|
||||
?? default_hitresult_skin_filenames[result];
|
||||
|
||||
return this.GetAnimation(filename, true, true);
|
||||
var animation = this.GetAnimation(filename, true, true);
|
||||
return animation == null ? null : new LegacyManiaJudgementPiece(result, animation);
|
||||
}
|
||||
|
||||
public override SampleChannel GetSample(ISampleInfo sampleInfo)
|
@ -8,7 +8,7 @@ using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Effects;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
|
||||
using osu.Game.Rulesets.Mania.Skinning.Default;
|
||||
using osu.Game.Rulesets.UI.Scrolling;
|
||||
using osuTK.Graphics;
|
||||
|
||||
|
@ -10,7 +10,7 @@ using osu.Framework.Graphics.Effects;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Rulesets.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.UI.Scrolling;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
@ -5,7 +5,6 @@ using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.UI
|
||||
{
|
||||
@ -20,37 +19,6 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
{
|
||||
}
|
||||
|
||||
protected override void ApplyMissAnimations()
|
||||
{
|
||||
if (!(JudgementBody.Drawable is DefaultManiaJudgementPiece))
|
||||
{
|
||||
// this is temporary logic until mania's skin transformer returns IAnimatableJudgements
|
||||
JudgementBody.ScaleTo(1.6f);
|
||||
JudgementBody.ScaleTo(1, 100, Easing.In);
|
||||
|
||||
JudgementBody.MoveTo(Vector2.Zero);
|
||||
JudgementBody.MoveToOffset(new Vector2(0, 100), 800, Easing.InQuint);
|
||||
|
||||
JudgementBody.RotateTo(0);
|
||||
JudgementBody.RotateTo(40, 800, Easing.InQuint);
|
||||
JudgementBody.FadeOutFromOne(800);
|
||||
|
||||
LifetimeEnd = JudgementBody.LatestTransformEndTime;
|
||||
}
|
||||
|
||||
base.ApplyMissAnimations();
|
||||
}
|
||||
|
||||
protected override void ApplyHitAnimations()
|
||||
{
|
||||
JudgementBody.ScaleTo(0.8f);
|
||||
JudgementBody.ScaleTo(1, 250, Easing.OutElastic);
|
||||
|
||||
JudgementBody.Delay(50)
|
||||
.ScaleTo(0.75f, 250)
|
||||
.FadeOut(200);
|
||||
}
|
||||
|
||||
protected override Drawable CreateDefaultJudgement(HitResult result) => new DefaultManiaJudgementPiece(result);
|
||||
|
||||
private class DefaultManiaJudgementPiece : DefaultJudgementPiece
|
||||
@ -66,6 +34,27 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
|
||||
JudgementText.Font = JudgementText.Font.With(size: 25);
|
||||
}
|
||||
|
||||
public override void PlayAnimation()
|
||||
{
|
||||
base.PlayAnimation();
|
||||
|
||||
switch (Result)
|
||||
{
|
||||
case HitResult.None:
|
||||
case HitResult.Miss:
|
||||
break;
|
||||
|
||||
default:
|
||||
this.ScaleTo(0.8f);
|
||||
this.ScaleTo(1, 250, Easing.OutElastic);
|
||||
|
||||
this.Delay(50)
|
||||
.ScaleTo(0.75f, 250)
|
||||
.FadeOut(200);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -106,7 +106,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Y = HIT_TARGET_POSITION + 150,
|
||||
Y = HIT_TARGET_POSITION + 150
|
||||
},
|
||||
topLevelContainer = new Container { RelativeSizeAxes = Axes.Both }
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
|
||||
using osu.Game.Rulesets.Osu.Skinning.Default;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Tests.Mods
|
||||
|
@ -12,7 +12,7 @@ using osu.Framework.Graphics.OpenGL.Textures;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Testing.Input;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Rulesets.Osu.Skinning;
|
||||
using osu.Game.Rulesets.Osu.Skinning.Legacy;
|
||||
using osu.Game.Rulesets.Osu.UI.Cursor;
|
||||
using osu.Game.Skinning;
|
||||
using osu.Game.Tests.Visual;
|
||||
|
@ -12,7 +12,7 @@ using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
|
||||
using osu.Game.Rulesets.Osu.Skinning.Default;
|
||||
using osu.Game.Skinning;
|
||||
using osu.Game.Tests.Visual;
|
||||
using osuTK;
|
||||
|
@ -19,7 +19,7 @@ using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Osu.Configuration;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
|
||||
using osu.Game.Rulesets.Osu.Skinning.Default;
|
||||
using osu.Game.Storyboards;
|
||||
using osuTK;
|
||||
|
||||
|
@ -12,5 +12,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
||||
public double ApproachRate;
|
||||
public double OverallDifficulty;
|
||||
public int HitCircleCount;
|
||||
public int SpinnerCount;
|
||||
}
|
||||
}
|
||||
|
@ -48,6 +48,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
||||
maxCombo += beatmap.HitObjects.OfType<Slider>().Sum(s => s.NestedHitObjects.Count - 1);
|
||||
|
||||
int hitCirclesCount = beatmap.HitObjects.Count(h => h is HitCircle);
|
||||
int spinnerCount = beatmap.HitObjects.Count(h => h is Spinner);
|
||||
|
||||
return new OsuDifficultyAttributes
|
||||
{
|
||||
@ -59,6 +60,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
||||
OverallDifficulty = (80 - hitWindowGreat) / 6,
|
||||
MaxCombo = maxCombo,
|
||||
HitCircleCount = hitCirclesCount,
|
||||
SpinnerCount = spinnerCount,
|
||||
Skills = skills
|
||||
};
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
||||
multiplier *= 0.90;
|
||||
|
||||
if (mods.Any(m => m is OsuModSpunOut))
|
||||
multiplier *= 0.95;
|
||||
multiplier *= 1.0 - Math.Pow((double)Attributes.SpinnerCount / totalHits, 0.85);
|
||||
|
||||
double aimValue = computeAimValue();
|
||||
double speedValue = computeSpeedValue();
|
||||
@ -92,23 +92,21 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
||||
|
||||
aimValue *= lengthBonus;
|
||||
|
||||
// Penalize misses exponentially. This mainly fixes tag4 maps and the likes until a per-hitobject solution is available
|
||||
aimValue *= Math.Pow(0.97, countMiss);
|
||||
// Penalize misses by assessing # of misses relative to the total # of objects. Default a 3% reduction for any # of misses.
|
||||
if (countMiss > 0)
|
||||
aimValue *= 0.97 * Math.Pow(1 - Math.Pow((double)countMiss / totalHits, 0.775), countMiss);
|
||||
|
||||
// Combo scaling
|
||||
if (Attributes.MaxCombo > 0)
|
||||
aimValue *= Math.Min(Math.Pow(scoreMaxCombo, 0.8) / Math.Pow(Attributes.MaxCombo, 0.8), 1.0);
|
||||
|
||||
double approachRateFactor = 1.0;
|
||||
|
||||
double approachRateFactor = 0.0;
|
||||
if (Attributes.ApproachRate > 10.33)
|
||||
approachRateFactor += 0.3 * (Attributes.ApproachRate - 10.33);
|
||||
approachRateFactor += 0.4 * (Attributes.ApproachRate - 10.33);
|
||||
else if (Attributes.ApproachRate < 8.0)
|
||||
{
|
||||
approachRateFactor += 0.01 * (8.0 - Attributes.ApproachRate);
|
||||
}
|
||||
approachRateFactor += 0.1 * (8.0 - Attributes.ApproachRate);
|
||||
|
||||
aimValue *= approachRateFactor;
|
||||
aimValue *= 1.0 + Math.Min(approachRateFactor, approachRateFactor * (totalHits / 1000.0));
|
||||
|
||||
// We want to give more reward for lower AR when it comes to aim and HD. This nerfs high AR and buffs lower AR.
|
||||
if (mods.Any(h => h is OsuModHidden))
|
||||
@ -137,21 +135,23 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
||||
double speedValue = Math.Pow(5.0 * Math.Max(1.0, Attributes.SpeedStrain / 0.0675) - 4.0, 3.0) / 100000.0;
|
||||
|
||||
// Longer maps are worth more
|
||||
speedValue *= 0.95 + 0.4 * Math.Min(1.0, totalHits / 2000.0) +
|
||||
(totalHits > 2000 ? Math.Log10(totalHits / 2000.0) * 0.5 : 0.0);
|
||||
double lengthBonus = 0.95 + 0.4 * Math.Min(1.0, totalHits / 2000.0) +
|
||||
(totalHits > 2000 ? Math.Log10(totalHits / 2000.0) * 0.5 : 0.0);
|
||||
speedValue *= lengthBonus;
|
||||
|
||||
// Penalize misses exponentially. This mainly fixes tag4 maps and the likes until a per-hitobject solution is available
|
||||
speedValue *= Math.Pow(0.97, countMiss);
|
||||
// Penalize misses by assessing # of misses relative to the total # of objects. Default a 3% reduction for any # of misses.
|
||||
if (countMiss > 0)
|
||||
speedValue *= 0.97 * Math.Pow(1 - Math.Pow((double)countMiss / totalHits, 0.775), Math.Pow(countMiss, .875));
|
||||
|
||||
// Combo scaling
|
||||
if (Attributes.MaxCombo > 0)
|
||||
speedValue *= Math.Min(Math.Pow(scoreMaxCombo, 0.8) / Math.Pow(Attributes.MaxCombo, 0.8), 1.0);
|
||||
|
||||
double approachRateFactor = 1.0;
|
||||
double approachRateFactor = 0.0;
|
||||
if (Attributes.ApproachRate > 10.33)
|
||||
approachRateFactor += 0.3 * (Attributes.ApproachRate - 10.33);
|
||||
approachRateFactor += 0.4 * (Attributes.ApproachRate - 10.33);
|
||||
|
||||
speedValue *= approachRateFactor;
|
||||
speedValue *= 1.0 + Math.Min(approachRateFactor, approachRateFactor * (totalHits / 1000.0));
|
||||
|
||||
if (mods.Any(m => m is OsuModHidden))
|
||||
speedValue *= 1.0 + 0.04 * (12.0 - Attributes.ApproachRate);
|
||||
|
@ -5,7 +5,7 @@ using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
|
||||
using osu.Game.Rulesets.Osu.Skinning.Default;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components
|
||||
|
@ -5,7 +5,7 @@ using System.Collections.Generic;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
|
||||
using osu.Game.Rulesets.Osu.Skinning.Default;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
|
@ -7,7 +7,7 @@ using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
|
||||
using osu.Game.Rulesets.Osu.Skinning.Default;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners.Components
|
||||
|
@ -7,7 +7,7 @@ using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
|
||||
using osu.Game.Rulesets.Osu.Skinning.Default;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Mods
|
||||
{
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user