mirror of
https://github.com/ppy/osu.git
synced 2025-01-06 21:12:55 +08:00
Merge pull request #8556 from smoogipoo/mania-hitexplosion-skinning
Implement mania normal-note hit-explosion skinning
This commit is contained in:
commit
aa74b3193e
@ -51,7 +51,7 @@
|
||||
<Reference Include="Java.Interop" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.331.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.402.1" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2020.402.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
@ -3,42 +3,32 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
|
||||
using osu.Game.Rulesets.Mania.UI;
|
||||
using osu.Game.Rulesets.UI.Scrolling;
|
||||
using osu.Game.Tests.Visual;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Tests
|
||||
namespace osu.Game.Rulesets.Mania.Tests.Skinning
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestSceneHitExplosion : OsuTestScene
|
||||
public class TestSceneHitExplosion : ManiaSkinnableTestScene
|
||||
{
|
||||
private ScrollingTestContainer scrolling;
|
||||
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(DrawableNote),
|
||||
typeof(DrawableManiaHitObject),
|
||||
};
|
||||
|
||||
protected override void LoadComplete()
|
||||
public TestSceneHitExplosion()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
Child = scrolling = new ScrollingTestContainer(ScrollingDirection.Down)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativePositionAxes = Axes.Y,
|
||||
Y = -0.25f,
|
||||
Size = new Vector2(Column.COLUMN_WIDTH, DefaultNotePiece.NOTE_HEIGHT),
|
||||
};
|
||||
|
||||
int runcount = 0;
|
||||
|
||||
AddRepeatStep("explode", () =>
|
||||
@ -48,15 +38,29 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
if (runcount % 15 > 12)
|
||||
return;
|
||||
|
||||
scrolling.AddRange(new Drawable[]
|
||||
CreatedDrawables.OfType<Container>().ForEach(c =>
|
||||
{
|
||||
new HitExplosion((runcount / 15) % 2 == 0 ? new Color4(94, 0, 57, 255) : new Color4(6, 84, 0, 255), runcount % 6 != 0)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
}
|
||||
c.Add(new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.HitExplosion),
|
||||
_ => new DefaultHitExplosion((runcount / 15) % 2 == 0 ? new Color4(94, 0, 57, 255) : new Color4(6, 84, 0, 255), runcount % 6 != 0)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
}));
|
||||
});
|
||||
}, 100);
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
SetContents(() => new ColumnTestContainer(0, ManiaAction.Key1)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativePositionAxes = Axes.Y,
|
||||
Y = -0.25f,
|
||||
Size = new Vector2(Column.COLUMN_WIDTH, DefaultNotePiece.NOTE_HEIGHT),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -26,5 +26,6 @@ namespace osu.Game.Rulesets.Mania
|
||||
HoldNoteHead,
|
||||
HoldNoteTail,
|
||||
HoldNoteBody,
|
||||
HitExplosion
|
||||
}
|
||||
}
|
||||
|
73
osu.Game.Rulesets.Mania/Skinning/LegacyHitExplosion.cs
Normal file
73
osu.Game.Rulesets.Mania/Skinning/LegacyHitExplosion.cs
Normal file
@ -0,0 +1,73 @@
|
||||
// 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.Framework.Graphics.Animations;
|
||||
using osu.Game.Rulesets.UI.Scrolling;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Skinning
|
||||
{
|
||||
public class LegacyHitExplosion : LegacyManiaColumnElement
|
||||
{
|
||||
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
|
||||
|
||||
private Drawable explosion;
|
||||
|
||||
public LegacyHitExplosion()
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(ISkinSource skin, IScrollingInfo scrollingInfo)
|
||||
{
|
||||
string imageName = GetManiaSkinConfig<string>(skin, LegacyManiaSkinConfigurationLookups.ExplosionImage)?.Value
|
||||
?? "lightingN";
|
||||
|
||||
float explosionScale = GetManiaSkinConfig<float>(skin, LegacyManiaSkinConfigurationLookups.ExplosionScale)?.Value
|
||||
?? 1;
|
||||
|
||||
// Create a temporary animation to retrieve the number of frames, in an effort to calculate the intended frame length.
|
||||
// This animation is discarded and re-queried with the appropriate frame length afterwards.
|
||||
var tmp = skin.GetAnimation(imageName, true, false);
|
||||
double frameLength = 0;
|
||||
if (tmp is IAnimation tmpAnimation && tmpAnimation.FrameCount > 0)
|
||||
frameLength = Math.Max(1000 / 60.0, 170.0 / tmpAnimation.FrameCount);
|
||||
|
||||
explosion = skin.GetAnimation(imageName, true, false, startAtCurrentTime: true, frameLength: frameLength).With(d =>
|
||||
{
|
||||
if (d == null)
|
||||
return;
|
||||
|
||||
d.Origin = Anchor.Centre;
|
||||
d.Blending = BlendingParameters.Additive;
|
||||
d.Scale = new Vector2(explosionScale);
|
||||
});
|
||||
|
||||
if (explosion != null)
|
||||
InternalChild = explosion;
|
||||
|
||||
direction.BindTo(scrollingInfo.Direction);
|
||||
direction.BindValueChanged(onDirectionChanged, true);
|
||||
}
|
||||
|
||||
private void onDirectionChanged(ValueChangedEvent<ScrollingDirection> direction)
|
||||
{
|
||||
if (explosion != null)
|
||||
explosion.Anchor = direction.NewValue == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre;
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
explosion?.FadeInFromZero(80)
|
||||
.Then().FadeOut(120);
|
||||
}
|
||||
}
|
||||
}
|
@ -74,6 +74,9 @@ namespace osu.Game.Rulesets.Mania.Skinning
|
||||
|
||||
case ManiaSkinComponents.HoldNoteBody:
|
||||
return new LegacyBodyPiece();
|
||||
|
||||
case ManiaSkinComponents.HitExplosion:
|
||||
return new LegacyHitExplosion();
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -105,11 +105,15 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
if (!result.IsHit || !judgedObject.DisplayResult || !DisplayJudgements.Value)
|
||||
return;
|
||||
|
||||
hitObjectArea.Explosions.Add(new HitExplosion(judgedObject.AccentColour.Value, judgedObject is DrawableHoldNoteTick)
|
||||
var explosion = new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.HitExplosion), _ =>
|
||||
new DefaultHitExplosion(judgedObject.AccentColour.Value, judgedObject is DrawableHoldNoteTick))
|
||||
{
|
||||
Anchor = Direction.Value == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre,
|
||||
Origin = Anchor.Centre
|
||||
});
|
||||
RelativeSizeAxes = Axes.Both
|
||||
};
|
||||
|
||||
hitObjectArea.Explosions.Add(explosion);
|
||||
|
||||
explosion.Delay(200).Expire(true);
|
||||
}
|
||||
|
||||
public bool OnPressed(ManiaAction action)
|
||||
|
@ -3,7 +3,6 @@
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osu.Game.Rulesets.UI.Scrolling;
|
||||
using osu.Game.Skinning;
|
||||
@ -12,7 +11,7 @@ namespace osu.Game.Rulesets.Mania.UI.Components
|
||||
{
|
||||
public class ColumnHitObjectArea : HitObjectArea
|
||||
{
|
||||
public readonly Container<HitExplosion> Explosions;
|
||||
public readonly Container Explosions;
|
||||
private readonly Drawable hitTarget;
|
||||
|
||||
public ColumnHitObjectArea(HitObjectContainer hitObjectContainer)
|
||||
@ -25,7 +24,7 @@ namespace osu.Game.Rulesets.Mania.UI.Components
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Depth = 1
|
||||
},
|
||||
Explosions = new Container<HitExplosion>
|
||||
Explosions = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Depth = -1,
|
||||
@ -38,15 +37,9 @@ namespace osu.Game.Rulesets.Mania.UI.Components
|
||||
base.UpdateHitPosition();
|
||||
|
||||
if (Direction.Value == ScrollingDirection.Up)
|
||||
{
|
||||
hitTarget.Anchor = hitTarget.Origin = Anchor.TopLeft;
|
||||
Explosions.Padding = new MarginPadding { Top = DefaultNotePiece.NOTE_HEIGHT / 2 };
|
||||
}
|
||||
else
|
||||
{
|
||||
hitTarget.Anchor = hitTarget.Origin = Anchor.BottomLeft;
|
||||
Explosions.Padding = new MarginPadding { Bottom = DefaultNotePiece.NOTE_HEIGHT / 2 };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,26 +1,33 @@
|
||||
// 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.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Effects;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
|
||||
using osu.Game.Rulesets.UI.Scrolling;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.UI
|
||||
{
|
||||
public class HitExplosion : CompositeDrawable
|
||||
public class DefaultHitExplosion : CompositeDrawable
|
||||
{
|
||||
public override bool RemoveWhenNotAlive => true;
|
||||
|
||||
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
|
||||
|
||||
private readonly CircularContainer largeFaint;
|
||||
private readonly CircularContainer mainGlow1;
|
||||
|
||||
public HitExplosion(Color4 objectColour, bool isSmall = false)
|
||||
public DefaultHitExplosion(Color4 objectColour, bool isSmall = false)
|
||||
{
|
||||
Origin = Anchor.Centre;
|
||||
|
||||
RelativeSizeAxes = Axes.X;
|
||||
Height = DefaultNotePiece.NOTE_HEIGHT;
|
||||
|
||||
@ -109,6 +116,13 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
};
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(IScrollingInfo scrollingInfo)
|
||||
{
|
||||
direction.BindTo(scrollingInfo.Direction);
|
||||
direction.BindValueChanged(onDirectionChanged, true);
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
const double duration = 200;
|
||||
@ -122,7 +136,20 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
mainGlow1.ScaleTo(1.4f, duration, Easing.OutQuint);
|
||||
|
||||
this.FadeOut(duration, Easing.Out);
|
||||
Expire(true);
|
||||
}
|
||||
|
||||
private void onDirectionChanged(ValueChangedEvent<ScrollingDirection> direction)
|
||||
{
|
||||
if (direction.NewValue == ScrollingDirection.Up)
|
||||
{
|
||||
Anchor = Anchor.TopCentre;
|
||||
Y = DefaultNotePiece.NOTE_HEIGHT / 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
Anchor = Anchor.BottomCentre;
|
||||
Y = -DefaultNotePiece.NOTE_HEIGHT / 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -10,6 +10,16 @@ namespace osu.Game.Skinning
|
||||
{
|
||||
public class LegacyManiaSkinConfiguration : IHasCustomColours
|
||||
{
|
||||
/// <summary>
|
||||
/// Conversion factor from converting legacy positioning values (based in x480 dimensions) to x768.
|
||||
/// </summary>
|
||||
public const float POSITION_SCALE_FACTOR = 1.6f;
|
||||
|
||||
/// <summary>
|
||||
/// Size of a legacy column in the default skin, used for determining relative scale factors.
|
||||
/// </summary>
|
||||
public const float DEFAULT_COLUMN_SIZE = 30 * POSITION_SCALE_FACTOR;
|
||||
|
||||
public readonly int Keys;
|
||||
|
||||
public Dictionary<string, Color4> CustomColours { get; set; } = new Dictionary<string, Color4>();
|
||||
@ -17,9 +27,10 @@ namespace osu.Game.Skinning
|
||||
public readonly float[] ColumnLineWidth;
|
||||
public readonly float[] ColumnSpacing;
|
||||
public readonly float[] ColumnWidth;
|
||||
public readonly float[] ExplosionWidth;
|
||||
|
||||
public float HitPosition = 124.8f; // (480 - 402) * 1.6f
|
||||
public float LightPosition = 107.2f; // (480 - 413) * 1.6f
|
||||
public float HitPosition = (480 - 402) * POSITION_SCALE_FACTOR;
|
||||
public float LightPosition = (480 - 413) * POSITION_SCALE_FACTOR;
|
||||
public bool ShowJudgementLine = true;
|
||||
|
||||
public LegacyManiaSkinConfiguration(int keys)
|
||||
@ -29,9 +40,10 @@ namespace osu.Game.Skinning
|
||||
ColumnLineWidth = new float[keys + 1];
|
||||
ColumnSpacing = new float[keys - 1];
|
||||
ColumnWidth = new float[keys];
|
||||
ExplosionWidth = new float[keys];
|
||||
|
||||
ColumnLineWidth.AsSpan().Fill(2);
|
||||
ColumnWidth.AsSpan().Fill(48);
|
||||
ColumnWidth.AsSpan().Fill(DEFAULT_COLUMN_SIZE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -34,6 +34,8 @@ namespace osu.Game.Skinning
|
||||
HoldNoteHeadImage,
|
||||
HoldNoteTailImage,
|
||||
HoldNoteBodyImage,
|
||||
ExplosionImage,
|
||||
ExplosionScale,
|
||||
ColumnLineColour
|
||||
}
|
||||
}
|
||||
|
@ -11,8 +11,6 @@ namespace osu.Game.Skinning
|
||||
{
|
||||
public class LegacyManiaSkinDecoder : LegacyDecoder<List<LegacyManiaSkinConfiguration>>
|
||||
{
|
||||
private const float size_scale_factor = 1.6f;
|
||||
|
||||
public LegacyManiaSkinDecoder()
|
||||
: base(1)
|
||||
{
|
||||
@ -94,16 +92,20 @@ namespace osu.Game.Skinning
|
||||
break;
|
||||
|
||||
case "HitPosition":
|
||||
currentConfig.HitPosition = (480 - float.Parse(pair.Value, CultureInfo.InvariantCulture)) * size_scale_factor;
|
||||
currentConfig.HitPosition = (480 - float.Parse(pair.Value, CultureInfo.InvariantCulture)) * LegacyManiaSkinConfiguration.POSITION_SCALE_FACTOR;
|
||||
break;
|
||||
|
||||
case "LightPosition":
|
||||
currentConfig.LightPosition = (480 - float.Parse(pair.Value, CultureInfo.InvariantCulture)) * size_scale_factor;
|
||||
currentConfig.LightPosition = (480 - float.Parse(pair.Value, CultureInfo.InvariantCulture)) * LegacyManiaSkinConfiguration.POSITION_SCALE_FACTOR;
|
||||
break;
|
||||
|
||||
case "JudgementLine":
|
||||
currentConfig.ShowJudgementLine = pair.Value == "1";
|
||||
break;
|
||||
|
||||
case "LightingNWidth":
|
||||
parseArrayValue(pair.Value, currentConfig.ExplosionWidth);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -117,7 +119,7 @@ namespace osu.Game.Skinning
|
||||
if (i >= output.Length)
|
||||
break;
|
||||
|
||||
output[i] = float.Parse(values[i], CultureInfo.InvariantCulture) * size_scale_factor;
|
||||
output[i] = float.Parse(values[i], CultureInfo.InvariantCulture) * LegacyManiaSkinConfiguration.POSITION_SCALE_FACTOR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -194,6 +194,17 @@ namespace osu.Game.Skinning
|
||||
case LegacyManiaSkinConfigurationLookups.ShowJudgementLine:
|
||||
return SkinUtils.As<TValue>(new Bindable<bool>(existing.ShowJudgementLine));
|
||||
|
||||
case LegacyManiaSkinConfigurationLookups.ExplosionScale:
|
||||
Debug.Assert(maniaLookup.TargetColumn != null);
|
||||
|
||||
if (GetConfig<LegacySkinConfiguration.LegacySetting, decimal>(LegacySkinConfiguration.LegacySetting.Version)?.Value < 2.5m)
|
||||
return SkinUtils.As<TValue>(new Bindable<float>(1));
|
||||
|
||||
if (existing.ExplosionWidth[maniaLookup.TargetColumn.Value] != 0)
|
||||
return SkinUtils.As<TValue>(new Bindable<float>(existing.ExplosionWidth[maniaLookup.TargetColumn.Value] / LegacyManiaSkinConfiguration.DEFAULT_COLUMN_SIZE));
|
||||
|
||||
return SkinUtils.As<TValue>(new Bindable<float>(existing.ColumnWidth[maniaLookup.TargetColumn.Value] / LegacyManiaSkinConfiguration.DEFAULT_COLUMN_SIZE));
|
||||
|
||||
case LegacyManiaSkinConfigurationLookups.ColumnLineColour:
|
||||
return SkinUtils.As<TValue>(getCustomColour(existing, "ColourColumnLine"));
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ namespace osu.Game.Skinning
|
||||
public static class LegacySkinExtensions
|
||||
{
|
||||
public static Drawable GetAnimation(this ISkin source, string componentName, bool animatable, bool looping, bool applyConfigFrameRate = false, string animationSeparator = "-",
|
||||
bool startAtCurrentTime = false)
|
||||
bool startAtCurrentTime = false, double? frameLength = null)
|
||||
{
|
||||
Texture texture;
|
||||
|
||||
@ -27,7 +27,7 @@ namespace osu.Game.Skinning
|
||||
{
|
||||
var animation = new SkinnableTextureAnimation(startAtCurrentTime)
|
||||
{
|
||||
DefaultFrameLength = getFrameLength(source, applyConfigFrameRate, textures),
|
||||
DefaultFrameLength = frameLength ?? getFrameLength(source, applyConfigFrameRate, textures),
|
||||
Repeat = looping,
|
||||
};
|
||||
|
||||
|
@ -22,7 +22,7 @@
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.331.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.402.1" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2020.402.0" />
|
||||
<PackageReference Include="Sentry" Version="2.1.1" />
|
||||
<PackageReference Include="SharpCompress" Version="0.24.0" />
|
||||
|
@ -70,7 +70,7 @@
|
||||
<Reference Include="System.Net.Http" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.331.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.402.1" />
|
||||
<PackageReference Include="ppy.osu.Framework.iOS" Version="2020.402.0" />
|
||||
</ItemGroup>
|
||||
<!-- Xamarin.iOS does not automatically handle transitive dependencies from NuGet packages. -->
|
||||
|
Loading…
Reference in New Issue
Block a user