// Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using OpenTK; using OpenTK.Graphics; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Sprites; using osu.Game.Users; using osu.Game.Graphics; using osu.Game.Graphics.Backgrounds; using osu.Game.Overlays.MedalSplash; using osu.Framework.Allocation; using osu.Framework.Audio.Sample; using osu.Framework.Audio; using osu.Framework.Graphics.Textures; using osu.Framework.Input; using OpenTK.Input; using System.Linq; using osu.Framework.Graphics.Shapes; using System; using osu.Framework.MathUtils; namespace osu.Game.Overlays { public class MedalOverlay : FocusedOverlayContainer { public const float DISC_SIZE = 400; private const float border_width = 5; private readonly Medal medal; private readonly Box background; private readonly Container backgroundStrip, particleContainer; private readonly BackgroundStrip leftStrip, rightStrip; private readonly CircularContainer disc; private readonly Sprite innerSpin, outerSpin; private DrawableMedal drawableMedal; private SampleChannel getSample; public MedalOverlay(Medal medal) { this.medal = medal; RelativeSizeAxes = Axes.Both; Children = new Drawable[] { background = new Box { RelativeSizeAxes = Axes.Both, Colour = Color4.Black.Opacity(60), }, outerSpin = new Sprite { Anchor = Anchor.Centre, Origin = Anchor.Centre, Size = new Vector2(DISC_SIZE + 500), Alpha = 0f, }, backgroundStrip = new Container { Anchor = Anchor.Centre, Origin = Anchor.Centre, RelativeSizeAxes = Axes.X, Height = border_width, Alpha = 0f, Children = new[] { new Container { RelativeSizeAxes = Axes.Both, Anchor = Anchor.Centre, Origin = Anchor.CentreRight, Width = 0.5f, Padding = new MarginPadding { Right = DISC_SIZE / 2 }, Children = new[] { leftStrip = new BackgroundStrip(0f, 1f) { Anchor = Anchor.TopRight, Origin = Anchor.TopRight, }, }, }, new Container { RelativeSizeAxes = Axes.Both, Anchor = Anchor.Centre, Origin = Anchor.CentreLeft, Width = 0.5f, Padding = new MarginPadding { Left = DISC_SIZE / 2 }, Children = new[] { rightStrip = new BackgroundStrip(1f, 0f), }, }, }, }, particleContainer = new Container { RelativeSizeAxes = Axes.Both, Alpha = 0f, }, disc = new CircularContainer { Anchor = Anchor.Centre, Origin = Anchor.Centre, Alpha = 0f, Masking = true, AlwaysPresent = true, BorderColour = Color4.White, BorderThickness = border_width, Size = new Vector2(DISC_SIZE), Scale = new Vector2(0.8f), Children = new Drawable[] { new Box { RelativeSizeAxes = Axes.Both, Colour = OsuColour.FromHex(@"05262f"), }, new Triangles { RelativeSizeAxes = Axes.Both, TriangleScale = 2, ColourDark = OsuColour.FromHex(@"04222b"), ColourLight = OsuColour.FromHex(@"052933"), }, innerSpin = new Sprite { Anchor = Anchor.Centre, Origin = Anchor.Centre, RelativeSizeAxes = Axes.Both, Size = new Vector2(1.05f), Alpha = 0.25f, }, }, }, }; } [BackgroundDependencyLoader] private void load(OsuColour colours, TextureStore textures, AudioManager audio) { getSample = audio.Sample.Get(@"MedalSplash/medal-get"); innerSpin.Texture = outerSpin.Texture = textures.Get(@"MedalSplash/disc-spin"); disc.EdgeEffect = leftStrip.EdgeEffect = rightStrip.EdgeEffect = new EdgeEffectParameters { Type = EdgeEffectType.Glow, Colour = colours.Blue.Opacity(0.5f), Radius = 50, }; disc.Add(drawableMedal = new DrawableMedal(medal) { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, RelativeSizeAxes = Axes.X, }); } protected override void LoadComplete() { base.LoadComplete(); Show(); } protected override void Update() { base.Update(); particleContainer.Add(new MedalParticle(RNG.Next(0, 359))); } protected override bool OnClick(InputState state) { dismiss(); return true; } protected override void OnFocusLost(InputState state) { if (state.Keyboard.Keys.Contains(Key.Escape)) dismiss(); } private const double initial_duration = 400; private const double step_duration = 900; protected override void PopIn() { base.PopIn(); FadeIn(200); background.FlashColour(Color4.White.Opacity(0.25f), 400); getSample.Play(); using (innerSpin.BeginLoopedSequence()) innerSpin.RotateTo(360, 20000); using (outerSpin.BeginLoopedSequence()) outerSpin.RotateTo(360, 40000); using (BeginDelayedSequence(200, true)) { disc.FadeIn(initial_duration); particleContainer.FadeIn(initial_duration); outerSpin.FadeTo(0.1f, initial_duration * 2); disc.ScaleTo(1f, initial_duration * 2, EasingTypes.OutElastic); using (BeginDelayedSequence(initial_duration + 200, true)) { backgroundStrip.FadeIn(step_duration); leftStrip.ResizeWidthTo(1f, step_duration, EasingTypes.OutQuint); rightStrip.ResizeWidthTo(1f, step_duration, EasingTypes.OutQuint); Schedule(() => { if (drawableMedal.State != DisplayState.Full) drawableMedal.State = DisplayState.Icon; }); using (BeginDelayedSequence(step_duration, true)) { Schedule(() => { if (drawableMedal.State != DisplayState.Full) drawableMedal.State = DisplayState.MedalUnlocked; }); using (BeginDelayedSequence(step_duration, true)) Schedule(() => { if (drawableMedal.State != DisplayState.Full) drawableMedal.State = DisplayState.Full; }); } } } } protected override void PopOut() { base.PopOut(); FadeOut(200); } private void dismiss() { if (drawableMedal.State != DisplayState.Full) { // if we haven't yet, play out the animation fully drawableMedal.State = DisplayState.Full; Flush(true); return; } Hide(); Expire(); } private class BackgroundStrip : Container { public BackgroundStrip(float start, float end) { RelativeSizeAxes = Axes.Both; Width = 0f; ColourInfo = ColourInfo.GradientHorizontal(Color4.White.Opacity(start), Color4.White.Opacity(end)); Masking = true; Children = new[] { new Box { RelativeSizeAxes = Axes.Both, Colour = Color4.White, } }; } } private class MedalParticle : CircularContainer { private readonly float direction; private Vector2 positionForOffset(float offset) => new Vector2((float)(offset * Math.Sin(direction)), (float)(offset * Math.Cos(direction))); public MedalParticle(float direction) { this.direction = direction; Anchor = Anchor.Centre; Origin = Anchor.Centre; Position = positionForOffset(DISC_SIZE / 2); Masking = true; } [BackgroundDependencyLoader] private void load(OsuColour colours) { EdgeEffect = new EdgeEffectParameters { Type = EdgeEffectType.Glow, Colour = colours.Blue.Opacity(0.5f), Radius = 5, }; MoveTo(positionForOffset(DISC_SIZE / 2 + 200), 500); FadeOut(500); Expire(); } } } }