mirror of
https://github.com/ppy/osu.git
synced 2025-03-19 09:07:18 +08:00
Merge pull request #7881 from peppy/catch-fruit-skinning
Implement osu!catch fruit skinning support
This commit is contained in:
commit
f84f829fe5
@ -20,6 +20,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
{
|
||||
typeof(CatchHitObject),
|
||||
typeof(Fruit),
|
||||
typeof(FruitPiece),
|
||||
typeof(Droplet),
|
||||
typeof(Banana),
|
||||
typeof(BananaShower),
|
||||
|
@ -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;
|
||||
|
@ -5,5 +5,11 @@ namespace osu.Game.Rulesets.Catch
|
||||
{
|
||||
public enum CatchSkinComponents
|
||||
{
|
||||
FruitBananas,
|
||||
FruitApple,
|
||||
FruitGrapes,
|
||||
FruitOrange,
|
||||
FruitPear,
|
||||
Droplet
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.Catch.Objects
|
||||
{
|
||||
public abstract class CatchHitObject : HitObject, IHasXPosition, IHasComboInformation
|
||||
{
|
||||
public const double OBJECT_RADIUS = 44;
|
||||
public const float OBJECT_RADIUS = 64;
|
||||
|
||||
private float x;
|
||||
|
||||
@ -90,7 +90,7 @@ namespace osu.Game.Rulesets.Catch.Objects
|
||||
|
||||
TimePreempt = (float)BeatmapDifficulty.DifficultyRange(difficulty.ApproachRate, 1800, 1200, 450);
|
||||
|
||||
Scale = 1.0f - 0.7f * (difficulty.CircleSize - 5) / 5;
|
||||
Scale = (1.0f - 0.7f * (difficulty.CircleSize - 5) / 5) / 2;
|
||||
}
|
||||
|
||||
protected override HitWindows CreateHitWindows() => HitWindows.Empty;
|
||||
|
@ -1,6 +1,10 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Utils;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
{
|
||||
public class DrawableBanana : DrawableFruit
|
||||
@ -9,5 +13,28 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
: base(h)
|
||||
{
|
||||
}
|
||||
|
||||
private Color4? colour;
|
||||
|
||||
protected override Color4 GetComboColour(IReadOnlyList<Color4> comboColours)
|
||||
{
|
||||
// override any external colour changes with banananana
|
||||
return colour ??= getBananaColour();
|
||||
}
|
||||
|
||||
private Color4 getBananaColour()
|
||||
{
|
||||
switch (RNG.Next(0, 3))
|
||||
{
|
||||
default:
|
||||
return new Color4(255, 240, 0, 255);
|
||||
|
||||
case 1:
|
||||
return new Color4(255, 192, 0, 255);
|
||||
|
||||
case 2:
|
||||
return new Color4(214, 221, 28, 255);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,11 +2,15 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using osuTK;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
{
|
||||
@ -15,11 +19,34 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
{
|
||||
public override bool CanBePlated => true;
|
||||
|
||||
protected Container ScaleContainer { get; private set; }
|
||||
|
||||
protected PalpableCatchHitObject(TObject hitObject)
|
||||
: base(hitObject)
|
||||
{
|
||||
Scale = new Vector2(HitObject.Scale);
|
||||
Origin = Anchor.Centre;
|
||||
Size = new Vector2(CatchHitObject.OBJECT_RADIUS * 2);
|
||||
Masking = false;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
AddRangeInternal(new Framework.Graphics.Drawable[]
|
||||
{
|
||||
ScaleContainer = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre,
|
||||
}
|
||||
});
|
||||
|
||||
ScaleContainer.Scale = new Vector2(HitObject.Scale);
|
||||
}
|
||||
|
||||
protected override Color4 GetComboColour(IReadOnlyList<Color4> comboColours) =>
|
||||
comboColours[(HitObject.IndexInBeatmap + 1) % comboColours.Count];
|
||||
}
|
||||
|
||||
public abstract class DrawableCatchHitObject<TObject> : DrawableCatchHitObject
|
||||
@ -41,6 +68,8 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
|
||||
public virtual bool StaysOnPlate => CanBePlated;
|
||||
|
||||
public float DisplayRadius => DrawSize.X / 2 * Scale.X * HitObject.Scale;
|
||||
|
||||
protected DrawableCatchHitObject(CatchHitObject hitObject)
|
||||
: base(hitObject)
|
||||
{
|
||||
|
@ -2,32 +2,28 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Catch.Objects.Drawable.Pieces;
|
||||
using osuTK;
|
||||
using osu.Game.Skinning;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
{
|
||||
public class DrawableDroplet : PalpableCatchHitObject<Droplet>
|
||||
{
|
||||
private Pulp pulp;
|
||||
|
||||
public override bool StaysOnPlate => false;
|
||||
|
||||
public DrawableDroplet(Droplet h)
|
||||
: base(h)
|
||||
{
|
||||
Origin = Anchor.Centre;
|
||||
Size = new Vector2((float)CatchHitObject.OBJECT_RADIUS) / 4;
|
||||
Masking = false;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
AddInternal(pulp = new Pulp { Size = Size });
|
||||
|
||||
AccentColour.BindValueChanged(colour => { pulp.AccentColour = colour.NewValue; }, true);
|
||||
ScaleContainer.Child = new SkinnableDrawable(new CatchSkinComponent(CatchSkinComponents.Droplet), _ => new Pulp
|
||||
{
|
||||
Size = Size / 4,
|
||||
AccentColour = { BindTarget = AccentColour }
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,313 +3,47 @@
|
||||
|
||||
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 osuTK;
|
||||
using osuTK.Graphics;
|
||||
using osu.Game.Skinning;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
{
|
||||
public class DrawableFruit : PalpableCatchHitObject<Fruit>
|
||||
{
|
||||
private Circle border;
|
||||
|
||||
private const float drawable_radius = (float)CatchHitObject.OBJECT_RADIUS * radius_adjust;
|
||||
|
||||
/// <summary>
|
||||
/// Because we're adding a border around the fruit, we need to scale down some.
|
||||
/// </summary>
|
||||
private const float radius_adjust = 1.1f;
|
||||
|
||||
public DrawableFruit(Fruit h)
|
||||
: base(h)
|
||||
{
|
||||
Origin = Anchor.Centre;
|
||||
|
||||
Size = new Vector2(drawable_radius);
|
||||
Masking = false;
|
||||
|
||||
Rotation = (float)(RNG.NextDouble() - 0.5f) * 40;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
// todo: this should come from the skin.
|
||||
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)
|
||||
});
|
||||
}
|
||||
ScaleContainer.Child = new SkinnableDrawable(
|
||||
new CatchSkinComponent(getComponent(HitObject.VisualRepresentation)), _ => new FruitPiece());
|
||||
}
|
||||
|
||||
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),
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
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,
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
default:
|
||||
case FruitVisualRepresentation.Pear:
|
||||
return new Color4(17, 136, 170, 255);
|
||||
|
||||
case FruitVisualRepresentation.Grape:
|
||||
return new Color4(204, 102, 0, 255);
|
||||
|
||||
case FruitVisualRepresentation.Raspberry:
|
||||
return new Color4(121, 9, 13, 255);
|
||||
return CatchSkinComponents.FruitGrapes;
|
||||
|
||||
case FruitVisualRepresentation.Pineapple:
|
||||
return new Color4(102, 136, 0, 255);
|
||||
return CatchSkinComponents.FruitApple;
|
||||
|
||||
case FruitVisualRepresentation.Raspberry:
|
||||
return CatchSkinComponents.FruitOrange;
|
||||
|
||||
case FruitVisualRepresentation.Banana:
|
||||
switch (RNG.Next(0, 3))
|
||||
{
|
||||
default:
|
||||
return new Color4(255, 240, 0, 255);
|
||||
return CatchSkinComponents.FruitBananas;
|
||||
|
||||
case 1:
|
||||
return new Color4(255, 192, 0, 255);
|
||||
|
||||
case 2:
|
||||
return new Color4(214, 221, 28, 255);
|
||||
}
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(hitObjectVisualRepresentation), hitObjectVisualRepresentation, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -42,10 +42,11 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
switch (hitObject)
|
||||
{
|
||||
case CatchHitObject catchObject:
|
||||
return createDrawableRepresentation?.Invoke(catchObject)?.With(o => ((DrawableCatchHitObject)o).CheckPosition = p => CheckPosition?.Invoke(p) ?? false);
|
||||
return createDrawableRepresentation?.Invoke(catchObject)?.With(o =>
|
||||
((DrawableCatchHitObject)o).CheckPosition = p => CheckPosition?.Invoke(p) ?? false);
|
||||
}
|
||||
|
||||
return base.CreateNestedHitObject(hitObject);
|
||||
throw new ArgumentException($"{nameof(hitObject)} must be of type {nameof(CatchHitObject)}.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
|
||||
using osuTK;
|
||||
using osu.Framework.Allocation;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
{
|
||||
@ -10,7 +10,12 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
public DrawableTinyDroplet(TinyDroplet h)
|
||||
: base(h)
|
||||
{
|
||||
Size = new Vector2((float)CatchHitObject.OBJECT_RADIUS) / 8;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
ScaleContainer.Scale /= 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
274
osu.Game.Rulesets.Catch/Objects/Drawable/FruitPiece.cs
Normal file
274
osu.Game.Rulesets.Catch/Objects/Drawable/FruitPiece.cs
Normal file
@ -0,0 +1,274 @@
|
||||
// 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.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
|
||||
{
|
||||
/// <summary>
|
||||
/// Because we're adding a border around the fruit, we need to scale down some.
|
||||
/// </summary>
|
||||
private const float radius_adjust = 1.1f;
|
||||
|
||||
private Circle border;
|
||||
|
||||
private CatchHitObject hitObject;
|
||||
|
||||
private readonly IBindable<Color4> accentColour = new Bindable<Color4>();
|
||||
|
||||
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 = 6f * radius_adjust,
|
||||
Children = new Framework.Graphics.Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
AlwaysPresent = true,
|
||||
Alpha = 0,
|
||||
RelativeSizeAxes = Axes.Both
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
if (hitObject.HyperDash)
|
||||
{
|
||||
AddInternal(new Pulp
|
||||
{
|
||||
RelativePositionAxes = Axes.Both,
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
AccentColour = { Value = 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 = 16f * 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 = { 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),
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
case FruitVisualRepresentation.Pineapple:
|
||||
return new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new Framework.Graphics.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),
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
case FruitVisualRepresentation.Pear:
|
||||
return new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new Framework.Graphics.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),
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
case FruitVisualRepresentation.Grape:
|
||||
return new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new Framework.Graphics.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),
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
case FruitVisualRepresentation.Banana:
|
||||
|
||||
return new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new Framework.Graphics.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,16 +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 osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Effects;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Graphics;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Objects.Drawable.Pieces
|
||||
{
|
||||
public class Pulp : Circle, IHasAccentColour
|
||||
public class Pulp : Circle
|
||||
{
|
||||
public Pulp()
|
||||
{
|
||||
@ -22,32 +22,23 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable.Pieces
|
||||
Colour = Color4.White.Opacity(0.9f);
|
||||
}
|
||||
|
||||
private Color4 accentColour;
|
||||
public readonly Bindable<Color4> AccentColour = new Bindable<Color4>();
|
||||
|
||||
public Color4 AccentColour
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
get => accentColour;
|
||||
set
|
||||
{
|
||||
accentColour = value;
|
||||
if (IsLoaded) updateAccentColour();
|
||||
}
|
||||
base.LoadComplete();
|
||||
|
||||
AccentColour.BindValueChanged(updateAccentColour, true);
|
||||
}
|
||||
|
||||
private void updateAccentColour()
|
||||
private void updateAccentColour(ValueChangedEvent<Color4> colour)
|
||||
{
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Type = EdgeEffectType.Glow,
|
||||
Radius = Size.X / 2,
|
||||
Colour = accentColour.Darken(0.2f).Opacity(0.75f)
|
||||
Colour = colour.NewValue.Darken(0.2f).Opacity(0.75f)
|
||||
};
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
updateAccentColour();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,58 @@
|
||||
// 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.Audio.Sample;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
|
||||
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:
|
||||
var lookupName = catchSkinComponent.Component.ToString().Kebaberize();
|
||||
if (GetTexture(lookupName) != null)
|
||||
return new LegacyFruitPiece(lookupName);
|
||||
|
||||
break;
|
||||
|
||||
case CatchSkinComponents.Droplet:
|
||||
if (GetTexture("fruit-drop") != null)
|
||||
return new LegacyFruitPiece("fruit-drop") { Scale = new Vector2(0.8f) };
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public Texture GetTexture(string componentName) => source.GetTexture(componentName);
|
||||
|
||||
public SampleChannel GetSample(ISampleInfo sample) => source.GetSample(sample);
|
||||
|
||||
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => source.GetConfig<TLookup, TValue>(lookup);
|
||||
}
|
||||
}
|
61
osu.Game.Rulesets.Catch/Skinning/LegacyFruitPiece.cs
Normal file
61
osu.Game.Rulesets.Catch/Skinning/LegacyFruitPiece.cs
Normal file
@ -0,0 +1,61 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using 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.Drawable;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Skinning
|
||||
{
|
||||
internal class LegacyFruitPiece : CompositeDrawable
|
||||
{
|
||||
private readonly string lookupName;
|
||||
|
||||
private readonly IBindable<Color4> accentColour = new Bindable<Color4>();
|
||||
private Sprite colouredSprite;
|
||||
|
||||
public LegacyFruitPiece(string lookupName)
|
||||
{
|
||||
this.lookupName = lookupName;
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(DrawableHitObject drawableObject, ISkinSource skin)
|
||||
{
|
||||
DrawableCatchHitObject drawableCatchObject = (DrawableCatchHitObject)drawableObject;
|
||||
|
||||
accentColour.BindTo(drawableCatchObject.AccentColour);
|
||||
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
colouredSprite = new Sprite
|
||||
{
|
||||
Texture = skin.GetTexture(lookupName),
|
||||
Colour = drawableObject.AccentColour.Value,
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
},
|
||||
new Sprite
|
||||
{
|
||||
Texture = skin.GetTexture($"{lookupName}-overlay"),
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
accentColour.BindValueChanged(colour => colouredSprite.Colour = colour.NewValue, true);
|
||||
}
|
||||
}
|
||||
}
|
@ -74,11 +74,11 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
|
||||
caughtFruit.Anchor = Anchor.TopCentre;
|
||||
caughtFruit.Origin = Anchor.Centre;
|
||||
caughtFruit.Scale *= 0.7f;
|
||||
caughtFruit.Scale *= 0.5f;
|
||||
caughtFruit.LifetimeStart = caughtFruit.HitObject.StartTime;
|
||||
caughtFruit.LifetimeEnd = double.MaxValue;
|
||||
|
||||
MovableCatcher.Add(caughtFruit);
|
||||
MovableCatcher.PlaceOnPlate(caughtFruit);
|
||||
lastPlateableFruit = caughtFruit;
|
||||
|
||||
if (!fruit.StaysOnPlate)
|
||||
@ -221,9 +221,9 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
/// Add a caught fruit to the catcher's stack.
|
||||
/// </summary>
|
||||
/// <param name="fruit">The fruit that was caught.</param>
|
||||
public void Add(DrawableHitObject fruit)
|
||||
public void PlaceOnPlate(DrawableCatchHitObject fruit)
|
||||
{
|
||||
float ourRadius = fruit.DrawSize.X / 2 * fruit.Scale.X;
|
||||
float ourRadius = fruit.DisplayRadius;
|
||||
float theirRadius = 0;
|
||||
|
||||
const float allowance = 6;
|
||||
|
Loading…
x
Reference in New Issue
Block a user