From 7ce00bebf0cbc94cba6624690089037fb07558d5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 17 Feb 2020 18:47:22 +0900 Subject: [PATCH] Add basic structure for skinning fruits --- osu.Game.Rulesets.Catch/CatchRuleset.cs | 4 + .../CatchSkinComponents.cs | 5 + .../Objects/Drawable/DrawableFruit.cs | 259 ++--------------- .../Objects/Drawable/FruitPiece.cs | 269 ++++++++++++++++++ .../Skinning/CatchLegacySkinTransformer.cs | 47 +++ 5 files changed, 346 insertions(+), 238 deletions(-) create mode 100644 osu.Game.Rulesets.Catch/Objects/Drawable/FruitPiece.cs create mode 100644 osu.Game.Rulesets.Catch/Skinning/CatchLegacySkinTransformer.cs diff --git a/osu.Game.Rulesets.Catch/CatchRuleset.cs b/osu.Game.Rulesets.Catch/CatchRuleset.cs index e5c3647f99..b9d791fdb1 100644 --- a/osu.Game.Rulesets.Catch/CatchRuleset.cs +++ b/osu.Game.Rulesets.Catch/CatchRuleset.cs @@ -21,6 +21,8 @@ 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.Skinning; namespace osu.Game.Rulesets.Catch { @@ -141,6 +143,8 @@ namespace osu.Game.Rulesets.Catch public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new CatchDifficultyCalculator(this, beatmap); + public override ISkin CreateLegacySkinProvider(ISkinSource source) => new CatchLegacySkinTransformer(source); + public override PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, ScoreInfo score) => new CatchPerformanceCalculator(this, beatmap, score); public int LegacyID => 2; diff --git a/osu.Game.Rulesets.Catch/CatchSkinComponents.cs b/osu.Game.Rulesets.Catch/CatchSkinComponents.cs index 7e482d4045..f64902b8e5 100644 --- a/osu.Game.Rulesets.Catch/CatchSkinComponents.cs +++ b/osu.Game.Rulesets.Catch/CatchSkinComponents.cs @@ -5,5 +5,10 @@ namespace osu.Game.Rulesets.Catch { public enum CatchSkinComponents { + FruitBananas, + FruitApple, + FruitGrapes, + FruitOrange, + FruitPear, } } diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableFruit.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableFruit.cs index 53a018c9f4..0953293dcd 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableFruit.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableFruit.cs @@ -3,13 +3,9 @@ using System; using osu.Framework.Allocation; -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.Utils; -using osu.Game.Rulesets.Catch.Objects.Drawable.Pieces; +using osu.Game.Skinning; using osuTK; using osuTK.Graphics; @@ -17,21 +13,19 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable { public class DrawableFruit : PalpableCatchHitObject { - private Circle border; - - private const float drawable_radius = (float)CatchHitObject.OBJECT_RADIUS * radius_adjust; + public const float DRAWABLE_RADIUS = (float)CatchHitObject.OBJECT_RADIUS * RADIUS_ADJUST; /// /// Because we're adding a border around the fruit, we need to scale down some. /// - private const float radius_adjust = 1.1f; + public const float RADIUS_ADJUST = 1.1f; public DrawableFruit(Fruit h) : base(h) { Origin = Anchor.Centre; - Size = new Vector2(drawable_radius); + Size = new Vector2(DRAWABLE_RADIUS); Masking = false; Rotation = (float)(RNG.NextDouble() - 0.5f) * 40; @@ -40,247 +34,36 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable [BackgroundDependencyLoader] private void load() { - // todo: this should come from the skin. + AddInternal(new SkinnableDrawable( + new CatchSkinComponent(getComponent(HitObject.VisualRepresentation)), _ => new FruitPiece())); + AccentColour.Value = colourForRepresentation(HitObject.VisualRepresentation); - - AddRangeInternal(new[] - { - createPulp(HitObject.VisualRepresentation), - border = new Circle - { - EdgeEffect = new EdgeEffectParameters - { - Hollow = !HitObject.HyperDash, - Type = EdgeEffectType.Glow, - Radius = 4 * radius_adjust, - Colour = HitObject.HyperDash ? Color4.Red : AccentColour.Value.Darken(1).Opacity(0.6f) - }, - Size = new Vector2(Height), - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - BorderColour = Color4.White, - BorderThickness = 3f * radius_adjust, - Children = new Framework.Graphics.Drawable[] - { - new Box - { - AlwaysPresent = true, - Colour = AccentColour.Value, - Alpha = 0, - RelativeSizeAxes = Axes.Both - } - } - }, - }); - - if (HitObject.HyperDash) - { - AddInternal(new Pulp - { - RelativePositionAxes = Axes.Both, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - AccentColour = Color4.Red, - Blending = BlendingParameters.Additive, - Alpha = 0.5f, - Scale = new Vector2(1.333f) - }); - } } - private Framework.Graphics.Drawable createPulp(FruitVisualRepresentation representation) + private CatchSkinComponents getComponent(FruitVisualRepresentation hitObjectVisualRepresentation) { - const float large_pulp_3 = 8f * radius_adjust; - const float distance_from_centre_3 = 0.15f; - - const float large_pulp_4 = large_pulp_3 * 0.925f; - const float distance_from_centre_4 = distance_from_centre_3 / 0.925f; - - const float small_pulp = large_pulp_3 / 2; - - static Vector2 positionAt(float angle, float distance) => new Vector2( - distance * MathF.Sin(angle * MathF.PI / 180), - distance * MathF.Cos(angle * MathF.PI / 180)); - - switch (representation) + switch (hitObjectVisualRepresentation) { - default: - return new Container(); - - case FruitVisualRepresentation.Raspberry: - return new Container - { - RelativeSizeAxes = Axes.Both, - Children = new Framework.Graphics.Drawable[] - { - new Pulp - { - AccentColour = AccentColour.Value, - Size = new Vector2(small_pulp), - Y = -0.34f, - }, - new Pulp - { - AccentColour = AccentColour.Value, - Size = new Vector2(large_pulp_4), - Position = positionAt(0, distance_from_centre_4), - }, - new Pulp - { - AccentColour = AccentColour.Value, - Size = new Vector2(large_pulp_4), - Position = positionAt(90, distance_from_centre_4), - }, - new Pulp - { - AccentColour = AccentColour.Value, - Size = new Vector2(large_pulp_4), - Position = positionAt(180, distance_from_centre_4), - }, - new Pulp - { - Size = new Vector2(large_pulp_4), - AccentColour = AccentColour.Value, - Position = positionAt(270, distance_from_centre_4), - }, - } - }; - - case FruitVisualRepresentation.Pineapple: - return new Container - { - RelativeSizeAxes = Axes.Both, - Children = new Framework.Graphics.Drawable[] - { - new Pulp - { - AccentColour = AccentColour.Value, - Size = new Vector2(small_pulp), - Y = -0.3f, - }, - new Pulp - { - AccentColour = AccentColour.Value, - Size = new Vector2(large_pulp_4), - Position = positionAt(45, distance_from_centre_4), - }, - new Pulp - { - AccentColour = AccentColour.Value, - Size = new Vector2(large_pulp_4), - Position = positionAt(135, distance_from_centre_4), - }, - new Pulp - { - AccentColour = AccentColour.Value, - Size = new Vector2(large_pulp_4), - Position = positionAt(225, distance_from_centre_4), - }, - new Pulp - { - Size = new Vector2(large_pulp_4), - AccentColour = AccentColour.Value, - Position = positionAt(315, distance_from_centre_4), - }, - } - }; - case FruitVisualRepresentation.Pear: - return new Container - { - RelativeSizeAxes = Axes.Both, - Children = new Framework.Graphics.Drawable[] - { - new Pulp - { - AccentColour = AccentColour.Value, - Size = new Vector2(small_pulp), - Y = -0.33f, - }, - new Pulp - { - AccentColour = AccentColour.Value, - Size = new Vector2(large_pulp_3), - Position = positionAt(60, distance_from_centre_3), - }, - new Pulp - { - AccentColour = AccentColour.Value, - Size = new Vector2(large_pulp_3), - Position = positionAt(180, distance_from_centre_3), - }, - new Pulp - { - Size = new Vector2(large_pulp_3), - AccentColour = AccentColour.Value, - Position = positionAt(300, distance_from_centre_3), - }, - } - }; + return CatchSkinComponents.FruitPear; case FruitVisualRepresentation.Grape: - return new Container - { - RelativeSizeAxes = Axes.Both, - Children = new Framework.Graphics.Drawable[] - { - new Pulp - { - AccentColour = AccentColour.Value, - Size = new Vector2(small_pulp), - Y = -0.25f, - }, - new Pulp - { - AccentColour = AccentColour.Value, - Size = new Vector2(large_pulp_3), - Position = positionAt(0, distance_from_centre_3), - }, - new Pulp - { - AccentColour = AccentColour.Value, - Size = new Vector2(large_pulp_3), - Position = positionAt(120, distance_from_centre_3), - }, - new Pulp - { - Size = new Vector2(large_pulp_3), - AccentColour = AccentColour.Value, - Position = positionAt(240, distance_from_centre_3), - }, - } - }; + return CatchSkinComponents.FruitGrapes; + + case FruitVisualRepresentation.Raspberry: + return CatchSkinComponents.FruitOrange; + + case FruitVisualRepresentation.Pineapple: + return CatchSkinComponents.FruitApple; case FruitVisualRepresentation.Banana: - return new Container - { - RelativeSizeAxes = Axes.Both, - Children = new Framework.Graphics.Drawable[] - { - new Pulp - { - AccentColour = AccentColour.Value, - Size = new Vector2(small_pulp), - Y = -0.3f - }, - new Pulp - { - AccentColour = AccentColour.Value, - Size = new Vector2(large_pulp_4 * 0.8f, large_pulp_4 * 2.5f), - Y = 0.05f, - }, - } - }; + return CatchSkinComponents.FruitBananas; + + default: + throw new ArgumentOutOfRangeException(nameof(hitObjectVisualRepresentation), hitObjectVisualRepresentation, null); } } - protected override void Update() - { - base.Update(); - - border.Alpha = (float)Math.Clamp((HitObject.StartTime - Time.Current) / 500, 0, 1); - } - private Color4 colourForRepresentation(FruitVisualRepresentation representation) { switch (representation) diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/FruitPiece.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/FruitPiece.cs new file mode 100644 index 0000000000..c59cac8de3 --- /dev/null +++ b/osu.Game.Rulesets.Catch/Objects/Drawable/FruitPiece.cs @@ -0,0 +1,269 @@ +// Copyright (c) ppy Pty Ltd . 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.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Rulesets.Catch.Objects.Drawable.Pieces; +using osu.Game.Rulesets.Objects.Drawables; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Rulesets.Catch.Objects.Drawable +{ + internal class FruitPiece : CompositeDrawable + { + private Circle border; + + private CatchHitObject hitObject; + + private readonly IBindable accentColour = new Bindable(); + + public FruitPiece() + { + RelativeSizeAxes = Axes.Both; + } + + [BackgroundDependencyLoader] + private void load(DrawableHitObject drawableObject) + { + DrawableCatchHitObject drawableCatchObject = (DrawableCatchHitObject)drawableObject; + hitObject = drawableCatchObject.HitObject; + + accentColour.BindTo(drawableCatchObject.AccentColour); + + AddRangeInternal(new[] + { + createPulp(drawableCatchObject.HitObject.VisualRepresentation), + border = new Circle + { + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + BorderColour = Color4.White, + BorderThickness = 3f * DrawableFruit.RADIUS_ADJUST, + Children = new Framework.Graphics.Drawable[] + { + new Box + { + AlwaysPresent = true, + Colour = drawableCatchObject.AccentColour.Value, + Alpha = 0, + RelativeSizeAxes = Axes.Both + } + } + }, + }); + + if (hitObject.HyperDash) + { + AddInternal(new Pulp + { + RelativePositionAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + AccentColour = Color4.Red, + Blending = BlendingParameters.Additive, + Alpha = 0.5f, + Scale = new Vector2(1.333f) + }); + } + } + + protected override void Update() + { + base.Update(); + + border.Alpha = (float)Math.Clamp((hitObject.StartTime - Time.Current) / 500, 0, 1); + } + + private Framework.Graphics.Drawable createPulp(FruitVisualRepresentation representation) + { + const float large_pulp_3 = 8f * DrawableFruit.RADIUS_ADJUST; + const float distance_from_centre_3 = 0.15f; + + const float large_pulp_4 = large_pulp_3 * 0.925f; + const float distance_from_centre_4 = distance_from_centre_3 / 0.925f; + + const float small_pulp = large_pulp_3 / 2; + + static Vector2 positionAt(float angle, float distance) => new Vector2( + distance * MathF.Sin(angle * MathF.PI / 180), + distance * MathF.Cos(angle * MathF.PI / 180)); + + switch (representation) + { + default: + return new Container(); + + case FruitVisualRepresentation.Raspberry: + return new Container + { + RelativeSizeAxes = Axes.Both, + Children = new Framework.Graphics.Drawable[] + { + new Pulp + { + AccentColour = accentColour.Value, + Size = new Vector2(small_pulp), + Y = -0.34f, + }, + new Pulp + { + AccentColour = accentColour.Value, + Size = new Vector2(large_pulp_4), + Position = positionAt(0, distance_from_centre_4), + }, + new Pulp + { + AccentColour = accentColour.Value, + Size = new Vector2(large_pulp_4), + Position = positionAt(90, distance_from_centre_4), + }, + new Pulp + { + AccentColour = accentColour.Value, + Size = new Vector2(large_pulp_4), + Position = positionAt(180, distance_from_centre_4), + }, + new Pulp + { + Size = new Vector2(large_pulp_4), + AccentColour = accentColour.Value, + Position = positionAt(270, distance_from_centre_4), + }, + } + }; + + case FruitVisualRepresentation.Pineapple: + return new Container + { + RelativeSizeAxes = Axes.Both, + Children = new Framework.Graphics.Drawable[] + { + new Pulp + { + AccentColour = accentColour.Value, + Size = new Vector2(small_pulp), + Y = -0.3f, + }, + new Pulp + { + AccentColour = accentColour.Value, + Size = new Vector2(large_pulp_4), + Position = positionAt(45, distance_from_centre_4), + }, + new Pulp + { + AccentColour = accentColour.Value, + Size = new Vector2(large_pulp_4), + Position = positionAt(135, distance_from_centre_4), + }, + new Pulp + { + AccentColour = accentColour.Value, + Size = new Vector2(large_pulp_4), + Position = positionAt(225, distance_from_centre_4), + }, + new Pulp + { + Size = new Vector2(large_pulp_4), + AccentColour = accentColour.Value, + Position = positionAt(315, distance_from_centre_4), + }, + } + }; + + case FruitVisualRepresentation.Pear: + return new Container + { + RelativeSizeAxes = Axes.Both, + Children = new Framework.Graphics.Drawable[] + { + new Pulp + { + AccentColour = accentColour.Value, + Size = new Vector2(small_pulp), + Y = -0.33f, + }, + new Pulp + { + AccentColour = accentColour.Value, + Size = new Vector2(large_pulp_3), + Position = positionAt(60, distance_from_centre_3), + }, + new Pulp + { + AccentColour = accentColour.Value, + Size = new Vector2(large_pulp_3), + Position = positionAt(180, distance_from_centre_3), + }, + new Pulp + { + Size = new Vector2(large_pulp_3), + AccentColour = accentColour.Value, + Position = positionAt(300, distance_from_centre_3), + }, + } + }; + + case FruitVisualRepresentation.Grape: + return new Container + { + RelativeSizeAxes = Axes.Both, + Children = new Framework.Graphics.Drawable[] + { + new Pulp + { + AccentColour = accentColour.Value, + Size = new Vector2(small_pulp), + Y = -0.25f, + }, + new Pulp + { + AccentColour = accentColour.Value, + Size = new Vector2(large_pulp_3), + Position = positionAt(0, distance_from_centre_3), + }, + new Pulp + { + AccentColour = accentColour.Value, + Size = new Vector2(large_pulp_3), + Position = positionAt(120, distance_from_centre_3), + }, + new Pulp + { + Size = new Vector2(large_pulp_3), + AccentColour = accentColour.Value, + Position = positionAt(240, distance_from_centre_3), + }, + } + }; + + case FruitVisualRepresentation.Banana: + return new Container + { + RelativeSizeAxes = Axes.Both, + Children = new Framework.Graphics.Drawable[] + { + new Pulp + { + AccentColour = accentColour.Value, + Size = new Vector2(small_pulp), + Y = -0.3f + }, + new Pulp + { + AccentColour = accentColour.Value, + Size = new Vector2(large_pulp_4 * 0.8f, large_pulp_4 * 2.5f), + Y = 0.05f, + }, + } + }; + } + } + } +} diff --git a/osu.Game.Rulesets.Catch/Skinning/CatchLegacySkinTransformer.cs b/osu.Game.Rulesets.Catch/Skinning/CatchLegacySkinTransformer.cs new file mode 100644 index 0000000000..c1e164ed5b --- /dev/null +++ b/osu.Game.Rulesets.Catch/Skinning/CatchLegacySkinTransformer.cs @@ -0,0 +1,47 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using Humanizer; +using osu.Framework.Audio.Sample; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Textures; +using osu.Game.Audio; +using osu.Game.Skinning; + +namespace osu.Game.Rulesets.Catch.Skinning +{ + public class CatchLegacySkinTransformer : ISkin + { + private readonly ISkin source; + + public CatchLegacySkinTransformer(ISkinSource source) + { + this.source = source; + } + + public Drawable GetDrawableComponent(ISkinComponent component) + { + if (!(component is CatchSkinComponent catchSkinComponent)) + return null; + + switch (catchSkinComponent.Component) + { + case CatchSkinComponents.FruitApple: + case CatchSkinComponents.FruitBananas: + case CatchSkinComponents.FruitOrange: + case CatchSkinComponents.FruitGrapes: + case CatchSkinComponents.FruitPear: + return this.GetAnimation(catchSkinComponent.Component.ToString().Underscore().Hyphenate(), true, false, true); + } + + return null; + } + + public Texture GetTexture(string componentName) => source.GetTexture(componentName); + + public SampleChannel GetSample(ISampleInfo sample) => source.GetSample(sample); + + public IBindable GetConfig(TLookup lookup) => source.GetConfig(lookup); + } +}