This commit is contained in:
Jorolf
2017-02-17 12:54:11 +01:00
57 changed files with 1154 additions and 249 deletions

View File

@ -122,6 +122,9 @@ namespace osu.Desktop.Deploy
uploadBuild(version); uploadBuild(version);
//reset assemblyinfo.
updateAssemblyInfo("0.0.0");
write("Done!", ConsoleColor.White); write("Done!", ConsoleColor.White);
Console.ReadLine(); Console.ReadLine();
} }

View File

@ -1,18 +1,23 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic;
using osu.Framework; using osu.Framework;
using osu.Framework.GameModes.Testing; using osu.Framework.GameModes.Testing;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Timing; using osu.Framework.Timing;
using OpenTK; using OpenTK;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Game.Modes.Objects; using osu.Game.Modes.Objects;
using osu.Game.Modes.Objects.Drawables; using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Osu.Objects; using osu.Game.Modes.Osu.Objects;
using osu.Game.Modes.Osu.Objects.Drawables; using osu.Game.Modes.Osu.Objects.Drawables;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
using osu.Game.Modes; using osu.Game.Modes;
using OpenTK.Graphics;
namespace osu.Desktop.VisualTests.Tests namespace osu.Desktop.VisualTests.Tests
{ {
@ -20,44 +25,125 @@ namespace osu.Desktop.VisualTests.Tests
{ {
public override string Name => @"Hit Objects"; public override string Name => @"Hit Objects";
private StopwatchClock rateAdjustClock;
private FramedClock framedClock;
bool auto = false;
public TestCaseHitObjects() public TestCaseHitObjects()
{ {
var swClock = new StopwatchClock(true) { Rate = 0.2f }; rateAdjustClock = new StopwatchClock(true);
Clock = new FramedClock(swClock); framedClock = new FramedClock(rateAdjustClock);
playbackSpeed.ValueChanged += delegate { rateAdjustClock.Rate = playbackSpeed.Value; };
}
HitObjectType mode = HitObjectType.Slider;
BindableNumber<double> playbackSpeed = new BindableDouble(0.5) { MinValue = 0, MaxValue = 1 };
private Container playfieldContainer;
private Container approachContainer;
private void load(HitObjectType mode)
{
this.mode = mode;
switch (mode)
{
case HitObjectType.Circle:
const int count = 10;
for (int i = 0; i < count; i++)
{
var h = new HitCircle
{
StartTime = framedClock.CurrentTime + 600 + i * 80,
Position = new Vector2((i - count / 2) * 14),
};
add(new DrawableHitCircle(h));
}
break;
case HitObjectType.Slider:
add(new DrawableSlider(new Slider
{
StartTime = framedClock.CurrentTime + 600,
ControlPoints = new List<Vector2>()
{
new Vector2(-200, 0),
new Vector2(400, 0),
},
Length = 400,
Position = new Vector2(-200, 0),
Velocity = 1,
TickDistance = 100,
}));
break;
case HitObjectType.Spinner:
add(new DrawableSpinner(new Spinner
{
StartTime = framedClock.CurrentTime + 600,
Length = 1000,
Position = new Vector2(0, 0),
}));
break;
}
} }
public override void Reset() public override void Reset()
{ {
base.Reset(); base.Reset();
Clock.ProcessFrame(); playbackSpeed.TriggerChange();
Container approachContainer = new Container { Depth = float.MinValue, }; AddButton(@"circles", () => load(HitObjectType.Circle));
AddButton(@"slider", () => load(HitObjectType.Slider));
AddButton(@"spinner", () => load(HitObjectType.Spinner));
Add(approachContainer); AddToggle(@"auto", () => { auto = !auto; load(mode); });
const int count = 10; ButtonsContainer.Add(new SpriteText { Text = "Playback Speed" });
ButtonsContainer.Add(new BasicSliderBar<double>
for (int i = 0; i < count; i++)
{ {
var h = new HitCircle Width = 150,
Height = 10,
SelectionColor = Color4.Orange,
Bindable = playbackSpeed
});
framedClock.ProcessFrame();
var clockAdjustContainer = new Container
{
RelativeSizeAxes = Axes.Both,
Clock = framedClock,
Children = new[]
{ {
StartTime = Clock.CurrentTime + 600 + i * 80, playfieldContainer = new Container { RelativeSizeAxes = Axes.Both },
Position = new Vector2((i - count / 2) * 14), approachContainer = new Container { RelativeSizeAxes = Axes.Both }
}; }
};
DrawableHitCircle d = new DrawableHitCircle(h) Add(clockAdjustContainer);
{
Anchor = Anchor.Centre,
Depth = i,
State = ArmedState.Hit,
Judgement = new OsuJudgementInfo { Result = HitResult.Hit }
};
load(mode);
}
approachContainer.Add(d.ApproachCircle.CreateProxy()); int depth;
Add(d); void add(DrawableHitObject h)
{
h.Anchor = Anchor.Centre;
h.Depth = depth++;
if (auto)
{
h.State = ArmedState.Hit;
h.Judgement = new OsuJudgementInfo { Result = HitResult.Hit };
} }
playfieldContainer.Add(h);
var proxyable = h as IDrawableHitObjectWithProxiedApproach;
if (proxyable != null)
approachContainer.Add(proxyable.ProxiedLayer.CreateProxy());
} }
} }
} }

View File

@ -1,6 +1,7 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Diagnostics;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
@ -13,6 +14,7 @@ using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures; using osu.Framework.Graphics.Textures;
using osu.Game.Graphics; using osu.Game.Graphics;
using OpenTK; using OpenTK;
using OpenTK.Graphics;
namespace osu.Desktop.Overlays namespace osu.Desktop.Overlays
{ {
@ -35,7 +37,18 @@ namespace osu.Desktop.Overlays
Origin = Anchor.BottomCentre; Origin = Anchor.BottomCentre;
Alpha = 0; Alpha = 0;
bool isDebug = false;
Debug.Assert(isDebug = true);
var asm = Assembly.GetEntryAssembly().GetName(); var asm = Assembly.GetEntryAssembly().GetName();
string version;
if (asm.Version.Major == 0)
{
version = @"local " + (isDebug ? @"debug" : @"release");
}
else
version = $@"{asm.Version.Major}.{asm.Version.Minor}.{asm.Version.Build}";
Children = new Drawable[] Children = new Drawable[]
{ {
new FlowContainer new FlowContainer
@ -60,7 +73,8 @@ namespace osu.Desktop.Overlays
}, },
new OsuSpriteText new OsuSpriteText
{ {
Text = $@"{asm.Version.Major}.{asm.Version.Minor}.{asm.Version.Build}" Colour = isDebug ? colours.Red : Color4.White,
Text = version
}, },
} }
}, },

View File

@ -1,4 +1,4 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Reflection; using System.Reflection;
@ -25,5 +25,5 @@ using System.Runtime.InteropServices;
// The following GUID is for the ID of the typelib if this project is exposed to COM // The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("55e28cb2-7b6c-4595-8dcc-9871d8aad7e9")] [assembly: Guid("55e28cb2-7b6c-4595-8dcc-9871d8aad7e9")]
[assembly: AssemblyVersion("2017.212.0")] [assembly: AssemblyVersion("0.0.0")]
[assembly: AssemblyFileVersion("2017.212.0")] [assembly: AssemblyFileVersion("0.0.0")]

View File

@ -24,6 +24,6 @@ namespace osu.Game.Modes.Catch
public override ScoreProcessor CreateScoreProcessor(int hitObjectCount) => null; public override ScoreProcessor CreateScoreProcessor(int hitObjectCount) => null;
public override HitObjectParser CreateHitObjectParser() => new OsuHitObjectParser(); public override HitObjectParser CreateHitObjectParser() => new NullHitObjectParser();
} }
} }

View File

@ -25,6 +25,6 @@ namespace osu.Game.Modes.Mania
public override ScoreProcessor CreateScoreProcessor(int hitObjectCount) => null; public override ScoreProcessor CreateScoreProcessor(int hitObjectCount) => null;
public override HitObjectParser CreateHitObjectParser() => new OsuHitObjectParser(); public override HitObjectParser CreateHitObjectParser() => new NullHitObjectParser();
} }
} }

View File

@ -2,7 +2,6 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System; using System;
using System.ComponentModel;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Transformations; using osu.Framework.Graphics.Transformations;
using osu.Game.Modes.Objects.Drawables; using osu.Game.Modes.Objects.Drawables;
@ -11,9 +10,9 @@ using OpenTK;
namespace osu.Game.Modes.Osu.Objects.Drawables namespace osu.Game.Modes.Osu.Objects.Drawables
{ {
public class DrawableHitCircle : DrawableOsuHitObject public class DrawableHitCircle : DrawableOsuHitObject, IDrawableHitObjectWithProxiedApproach
{ {
private HitCircle osuObject; private OsuHitObject osuObject;
public ApproachCircle ApproachCircle; public ApproachCircle ApproachCircle;
private CirclePiece circle; private CirclePiece circle;
@ -23,11 +22,12 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
private NumberPiece number; private NumberPiece number;
private GlowPiece glow; private GlowPiece glow;
public DrawableHitCircle(HitCircle h) : base(h) public DrawableHitCircle(OsuHitObject h) : base(h)
{ {
Origin = Anchor.Centre;
osuObject = h; osuObject = h;
Origin = Anchor.Centre;
Position = osuObject.StackedPosition; Position = osuObject.StackedPosition;
Scale = new Vector2(osuObject.Scale); Scale = new Vector2(osuObject.Scale);
@ -49,7 +49,10 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
return true; return true;
}, },
}, },
number = new NumberPiece(), number = new NumberPiece()
{
Text = h is Spinner ? "S" : (HitObject.ComboIndex + 1).ToString(),
},
ring = new RingPiece(), ring = new RingPiece(),
flash = new FlashPiece(), flash = new FlashPiece(),
explode = new ExplodePiece explode = new ExplodePiece
@ -81,18 +84,18 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
double hitOffset = Math.Abs(Judgement.TimeOffset); double hitOffset = Math.Abs(Judgement.TimeOffset);
OsuJudgementInfo osuJudgement = Judgement as OsuJudgementInfo;
if (hitOffset < hit50) if (hitOffset < hit50)
{ {
Judgement.Result = HitResult.Hit; Judgement.Result = HitResult.Hit;
OsuJudgementInfo osuInfo = Judgement as OsuJudgementInfo;
if (hitOffset < hit300) if (hitOffset < hit300)
osuInfo.Score = OsuScoreResult.Hit300; osuJudgement.Score = OsuScoreResult.Hit300;
else if (hitOffset < hit100) else if (hitOffset < hit100)
osuInfo.Score = OsuScoreResult.Hit100; osuJudgement.Score = OsuScoreResult.Hit100;
else if (hitOffset < hit50) else if (hitOffset < hit50)
osuInfo.Score = OsuScoreResult.Hit50; osuJudgement.Score = OsuScoreResult.Hit50;
} }
else else
Judgement.Result = HitResult.Miss; Judgement.Result = HitResult.Miss;
@ -124,6 +127,8 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
base.UpdateState(state); base.UpdateState(state);
ApproachCircle.FadeOut(); ApproachCircle.FadeOut();
glow.Delay(osuObject.Duration);
glow.FadeOut(400); glow.FadeOut(400);
switch (state) switch (state)
@ -156,5 +161,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
break; break;
} }
} }
public Drawable ProxiedLayer => ApproachCircle;
} }
} }

