mirror of
https://github.com/ppy/osu.git
synced 2025-01-14 00:42:55 +08:00
Merge pull request #1278 from Damnae/storyboard_integration
Storyboard integration
This commit is contained in:
commit
3fd4a97a19
@ -54,6 +54,7 @@ namespace osu.Game.Configuration
|
||||
// Graphics
|
||||
Set(OsuSetting.ShowFpsDisplay, false);
|
||||
|
||||
Set(OsuSetting.ShowStoryboard, true);
|
||||
Set(OsuSetting.CursorRotation, true);
|
||||
|
||||
Set(OsuSetting.MenuParallax, true);
|
||||
@ -89,6 +90,7 @@ namespace osu.Game.Configuration
|
||||
GameplayCursorSize,
|
||||
AutoCursorSize,
|
||||
DimLevel,
|
||||
ShowStoryboard,
|
||||
KeyOverlay,
|
||||
FloatingComments,
|
||||
PlaybackSpeed,
|
||||
|
@ -14,6 +14,11 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
|
||||
{
|
||||
Children = new[]
|
||||
{
|
||||
new SettingsCheckbox
|
||||
{
|
||||
LabelText = "Storyboards",
|
||||
Bindable = config.GetBindable<bool>(OsuSetting.ShowStoryboard)
|
||||
},
|
||||
new SettingsCheckbox
|
||||
{
|
||||
LabelText = "Rotate cursor when dragging",
|
||||
|
@ -24,6 +24,8 @@ using osu.Game.Screens.Ranking;
|
||||
using osu.Framework.Audio.Sample;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Storyboards.Drawables;
|
||||
using OpenTK.Graphics;
|
||||
|
||||
namespace osu.Game.Screens.Play
|
||||
{
|
||||
@ -59,6 +61,7 @@ namespace osu.Game.Screens.Play
|
||||
#region User Settings
|
||||
|
||||
private Bindable<double> dimLevel;
|
||||
private Bindable<bool> showStoryboard;
|
||||
private Bindable<bool> mouseWheelDisabled;
|
||||
private Bindable<double> userAudioOffset;
|
||||
|
||||
@ -66,6 +69,9 @@ namespace osu.Game.Screens.Play
|
||||
|
||||
#endregion
|
||||
|
||||
private Container storyboardContainer;
|
||||
private DrawableStoryboard storyboard;
|
||||
|
||||
private HUDOverlay hudOverlay;
|
||||
private FailOverlay failOverlay;
|
||||
|
||||
@ -77,6 +83,7 @@ namespace osu.Game.Screens.Play
|
||||
this.api = api;
|
||||
|
||||
dimLevel = config.GetBindable<double>(OsuSetting.DimLevel);
|
||||
showStoryboard = config.GetBindable<bool>(OsuSetting.ShowStoryboard);
|
||||
|
||||
mouseWheelDisabled = config.GetBindable<bool>(OsuSetting.MouseDisableWheel);
|
||||
|
||||
@ -145,6 +152,12 @@ namespace osu.Game.Screens.Play
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
storyboardContainer = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Clock = offsetClock,
|
||||
Alpha = 0,
|
||||
},
|
||||
pauseContainer = new PauseContainer
|
||||
{
|
||||
AudioClock = decoupledClock,
|
||||
@ -196,6 +209,9 @@ namespace osu.Game.Screens.Play
|
||||
|
||||
scoreProcessor = RulesetContainer.CreateScoreProcessor();
|
||||
|
||||
if (showStoryboard)
|
||||
initializeStoryboard(false);
|
||||
|
||||
hudOverlay.BindProcessor(scoreProcessor);
|
||||
hudOverlay.BindRulesetContainer(RulesetContainer);
|
||||
|
||||
@ -211,6 +227,16 @@ namespace osu.Game.Screens.Play
|
||||
scoreProcessor.Failed += onFail;
|
||||
}
|
||||
|
||||
private void initializeStoryboard(bool asyncLoad)
|
||||
{
|
||||
var beatmap = Beatmap.Value.Beatmap;
|
||||
|
||||
storyboard = beatmap.Storyboard.CreateDrawable(Beatmap.Value);
|
||||
storyboard.Masking = true;
|
||||
|
||||
storyboardContainer.Add(asyncLoad ? new AsyncLoadWrapper(storyboard) { RelativeSizeAxes = Axes.Both } : (Drawable)storyboard);
|
||||
}
|
||||
|
||||
public void Restart()
|
||||
{
|
||||
sampleRestart?.Play();
|
||||
@ -266,12 +292,12 @@ namespace osu.Game.Screens.Play
|
||||
return;
|
||||
|
||||
(Background as BackgroundScreenBeatmap)?.BlurTo(Vector2.Zero, 1500, Easing.OutQuint);
|
||||
Background?.FadeTo(1 - (float)dimLevel, 1500, Easing.OutQuint);
|
||||
|
||||
dimLevel.ValueChanged += dimLevel_ValueChanged;
|
||||
showStoryboard.ValueChanged += showStoryboard_ValueChanged;
|
||||
updateBackgroundElements();
|
||||
|
||||
Content.Alpha = 0;
|
||||
|
||||
dimLevel.ValueChanged += newDim => Background?.FadeTo(1 - (float)newDim, 800);
|
||||
|
||||
Content
|
||||
.ScaleTo(0.7f)
|
||||
.ScaleTo(1, 750, Easing.OutQuint)
|
||||
@ -310,8 +336,33 @@ namespace osu.Game.Screens.Play
|
||||
return true;
|
||||
}
|
||||
|
||||
private void dimLevel_ValueChanged(double newValue)
|
||||
=> updateBackgroundElements();
|
||||
|
||||
private void showStoryboard_ValueChanged(bool newValue)
|
||||
=> updateBackgroundElements();
|
||||
|
||||
private void updateBackgroundElements()
|
||||
{
|
||||
var opacity = 1 - (float)dimLevel;
|
||||
|
||||
if (showStoryboard && storyboard == null)
|
||||
initializeStoryboard(true);
|
||||
|
||||
var beatmap = Beatmap.Value;
|
||||
var storyboardVisible = showStoryboard && beatmap.Beatmap.Storyboard.HasDrawable;
|
||||
|
||||
storyboardContainer.FadeColour(new Color4(opacity, opacity, opacity, 1), 800);
|
||||
storyboardContainer.FadeTo(storyboardVisible && opacity > 0 ? 1 : 0);
|
||||
|
||||
Background?.FadeTo(!storyboardVisible || beatmap.Background == null ? opacity : 0, 800, Easing.OutQuint);
|
||||
}
|
||||
|
||||
private void fadeOut()
|
||||
{
|
||||
dimLevel.ValueChanged -= dimLevel_ValueChanged;
|
||||
showStoryboard.ValueChanged -= showStoryboard_ValueChanged;
|
||||
|
||||
const float fade_out_duration = 250;
|
||||
|
||||
RulesetContainer?.FadeOut(fade_out_duration);
|
||||
|
@ -10,8 +10,8 @@ namespace osu.Game.Storyboards
|
||||
public double LoopStartTime;
|
||||
public int LoopCount;
|
||||
|
||||
public override double StartTime => LoopStartTime;
|
||||
public override double EndTime => LoopStartTime + CommandsDuration * LoopCount;
|
||||
public override double StartTime => LoopStartTime + CommandsStartTime;
|
||||
public override double EndTime => StartTime + CommandsDuration * LoopCount;
|
||||
|
||||
public CommandLoop(double startTime, int loopCount)
|
||||
{
|
||||
|
@ -5,6 +5,7 @@ using OpenTK;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Game.IO;
|
||||
|
||||
@ -14,6 +15,16 @@ namespace osu.Game.Storyboards.Drawables
|
||||
{
|
||||
public Storyboard Storyboard { get; private set; }
|
||||
|
||||
private readonly Background background;
|
||||
public Texture BackgroundTexture
|
||||
{
|
||||
get { return background.Texture; }
|
||||
set { background.Texture = value; }
|
||||
}
|
||||
|
||||
private readonly Container<DrawableStoryboardLayer> content;
|
||||
protected override Container<DrawableStoryboardLayer> Content => content;
|
||||
|
||||
protected override Vector2 DrawScale => new Vector2(Parent.DrawHeight / 480);
|
||||
public override bool HandleInput => false;
|
||||
|
||||
@ -39,6 +50,18 @@ namespace osu.Game.Storyboards.Drawables
|
||||
Size = new Vector2(640, 480);
|
||||
Anchor = Anchor.Centre;
|
||||
Origin = Anchor.Centre;
|
||||
|
||||
AddInternal(background = new Background
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
});
|
||||
AddInternal(content = new Container<DrawableStoryboardLayer>
|
||||
{
|
||||
Size = new Vector2(640, 480),
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
});
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
@ -55,5 +78,10 @@ namespace osu.Game.Storyboards.Drawables
|
||||
foreach (var layer in Children)
|
||||
layer.Enabled = passing ? layer.Layer.EnabledWhenPassing : layer.Layer.EnabledWhenFailing;
|
||||
}
|
||||
|
||||
private class Background : Sprite
|
||||
{
|
||||
protected override Vector2 DrawScale => Texture != null ? new Vector2(Parent.DrawHeight / Texture.DisplayHeight) : base.DrawScale;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,9 +14,6 @@ namespace osu.Game.Storyboards.Drawables
|
||||
{
|
||||
public StoryboardAnimation Animation { get; private set; }
|
||||
|
||||
protected override bool ShouldBeAlive => Animation.HasCommands && base.ShouldBeAlive;
|
||||
public override bool RemoveWhenNotAlive => !Animation.HasCommands || base.RemoveWhenNotAlive;
|
||||
|
||||
public bool FlipH { get; set; }
|
||||
public bool FlipV { get; set; }
|
||||
|
||||
@ -59,11 +56,8 @@ namespace osu.Game.Storyboards.Drawables
|
||||
Position = animation.InitialPosition;
|
||||
Repeat = animation.LoopType == AnimationLoopType.LoopForever;
|
||||
|
||||
if (animation.HasCommands)
|
||||
{
|
||||
LifetimeStart = animation.StartTime;
|
||||
LifetimeEnd = animation.EndTime;
|
||||
}
|
||||
LifetimeStart = animation.StartTime;
|
||||
LifetimeEnd = animation.EndTime;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
|
@ -28,9 +28,8 @@ namespace osu.Game.Storyboards.Drawables
|
||||
{
|
||||
foreach (var element in Layer.Elements)
|
||||
{
|
||||
var drawable = element.CreateDrawable();
|
||||
if (drawable != null)
|
||||
Add(drawable);
|
||||
if (element.IsDrawable)
|
||||
Add(element.CreateDrawable());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,9 +14,6 @@ namespace osu.Game.Storyboards.Drawables
|
||||
{
|
||||
public StoryboardSprite Sprite { get; private set; }
|
||||
|
||||
protected override bool ShouldBeAlive => Sprite.HasCommands && base.ShouldBeAlive;
|
||||
public override bool RemoveWhenNotAlive => !Sprite.HasCommands || base.RemoveWhenNotAlive;
|
||||
|
||||
public bool FlipH { get; set; }
|
||||
public bool FlipV { get; set; }
|
||||
|
||||
@ -58,11 +55,8 @@ namespace osu.Game.Storyboards.Drawables
|
||||
Origin = sprite.Origin;
|
||||
Position = sprite.InitialPosition;
|
||||
|
||||
if (sprite.HasCommands)
|
||||
{
|
||||
LifetimeStart = sprite.StartTime;
|
||||
LifetimeEnd = sprite.EndTime;
|
||||
}
|
||||
LifetimeStart = sprite.StartTime;
|
||||
LifetimeEnd = sprite.EndTime;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
|
@ -8,6 +8,8 @@ namespace osu.Game.Storyboards
|
||||
public interface IStoryboardElement
|
||||
{
|
||||
string Path { get; }
|
||||
bool IsDrawable { get; }
|
||||
|
||||
Drawable CreateDrawable();
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Storyboards.Drawables;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@ -12,6 +13,8 @@ namespace osu.Game.Storyboards
|
||||
private readonly Dictionary<string, StoryboardLayer> layers = new Dictionary<string, StoryboardLayer>();
|
||||
public IEnumerable<StoryboardLayer> Layers => layers.Values;
|
||||
|
||||
public bool HasDrawable => Layers.Any(l => l.Elements.Any(e => e.IsDrawable));
|
||||
|
||||
public Storyboard()
|
||||
{
|
||||
layers.Add("Background", new StoryboardLayer("Background", 3));
|
||||
@ -29,7 +32,32 @@ namespace osu.Game.Storyboards
|
||||
return layer;
|
||||
}
|
||||
|
||||
public DrawableStoryboard CreateDrawable()
|
||||
=> new DrawableStoryboard(this);
|
||||
/// <summary>
|
||||
/// Whether the beatmap's background should be hidden while this storyboard is being displayed.
|
||||
/// </summary>
|
||||
public bool ReplacesBackground(BeatmapInfo beatmapInfo)
|
||||
{
|
||||
var backgroundPath = beatmapInfo.BeatmapSet?.Metadata?.BackgroundFile?.ToLowerInvariant();
|
||||
if (backgroundPath == null)
|
||||
return false;
|
||||
|
||||
return GetLayer("Background").Elements.Any(e => e.Path.ToLowerInvariant() == backgroundPath);
|
||||
}
|
||||
|
||||
public float AspectRatio(BeatmapInfo beatmapInfo)
|
||||
=> beatmapInfo.WidescreenStoryboard ? 16 / 9f : 4 / 3f;
|
||||
|
||||
public DrawableStoryboard CreateDrawable(WorkingBeatmap working = null)
|
||||
{
|
||||
var drawable = new DrawableStoryboard(this);
|
||||
if (working != null)
|
||||
{
|
||||
var beatmapInfo = working.Beatmap.BeatmapInfo;
|
||||
drawable.Width = drawable.Height * AspectRatio(beatmapInfo);
|
||||
if (!ReplacesBackground(beatmapInfo))
|
||||
drawable.BackgroundTexture = working.Background;
|
||||
}
|
||||
return drawable;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,12 +2,15 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using System;
|
||||
|
||||
namespace osu.Game.Storyboards
|
||||
{
|
||||
public class StoryboardSample : IStoryboardElement
|
||||
{
|
||||
public string Path { get; set; }
|
||||
public bool IsDrawable => false;
|
||||
|
||||
public double Time;
|
||||
public float Volume;
|
||||
|
||||
@ -19,6 +22,8 @@ namespace osu.Game.Storyboards
|
||||
}
|
||||
|
||||
public Drawable CreateDrawable()
|
||||
=> null;
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,8 @@ namespace osu.Game.Storyboards
|
||||
private readonly List<CommandTrigger> triggers = new List<CommandTrigger>();
|
||||
|
||||
public string Path { get; set; }
|
||||
public bool IsDrawable => HasCommands;
|
||||
|
||||
public Anchor Origin;
|
||||
public Vector2 InitialPosition;
|
||||
|
||||
|
@ -79,11 +79,13 @@ namespace osu.Game.Tests.Visual
|
||||
storyboardContainer.Remove(storyboard);
|
||||
|
||||
var decoupledClock = new DecoupleableInterpolatingFramedClock { IsCoupled = true };
|
||||
decoupledClock.ChangeSource(working.Track);
|
||||
storyboardContainer.Clock = decoupledClock;
|
||||
|
||||
storyboardContainer.Add(storyboard = working.Beatmap.Storyboard.CreateDrawable());
|
||||
storyboard = working.Beatmap.Storyboard.CreateDrawable(beatmapBacking);
|
||||
storyboard.Passing = false;
|
||||
|
||||
storyboardContainer.Add(storyboard);
|
||||
decoupledClock.ChangeSource(working.Track);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user