// 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.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.MathUtils; using osu.Game.Screens.Menu; using osuTK; namespace osu.Game.Graphics.Containers { /// /// A container that creates a to be used to update and track the position of an . /// public class LogoFacadeContainer : Container { protected virtual Facade CreateFacade() => new Facade(); public Facade LogoFacade { get; } /// /// Whether or not the logo assigned to this FacadeContainer should be tracking the position its facade. /// public bool Tracking = false; protected OsuLogo Logo; private float facadeScale; private Easing easing; private Vector2? startPosition; private double? startTime; private double duration; public LogoFacadeContainer() { LogoFacade = CreateFacade(); } /// /// Assign the logo that should track the Facade's position, as well as how it should transform to its initial position. /// /// The instance of the logo to be used for tracking. /// The scale of the facade. Does not actually affect the logo itself. /// The duration of the initial transform. Default is instant. /// The easing type of the initial transform. public void SetLogo(OsuLogo logo, float facadeScale = 1.0f, double duration = 0, Easing easing = Easing.None) { Logo = logo ?? throw new ArgumentNullException(nameof(logo)); this.facadeScale = facadeScale; this.duration = duration; this.easing = easing; startTime = null; startPosition = null; } /// /// Gets the position that the logo should move to with respect to the . /// Manually performs a conversion of the Facade's position to the relative position of the Logo's Parent. /// /// Will only be correct if the logo's are set to Axes.Both /// The position that the logo should move to in its parent's relative space. protected Vector2 LogoTrackingPosition() { Vector2 local; local.X = Logo.Parent.ToLocalSpace(LogoFacade.ScreenSpaceDrawQuad.Centre).X / Logo.Parent.RelativeToAbsoluteFactor.X; local.Y = Logo.Parent.ToLocalSpace(LogoFacade.ScreenSpaceDrawQuad.Centre).Y / Logo.Parent.RelativeToAbsoluteFactor.Y; return local; } protected override void Update() { base.Update(); if (Logo == null || !Tracking) return; // Account for the scale of the actual logo container, as SizeForFlow only accounts for the sprite scale. LogoFacade.Size = new Vector2(Logo.SizeForFlow * Logo.Scale.X * facadeScale); if (LogoFacade.Parent != null && Logo.Position != LogoTrackingPosition()) { // If this is our first update since tracking has started, initialize our starting values for interpolation if (startTime == null || startPosition == null) { startTime = Time.Current; startPosition = Logo.Position; } if (duration != 0) { double elapsedDuration = Time.Current - startTime ?? throw new ArgumentNullException(nameof(startTime)); var mount = (float)Interpolation.ApplyEasing(easing, Math.Min(elapsedDuration / duration, 1)); // Interpolate the position of the logo, where mount 0 is where the logo was when it first began interpolating, and mount 1 is the target location. Logo.Position = Vector2.Lerp(startPosition ?? throw new ArgumentNullException(nameof(startPosition)), LogoTrackingPosition(), mount); } else { Logo.Position = LogoTrackingPosition(); } } } /// /// A placeholder container that serves as a dummy object to denote another object's location and size. /// public class Facade : Container { } } }