View File

@ -18,7 +18,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
{ {
} }
public override JudgementInfo CreateJudgementInfo() => new OsuJudgementInfo(); public override JudgementInfo CreateJudgementInfo() => new OsuJudgementInfo { MaxScore = OsuScoreResult.Hit300 };
protected override void UpdateState(ArmedState state) protected override void UpdateState(ArmedState state)
{ {
@ -48,7 +48,37 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
public class OsuJudgementInfo : PositionalJudgementInfo public class OsuJudgementInfo : PositionalJudgementInfo
{ {
/// <summary>
/// The score the user achieved.
/// </summary>
public OsuScoreResult Score; public OsuScoreResult Score;
/// <summary>
/// The score which would be achievable on a perfect hit.
/// </summary>
public OsuScoreResult MaxScore = OsuScoreResult.Hit300;
public int ScoreValue => scoreToInt(Score);
public int MaxScoreValue => scoreToInt(MaxScore);
private int scoreToInt(OsuScoreResult result)
{
switch (result)
{
default:
return 0;
case OsuScoreResult.Hit50:
return 50;
case OsuScoreResult.Hit100:
return 100;
case OsuScoreResult.Hit300:
return 300;
case OsuScoreResult.SliderTick:
return 10;
}
}
public ComboResult Combo; public ComboResult Combo;
} }
@ -72,5 +102,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
Hit100, Hit100,
[Description(@"300")] [Description(@"300")]
Hit300, Hit300,
[Description(@"10")]
SliderTick
} }
} }

View File

@ -1,16 +1,17 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic; using OpenTK;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Modes.Objects.Drawables; using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Osu.Objects.Drawables.Pieces; using osu.Game.Modes.Osu.Objects.Drawables.Pieces;
using OpenTK; using System.Collections.Generic;
using osu.Framework.Input; using System.Linq;
using osu.Framework.Graphics.Containers;
namespace osu.Game.Modes.Osu.Objects.Drawables namespace osu.Game.Modes.Osu.Objects.Drawables
{ {
class DrawableSlider : DrawableOsuHitObject public class DrawableSlider : DrawableOsuHitObject, IDrawableHitObjectWithProxiedApproach
{ {
private Slider slider; private Slider slider;
@ -18,6 +19,8 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
private List<ISliderProgress> components = new List<ISliderProgress>(); private List<ISliderProgress> components = new List<ISliderProgress>();
private Container<DrawableSliderTick> ticks;
SliderBody body; SliderBody body;
SliderBall ball; SliderBall ball;
@ -34,6 +37,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
Position = s.StackedPosition, Position = s.StackedPosition,
PathWidth = s.Scale * 64, PathWidth = s.Scale * 64,
}, },
ticks = new Container<DrawableSliderTick>(),
bouncer1 = new SliderBouncer(s, false) bouncer1 = new SliderBouncer(s, false)
{ {
Position = s.Curve.PositionAt(1), Position = s.Curve.PositionAt(1),
@ -50,8 +54,10 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
}, },
initialCircle = new DrawableHitCircle(new HitCircle initialCircle = new DrawableHitCircle(new HitCircle
{ {
//todo: avoid creating this temporary HitCircle.
StartTime = s.StartTime, StartTime = s.StartTime,
Position = s.StackedPosition, Position = s.StackedPosition,
ComboIndex = s.ComboIndex,
Scale = s.Scale, Scale = s.Scale,
Colour = s.Colour, Colour = s.Colour,
Sample = s.Sample, Sample = s.Sample,
@ -62,6 +68,26 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
components.Add(ball); components.Add(ball);
components.Add(bouncer1); components.Add(bouncer1);
components.Add(bouncer2); components.Add(bouncer2);
AddNested(initialCircle);
var repeatDuration = s.Curve.Length / s.Velocity;
foreach (var tick in s.Ticks)
{
var repeatStartTime = s.StartTime + tick.RepeatIndex * repeatDuration;
var fadeInTime = repeatStartTime + (tick.StartTime - repeatStartTime) / 2 - (tick.RepeatIndex == 0 ? TIME_FADEIN : TIME_FADEIN / 2);
var fadeOutTime = repeatStartTime + repeatDuration;
var drawableTick = new DrawableSliderTick(tick)
{
FadeInTime = fadeInTime,
FadeOutTime = fadeOutTime,
Position = tick.Position,
};
ticks.Add(drawableTick);
AddNested(drawableTick);
}
} }
// Since the DrawableSlider itself is just a container without a size we need to // Since the DrawableSlider itself is just a container without a size we need to
@ -95,7 +121,8 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
if (initialCircle.Judgement?.Result != HitResult.Hit) if (initialCircle.Judgement?.Result != HitResult.Hit)
initialCircle.Position = slider.Curve.PositionAt(progress); initialCircle.Position = slider.Curve.PositionAt(progress);
components.ForEach(c => c.UpdateProgress(progress, repeat)); foreach (var c in components) c.UpdateProgress(progress, repeat);
foreach (var t in ticks.Children) t.Tracking = ball.Tracking;
} }
protected override void CheckJudgement(bool userTriggered) protected override void CheckJudgement(bool userTriggered)
@ -105,8 +132,22 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
if (!userTriggered && Time.Current >= HitObject.EndTime) if (!userTriggered && Time.Current >= HitObject.EndTime)
{ {
j.Score = sc.Score; var ticksCount = ticks.Children.Count() + 1;
j.Result = sc.Result; var ticksHit = ticks.Children.Count(t => t.Judgement.Result == HitResult.Hit);
if (sc.Result == HitResult.Hit)
ticksHit++;
var hitFraction = (double)ticksHit / ticksCount;
if (hitFraction == 1 && sc.Score == OsuScoreResult.Hit300)
j.Score = OsuScoreResult.Hit300;
else if (hitFraction >= 0.5 && sc.Score >= OsuScoreResult.Hit100)
j.Score = OsuScoreResult.Hit100;
else if (hitFraction > 0)
j.Score = OsuScoreResult.Hit50;
else
j.Score = OsuScoreResult.Miss;
j.Result = j.Score != OsuScoreResult.Miss ? HitResult.Hit : HitResult.Miss;
} }
} }
@ -133,6 +174,8 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
FadeOut(800); FadeOut(800);
} }
public Drawable ProxiedLayer => initialCircle.ApproachCircle;
} }
internal interface ISliderProgress internal interface ISliderProgress

View File

@ -0,0 +1,120 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Transformations;
using osu.Game.Beatmaps.Samples;
using osu.Game.Modes.Objects.Drawables;
using OpenTK;
using OpenTK.Graphics;
namespace osu.Game.Modes.Osu.Objects.Drawables
{
public class DrawableSliderTick : DrawableOsuHitObject
{
private SliderTick sliderTick;
public double FadeInTime;
public double FadeOutTime;
public bool Tracking;
public override bool RemoveWhenNotAlive => false;
public override JudgementInfo CreateJudgementInfo() => new OsuJudgementInfo { MaxScore = OsuScoreResult.SliderTick };
public DrawableSliderTick(SliderTick sliderTick) : base(sliderTick)
{
this.sliderTick = sliderTick;
Size = new Vector2(16) * sliderTick.Scale;
Masking = true;
CornerRadius = Size.X / 2;
Origin = Anchor.Centre;
BorderThickness = 2;
BorderColour = Color4.White;
Children = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = sliderTick.Colour,
Alpha = 0.3f,
}
};
}
private AudioSample sample;
[BackgroundDependencyLoader]
private void load(AudioManager audio)
{
string sampleSet = (HitObject.Sample?.Set ?? SampleSet.Normal).ToString().ToLower();
sample = audio.Sample.Get($@"Gameplay/{sampleSet}-slidertick");
}
protected override void PlaySample()
{
sample?.Play();
}
protected override void CheckJudgement(bool userTriggered)
{
var j = Judgement as OsuJudgementInfo;
if (Judgement.TimeOffset >= 0)
{
j.Result = Tracking ? HitResult.Hit : HitResult.Miss;
j.Score = Tracking ? OsuScoreResult.SliderTick : OsuScoreResult.Miss;
}
}
protected override void UpdatePreemptState()
{
var animIn = Math.Min(150, sliderTick.StartTime - FadeInTime);
ScaleTo(0.5f);
ScaleTo(1.2f, animIn);
FadeIn(animIn);
Delay(animIn);
ScaleTo(1, 150, EasingTypes.Out);
Delay(-animIn);
}
protected override void UpdateState(ArmedState state)
{
if (!IsLoaded) return;
base.UpdateState(state);
switch (state)
{
case ArmedState.Idle:
Delay(FadeOutTime - sliderTick.StartTime);
FadeOut();
break;
case ArmedState.Miss:
FadeOut(160);
FadeColour(Color4.Red, 80);
break;
case ArmedState.Hit:
FadeOut(120, EasingTypes.OutQuint);
ScaleTo(Scale * 1.5f, 120, EasingTypes.OutQuint);
break;
}
}
}
}

