mirror of
https://github.com/ppy/osu.git
synced 2025-01-31 17:12:56 +08:00
Add seasonal lighting
Replaces kiai fountains for now.
This commit is contained in:
parent
34c255c941
commit
6dd80589dd
@ -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 System.Linq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Testing;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Database;
|
||||||
|
using osu.Game.Screens.Menu;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual.Menus
|
||||||
|
{
|
||||||
|
public partial class TestSceneMainMenuSeasonalLighting : OsuTestScene
|
||||||
|
{
|
||||||
|
[Resolved]
|
||||||
|
private BeatmapManager beatmaps { get; set; } = null!;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private RealmAccess realm { get; set; } = null!;
|
||||||
|
|
||||||
|
[SetUpSteps]
|
||||||
|
public void SetUpSteps()
|
||||||
|
{
|
||||||
|
AddStep("prepare beatmap", () =>
|
||||||
|
{
|
||||||
|
var setInfo = beatmaps.QueryBeatmapSet(b => b.Protected && b.Hash == "7e26183e72a496f672c3a21292e6b469fdecd084d31c259ea10a31df5b46cd77");
|
||||||
|
|
||||||
|
Beatmap.Value = beatmaps.GetWorkingBeatmap(setInfo!.Value.Beatmaps.First());
|
||||||
|
});
|
||||||
|
|
||||||
|
AddStep("create lighting", () => Child = new MainMenuSeasonalLighting());
|
||||||
|
|
||||||
|
AddStep("restart beatmap", () =>
|
||||||
|
{
|
||||||
|
Beatmap.Value.Track.Start();
|
||||||
|
Beatmap.Value.Track.Seek(4000);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestBasic()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -124,6 +124,7 @@ namespace osu.Game.Screens.Menu
|
|||||||
|
|
||||||
AddRangeInternal(new[]
|
AddRangeInternal(new[]
|
||||||
{
|
{
|
||||||
|
SeasonalUI.ENABLED ? new MainMenuSeasonalLighting() : Empty(),
|
||||||
buttonsContainer = new ParallaxContainer
|
buttonsContainer = new ParallaxContainer
|
||||||
{
|
{
|
||||||
ParallaxAmount = 0.01f,
|
ParallaxAmount = 0.01f,
|
||||||
@ -166,7 +167,8 @@ namespace osu.Game.Screens.Menu
|
|||||||
Origin = Anchor.TopRight,
|
Origin = Anchor.TopRight,
|
||||||
Margin = new MarginPadding { Right = 15, Top = 5 }
|
Margin = new MarginPadding { Right = 15, Top = 5 }
|
||||||
},
|
},
|
||||||
new KiaiMenuFountains(),
|
// For now, this is too much alongside the seasonal lighting.
|
||||||
|
SeasonalUI.ENABLED ? Empty() : new KiaiMenuFountains(),
|
||||||
bottomElementsFlow = new FillFlowContainer
|
bottomElementsFlow = new FillFlowContainer
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
|
188
osu.Game/Screens/Menu/MainMenuSeasonalLighting.cs
Normal file
188
osu.Game/Screens/Menu/MainMenuSeasonalLighting.cs
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
// 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.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
|
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.Graphics.Shapes;
|
||||||
|
using osu.Framework.Timing;
|
||||||
|
using osu.Framework.Utils;
|
||||||
|
using osu.Game.Audio;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
|
using osu.Game.Rulesets.Objects;
|
||||||
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
|
using osuTK;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Menu
|
||||||
|
{
|
||||||
|
public partial class MainMenuSeasonalLighting : CompositeDrawable
|
||||||
|
{
|
||||||
|
private IBindable<WorkingBeatmap> working = null!;
|
||||||
|
|
||||||
|
private InterpolatingFramedClock beatmapClock = null!;
|
||||||
|
|
||||||
|
private List<HitObject> hitObjects = null!;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private RulesetStore rulesets { get; set; } = null!;
|
||||||
|
|
||||||
|
public MainMenuSeasonalLighting()
|
||||||
|
{
|
||||||
|
RelativeChildSize = new Vector2(512, 384);
|
||||||
|
|
||||||
|
RelativeSizeAxes = Axes.X;
|
||||||
|
|
||||||
|
Anchor = Anchor.Centre;
|
||||||
|
Origin = Anchor.Centre;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(IBindable<WorkingBeatmap> working)
|
||||||
|
{
|
||||||
|
this.working = working.GetBoundCopy();
|
||||||
|
this.working.BindValueChanged(_ => Scheduler.AddOnce(updateBeatmap), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateBeatmap()
|
||||||
|
{
|
||||||
|
lastObjectIndex = null;
|
||||||
|
beatmapClock = new InterpolatingFramedClock(new FramedClock(working.Value.Track));
|
||||||
|
hitObjects = working.Value.GetPlayableBeatmap(rulesets.GetRuleset(0)).HitObjects.SelectMany(h => h.NestedHitObjects.Prepend(h))
|
||||||
|
.OrderBy(h => h.StartTime)
|
||||||
|
.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private int? lastObjectIndex;
|
||||||
|
|
||||||
|
protected override void Update()
|
||||||
|
{
|
||||||
|
base.Update();
|
||||||
|
|
||||||
|
Height = DrawWidth / 16 * 10;
|
||||||
|
|
||||||
|
beatmapClock.ProcessFrame();
|
||||||
|
|
||||||
|
// intentionally slightly early since we are doing fades on the lighting.
|
||||||
|
double time = beatmapClock.CurrentTime + 50;
|
||||||
|
|
||||||
|
// handle seeks or OOB by skipping to current.
|
||||||
|
if (lastObjectIndex == null || lastObjectIndex >= hitObjects.Count || (lastObjectIndex >= 0 && hitObjects[lastObjectIndex.Value].StartTime > time)
|
||||||
|
|| Math.Abs(beatmapClock.ElapsedFrameTime) > 500)
|
||||||
|
lastObjectIndex = hitObjects.Count(h => h.StartTime < time) - 1;
|
||||||
|
|
||||||
|
while (lastObjectIndex < hitObjects.Count - 1)
|
||||||
|
{
|
||||||
|
var h = hitObjects[lastObjectIndex.Value + 1];
|
||||||
|
|
||||||
|
if (h.StartTime > time)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Don't add lighting if the game is running too slow.
|
||||||
|
if (Clock.ElapsedFrameTime < 20)
|
||||||
|
addLight(h);
|
||||||
|
|
||||||
|
lastObjectIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addLight(HitObject h)
|
||||||
|
{
|
||||||
|
var light = new Light
|
||||||
|
{
|
||||||
|
RelativePositionAxes = Axes.Both,
|
||||||
|
Position = ((IHasPosition)h).Position
|
||||||
|
};
|
||||||
|
|
||||||
|
AddInternal(light);
|
||||||
|
|
||||||
|
if (h.GetType().Name.Contains("Tick"))
|
||||||
|
{
|
||||||
|
light.Colour = SeasonalUI.AMBIENT_COLOUR_1;
|
||||||
|
light.Scale = new Vector2(0.5f);
|
||||||
|
light
|
||||||
|
.FadeInFromZero(250)
|
||||||
|
.Then()
|
||||||
|
.FadeOutFromOne(1000, Easing.Out);
|
||||||
|
|
||||||
|
light.MoveToOffset(new Vector2(RNG.Next(-20, 20), RNG.Next(-20, 20)), 1400, Easing.Out);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// default green
|
||||||
|
Color4 col = SeasonalUI.PRIMARY_COLOUR_2;
|
||||||
|
|
||||||
|
// whistle red
|
||||||
|
if (h.Samples.Any(s => s.Name == HitSampleInfo.HIT_WHISTLE))
|
||||||
|
col = SeasonalUI.PRIMARY_COLOUR_1;
|
||||||
|
// clap is third colour
|
||||||
|
else if (h.Samples.Any(s => s.Name == HitSampleInfo.HIT_CLAP))
|
||||||
|
col = SeasonalUI.AMBIENT_COLOUR_1;
|
||||||
|
|
||||||
|
light.Colour = col;
|
||||||
|
|
||||||
|
// finish larger lighting
|
||||||
|
if (h.Samples.Any(s => s.Name == HitSampleInfo.HIT_FINISH))
|
||||||
|
light.Scale = new Vector2(3);
|
||||||
|
|
||||||
|
light
|
||||||
|
.FadeInFromZero(150)
|
||||||
|
.Then()
|
||||||
|
.FadeOutFromOne(1000, Easing.In);
|
||||||
|
|
||||||
|
light.Expire();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public partial class Light : CompositeDrawable
|
||||||
|
{
|
||||||
|
private readonly Circle circle;
|
||||||
|
|
||||||
|
public new Color4 Colour
|
||||||
|
{
|
||||||
|
set
|
||||||
|
{
|
||||||
|
circle.Colour = value.Darken(0.8f);
|
||||||
|
circle.EdgeEffect = new EdgeEffectParameters
|
||||||
|
{
|
||||||
|
Type = EdgeEffectType.Glow,
|
||||||
|
Colour = value,
|
||||||
|
Radius = 80,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Light()
|
||||||
|
{
|
||||||
|
InternalChildren = new Drawable[]
|
||||||
|
{
|
||||||
|
circle = new Circle
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Size = new Vector2(12),
|
||||||
|
Colour = SeasonalUI.AMBIENT_COLOUR_1,
|
||||||
|
Blending = BlendingParameters.Additive,
|
||||||
|
EdgeEffect = new EdgeEffectParameters
|
||||||
|
{
|
||||||
|
Type = EdgeEffectType.Glow,
|
||||||
|
Colour = SeasonalUI.AMBIENT_COLOUR_2,
|
||||||
|
Radius = 80,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Origin = Anchor.Centre;
|
||||||
|
Alpha = 0.5f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user