Merge branch 'master' into slider_ticks

Conflicts:
	osu.Game.Modes.Osu/Objects/Drawables/DrawableSlider.cs
	osu.Game.Modes.Osu/Objects/Slider.cs
This commit is contained in:
Damnae
2017-02-15 10:48:29 +01:00
81 changed files with 1608 additions and 291 deletions

View File

@ -2,7 +2,6 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.ComponentModel;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Transformations;
using osu.Game.Modes.Objects.Drawables;
@ -11,9 +10,9 @@ using OpenTK;
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;
private CirclePiece circle;
@ -23,11 +22,12 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
private NumberPiece number;
private GlowPiece glow;
public DrawableHitCircle(HitCircle h) : base(h)
public DrawableHitCircle(OsuHitObject h) : base(h)
{
Origin = Anchor.Centre;
osuObject = h;
Origin = Anchor.Centre;
Position = osuObject.StackedPosition;
Scale = new Vector2(osuObject.Scale);
@ -156,5 +156,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
break;
}
}
public Drawable ProxiedLayer => ApproachCircle;
}
}

View File

@ -4,6 +4,7 @@
using System.ComponentModel;
using osu.Game.Modes.Objects;
using osu.Game.Modes.Objects.Drawables;
using osu.Framework.Graphics;
namespace osu.Game.Modes.Osu.Objects.Drawables
{

View File

@ -3,7 +3,6 @@
using OpenTK;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Osu.Objects.Drawables.Pieces;
using System.Collections.Generic;
@ -11,7 +10,7 @@ using System.Linq;
namespace osu.Game.Modes.Osu.Objects.Drawables
{
class DrawableSlider : DrawableOsuHitObject
public class DrawableSlider : DrawableOsuHitObject, IDrawableHitObjectWithProxiedApproach
{
private Slider slider;
@ -157,6 +156,8 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
FadeOut(800);
}
public Drawable ProxiedLayer => initialCircle.ApproachCircle;
}
internal interface ISliderProgress

View File

@ -0,0 +1,140 @@
// 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.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 DrawableHitCircle circle;
private NumberPiece number;
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
},
circle = new DrawableHitCircle(s)
{
Interactive = false,
Position = Vector2.Zero,
Anchor = Anchor.Centre,
}
};
circle.ApproachCircle.Colour = Color4.Transparent;
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 (!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;
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);
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)
{
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

@ -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,168 @@
// 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.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 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; }
}
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);
}
}
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;
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;
RotateTo(currentRotation, 100, EasingTypes.OutExpo);
}
}
}

View File

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

View File

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

View File

@ -1,11 +1,11 @@
// 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 OpenTK;
using System.Collections.Generic;
using System;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Samples;
using System;
using System.Collections.Generic;
namespace osu.Game.Modes.Osu.Objects
{
@ -22,11 +22,28 @@ namespace osu.Game.Modes.Osu.Objects
set
{
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 TickDistance;
@ -43,9 +60,9 @@ namespace osu.Game.Modes.Osu.Objects
TickDistance = (100 * baseDifficulty.SliderMultiplier) / baseDifficulty.SliderTickRate / (multipliedStartBeatLength / startBeatLength);
}
public int RepeatCount;
public int RepeatCount = 1;
public SliderCurve Curve;
internal readonly SliderCurve Curve = new SliderCurve();
public IEnumerable<SliderTick> Ticks
{

View File

@ -15,7 +15,7 @@ namespace osu.Game.Modes.Osu.Objects
public List<Vector2> ControlPoints;
public CurveTypes CurveType;
public CurveTypes CurveType = CurveTypes.PerfectCurve;
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>
public void GetPathToProgress(List<Vector2> path, double p0, double p1)
{
if (calculatedPath.Count == 0 && ControlPoints.Count > 0)
Calculate();
double d0 = progressToDistance(p0);
double d1 = progressToDistance(p1);
@ -196,6 +199,9 @@ namespace osu.Game.Modes.Osu.Objects
/// <returns></returns>
public Vector2 PositionAt(double progress)
{
if (calculatedPath.Count == 0 && ControlPoints.Count > 0)
Calculate();
double d = progressToDistance(progress);
return interpolateVertices(indexOfDistance(d), d) + Offset;
}

View File

@ -1,9 +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
using osu.Game.Beatmaps;
namespace osu.Game.Modes.Osu.Objects
{
public class Spinner : OsuHitObject
{
public double Length;
public override double EndTime => StartTime + Length;
}
}