View File

@ -0,0 +1,155 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Transformations;
using osu.Framework.MathUtils;
using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Osu.Objects.Drawables.Pieces;
using OpenTK;
using OpenTK.Graphics;
namespace osu.Game.Modes.Osu.Objects.Drawables
{
public class DrawableSpinner : DrawableOsuHitObject
{
private Spinner spinner;
private SpinnerDisc disc;
private SpinnerBackground background;
private Container circleContainer;
private DrawableHitCircle circle;
public DrawableSpinner(Spinner s) : base(s)
{
Origin = Anchor.Centre;
Position = s.Position;
//take up full playfield.
Size = new Vector2(512);
spinner = s;
Children = new Drawable[]
{
background = new SpinnerBackground
{
Alpha = 0,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
DiscColour = Color4.Black
},
disc = new SpinnerDisc
{
Alpha = 0,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
DiscColour = s.Colour
},
circleContainer = new Container
{
AutoSizeAxes = Axes.Both,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Children = new []
{
circle = new DrawableHitCircle(s)
{
Interactive = false,
Position = Vector2.Zero,
Anchor = Anchor.Centre,
}
}
}
};
background.Scale = scaleToCircle;
disc.Scale = scaleToCircle;
}
public override bool Contains(Vector2 screenSpacePos) => true;
protected override void CheckJudgement(bool userTriggered)
{
if (Time.Current < HitObject.StartTime) return;
var j = Judgement as OsuJudgementInfo;
disc.ScaleTo(Interpolation.ValueAt(Math.Sqrt(Progress), scaleToCircle, Vector2.One, 0, 1), 100);
if (Progress >= 1)
disc.Complete = true;
if (!userTriggered && Time.Current >= HitObject.EndTime)
{
if (Progress >= 1)
{
j.Score = OsuScoreResult.Hit300;
j.Result = HitResult.Hit;
}
else if (Progress > .9)
{
j.Score = OsuScoreResult.Hit100;
j.Result = HitResult.Hit;
}
else if (Progress > .75)
{
j.Score = OsuScoreResult.Hit50;
j.Result = HitResult.Hit;
}
else
{
j.Score = OsuScoreResult.Miss;
if (Time.Current >= HitObject.EndTime)
j.Result = HitResult.Miss;
}
}
}
private Vector2 scaleToCircle => new Vector2(circle.Scale * circle.DrawWidth / DrawWidth) * 0.95f;
private float spinsPerMinuteNeeded = 100 + (5 * 15); //TODO: read per-map OD and place it on the 5
private float rotationsNeeded => (float)(spinsPerMinuteNeeded * (spinner.EndTime - spinner.StartTime) / 60000f);
public float Progress => MathHelper.Clamp(disc.RotationAbsolute / 360 / rotationsNeeded, 0, 1);
protected override void UpdatePreemptState()
{
base.UpdatePreemptState();
FadeIn(200);
circleContainer.ScaleTo(1, 400, EasingTypes.OutElastic);
background.Delay(TIME_PREEMPT - 100);
background.FadeIn(200);
background.ScaleTo(1, 200, EasingTypes.OutQuint);
disc.Delay(TIME_PREEMPT - 50);
disc.FadeIn(200);
}
protected override void UpdateState(ArmedState state)
{
if (!IsLoaded) return;
base.UpdateState(state);
Delay(HitObject.Duration, true);
FadeOut(160);
switch (state)
{
case ArmedState.Hit:
ScaleTo(Scale * 1.2f, 320, EasingTypes.Out);
break;
case ArmedState.Miss:
ScaleTo(Scale * 0.8f, 320, EasingTypes.In);
break;
}
}
}
}

View File

@ -6,6 +6,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Transformations; using osu.Framework.Graphics.Transformations;
using osu.Game.Graphics.Sprites;
using osu.Game.Modes.Objects.Drawables; using osu.Game.Modes.Objects.Drawables;
using OpenTK; using OpenTK;
using OpenTK.Graphics; using OpenTK.Graphics;
@ -30,7 +31,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
Children = new Drawable[] Children = new Drawable[]
{ {
line1 = new SpriteText line1 = new OsuSpriteText
{ {
Anchor = Anchor.TopCentre, Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre, Origin = Anchor.TopCentre,
@ -38,7 +39,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
Font = @"Venera", Font = @"Venera",
TextSize = 16, TextSize = 16,
}, },
line2 = new SpriteText line2 = new OsuSpriteText
{ {
Text = judgement.Combo.GetDescription(), Text = judgement.Combo.GetDescription(),
Font = @"Venera", Font = @"Venera",

View File

@ -14,9 +14,8 @@ namespace osu.Game.Modes.Osu.Objects.Drawables.Pieces
{ {
public class CirclePiece : Container public class CirclePiece : Container
{ {
private Sprite disc; private Sprite disc;
private Triangles triangles;
public Func<bool> Hit; public Func<bool> Hit;
@ -36,10 +35,11 @@ namespace osu.Game.Modes.Osu.Objects.Drawables.Pieces
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre Origin = Anchor.Centre
}, },
triangles = new Triangles new TrianglesPiece
{ {
RelativeSizeAxes = Axes.Both,
BlendingMode = BlendingMode.Additive, BlendingMode = BlendingMode.Additive,
RelativeSizeAxes = Axes.Both Alpha = 0.5f,
} }
}; };
} }

View File

@ -21,10 +21,11 @@ namespace osu.Game.Modes.Osu.Objects.Drawables.Pieces
Children = new Drawable[] Children = new Drawable[]
{ {
new Triangles new TrianglesPiece
{ {
BlendingMode = BlendingMode.Additive, BlendingMode = BlendingMode.Additive,
RelativeSizeAxes = Axes.Both RelativeSizeAxes = Axes.Both,
Alpha = 0.2f,
} }
}; };
} }

View File

@ -6,33 +6,54 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures; using osu.Framework.Graphics.Textures;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using OpenTK;
using OpenTK.Graphics;
namespace osu.Game.Modes.Osu.Objects.Drawables.Pieces namespace osu.Game.Modes.Osu.Objects.Drawables.Pieces
{ {
public class NumberPiece : Container public class NumberPiece : Container
{ {
private Sprite number; private SpriteText number;
public string Text
{
get { return number.Text; }
set { number.Text = value; }
}
public NumberPiece() public NumberPiece()
{ {
Anchor = Anchor.Centre; Anchor = Anchor.Centre;
Origin = Anchor.Centre; Origin = Anchor.Centre;
Children = new[] Children = new Drawable[]
{ {
number = new Sprite new CircularContainer
{ {
EdgeEffect = new EdgeEffect
{
Type = EdgeEffectType.Glow,
Radius = 60,
Colour = Color4.White.Opacity(0.5f),
},
Children = new[]
{
new Box()
}
},
number = new OsuSpriteText
{
Text = @"1",
Font = @"Venera",
UseFullGlyphHeight = false,
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
TextSize = 40,
Alpha = 1 Alpha = 1
} }
}; };
} }
[BackgroundDependencyLoader]
private void load(TextureStore textures)
{
number.Texture = textures.Get(@"Play/osu/number");
}
} }
} }

View File

