1
0
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:
Dean Herbert 2017-09-26 20:47:07 +08:00 committed by GitHub
commit 3fd4a97a19
13 changed files with 142 additions and 30 deletions

View File

@ -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,

View File

@ -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",

View File

@ -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);

View File

@ -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)
{

View File

@ -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;
}
}
}

View File

@ -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]

View File

@ -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());
}
}
}

View File

@ -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]

View File

@ -8,6 +8,8 @@ namespace osu.Game.Storyboards
public interface IStoryboardElement
{
string Path { get; }
bool IsDrawable { get; }
Drawable CreateDrawable();
}
}

View File

@ -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;
}
}
}

View File

@ -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();
}
}
}

View File

@ -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;

View File

@ -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);
}
}
}