@ -11,7 +11,7 @@ using OpenTK.Graphics;
namespace osu.Game.Modes.Osu.Objects.Drawables.Pieces namespace osu.Game.Modes.Osu.Objects.Drawables.Pieces
{ {
public class SliderBall : Container, ISliderProgress public class SliderBall : CircularContainer, ISliderProgress
{ {
private readonly Slider slider; private readonly Slider slider;
private Box follow; private Box follow;
@ -39,7 +39,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables.Pieces
Height = width, Height = width,
Alpha = 0, Alpha = 0,
}, },
new Container new CircularContainer
{ {
Masking = true, Masking = true,
AutoSizeAxes = Axes.Both, AutoSizeAxes = Axes.Both,
@ -48,7 +48,6 @@ namespace osu.Game.Modes.Osu.Objects.Drawables.Pieces
BorderThickness = 10, BorderThickness = 10,
BorderColour = Color4.White, BorderColour = Color4.White,
Alpha = 1, Alpha = 1,
CornerRadius = width / 2,
Children = new[] Children = new[]
{ {
new Box new Box
@ -104,8 +103,8 @@ namespace osu.Game.Modes.Osu.Objects.Drawables.Pieces
{ {
base.Update(); base.Update();
CornerRadius = DrawWidth / 2; if (Time.Current < slider.EndTime)
Tracking = canCurrentlyTrack && lastState != null && Contains(lastState.Mouse.NativeState.Position) && lastState.Mouse.HasMainButtonPressed; Tracking = canCurrentlyTrack && lastState != null && Contains(lastState.Mouse.NativeState.Position) && lastState.Mouse.HasMainButtonPressed;
} }
public void UpdateProgress(double progress, int repeat) public void UpdateProgress(double progress, int repeat)

View File

@ -8,7 +8,7 @@ using osu.Framework.Configuration;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.OpenGL.Textures; using osu.Framework.Graphics.OpenGL.Textures;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Lines;
using osu.Framework.Graphics.Textures; using osu.Framework.Graphics.Textures;
using osu.Game.Configuration; using osu.Game.Configuration;
using OpenTK; using OpenTK;

View File

@ -0,0 +1,10 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
namespace osu.Game.Modes.Osu.Objects.Drawables.Pieces
{
public class SpinnerBackground : SpinnerDisc
{
public override bool HandleInput => false;
}
}

View File

@ -0,0 +1,206 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Transformations;
using osu.Framework.Input;
using osu.Framework.Logging;
using osu.Game.Graphics;
using OpenTK;
using OpenTK.Graphics;
namespace osu.Game.Modes.Osu.Objects.Drawables.Pieces
{
public class SpinnerDisc : CircularContainer
{
public override bool Contains(Vector2 screenSpacePos) => true;
protected Sprite Disc;
public SRGBColour DiscColour
{
get { return Disc.Colour; }
set { Disc.Colour = value; }
}
Color4 completeColour;
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
completeColour = colours.YellowLight.Opacity(0.8f);
}
class SpinnerBorder : Container
{
public SpinnerBorder()
{
Origin = Anchor.Centre;
Anchor = Anchor.Centre;
RelativeSizeAxes = Axes.Both;
layout();
}
private int lastLayoutDotCount;
private void layout()
{
int count = (int)(MathHelper.Pi * ScreenSpaceDrawQuad.Width / 9);
if (count == lastLayoutDotCount) return;
lastLayoutDotCount = count;
while (Children.Count() < count)
{
Add(new CircularContainer
{
Colour = Color4.White,
RelativePositionAxes = Axes.Both,
Origin = Anchor.Centre,
Size = new Vector2(1 / ScreenSpaceDrawQuad.Width * 2000),
Children = new[]
{
new Box
{
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
}
}
});
}
var size = new Vector2(1 / ScreenSpaceDrawQuad.Width * 2000);
int i = 0;
foreach (var d in Children)
{
d.Size = size;
d.Position = new Vector2(
0.5f + (float)Math.Sin((float)i / count * 2 * MathHelper.Pi) / 2,
0.5f + (float)Math.Cos((float)i / count * 2 * MathHelper.Pi) / 2
);
i++;
}
}
protected override void Update()
{
base.Update();
layout();
}
}
public SpinnerDisc()
{
RelativeSizeAxes = Axes.Both;
Children = new Drawable[]
{
Disc = new Box
{
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Alpha = 0.2f,
},
new SpinnerBorder()
};
}
bool tracking;
public bool Tracking
{
get { return tracking; }
set
{
if (value == tracking) return;
tracking = value;
Disc.FadeTo(tracking ? 0.5f : 0.2f, 100);
}
}
bool complete;
public bool Complete
{
get { return complete; }
set
{
if (value == complete) return;
complete = value;
Disc.FadeColour(completeColour, 200);
updateCompleteTick();
}
}
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
{
Tracking = true;
return base.OnMouseDown(state, args);
}
protected override bool OnMouseUp(InputState state, MouseUpEventArgs args)
{
Tracking = false;
return base.OnMouseUp(state, args);
}
protected override bool OnMouseMove(InputState state)
{
Tracking |= state.Mouse.HasMainButtonPressed;
mousePosition = state.Mouse.Position;
return base.OnMouseMove(state);
}
private Vector2 mousePosition;
private float lastAngle;
private float currentRotation;
public float RotationAbsolute;
private int completeTick;
private bool updateCompleteTick() => completeTick != (completeTick = (int)(RotationAbsolute / 720));
protected override void Update()
{
base.Update();
var thisAngle = -(float)MathHelper.RadiansToDegrees(Math.Atan2(mousePosition.X - DrawSize.X / 2, mousePosition.Y - DrawSize.Y / 2));
if (tracking)
{
if (thisAngle - lastAngle > 180)
lastAngle += 360;
else if (lastAngle - thisAngle > 180)
lastAngle -= 360;
currentRotation += thisAngle - lastAngle;
RotationAbsolute += Math.Abs(thisAngle - lastAngle);
}
lastAngle = thisAngle;
if (Complete && updateCompleteTick())
{
Disc.Flush(flushType: typeof(TransformAlpha));
Disc.FadeTo(0.75f, 30, EasingTypes.OutExpo);
Disc.Delay(30);
Disc.FadeTo(0.5f, 250, EasingTypes.OutQuint);
}
RotateTo(currentRotation, 100, EasingTypes.OutExpo);
}
}
}

View File

@ -1,46 +0,0 @@
// 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.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Framework.MathUtils;
using OpenTK;
namespace osu.Game.Modes.Osu.Objects.Drawables.Pieces
{
public class Triangles : Container<Triangle>
{
public override bool HandleInput => false;
protected override void LoadComplete()
{
base.LoadComplete();
const float size = 100;
for (int i = 0; i < 10; i++)
{
Add(new Triangle
{
Origin = Anchor.Centre,
RelativePositionAxes = Axes.Both,
Position = new Vector2(RNG.NextSingle(), RNG.NextSingle()),
Scale = new Vector2(RNG.NextSingle() * 0.4f + 0.2f),
// Scaling height by 0.866 results in equiangular triangles (== 60° and equal side length)
Size = new Vector2(size, 0.866f * size),
Alpha = RNG.NextSingle() * 0.3f,
});
}
}
protected override void Update()
{
base.Update();
foreach (Drawable d in Children)
d.Position -= new Vector2(0, (float)(d.Scale.X * (Time.Elapsed / 2880)));
}
}
}

View File

@ -0,0 +1,26 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Game.Graphics.Backgrounds;
namespace osu.Game.Modes.Osu.Objects.Drawables.Pieces
{
public class TrianglesPiece : Triangles
{
protected override bool ExpireOffScreenTriangles => false;
protected override bool CreateNewTriangles => false;
protected override float SpawnRatio => 0.5f;
public TrianglesPiece()
{
TriangleScale = 1.2f;
}
protected override void Update()
{
if (IsPresent)
base.Update();
}
}
}

View File

@ -31,19 +31,19 @@ namespace osu.Game.Modes.Osu.Objects
Scale = (1.0f - 0.7f * (beatmap.BeatmapInfo.BaseDifficulty.CircleSize - 5) / 5) / 2; Scale = (1.0f - 0.7f * (beatmap.BeatmapInfo.BaseDifficulty.CircleSize - 5) / 5) / 2;
} }
}
[Flags] [Flags]
internal enum HitObjectType public enum HitObjectType
{ {
Circle = 1, Circle = 1,
Slider = 2, Slider = 2,
NewCombo = 4, NewCombo = 4,
CircleNewCombo = 5, CircleNewCombo = 5,
SliderNewCombo = 6, SliderNewCombo = 6,
Spinner = 8, Spinner = 8,
ColourHax = 122, ColourHax = 122,
Hold = 128, Hold = 128,
ManiaLong = 128, ManiaLong = 128,
}
} }
} }

View File

@ -15,8 +15,14 @@ namespace osu.Game.Modes.Osu.Objects
{ {
List<OsuHitObject> output = new List<OsuHitObject>(); List<OsuHitObject> output = new List<OsuHitObject>();
int combo = 0;
foreach (HitObject h in beatmap.HitObjects) foreach (HitObject h in beatmap.HitObjects)
{
if (h.NewCombo) combo = 0;
h.ComboIndex = combo++;
output.Add(h as OsuHitObject); output.Add(h as OsuHitObject);
}
UpdateStacking(output, beatmap.BeatmapInfo?.StackLeniency ?? 0.7f); UpdateStacking(output, beatmap.BeatmapInfo?.StackLeniency ?? 0.7f);

View File

@ -18,21 +18,22 @@ namespace osu.Game.Modes.Osu.Objects
public override HitObject Parse(string text) public override HitObject Parse(string text)
{ {
string[] split = text.Split(','); string[] split = text.Split(',');
var type = (OsuHitObject.HitObjectType)int.Parse(split[3]); var type = (HitObjectType)int.Parse(split[3]);
bool combo = type.HasFlag(OsuHitObject.HitObjectType.NewCombo); bool combo = type.HasFlag(HitObjectType.NewCombo);
type &= (OsuHitObject.HitObjectType)0xF; type &= (HitObjectType)0xF;
type &= ~OsuHitObject.HitObjectType.NewCombo; type &= ~HitObjectType.NewCombo;
OsuHitObject result; OsuHitObject result;
switch (type) switch (type)
{ {
case OsuHitObject.HitObjectType.Circle: case HitObjectType.Circle:
result = new HitCircle(); result = new HitCircle
{
Position = new Vector2(int.Parse(split[0]), int.Parse(split[1]))
};
break; break;
case OsuHitObject.HitObjectType.Slider: case HitObjectType.Slider:
Slider s = new Slider();
CurveTypes curveType = CurveTypes.Catmull; CurveTypes curveType = CurveTypes.Catmull;
int repeatCount = 0; int repeatCount;
double length = 0; double length = 0;
List<Vector2> points = new List<Vector2>(); List<Vector2> points = new List<Vector2>();
@ -79,29 +80,28 @@ namespace osu.Game.Modes.Osu.Objects
if (split.Length > 7) if (split.Length > 7)
length = Convert.ToDouble(split[7], CultureInfo.InvariantCulture); length = Convert.ToDouble(split[7], CultureInfo.InvariantCulture);
s.RepeatCount = repeatCount; result = new Slider
s.Curve = new SliderCurve
{ {
ControlPoints = points, ControlPoints = points,
Length = length, Length = length,
CurveType = curveType CurveType = curveType,
RepeatCount = repeatCount,
Position = new Vector2(int.Parse(split[0]), int.Parse(split[1]))
}; };
s.Curve.Calculate();
result = s;
break; break;
case OsuHitObject.HitObjectType.Spinner: case HitObjectType.Spinner:
result = new Spinner(); result = new Spinner
{
Length = Convert.ToDouble(split[5], CultureInfo.InvariantCulture) - Convert.ToDouble(split[2], CultureInfo.InvariantCulture),
Position = new Vector2(512, 384) / 2,
};
break; break;
default: default:
//throw new InvalidOperationException($@"Unknown hit object type {type}"); throw new InvalidOperationException($@"Unknown hit object type {type}");
return null;
} }
result.Position = new Vector2(int.Parse(split[0]), int.Parse(split[1])); result.StartTime = Convert.ToDouble(split[2], CultureInfo.InvariantCulture);
result.StartTime = double.Parse(split[2]); result.Sample = new HitSampleInfo
result.Sample = new HitSampleInfo { {
Type = (SampleType)int.Parse(split[4]), Type = (SampleType)int.Parse(split[4]),
Set = SampleSet.Soft, Set = SampleSet.Soft,
}; };

View File

@ -1,8 +1,12 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Beatmaps;
using OpenTK; using OpenTK;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Samples;
using osu.Game.Beatmaps.Timing;
using System;
using System.Collections.Generic;
namespace osu.Game.Modes.Osu.Objects namespace osu.Game.Modes.Osu.Objects
{ {
@ -19,23 +23,93 @@ namespace osu.Game.Modes.Osu.Objects
set set
{ {
stackHeight = value; stackHeight = value;
if (Curve != null) Curve.Offset = StackOffset;
Curve.Offset = StackOffset;
} }
} }
public List<Vector2> ControlPoints
{
get { return Curve.ControlPoints; }
set { Curve.ControlPoints = value; }
}
public double Length
{
get { return Curve.Length; }
set { Curve.Length = value; }
}
public CurveTypes CurveType
{
get { return Curve.CurveType; }
set { Curve.CurveType = value; }
}
public double Velocity; public double Velocity;
public double TickDistance;
public override void SetDefaultsFromBeatmap(Beatmap beatmap) public override void SetDefaultsFromBeatmap(Beatmap beatmap)
{ {
base.SetDefaultsFromBeatmap(beatmap); base.SetDefaultsFromBeatmap(beatmap);
Velocity = 100 / beatmap.BeatLengthAt(StartTime, true) * beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier; var baseDifficulty = beatmap.BeatmapInfo.BaseDifficulty;
ControlPoint overridePoint;
ControlPoint timingPoint = beatmap.TimingPointAt(StartTime, out overridePoint);
var velocityAdjustment = overridePoint?.VelocityAdjustment ?? 1;
var baseVelocity = 100 * baseDifficulty.SliderMultiplier;
Velocity = baseVelocity / (timingPoint.BeatLength * velocityAdjustment);
TickDistance = baseVelocity / (baseDifficulty.SliderTickRate * velocityAdjustment);
} }
public int RepeatCount; public int RepeatCount = 1;
public SliderCurve Curve; internal readonly SliderCurve Curve = new SliderCurve();
public IEnumerable<SliderTick> Ticks
{
get
{
if (TickDistance == 0) yield break;
var length = Curve.Length;
var tickDistance = Math.Min(TickDistance, length);
var repeatDuration = length / Velocity;
var minDistanceFromEnd = Velocity * 0.01;
for (var repeat = 0; repeat < RepeatCount; repeat++)
{
var repeatStartTime = StartTime + repeat * repeatDuration;
var reversed = repeat % 2 == 1;
for (var d = tickDistance; d <= length; d += tickDistance)
{
if (d > length - minDistanceFromEnd)
break;
var distanceProgress = d / length;
var timeProgress = reversed ? 1 - distanceProgress : distanceProgress;
yield return new SliderTick
{
RepeatIndex = repeat,
StartTime = repeatStartTime + timeProgress * repeatDuration,
Position = Curve.PositionAt(distanceProgress),
StackHeight = StackHeight,
Scale = Scale,
Colour = Colour,
Sample = new HitSampleInfo
{
Type = SampleType.None,
Set = SampleSet.Soft,
},
};
}
}
}
}
} }
public enum CurveTypes public enum CurveTypes

View File

@ -15,7 +15,7 @@ namespace osu.Game.Modes.Osu.Objects
public List<Vector2> ControlPoints; public List<Vector2> ControlPoints;
public CurveTypes CurveType; public CurveTypes CurveType = CurveTypes.PerfectCurve;
public Vector2 Offset; public Vector2 Offset;
@ -172,6 +172,9 @@ namespace osu.Game.Modes.Osu.Objects
/// <param name="p1">End progress. Ranges from 0 (beginning of the slider) to 1 (end of the slider).</param> /// <param name="p1">End progress. Ranges from 0 (beginning of the slider) to 1 (end of the slider).</param>
public void GetPathToProgress(List<Vector2> path, double p0, double p1) public void GetPathToProgress(List<Vector2> path, double p0, double p1)
{ {
if (calculatedPath.Count == 0 && ControlPoints.Count > 0)
Calculate();
double d0 = progressToDistance(p0); double d0 = progressToDistance(p0);
double d1 = progressToDistance(p1); double d1 = progressToDistance(p1);
@ -196,6 +199,9 @@ namespace osu.Game.Modes.Osu.Objects
/// <returns></returns> /// <returns></returns>
public Vector2 PositionAt(double progress) public Vector2 PositionAt(double progress)
{ {
if (calculatedPath.Count == 0 && ControlPoints.Count > 0)
Calculate();
double d = progressToDistance(progress); double d = progressToDistance(progress);
return interpolateVertices(indexOfDistance(d), d) + Offset; return interpolateVertices(indexOfDistance(d), d) + Offset;
} }

View File

@ -0,0 +1,9 @@
using OpenTK;
namespace osu.Game.Modes.Osu.Objects
{
public class SliderTick : OsuHitObject
{
public int RepeatIndex { get; set; }
}
}

View File

@ -1,9 +1,14 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Beatmaps;
namespace osu.Game.Modes.Osu.Objects namespace osu.Game.Modes.Osu.Objects
{ {
public class Spinner : OsuHitObject public class Spinner : OsuHitObject
{ {
public double Length;
public override double EndTime => StartTime + Length;
} }
} }

View File

@ -36,24 +36,8 @@ namespace osu.Game.Modes.Osu
foreach (OsuJudgementInfo j in Judgements) foreach (OsuJudgementInfo j in Judgements)
{ {
switch (j.Score) score += j.ScoreValue;
{ maxScore += j.MaxScoreValue;
case OsuScoreResult.Miss:
maxScore += 300;
break;
case OsuScoreResult.Hit50:
score += 50;
maxScore += 300;
break;
case OsuScoreResult.Hit100:
score += 100;
maxScore += 300;
break;
case OsuScoreResult.Hit300:
score += 300;
maxScore += 300;
break;
}
} }
TotalScore.Value = score; TotalScore.Value = score;

View File

@ -21,7 +21,8 @@ namespace osu.Game.Modes.Osu.UI
return new DrawableHitCircle(h as HitCircle); return new DrawableHitCircle(h as HitCircle);
if (h is Slider) if (h is Slider)
return new DrawableSlider(h as Slider); return new DrawableSlider(h as Slider);
if (h is Spinner)
return new DrawableSpinner(h as Spinner);
return null; return null;
} }
} }

View File

@ -60,10 +60,10 @@ namespace osu.Game.Modes.Osu.UI
public override void Add(DrawableHitObject h) public override void Add(DrawableHitObject h)
{ {
h.Depth = (float)h.HitObject.StartTime; h.Depth = (float)h.HitObject.StartTime;
DrawableHitCircle c = h as DrawableHitCircle; IDrawableHitObjectWithProxiedApproach c = h as IDrawableHitObjectWithProxiedApproach;
if (c != null) if (c != null)
{ {
approachCircles.Add(c.ApproachCircle.CreateProxy()); approachCircles.Add(c.ProxiedLayer.CreateProxy());
} }
h.OnJudgement += judgement; h.OnJudgement += judgement;

View File

@ -15,17 +15,19 @@ namespace osu.Game.Modes.Osu.UI
{ {
protected override ScoreCounter CreateScoreCounter() => new ScoreCounter() protected override ScoreCounter CreateScoreCounter() => new ScoreCounter()
{ {
Anchor = Anchor.TopRight, Anchor = Anchor.TopCentre,
Origin = Anchor.TopRight, Origin = Anchor.TopCentre,
TextSize = 60, TextSize = 40,
Position = new Vector2(0, 30),
Margin = new MarginPadding { Right = 5 }, Margin = new MarginPadding { Right = 5 },
}; };
protected override PercentageCounter CreateAccuracyCounter() => new PercentageCounter() protected override PercentageCounter CreateAccuracyCounter() => new PercentageCounter()
{ {
Anchor = Anchor.TopRight, Anchor = Anchor.TopCentre,
Origin = Anchor.TopRight, Origin = Anchor.TopCentre,
Position = new Vector2(0, 55), Position = new Vector2(0, 65),
TextSize = 20,
Margin = new MarginPadding { Right = 5 }, Margin = new MarginPadding { Right = 5 },
}; };

View File

@ -49,21 +49,26 @@
<Compile Include="Objects\Drawables\Connections\ConnectionRenderer.cs" /> <Compile Include="Objects\Drawables\Connections\ConnectionRenderer.cs" />
<Compile Include="Objects\Drawables\Connections\FollowPointRenderer.cs" /> <Compile Include="Objects\Drawables\Connections\FollowPointRenderer.cs" />
<Compile Include="Objects\Drawables\Pieces\ApproachCircle.cs" /> <Compile Include="Objects\Drawables\Pieces\ApproachCircle.cs" />
<Compile Include="Objects\Drawables\Pieces\SpinnerBackground.cs" />
<Compile Include="Objects\Drawables\Pieces\CirclePiece.cs" /> <Compile Include="Objects\Drawables\Pieces\CirclePiece.cs" />
<Compile Include="Objects\Drawables\DrawableSlider.cs" /> <Compile Include="Objects\Drawables\DrawableSlider.cs" />
<Compile Include="Objects\Drawables\Connections\FollowPoint.cs" /> <Compile Include="Objects\Drawables\Connections\FollowPoint.cs" />
<Compile Include="Objects\Drawables\DrawableSpinner.cs" />
<Compile Include="Objects\Drawables\Pieces\ExplodePiece.cs" /> <Compile Include="Objects\Drawables\Pieces\ExplodePiece.cs" />
<Compile Include="Objects\Drawables\Pieces\FlashPiece.cs" /> <Compile Include="Objects\Drawables\Pieces\FlashPiece.cs" />
<Compile Include="Objects\Drawables\Pieces\GlowPiece.cs" /> <Compile Include="Objects\Drawables\Pieces\GlowPiece.cs" />
<Compile Include="Objects\Drawables\HitExplosion.cs" /> <Compile Include="Objects\Drawables\HitExplosion.cs" />
<Compile Include="Objects\Drawables\Pieces\NumberPiece.cs" /> <Compile Include="Objects\Drawables\Pieces\NumberPiece.cs" />
<Compile Include="Objects\Drawables\DrawableSliderTick.cs" />
<Compile Include="Objects\Drawables\Pieces\RingPiece.cs" /> <Compile Include="Objects\Drawables\Pieces\RingPiece.cs" />
<Compile Include="Objects\Drawables\Pieces\SliderBouncer.cs" /> <Compile Include="Objects\Drawables\Pieces\SliderBouncer.cs" />
<Compile Include="Objects\Drawables\Pieces\Triangles.cs" /> <Compile Include="Objects\Drawables\Pieces\SpinnerDisc.cs" />
<Compile Include="Objects\Drawables\Pieces\TrianglesPiece.cs" />
<Compile Include="Objects\Drawables\Pieces\SliderBall.cs" /> <Compile Include="Objects\Drawables\Pieces\SliderBall.cs" />
<Compile Include="Objects\Drawables\Pieces\SliderBody.cs" /> <Compile Include="Objects\Drawables\Pieces\SliderBody.cs" />
<Compile Include="Objects\OsuHitObjectParser.cs" /> <Compile Include="Objects\OsuHitObjectParser.cs" />
<Compile Include="Objects\SliderCurve.cs" /> <Compile Include="Objects\SliderCurve.cs" />
<Compile Include="Objects\SliderTick.cs" />
<Compile Include="OsuScore.cs" /> <Compile Include="OsuScore.cs" />
<Compile Include="OsuScoreProcessor.cs" /> <Compile Include="OsuScoreProcessor.cs" />
<Compile Include="UI\OsuComboCounter.cs" /> <Compile Include="UI\OsuComboCounter.cs" />

View File

@ -25,6 +25,6 @@ namespace osu.Game.Modes.Taiko
public override ScoreProcessor CreateScoreProcessor(int hitObjectCount) => null; public override ScoreProcessor CreateScoreProcessor(int hitObjectCount) => null;
public override HitObjectParser CreateHitObjectParser() => new OsuHitObjectParser(); public override HitObjectParser CreateHitObjectParser() => new NullHitObjectParser();
} }
} }

View File

@ -26,26 +26,31 @@ namespace osu.Game.Beatmaps
return 60000 / BeatLengthAt(time); return 60000 / BeatLengthAt(time);
} }
public double BeatLengthAt(double time, bool applyMultipliers = false) public double BeatLengthAt(double time)
{ {
int point = 0; ControlPoint overridePoint;
int samplePoint = 0; ControlPoint timingPoint = TimingPointAt(time, out overridePoint);
return timingPoint.BeatLength;
}
for (int i = 0; i < ControlPoints.Count; i++) public ControlPoint TimingPointAt(double time, out ControlPoint overridePoint)
if (ControlPoints[i].Time <= time) {
overridePoint = null;
ControlPoint timingPoint = null;
foreach (var controlPoint in ControlPoints)
if (controlPoint.Time <= time)
{ {
if (ControlPoints[i].TimingChange) if (controlPoint.TimingChange)
point = i; {
else timingPoint = controlPoint;
samplePoint = i; overridePoint = null;
}
else overridePoint = controlPoint;
} }
else break;
double mult = 1; return timingPoint;
if (applyMultipliers && samplePoint > point)
mult = ControlPoints[samplePoint].VelocityAdjustment;
return ControlPoints[point].BeatLength * mult;
} }
} }
} }

View File

@ -2,12 +2,10 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Linq; using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Framework.MathUtils; using osu.Framework.MathUtils;
using OpenTK; using OpenTK;
using OpenTK.Graphics; using OpenTK.Graphics;
@ -22,6 +20,21 @@ namespace osu.Game.Graphics.Backgrounds
public Color4 ColourLight = Color4.White; public Color4 ColourLight = Color4.White;
public Color4 ColourDark = Color4.Black; public Color4 ColourDark = Color4.Black;
/// <summary>
/// Whether we want to expire triangles as they exit our draw area completely.
/// </summary>
protected virtual bool ExpireOffScreenTriangles => true;
/// <summary>
/// Whether we should create new triangles as others expire.
/// </summary>
protected virtual bool CreateNewTriangles => true;
/// <summary>
/// The amount of triangles we want compared to the default distribution.
/// </summary>
protected virtual float SpawnRatio => 1;
private float triangleScale = 1; private float triangleScale = 1;
public float TriangleScale public float TriangleScale
@ -29,9 +42,11 @@ namespace osu.Game.Graphics.Backgrounds
get { return triangleScale; } get { return triangleScale; }
set set
{ {
float change = value / triangleScale;
triangleScale = value; triangleScale = value;
Children.ForEach(t => t.ScaleTo(triangleScale)); if (change != 1)
Children.ForEach(t => t.Scale *= change);
} }
} }
@ -42,20 +57,20 @@ namespace osu.Game.Graphics.Backgrounds
addTriangle(true); addTriangle(true);
} }
private int aimTriangleCount => (int)(DrawWidth * DrawHeight * 0.002f / (triangleScale * triangleScale)); private int aimTriangleCount => (int)(DrawWidth * DrawHeight * 0.002f / (triangleScale * triangleScale) * SpawnRatio);
protected override void Update() protected override void Update()
{ {
base.Update(); base.Update();
foreach (Drawable d in Children) foreach (var t in Children)
{ {
d.Position -= new Vector2(0, (float)(d.Scale.X * (50 / DrawHeight) * (Time.Elapsed / 950)) / triangleScale); t.Position -= new Vector2(0, (float)(t.Scale.X * (50 / DrawHeight) * (Time.Elapsed / 950)) / triangleScale);
if (d.DrawPosition.Y + d.DrawSize.Y * d.Scale.Y < 0) if (ExpireOffScreenTriangles && t.DrawPosition.Y + t.DrawSize.Y * t.Scale.Y < 0)
d.Expire(); t.Expire();
} }
while (Children.Count() < aimTriangleCount) while (CreateNewTriangles && Children.Count() < aimTriangleCount)
addTriangle(false); addTriangle(false);
} }
@ -77,8 +92,8 @@ namespace osu.Game.Graphics.Backgrounds
RelativePositionAxes = Axes.Both, RelativePositionAxes = Axes.Both,
Scale = new Vector2(scale), Scale = new Vector2(scale),
EdgeSmoothness = new Vector2(1), EdgeSmoothness = new Vector2(1),
// Scaling height by 0.866 results in equiangular triangles (== 60° and equal side length)
Colour = GetTriangleShade(), Colour = GetTriangleShade(),
// Scaling height by 0.866 results in equiangular triangles (== 60° and equal side length)
Size = new Vector2(size, 0.866f * size), Size = new Vector2(size, 0.866f * size),
Depth = scale, Depth = scale,
}; };
@ -89,8 +104,8 @@ namespace osu.Game.Graphics.Backgrounds
private void addTriangle(bool randomY) private void addTriangle(bool randomY)
{ {
var sprite = CreateTriangle(); var sprite = CreateTriangle();
var triangleHeight = sprite.DrawHeight / DrawHeight; float triangleHeight = (sprite.DrawHeight / DrawHeight);
sprite.Position = new Vector2(RNG.NextSingle(), randomY ? (RNG.NextSingle() * (1 + triangleHeight) - triangleHeight) : 1); sprite.Position = new Vector2(RNG.NextSingle(), randomY ? RNG.NextSingle() * (1 + triangleHeight) - triangleHeight : 1);
Add(sprite); Add(sprite);
} }
} }

View File

@ -107,7 +107,10 @@ namespace osu.Game.Graphics.UserInterface
{ {
Children = new Drawable[] Children = new Drawable[]
{ {
DisplayedCountSpriteText = new OsuSpriteText(), DisplayedCountSpriteText = new OsuSpriteText()
{
Font = @"Venera"
},
}; };
TextSize = 40; TextSize = 40;

View File

@ -2,6 +2,7 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System; using System;
using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
using System.Diagnostics; using System.Diagnostics;
using osu.Framework; using osu.Framework;
@ -19,7 +20,9 @@ namespace osu.Game.Modes.Objects.Drawables
{ {
public event Action<DrawableHitObject, JudgementInfo> OnJudgement; public event Action<DrawableHitObject, JudgementInfo> OnJudgement;
public Container<DrawableHitObject> ChildObjects; public override bool HandleInput => Interactive;
public bool Interactive = true;
public JudgementInfo Judgement; public JudgementInfo Judgement;
@ -62,7 +65,7 @@ namespace osu.Game.Modes.Objects.Drawables
sample = audio.Sample.Get($@"Gameplay/{sampleSet}-hit{hitType}"); sample = audio.Sample.Get($@"Gameplay/{sampleSet}-hit{hitType}");
} }
protected void PlaySample() protected virtual void PlaySample()
{ {
sample?.Play(); sample?.Play();
} }
@ -81,6 +84,19 @@ namespace osu.Game.Modes.Objects.Drawables
Expire(true); Expire(true);
} }
private List<DrawableHitObject> nestedHitObjects;
protected IEnumerable<DrawableHitObject> NestedHitObjects => nestedHitObjects;
protected void AddNested(DrawableHitObject h)
{
if (nestedHitObjects == null)
nestedHitObjects = new List<DrawableHitObject>();
h.OnJudgement += (d, j) => { OnJudgement?.Invoke(d, j); } ;
nestedHitObjects.Add(h);
}
/// <summary> /// <summary>
/// Process a hit of this hitobject. Carries out judgement. /// Process a hit of this hitobject. Carries out judgement.
/// </summary> /// </summary>
@ -115,7 +131,11 @@ namespace osu.Game.Modes.Objects.Drawables
protected virtual void CheckJudgement(bool userTriggered) protected virtual void CheckJudgement(bool userTriggered)
{ {
//todo: consider making abstract. if (NestedHitObjects != null)
{
foreach (var d in NestedHitObjects)
d.CheckJudgement(userTriggered);
}
} }
protected override void UpdateAfterChildren() protected override void UpdateAfterChildren()

View File

@ -0,0 +1,17 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using osu.Framework.Graphics;
namespace osu.Game.Modes.Objects.Drawables
{
public interface IDrawableHitObjectWithProxiedApproach
{
Drawable ProxiedLayer { get; }
}
}

View File

@ -24,6 +24,8 @@ namespace osu.Game.Modes.Objects
public HitSampleInfo Sample; public HitSampleInfo Sample;
public int ComboIndex;
public virtual void SetDefaultsFromBeatmap(Beatmap beatmap) { } public virtual void SetDefaultsFromBeatmap(Beatmap beatmap) { }
} }
} }

View File

@ -0,0 +1,14 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
namespace osu.Game.Modes.Objects
{
/// <summary>
/// Returns null HitObjects but at least allows us to run.
/// </summary>
public class NullHitObjectParser : HitObjectParser
{
public override HitObject Parse(string text) => null;
}
}

View File

@ -1,23 +1,29 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
using OpenTK; using System;
using OpenTK.Graphics; using osu.Framework.Allocation;
using osu.Framework.Configuration; using osu.Framework.Configuration;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Transformations; using osu.Framework.Graphics.Transformations;
using System; using osu.Game.Graphics;
using OpenTK;
using OpenTK.Graphics;
namespace osu.Game.Modes.UI namespace osu.Game.Modes.UI
{ {
public class HealthDisplay : Container public class HealthDisplay : Container
{ {
private Box background; private Box background;
private Box fill; private Container fill;
public BindableDouble Current = new BindableDouble() { MinValue = 0, MaxValue = 1 }; public BindableDouble Current = new BindableDouble()
{
MinValue = 0,
MaxValue = 1
};
public HealthDisplay() public HealthDisplay()
{ {
@ -26,19 +32,38 @@ namespace osu.Game.Modes.UI
background = new Box background = new Box
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Colour = Color4.Gray, Colour = Color4.Black,
}, },
fill = new Box fill = new Container
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Colour = Color4.White,
Scale = new Vector2(0, 1), Scale = new Vector2(0, 1),
}, Masking = true,
Children = new[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
}
}
},
}; };
Current.ValueChanged += current_ValueChanged; Current.ValueChanged += current_ValueChanged;
} }
[BackgroundDependencyLoader]
private void laod(OsuColour colours)
{
fill.Colour = colours.BlueLighter;
fill.EdgeEffect = new EdgeEffect
{
Colour = colours.BlueDarker.Opacity(0.6f),
Radius = 8,
Type= EdgeEffectType.Glow
};
}
private void current_ValueChanged(object sender, EventArgs e) private void current_ValueChanged(object sender, EventArgs e)
{ {
fill.ScaleTo(new Vector2((float)Current, 1), 200, EasingTypes.OutQuint); fill.ScaleTo(new Vector2((float)Current, 1), 200, EasingTypes.OutQuint);

View File

@ -27,9 +27,9 @@ namespace osu.Game.Modes.UI
protected abstract ScoreCounter CreateScoreCounter(); protected abstract ScoreCounter CreateScoreCounter();
protected virtual HealthDisplay CreateHealthDisplay() => new HealthDisplay protected virtual HealthDisplay CreateHealthDisplay() => new HealthDisplay
{ {
Size = new Vector2(0.5f, 20), Size = new Vector2(1, 5),
RelativeSizeAxes = Axes.X, RelativeSizeAxes = Axes.X,
Padding = new MarginPadding(5) Margin = new MarginPadding { Top = 20 }
}; };
public virtual void OnHit(HitObject h) public virtual void OnHit(HitObject h)

View File

@ -25,6 +25,7 @@ using OpenTK;
using System.Linq; using System.Linq;
using osu.Framework.Graphics.Primitives; using osu.Framework.Graphics.Primitives;
using System.Collections.Generic; using System.Collections.Generic;
using osu.Game.Overlays.Notifications;
namespace osu.Game namespace osu.Game
{ {
@ -130,6 +131,16 @@ namespace osu.Game
Origin = Anchor.TopRight, Origin = Anchor.TopRight,
}).Preload(this, overlayContent.Add); }).Preload(this, overlayContent.Add);
Logger.NewEntry += entry =>
{
if (entry.Level < LogLevel.Important) return;
notificationManager.Post(new SimpleNotification
{
Text = $@"{entry.Level}: {entry.Message}"
});
};
Dependencies.Cache(options); Dependencies.Cache(options);
Dependencies.Cache(musicController); Dependencies.Cache(musicController);
Dependencies.Cache(notificationManager); Dependencies.Cache(notificationManager);

View File

@ -9,6 +9,7 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Transformations; using osu.Framework.Graphics.Transformations;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using OpenTK; using OpenTK;
using OpenTK.Graphics; using OpenTK.Graphics;
@ -118,7 +119,7 @@ namespace osu.Game.Overlays.Notifications
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
}); });
Content.Add(textDrawable = new SpriteText Content.Add(textDrawable = new OsuSpriteText
{ {
TextSize = 16, TextSize = 16,
Colour = OsuColour.Gray(128), Colour = OsuColour.Gray(128),

View File

@ -6,6 +6,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
namespace osu.Game.Overlays.Notifications namespace osu.Game.Overlays.Notifications
{ {
@ -52,7 +53,7 @@ namespace osu.Game.Overlays.Notifications
} }
}); });
Content.Add(textDrawable = new SpriteText Content.Add(textDrawable = new OsuSpriteText
{ {
TextSize = 16, TextSize = 16,
Colour = OsuColour.Gray(128), Colour = OsuColour.Gray(128),

View File

@ -11,6 +11,7 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Audio.Sample; using osu.Framework.Audio.Sample;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Backgrounds; using osu.Game.Graphics.Backgrounds;
using osu.Game.Graphics.Sprites;
namespace osu.Game.Overlays.Pause namespace osu.Game.Overlays.Pause
{ {
@ -224,7 +225,7 @@ namespace osu.Game.Overlays.Pause
} }
} }
}, },
spriteText = new SpriteText spriteText = new OsuSpriteText
{ {
Text = Text, Text = Text,
Anchor = Anchor.Centre, Anchor = Anchor.Centre,

View File

@ -13,6 +13,7 @@ using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Transformations; using osu.Framework.Graphics.Transformations;
using System.Threading.Tasks; using System.Threading.Tasks;
using osu.Game.Graphics.Sprites;
namespace osu.Game.Overlays.Pause namespace osu.Game.Overlays.Pause
{ {
@ -39,14 +40,14 @@ namespace osu.Game.Overlays.Pause
retryCounterContainer.Children = new Drawable[] retryCounterContainer.Children = new Drawable[]
{ {
new SpriteText new OsuSpriteText
{ {
Text = "You've retried ", Text = "You've retried ",
Shadow = true, Shadow = true,
ShadowColour = new Color4(0, 0, 0, 0.25f), ShadowColour = new Color4(0, 0, 0, 0.25f),
TextSize = 18 TextSize = 18
}, },
new SpriteText new OsuSpriteText
{ {
Text = String.Format("{0:n0}", value), Text = String.Format("{0:n0}", value),
Font = @"Exo2.0-Bold", Font = @"Exo2.0-Bold",
@ -54,7 +55,7 @@ namespace osu.Game.Overlays.Pause
ShadowColour = new Color4(0, 0, 0, 0.25f), ShadowColour = new Color4(0, 0, 0, 0.25f),
TextSize = 18 TextSize = 18
}, },
new SpriteText new OsuSpriteText
{ {
Text = $" time{((value == 1) ? "" : "s")} in this session", Text = $" time{((value == 1) ? "" : "s")} in this session",
Shadow = true, Shadow = true,
@ -119,7 +120,7 @@ namespace osu.Game.Overlays.Pause
Anchor = Anchor.TopCentre, Anchor = Anchor.TopCentre,
Children = new Drawable[] Children = new Drawable[]
{ {
new SpriteText new OsuSpriteText
{ {
Text = @"paused", Text = @"paused",
Font = @"Exo2.0-Medium", Font = @"Exo2.0-Medium",
@ -131,7 +132,7 @@ namespace osu.Game.Overlays.Pause
Shadow = true, Shadow = true,
ShadowColour = new Color4(0, 0, 0, 0.25f) ShadowColour = new Color4(0, 0, 0, 0.25f)
}, },
new SpriteText new OsuSpriteText
{ {
Text = @"you're not going to do what i think you're going to do, are ya?", Text = @"you're not going to do what i think you're going to do, are ya?",
Origin = Anchor.TopCentre, Origin = Anchor.TopCentre,

View File

@ -195,11 +195,12 @@ namespace osu.Game.Screens.Menu
protected override bool OnMouseUp(InputState state, MouseUpEventArgs args) protected override bool OnMouseUp(InputState state, MouseUpEventArgs args)
{ {
logoBounceContainer.ScaleTo(1f, 500, EasingTypes.OutElastic); logoBounceContainer.ScaleTo(1f, 500, EasingTypes.OutElastic);
return true; return true;
} }
protected override bool OnDragStart(InputState state) => true;
protected override bool OnClick(InputState state) protected override bool OnClick(InputState state)
{ {
if (!Interactive) return false; if (!Interactive) return false;

View File

@ -89,6 +89,8 @@ namespace osu.Game.Screens.Play
new OsuSpriteText new OsuSpriteText
{ {
Text = Name, Text = Name,
Font = @"Venera",
TextSize = 12,
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
RelativePositionAxes = Axes.Both, RelativePositionAxes = Axes.Both,

View File

@ -23,6 +23,7 @@ using System.Linq;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using OpenTK.Graphics; using OpenTK.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Logging;
namespace osu.Game.Screens.Play namespace osu.Game.Screens.Play
{ {
@ -75,9 +76,14 @@ namespace osu.Game.Screens.Play
{ {
if (Beatmap == null) if (Beatmap == null)
Beatmap = beatmaps.GetWorkingBeatmap(BeatmapInfo, withStoryboard: true); Beatmap = beatmaps.GetWorkingBeatmap(BeatmapInfo, withStoryboard: true);
if ((Beatmap?.Beatmap?.HitObjects.Count ?? 0) == 0)
throw new Exception("No valid objects were found!");
} }
catch catch (Exception e)
{ {
Logger.Log($"Could not load this beatmap sucessfully ({e})!", LoggingTarget.Runtime, LogLevel.Error);
//couldn't load, hard abort! //couldn't load, hard abort!
Exit(); Exit();
return; return;
@ -117,7 +123,8 @@ namespace osu.Game.Screens.Play
pauseOverlay = new PauseOverlay pauseOverlay = new PauseOverlay
{ {
Depth = -1, Depth = -1,
OnResume = delegate { OnResume = delegate
{
Delay(400); Delay(400);
Schedule(Resume); Schedule(Resume);
}, },
@ -277,9 +284,9 @@ namespace osu.Game.Screens.Play
protected override void OnEntering(GameMode last) protected override void OnEntering(GameMode last)
{ {
base.OnEntering(last); base.OnEntering(last);
(Background as BackgroundModeBeatmap)?.BlurTo(Vector2.Zero, 1000); (Background as BackgroundModeBeatmap)?.BlurTo(Vector2.Zero, 1000);
Background?.FadeTo((100f- dimLevel)/100, 1000); Background?.FadeTo((100f - dimLevel) / 100, 1000);
Content.Alpha = 0; Content.Alpha = 0;
dimLevel.ValueChanged += dimChanged; dimLevel.ValueChanged += dimChanged;
@ -287,6 +294,8 @@ namespace osu.Game.Screens.Play
protected override bool OnExiting(GameMode next) protected override bool OnExiting(GameMode next)
{ {
if (pauseOverlay == null) return false;
if (pauseOverlay.State != Visibility.Visible && !canPause) return true; if (pauseOverlay.State != Visibility.Visible && !canPause) return true;
if (!IsPaused && sourceClock.IsRunning) // For if the user presses escape quickly when entering the map if (!IsPaused && sourceClock.IsRunning) // For if the user presses escape quickly when entering the map

View File

@ -74,7 +74,7 @@ namespace osu.Game.Screens.Select
{ {
Name = "Length", Name = "Length",
Icon = FontAwesome.fa_clock_o, Icon = FontAwesome.fa_clock_o,
Content = TimeSpan.FromMilliseconds(beatmap.Beatmap.HitObjects.Last().EndTime - beatmap.Beatmap.HitObjects.First().StartTime).ToString(@"m\:ss"), Content = beatmap.Beatmap.HitObjects.Count == 0 ? "-" : TimeSpan.FromMilliseconds(beatmap.Beatmap.HitObjects.Last().EndTime - beatmap.Beatmap.HitObjects.First().StartTime).ToString(@"m\:ss"),
})); }));
labels.Add(new InfoLabel(new BeatmapStatistic labels.Add(new InfoLabel(new BeatmapStatistic

View File

@ -12,6 +12,7 @@ using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface; using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input; using osu.Framework.Input;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
namespace osu.Game.Screens.Select namespace osu.Game.Screens.Select
{ {
@ -127,7 +128,7 @@ namespace osu.Game.Screens.Select
AutoSizeAxes = Axes.Both; AutoSizeAxes = Axes.Both;
Children = new Drawable[] Children = new Drawable[]
{ {
text = new SpriteText text = new OsuSpriteText
{ {
Margin = new MarginPadding(5), Margin = new MarginPadding(5),
TextSize = 14, TextSize = 14,
@ -213,7 +214,7 @@ namespace osu.Game.Screens.Select
Anchor = Anchor.TopRight, Anchor = Anchor.TopRight,
Children = new Drawable[] Children = new Drawable[]
{ {
sortLabel = new SpriteText sortLabel = new OsuSpriteText
{ {
Font = @"Exo2.0-Bold", Font = @"Exo2.0-Bold",
Text = "Sort results by", Text = "Sort results by",

View File

@ -25,6 +25,8 @@ namespace osu.Game.Screens.Select
private const float padding = 80; private const float padding = 80;
public override bool Contains(Vector2 screenSpacePos) => true;
public Action OnBack; public Action OnBack;
public Action OnStart; public Action OnStart;

View File

@ -75,7 +75,9 @@
<Compile Include="Graphics\UserInterface\OsuSliderBar.cs" /> <Compile Include="Graphics\UserInterface\OsuSliderBar.cs" />
<Compile Include="Graphics\UserInterface\OsuTextBox.cs" /> <Compile Include="Graphics\UserInterface\OsuTextBox.cs" />
<Compile Include="Graphics\UserInterface\TwoLayerButton.cs" /> <Compile Include="Graphics\UserInterface\TwoLayerButton.cs" />
<Compile Include="Modes\Objects\Drawables\IDrawableHitObjectWithProxiedApproach.cs" />
<Compile Include="Modes\Objects\HitObjectParser.cs" /> <Compile Include="Modes\Objects\HitObjectParser.cs" />
<Compile Include="Modes\Objects\NullHitObjectParser.cs" />
<Compile Include="Modes\Score.cs" /> <Compile Include="Modes\Score.cs" />
<Compile Include="Modes\ScoreProcesssor.cs" /> <Compile Include="Modes\ScoreProcesssor.cs" />
<Compile Include="Modes\UI\HealthDisplay.cs" /> <Compile Include="Modes\UI\HealthDisplay.cs" />

View File

@ -21,8 +21,10 @@
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=SuggestVarOrType_005FSimpleTypes/@EntryIndexedValue">DO_NOT_SHOW</s:String> <s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=SuggestVarOrType_005FSimpleTypes/@EntryIndexedValue">DO_NOT_SHOW</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=SwitchStatementMissingSomeCases/@EntryIndexedValue">DO_NOT_SHOW</s:String> <s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=SwitchStatementMissingSomeCases/@EntryIndexedValue">DO_NOT_SHOW</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=UnusedMember_002EGlobal/@EntryIndexedValue">HINT</s:String> <s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=UnusedMember_002EGlobal/@EntryIndexedValue">HINT</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=UnusedMember_002ELocal/@EntryIndexedValue">HINT</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=UnusedMethodReturnValue_002ELocal/@EntryIndexedValue">SUGGESTION</s:String> <s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=UnusedMethodReturnValue_002ELocal/@EntryIndexedValue">SUGGESTION</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=UnusedParameter_002EGlobal/@EntryIndexedValue">HINT</s:String> <s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=UnusedParameter_002EGlobal/@EntryIndexedValue">HINT</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=VirtualMemberCallInConstructor/@EntryIndexedValue">HINT</s:String>
<s:String x:Key="/Default/CodeStyle/CodeCleanup/Profiles/=Code_0020Cleanup_0020_0028peppy_0029/@EntryIndexedValue">&lt;?xml version="1.0" encoding="utf-16"?&gt;&lt;Profile name="Code Cleanup (peppy)"&gt;&lt;CSArrangeThisQualifier&gt;True&lt;/CSArrangeThisQualifier&gt;&lt;CSUseVar&gt;&lt;BehavourStyle&gt;CAN_CHANGE_TO_EXPLICIT&lt;/BehavourStyle&gt;&lt;LocalVariableStyle&gt;ALWAYS_EXPLICIT&lt;/LocalVariableStyle&gt;&lt;ForeachVariableStyle&gt;ALWAYS_EXPLICIT&lt;/ForeachVariableStyle&gt;&lt;/CSUseVar&gt;&lt;CSOptimizeUsings&gt;&lt;OptimizeUsings&gt;True&lt;/OptimizeUsings&gt;&lt;EmbraceInRegion&gt;False&lt;/EmbraceInRegion&gt;&lt;RegionName&gt;&lt;/RegionName&gt;&lt;/CSOptimizeUsings&gt;&lt;CSShortenReferences&gt;True&lt;/CSShortenReferences&gt;&lt;CSReformatCode&gt;True&lt;/CSReformatCode&gt;&lt;CSUpdateFileHeader&gt;True&lt;/CSUpdateFileHeader&gt;&lt;CSCodeStyleAttributes ArrangeTypeAccessModifier="False" ArrangeTypeMemberAccessModifier="False" SortModifiers="True" RemoveRedundantParentheses="True" AddMissingParentheses="False" ArrangeBraces="False" ArrangeAttributes="False" ArrangeArgumentsStyle="False" /&gt;&lt;XAMLCollapseEmptyTags&gt;False&lt;/XAMLCollapseEmptyTags&gt;&lt;CSFixBuiltinTypeReferences&gt;True&lt;/CSFixBuiltinTypeReferences&gt;&lt;CSArrangeQualifiers&gt;True&lt;/CSArrangeQualifiers&gt;&lt;/Profile&gt;</s:String> <s:String x:Key="/Default/CodeStyle/CodeCleanup/Profiles/=Code_0020Cleanup_0020_0028peppy_0029/@EntryIndexedValue">&lt;?xml version="1.0" encoding="utf-16"?&gt;&lt;Profile name="Code Cleanup (peppy)"&gt;&lt;CSArrangeThisQualifier&gt;True&lt;/CSArrangeThisQualifier&gt;&lt;CSUseVar&gt;&lt;BehavourStyle&gt;CAN_CHANGE_TO_EXPLICIT&lt;/BehavourStyle&gt;&lt;LocalVariableStyle&gt;ALWAYS_EXPLICIT&lt;/LocalVariableStyle&gt;&lt;ForeachVariableStyle&gt;ALWAYS_EXPLICIT&lt;/ForeachVariableStyle&gt;&lt;/CSUseVar&gt;&lt;CSOptimizeUsings&gt;&lt;OptimizeUsings&gt;True&lt;/OptimizeUsings&gt;&lt;EmbraceInRegion&gt;False&lt;/EmbraceInRegion&gt;&lt;RegionName&gt;&lt;/RegionName&gt;&lt;/CSOptimizeUsings&gt;&lt;CSShortenReferences&gt;True&lt;/CSShortenReferences&gt;&lt;CSReformatCode&gt;True&lt;/CSReformatCode&gt;&lt;CSUpdateFileHeader&gt;True&lt;/CSUpdateFileHeader&gt;&lt;CSCodeStyleAttributes ArrangeTypeAccessModifier="False" ArrangeTypeMemberAccessModifier="False" SortModifiers="True" RemoveRedundantParentheses="True" AddMissingParentheses="False" ArrangeBraces="False" ArrangeAttributes="False" ArrangeArgumentsStyle="False" /&gt;&lt;XAMLCollapseEmptyTags&gt;False&lt;/XAMLCollapseEmptyTags&gt;&lt;CSFixBuiltinTypeReferences&gt;True&lt;/CSFixBuiltinTypeReferences&gt;&lt;CSArrangeQualifiers&gt;True&lt;/CSArrangeQualifiers&gt;&lt;/Profile&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/CodeCleanup/RecentlyUsedProfile/@EntryValue">Code Cleanup (peppy)</s:String> <s:String x:Key="/Default/CodeStyle/CodeCleanup/RecentlyUsedProfile/@EntryValue">Code Cleanup (peppy)</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_LINQ_QUERY/@EntryValue">True</s:Boolean> <s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_LINQ_QUERY/@EntryValue">True</s:Boolean>