1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-07 11:07:32 +08:00

Merge branch 'master' into taiko_drumroll_drawable

This commit is contained in:
Dan Balasescu 2017-03-23 17:55:08 +09:00 committed by GitHub
commit 2d5bb326f0
186 changed files with 3436 additions and 1169 deletions

@ -1 +1 @@
Subproject commit e6394035d443d4498b71e845e5763dd3faf98c7c
Subproject commit 34c9f17a6ac6fa5e9fd5569f9e119331316c1313

View File

@ -53,7 +53,7 @@ namespace osu.Desktop.Deploy
private static string nupkgFilename(string ver) => $"{PackageName}.{ver}.nupkg";
private static string nupkgDistroFilename(string ver) => $"{PackageName}-{ver}-full.nupkg";
private static Stopwatch sw = new Stopwatch();
private static readonly Stopwatch sw = new Stopwatch();
private static string codeSigningPassword;

View File

@ -0,0 +1,24 @@
// 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.Audio.Track;
using osu.Framework.Graphics.Textures;
using osu.Game.Beatmaps;
namespace osu.Desktop.VisualTests.Beatmaps
{
public class TestWorkingBeatmap : WorkingBeatmap
{
public TestWorkingBeatmap(Beatmap beatmap)
: base(beatmap.BeatmapInfo, beatmap.BeatmapInfo.BeatmapSet)
{
this.beatmap = beatmap;
}
private readonly Beatmap beatmap;
protected override Beatmap GetBeatmap() => beatmap;
protected override Texture GetBackground() => null;
protected override Track GetTrack() => null;
}
}

View File

@ -10,7 +10,7 @@ namespace osu.Desktop.VisualTests
{
public class Benchmark : OsuGameBase
{
private double timePerTest = 200;
private const double time_per_test = 200;
[BackgroundDependencyLoader]
private void load()
@ -27,7 +27,7 @@ namespace osu.Desktop.VisualTests
TestBrowser f = new TestBrowser();
Add(f);
Console.WriteLine($@"{Time}: Running {f.TestCount} tests for {timePerTest}ms each...");
Console.WriteLine($@"{Time}: Running {f.TestCount} tests for {time_per_test}ms each...");
for (int i = 1; i < f.TestCount; i++)
{
@ -36,10 +36,10 @@ namespace osu.Desktop.VisualTests
{
f.LoadTest(loadableCase);
Console.WriteLine($@"{Time}: Switching to test #{loadableCase}");
}, loadableCase * timePerTest);
}, loadableCase * time_per_test);
}
Scheduler.AddDelayed(Host.Exit, f.TestCount * timePerTest);
Scheduler.AddDelayed(Host.Exit, f.TestCount * time_per_test);
}
}
}

View File

@ -0,0 +1,27 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using osu.Framework.Graphics;
using osu.Framework.Screens.Testing;
using osu.Game.Screens.Select;
namespace osu.Desktop.VisualTests.Tests
{
internal class TestCaseBeatmapDetailArea : TestCase
{
public override string Description => @"Beatmap details in song select";
public override void Reset()
{
base.Reset();
Add(new BeatmapDetailArea
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(550f, 450f),
});
}
}
}

View File

@ -5,6 +5,7 @@ using System.Collections.Generic;
using osu.Framework.Screens.Testing;
using osu.Game.Screens.Tournament;
using osu.Game.Screens.Tournament.Teams;
using osu.Game.Users;
namespace osu.Desktop.VisualTests.Tests
{
@ -24,57 +25,57 @@ namespace osu.Desktop.VisualTests.Tests
private class TestTeamList : ITeamList
{
public IEnumerable<Team> Teams { get; } = new[]
public IEnumerable<Country> Teams { get; } = new[]
{
new Team
new Country
{
FlagName = "GB",
FullName = "United Kingdom",
Acronym = "UK"
},
new Team
new Country
{
FlagName = "FR",
FullName = "France",
Acronym = "FRA"
},
new Team
new Country
{
FlagName = "CN",
FullName = "China",
Acronym = "CHN"
},
new Team
new Country
{
FlagName = "AU",
FullName = "Australia",
Acronym = "AUS"
},
new Team
new Country
{
FlagName = "JP",
FullName = "Japan",
Acronym = "JPN"
},
new Team
new Country
{
FlagName = "RO",
FullName = "Romania",
Acronym = "ROM"
},
new Team
new Country
{
FlagName = "IT",
FullName = "Italy",
Acronym = "PIZZA"
},
new Team
new Country
{
FlagName = "VE",
FullName = "Venezuela",
Acronym = "VNZ"
},
new Team
new Country
{
FlagName = "US",
FullName = "United States of America",

View File

@ -8,7 +8,6 @@ using osu.Framework.MathUtils;
using osu.Framework.Screens.Testing;
using osu.Framework.Timing;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.IO;
using osu.Game.Database;
using osu.Game.Modes.Catch.UI;
using osu.Game.Modes.Mania.UI;
@ -17,6 +16,7 @@ using osu.Game.Modes.Osu.Objects;
using osu.Game.Modes.Osu.UI;
using osu.Game.Modes.Taiko.UI;
using System.Collections.Generic;
using osu.Desktop.VisualTests.Beatmaps;
namespace osu.Desktop.VisualTests.Tests
{
@ -95,16 +95,5 @@ namespace osu.Desktop.VisualTests.Tests
}
});
}
private class TestWorkingBeatmap : WorkingBeatmap
{
public TestWorkingBeatmap(Beatmap beatmap)
: base(beatmap.BeatmapInfo, beatmap.BeatmapInfo.BeatmapSet)
{
Beatmap = beatmap;
}
protected override ArchiveReader GetReader() => null;
}
}
}

View File

@ -21,7 +21,7 @@ namespace osu.Desktop.VisualTests.Tests
{
internal class TestCaseHitObjects : TestCase
{
private FramedClock framedClock;
private readonly FramedClock framedClock;
private bool auto;
@ -34,7 +34,7 @@ namespace osu.Desktop.VisualTests.Tests
private HitObjectType mode = HitObjectType.Slider;
private BindableNumber<double> playbackSpeed = new BindableDouble(0.5) { MinValue = 0, MaxValue = 1 };
private readonly BindableNumber<double> playbackSpeed = new BindableDouble(0.5) { MinValue = 0, MaxValue = 1 };
private Container playfieldContainer;
private Container approachContainer;

View File

@ -0,0 +1,225 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using osu.Framework.Graphics;
using osu.Framework.Screens.Testing;
using osu.Game.Modes;
using osu.Game.Modes.Mods;
using osu.Game.Modes.Osu.Mods;
using osu.Game.Screens.Select.Leaderboards;
using osu.Game.Users;
namespace osu.Desktop.VisualTests.Tests
{
internal class TestCaseLeaderboard : TestCase
{
public override string Description => @"From song select";
private Leaderboard leaderboard;
private void newScores()
{
var scores = new[]
{
new Score
{
Rank = ScoreRank.XH,
Accuracy = 100,
MaxCombo = 244,
TotalScore = 1707827,
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
User = new User
{
Id = 6602580,
Username = @"waaiiru",
Country = new Country
{
FullName = @"Spain",
FlagName = @"ES",
},
},
},
new Score
{
Rank = ScoreRank.X,
Accuracy = 100,
MaxCombo = 244,
TotalScore = 1707827,
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
User = new User
{
Id = 4608074,
Username = @"Skycries",
Country = new Country
{
FullName = @"Brazil",
FlagName = @"BR",
},
},
},
new Score
{
Rank = ScoreRank.SH,
Accuracy = 100,
MaxCombo = 244,
TotalScore = 1707827,
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
User = new User
{
Id = 1014222,
Username = @"eLy",
Country = new Country
{
FullName = @"Japan",
FlagName = @"JP",
},
},
},
new Score
{
Rank = ScoreRank.S,
Accuracy = 100,
MaxCombo = 244,
TotalScore = 1707827,
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
User = new User
{
Id = 1541390,
Username = @"Toukai",
Country = new Country
{
FullName = @"Canada",
FlagName = @"CA",
},
},
},
new Score
{
Rank = ScoreRank.A,
Accuracy = 100,
MaxCombo = 244,
TotalScore = 1707827,
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
User = new User
{
Id = 2243452,
Username = @"Satoruu",
Country = new Country
{
FullName = @"Venezuela",
FlagName = @"VE",
},
},
},
new Score
{
Rank = ScoreRank.B,
Accuracy = 98.26,
MaxCombo = 244,
TotalScore = 1707827,
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
User = new User
{
Id = 2705430,
Username = @"Mooha",
Country = new Country
{
FullName = @"France",
FlagName = @"FR",
},
},
},
new Score
{
Rank = ScoreRank.C,
Accuracy = 96.54,
MaxCombo = 244,
TotalScore = 1707827,
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
User = new User
{
Id = 7151382,
Username = @"Mayuri Hana",
Country = new Country
{
FullName = @"Thailand",
FlagName = @"TH",
},
},
},
new Score
{
Rank = ScoreRank.F,
Accuracy = 60.25,
MaxCombo = 244,
TotalScore = 1707827,
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
User = new User
{
Id = 2051389,
Username = @"FunOrange",
Country = new Country
{
FullName = @"Canada",
FlagName = @"CA",
},
},
},
new Score
{
Rank = ScoreRank.F,
Accuracy = 51.40,
MaxCombo = 244,
TotalScore = 1707827,
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
User = new User
{
Id = 6169483,
Username = @"-Hebel-",
Country = new Country
{
FullName = @"Mexico",
FlagName = @"MX",
},
},
},
new Score
{
Rank = ScoreRank.F,
Accuracy = 42.22,
MaxCombo = 244,
TotalScore = 1707827,
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
User = new User
{
Id = 6702666,
Username = @"prhtnsm",
Country = new Country
{
FullName = @"Germany",
FlagName = @"DE",
},
},
},
};
leaderboard.Scores = scores;
}
public override void Reset()
{
base.Reset();
Add(leaderboard = new Leaderboard
{
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
Size = new Vector2(550f, 450f),
});
AddButton(@"New Scores", newScores);
newScores();
}
}
}

View File

@ -95,7 +95,7 @@ namespace osu.Desktop.VisualTests.Tests
progressingNotifications.Add(n);
}
private List<ProgressNotification> progressingNotifications = new List<ProgressNotification>();
private readonly List<ProgressNotification> progressingNotifications = new List<ProgressNotification>();
private void sendProgress1()
{

View File

@ -8,13 +8,13 @@ using osu.Framework.Screens.Testing;
using osu.Game.Beatmaps;
using OpenTK;
using osu.Framework.Graphics.Sprites;
using osu.Game.Beatmaps.IO;
using osu.Game.Database;
using osu.Game.Modes;
using osu.Game.Modes.Objects;
using osu.Game.Modes.Osu.Objects;
using osu.Game.Screens.Play;
using OpenTK.Graphics;
using osu.Desktop.VisualTests.Beatmaps;
namespace osu.Desktop.VisualTests.Tests
{
@ -23,7 +23,6 @@ namespace osu.Desktop.VisualTests.Tests
protected Player Player;
private BeatmapDatabase db;
public override string Description => @"Showing everything to play the game.";
[BackgroundDependencyLoader]
@ -97,16 +96,5 @@ namespace osu.Desktop.VisualTests.Tests
Beatmap = beatmap
};
}
private class TestWorkingBeatmap : WorkingBeatmap
{
public TestWorkingBeatmap(Beatmap beatmap)
: base(beatmap.BeatmapInfo, beatmap.BeatmapInfo.BeatmapSet)
{
Beatmap = beatmap;
}
protected override ArchiveReader GetReader() => null;
}
}
}

View File

@ -0,0 +1,77 @@
// 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.MathUtils;
using osu.Framework.Screens.Testing;
using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Taiko.Judgements;
using osu.Game.Modes.Taiko.Objects;
using osu.Game.Modes.Taiko.UI;
namespace osu.Desktop.VisualTests.Tests
{
internal class TestCaseTaikoPlayfield : TestCase
{
public override string Description => "Taiko playfield";
private TaikoPlayfield playfield;
public override void Reset()
{
base.Reset();
AddButton("Hit!", addHitJudgement);
AddButton("Miss :(", addMissJudgement);
Add(playfield = new TaikoPlayfield
{
Y = 200
});
}
private void addHitJudgement()
{
TaikoHitResult hitResult = RNG.Next(2) == 0 ? TaikoHitResult.Good : TaikoHitResult.Great;
playfield.OnJudgement(new DrawableTestHit(new Hit())
{
X = RNG.NextSingle(hitResult == TaikoHitResult.Good ? -0.1f : -0.05f, hitResult == TaikoHitResult.Good ? 0.1f : 0.05f),
Judgement = new TaikoJudgementInfo
{
Result = HitResult.Hit,
TaikoResult = hitResult,
TimeOffset = 0,
ComboAtHit = 1,
SecondHit = RNG.Next(10) == 0
}
});
}
private void addMissJudgement()
{
playfield.OnJudgement(new DrawableTestHit(new Hit())
{
Judgement = new TaikoJudgementInfo
{
Result = HitResult.Miss,
TimeOffset = 0,
ComboAtHit = 0
}
});
}
private class DrawableTestHit : DrawableHitObject<TaikoHitObject, TaikoJudgementInfo>
{
public DrawableTestHit(TaikoHitObject hitObject)
: base(hitObject)
{
}
protected override TaikoJudgementInfo CreateJudgementInfo() => new TaikoJudgementInfo();
protected override void UpdateState(ArmedState state)
{
}
}
}
}

View File

@ -23,7 +23,7 @@
<SignAssembly>false</SignAssembly>
<TargetZone>LocalIntranet</TargetZone>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
@ -194,6 +194,7 @@
<Compile Include="Tests\TestCaseReplay.cs" />
<Compile Include="Tests\TestCaseScoreCounter.cs" />
<Compile Include="Tests\TestCaseTabControl.cs" />
<Compile Include="Tests\TestCaseTaikoPlayfield.cs" />
<Compile Include="Tests\TestCaseTextAwesome.cs" />
<Compile Include="Tests\TestCasePlaySongSelect.cs" />
<Compile Include="Tests\TestCaseTwoLayerButton.cs" />
@ -204,9 +205,15 @@
<Compile Include="Tests\TestCaseModSelectOverlay.cs" />
<Compile Include="Tests\TestCaseDialogOverlay.cs" />
<Compile Include="Tests\TestCaseBeatmapOptionsOverlay.cs" />
<Compile Include="Tests\TestCaseLeaderboard.cs" />
<Compile Include="Beatmaps\TestWorkingBeatmap.cs" />
<Compile Include="Tests\TestCaseBeatmapDetailArea.cs" />
</ItemGroup>
<ItemGroup />
<ItemGroup />
<ItemGroup>
<Folder Include="Beatmaps\" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.

View File

@ -17,7 +17,7 @@ namespace osu.Desktop
{
internal class OsuGameDesktop : OsuGame
{
private VersionManager versionManager;
private readonly VersionManager versionManager;
public OsuGameDesktop(string[] args = null)
: base(args)

View File

@ -7,5 +7,8 @@ namespace osu.Game.Modes.Catch.Judgements
{
public class CatchJudgementInfo : JudgementInfo
{
public override string ScoreString => string.Empty;
public override string MaxScoreString => string.Empty;
}
}

View File

@ -12,7 +12,7 @@ namespace osu.Game.Modes.Catch.Objects.Drawable
{
internal class DrawableFruit : Sprite
{
private CatchBaseHit h;
private readonly CatchBaseHit h;
public DrawableFruit(CatchBaseHit h)
{
@ -29,7 +29,7 @@ namespace osu.Game.Modes.Catch.Objects.Drawable
{
Texture = textures.Get(@"Menu/logo");
double duration = 0;
const double duration = 0;
Transforms.Add(new TransformPosition { StartTime = h.StartTime - 200, EndTime = h.StartTime, StartValue = new Vector2(h.Position, -0.1f), EndValue = new Vector2(h.Position, 0.9f) });
Transforms.Add(new TransformAlpha { StartTime = h.StartTime + duration + 200, EndTime = h.StartTime + duration + 400, StartValue = 1, EndValue = 0 });

View File

@ -7,5 +7,8 @@ namespace osu.Game.Modes.Mania.Judgements
{
public class ManiaJudgementInfo : JudgementInfo
{
public override string ScoreString => string.Empty;
public override string MaxScoreString => string.Empty;
}
}

View File

@ -26,7 +26,7 @@ namespace osu.Game.Modes.Mania.Objects.Drawable
{
Texture = textures.Get(@"Menu/logo");
double duration = 0;
const double duration = 0;
Transforms.Add(new TransformPositionY { StartTime = note.StartTime - 200, EndTime = note.StartTime, StartValue = -0.1f, EndValue = 0.9f });
Transforms.Add(new TransformAlpha { StartTime = note.StartTime + duration + 200, EndTime = note.StartTime + duration + 400, StartValue = 1, EndValue = 0 });

View File

@ -44,11 +44,8 @@ namespace osu.Game.Modes.Osu.Beatmaps
{
StartTime = original.StartTime,
Sample = original.Sample,
CurveObject = curveData,
Position = positionData?.Position ?? Vector2.Zero,
NewCombo = comboData?.NewCombo ?? false
};
}
@ -60,7 +57,6 @@ namespace osu.Game.Modes.Osu.Beatmaps
StartTime = original.StartTime,
Sample = original.Sample,
Position = new Vector2(512, 384) / 2,
EndTime = endTimeData.EndTime
};
}
@ -69,9 +65,7 @@ namespace osu.Game.Modes.Osu.Beatmaps
{
StartTime = original.StartTime,
Sample = original.Sample,
Position = positionData?.Position ?? Vector2.Zero,
NewCombo = comboData?.NewCombo ?? false
};
}
@ -81,7 +75,7 @@ namespace osu.Game.Modes.Osu.Beatmaps
if (endIndex == -1)
endIndex = hitObjects.Count - 1;
int stackDistance = 3;
const int stack_distance = 3;
float stackThreshold = DrawableOsuHitObject.TIME_PREEMPT * stackLeniency;
// Reset stacking inside the update range
@ -108,8 +102,8 @@ namespace osu.Game.Modes.Osu.Beatmaps
//We are no longer within stacking range of the next object.
break;
if (Vector2.Distance(stackBaseObject.Position, objectN.Position) < stackDistance ||
stackBaseObject is Slider && Vector2.Distance(stackBaseObject.EndPosition, objectN.Position) < stackDistance)
if (Vector2.Distance(stackBaseObject.Position, objectN.Position) < stack_distance ||
stackBaseObject is Slider && Vector2.Distance(stackBaseObject.EndPosition, objectN.Position) < stack_distance)
{
stackBaseIndex = n;
@ -174,14 +168,14 @@ namespace osu.Game.Modes.Osu.Beatmaps
* o <- hitCircle has stack of -1
* o <- hitCircle has stack of -2
*/
if (objectN is Slider && Vector2.Distance(objectN.EndPosition, objectI.Position) < stackDistance)
if (objectN is Slider && Vector2.Distance(objectN.EndPosition, objectI.Position) < stack_distance)
{
int offset = objectI.StackHeight - objectN.StackHeight + 1;
for (int j = n + 1; j <= i; j++)
{
//For each object which was declared under this slider, we will offset it to appear *below* the slider end (rather than above).
OsuHitObject objectJ = hitObjects[j];
if (Vector2.Distance(objectN.EndPosition, objectJ.Position) < stackDistance)
if (Vector2.Distance(objectN.EndPosition, objectJ.Position) < stack_distance)
objectJ.StackHeight -= offset;
}
@ -190,7 +184,7 @@ namespace osu.Game.Modes.Osu.Beatmaps
break;
}
if (Vector2.Distance(objectN.Position, objectI.Position) < stackDistance)
if (Vector2.Distance(objectN.Position, objectI.Position) < stack_distance)
{
//Keep processing as if there are no sliders. If we come across a slider, this gets cancelled out.
//NOTE: Sliders with start positions stacking are a special case that is also handled here.
@ -214,7 +208,7 @@ namespace osu.Game.Modes.Osu.Beatmaps
//We are no longer within stacking range of the previous object.
break;
if (Vector2.Distance(objectN.EndPosition, objectI.Position) < stackDistance)
if (Vector2.Distance(objectN.EndPosition, objectI.Position) < stack_distance)
{
objectN.StackHeight = objectI.StackHeight + 1;
objectI = objectN;

View File

@ -4,6 +4,7 @@
using OpenTK;
using osu.Game.Modes.Judgements;
using osu.Game.Modes.Osu.Objects.Drawables;
using osu.Framework.Extensions;
namespace osu.Game.Modes.Osu.Judgements
{
@ -24,6 +25,10 @@ namespace osu.Game.Modes.Osu.Judgements
/// </summary>
public OsuScoreResult MaxScore = OsuScoreResult.Hit300;
public override string ScoreString => Score.GetDescription();
public override string MaxScoreString => MaxScore.GetDescription();
public int ScoreValue => scoreToInt(Score);
public int MaxScoreValue => scoreToInt(MaxScore);

View File

@ -13,34 +13,30 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
{
public class DrawableHitCircle : DrawableOsuHitObject, IDrawableHitObjectWithProxiedApproach
{
private OsuHitObject osuObject;
public ApproachCircle ApproachCircle;
private CirclePiece circle;
private RingPiece ring;
private FlashPiece flash;
private ExplodePiece explode;
private NumberPiece number;
private GlowPiece glow;
private readonly CirclePiece circle;
private readonly RingPiece ring;
private readonly FlashPiece flash;
private readonly ExplodePiece explode;
private readonly NumberPiece number;
private readonly GlowPiece glow;
public DrawableHitCircle(OsuHitObject h) : base(h)
{
Origin = Anchor.Centre;
osuObject = h;
Position = osuObject.StackedPosition;
Scale = new Vector2(osuObject.Scale);
Position = HitObject.StackedPosition;
Scale = new Vector2(HitObject.Scale);
Children = new Drawable[]
{
glow = new GlowPiece
{
Colour = osuObject.ComboColour
Colour = AccentColour
},
circle = new CirclePiece
{
Colour = osuObject.ComboColour,
Colour = AccentColour,
Hit = () =>
{
if (Judgement.Result.HasValue) return false;
@ -58,11 +54,11 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
flash = new FlashPiece(),
explode = new ExplodePiece
{
Colour = osuObject.ComboColour,
Colour = AccentColour,
},
ApproachCircle = new ApproachCircle
{
Colour = osuObject.ComboColour,
Colour = AccentColour,
}
};
@ -111,14 +107,12 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
protected override void UpdateState(ArmedState state)
{
if (!IsLoaded) return;
base.UpdateState(state);
ApproachCircle.FadeOut();
double endTime = (osuObject as IHasEndTime)?.EndTime ?? osuObject.StartTime;
double duration = endTime - osuObject.StartTime;
double endTime = (HitObject as IHasEndTime)?.EndTime ?? HitObject.StartTime;
double duration = endTime - HitObject.StartTime;
glow.Delay(duration);
glow.FadeOut(400);

View File

@ -13,17 +13,16 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
public const float TIME_FADEIN = 400;
public const float TIME_FADEOUT = 500;
public DrawableOsuHitObject(OsuHitObject hitObject)
protected DrawableOsuHitObject(OsuHitObject hitObject)
: base(hitObject)
{
AccentColour = HitObject.ComboColour;
}
protected override OsuJudgementInfo CreateJudgementInfo() => new OsuJudgementInfo { MaxScore = OsuScoreResult.Hit300 };
protected override void UpdateState(ArmedState state)
{
if (!IsLoaded) return;
Flush();
UpdateInitialState();

View File

@ -0,0 +1,31 @@
// 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.Graphics.Transforms;
using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Osu.Judgements;
using OpenTK;
using osu.Game.Modes.Judgements;
namespace osu.Game.Modes.Osu.Objects.Drawables
{
public class DrawableOsuJudgementInfo : DrawableJudgementInfo<OsuJudgementInfo>
{
public DrawableOsuJudgementInfo(OsuJudgementInfo judgement) : base(judgement)
{
}
protected override void LoadComplete()
{
base.LoadComplete();
if (Judgement.Result != HitResult.Miss)
{
JudgementText.TransformSpacingTo(new Vector2(14, 0), 1800, EasingTypes.OutQuint);
FadeOut(500);
}
Expire();
}
}
}

View File

@ -13,18 +13,18 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
{
public class DrawableSlider : DrawableOsuHitObject, IDrawableHitObjectWithProxiedApproach
{
private Slider slider;
private readonly Slider slider;
private DrawableHitCircle initialCircle;
private readonly DrawableHitCircle initialCircle;
private List<ISliderProgress> components = new List<ISliderProgress>();
private readonly List<ISliderProgress> components = new List<ISliderProgress>();
private Container<DrawableSliderTick> ticks;
private readonly Container<DrawableSliderTick> ticks;
private SliderBody body;
private SliderBall ball;
private readonly SliderBody body;
private readonly SliderBall ball;
private SliderBouncer bouncer2;
private readonly SliderBouncer bouncer2;
public DrawableSlider(Slider s) : base(s)
{
@ -39,6 +39,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
{
body = new SliderBody(s)
{
AccentColour = AccentColour,
Position = s.StackedPosition,
PathWidth = s.Scale * 64,
},
@ -56,6 +57,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
ball = new SliderBall(s)
{
Scale = new Vector2(s.Scale),
AccentColour = AccentColour
},
initialCircle = new DrawableHitCircle(new HitCircle
{

View File

@ -18,7 +18,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
{
public class DrawableSliderTick : DrawableOsuHitObject
{
private SliderTick sliderTick;
private readonly SliderTick sliderTick;
public double FadeInTime;
public double FadeOutTime;
@ -48,7 +48,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = sliderTick.ComboColour,
Colour = AccentColour,
Alpha = 0.3f,
}
};
@ -95,8 +95,6 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
protected override void UpdateState(ArmedState state)
{
if (!IsLoaded) return;
base.UpdateState(state);
switch (state)

View File

@ -15,12 +15,12 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
{
public class DrawableSpinner : DrawableOsuHitObject
{
private Spinner spinner;
private readonly Spinner spinner;
private SpinnerDisc disc;
private SpinnerBackground background;
private Container circleContainer;
private DrawableHitCircle circle;
private readonly SpinnerDisc disc;
private readonly SpinnerBackground background;
private readonly Container circleContainer;
private readonly DrawableHitCircle circle;
public DrawableSpinner(Spinner s) : base(s)
{
@ -48,7 +48,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
Alpha = 0,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
DiscColour = s.ComboColour
DiscColour = AccentColour
},
circleContainer = new Container
{
@ -108,9 +108,9 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
private Vector2 scaleToCircle => 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 const float spins_per_minute_needed = 100 + 5 * 15; //TODO: read per-map OD and place it on the 5
private float rotationsNeeded => (float)(spinsPerMinuteNeeded * (spinner.EndTime - spinner.StartTime) / 60000f);
private float rotationsNeeded => (float)(spins_per_minute_needed * (spinner.EndTime - spinner.StartTime) / 60000f);
public float Progress => MathHelper.Clamp(disc.RotationAbsolute / 360 / rotationsNeeded, 0, 1);
@ -134,8 +134,6 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
protected override void UpdateState(ArmedState state)
{
if (!IsLoaded) return;
base.UpdateState(state);
Delay(spinner.Duration, true);

View File

@ -1,86 +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.Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Transforms;
using osu.Game.Graphics.Sprites;
using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Osu.Judgements;
using OpenTK;
using OpenTK.Graphics;
namespace osu.Game.Modes.Osu.Objects.Drawables
{
public class HitExplosion : FillFlowContainer
{
private readonly OsuJudgementInfo judgement;
private SpriteText line1;
private SpriteText line2;
public HitExplosion(OsuJudgementInfo judgement, OsuHitObject h = null)
{
this.judgement = judgement;
AutoSizeAxes = Axes.Both;
Origin = Anchor.Centre;
Direction = FillDirection.Vertical;
Spacing = new Vector2(0, 2);
Position = (h?.StackedEndPosition ?? Vector2.Zero) + judgement.PositionOffset;
Children = new Drawable[]
{
line1 = new OsuSpriteText
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Text = judgement.Score.GetDescription(),
Font = @"Venera",
TextSize = 16,
},
line2 = new OsuSpriteText
{
Text = judgement.Combo.GetDescription(),
Font = @"Venera",
TextSize = 11,
}
};
}
protected override void LoadComplete()
{
base.LoadComplete();
if (judgement.Result == HitResult.Miss)
{
FadeInFromZero(60);
ScaleTo(1.6f);
ScaleTo(1, 100, EasingTypes.In);
MoveToOffset(new Vector2(0, 100), 800, EasingTypes.InQuint);
RotateTo(40, 800, EasingTypes.InQuint);
Delay(600);
FadeOut(200);
}
else
{
line1.TransformSpacingTo(new Vector2(14, 0), 1800, EasingTypes.OutQuint);
line2.TransformSpacingTo(new Vector2(14, 0), 1800, EasingTypes.OutQuint);
FadeOut(500);
}
switch (judgement.Result)
{
case HitResult.Miss:
Colour = Color4.Red;
break;
}
Expire();
}
}
}

View File

@ -11,7 +11,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables.Pieces
{
public class ApproachCircle : Container
{
private Sprite approachCircle;
private readonly Sprite approachCircle;
public ApproachCircle()
{

View File

@ -14,7 +14,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables.Pieces
{
public class CirclePiece : Container
{
private Sprite disc;
private readonly Sprite disc;
public Func<bool> Hit;

View File

@ -11,7 +11,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables.Pieces
{
public class GlowPiece : Container
{
private Sprite layer;
private readonly Sprite layer;
public GlowPiece()
{

View File

@ -12,7 +12,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables.Pieces
{
public class NumberPiece : Container
{
private SpriteText number;
private readonly SpriteText number;
public string Text
{
@ -29,6 +29,8 @@ namespace osu.Game.Modes.Osu.Objects.Drawables.Pieces
{
new CircularContainer
{
Masking = true,
Origin = Anchor.Centre,
EdgeEffect = new EdgeEffect
{
Type = EdgeEffectType.Glow,

View File

@ -12,11 +12,27 @@ namespace osu.Game.Modes.Osu.Objects.Drawables.Pieces
{
public class SliderBall : CircularContainer, ISliderProgress
{
private readonly Slider slider;
private Box follow;
private const float width = 128;
private Color4 accentColour = Color4.Black;
/// <summary>
/// The colour that is used for the slider ball.
/// </summary>
public Color4 AccentColour
{
get { return accentColour; }
set
{
accentColour = value;
if (ball != null)
ball.Colour = value;
}
}
private readonly Slider slider;
private readonly Box follow;
private readonly Box ball;
public SliderBall(Slider slider)
{
this.slider = slider;
@ -49,9 +65,9 @@ namespace osu.Game.Modes.Osu.Objects.Drawables.Pieces
Alpha = 1,
Children = new[]
{
new Box
ball = new Box
{
Colour = slider.ComboColour,
Colour = AccentColour,
Alpha = 0.4f,
Width = width,
Height = width,

View File

@ -13,27 +13,45 @@ using osu.Framework.Graphics.Textures;
using osu.Game.Configuration;
using OpenTK;
using OpenTK.Graphics.ES30;
using OpenTK.Graphics;
namespace osu.Game.Modes.Osu.Objects.Drawables.Pieces
{
public class SliderBody : Container, ISliderProgress
{
private Path path;
private BufferedContainer container;
private readonly Path path;
private readonly BufferedContainer container;
public float PathWidth
{
get { return path.PathWidth; }
set
{
path.PathWidth = value;
}
set { path.PathWidth = value; }
}
public double? SnakedStart { get; private set; }
public double? SnakedEnd { get; private set; }
private Slider slider;
private Color4 accentColour;
/// <summary>
/// Used to colour the path.
/// </summary>
public Color4 AccentColour
{
get { return accentColour; }
set
{
if (accentColour == value)
return;
accentColour = value;
if (LoadState == LoadState.Loaded)
Schedule(reloadTexture);
}
}
private int textureWidth => (int)PathWidth * 2;
private readonly Slider slider;
public SliderBody(Slider s)
{
slider = s;
@ -82,7 +100,12 @@ namespace osu.Game.Modes.Osu.Objects.Drawables.Pieces
snakingIn = config.GetBindable<bool>(OsuConfig.SnakingInSliders);
snakingOut = config.GetBindable<bool>(OsuConfig.SnakingOutSliders);
int textureWidth = (int)PathWidth * 2;
reloadTexture();
}
private void reloadTexture()
{
var texture = new Texture(textureWidth, 1);
//initialise background
var upload = new TextureUpload(textureWidth * 4);
@ -110,19 +133,18 @@ namespace osu.Game.Modes.Osu.Objects.Drawables.Pieces
{
progress -= border_portion;
bytes[i * 4] = (byte)(slider.ComboColour.R * 255);
bytes[i * 4 + 1] = (byte)(slider.ComboColour.G * 255);
bytes[i * 4 + 2] = (byte)(slider.ComboColour.B * 255);
bytes[i * 4 + 3] = (byte)((opacity_at_edge - (opacity_at_edge - opacity_at_centre) * progress / gradient_portion) * (slider.ComboColour.A * 255));
bytes[i * 4] = (byte)(AccentColour.R * 255);
bytes[i * 4 + 1] = (byte)(AccentColour.G * 255);
bytes[i * 4 + 2] = (byte)(AccentColour.B * 255);
bytes[i * 4 + 3] = (byte)((opacity_at_edge - (opacity_at_edge - opacity_at_centre) * progress / gradient_portion) * (AccentColour.A * 255));
}
}
var texture = new Texture(textureWidth, 1);
texture.SetData(upload);
path.Texture = texture;
}
private List<Vector2> currentCurve = new List<Vector2>();
private readonly List<Vector2> currentCurve = new List<Vector2>();
private bool updateSnaking(double p0, double p1)
{
if (SnakedStart == p0 && SnakedEnd == p1) return false;

View File

@ -11,7 +11,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables.Pieces
{
private readonly Slider slider;
private readonly bool isEnd;
private TextAwesome icon;
private readonly TextAwesome icon;
public SliderBouncer(Slider slider, bool isEnd)
{

View File

@ -33,6 +33,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables.Pieces
private void load(OsuColour colours)
{
completeColour = colours.YellowLight.Opacity(0.8f);
Masking = true;
}
private class SpinnerBorder : Container
@ -61,6 +62,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables.Pieces
{
Colour = Color4.White,
RelativePositionAxes = Axes.Both,
Masking = true,
Origin = Anchor.Centre,
Size = new Vector2(1 / ScreenSpaceDrawQuad.Width * 2000),
Children = new[]

View File

@ -36,7 +36,7 @@ namespace osu.Game.Modes.Osu.Objects
public float Scale { get; set; } = 1;
public Color4 ComboColour { get; set; }
public Color4 ComboColour { get; set; } = Color4.Gray;
public virtual bool NewCombo { get; set; }
public int ComboIndex { get; set; }

View File

@ -47,11 +47,11 @@ namespace osu.Game.Modes.Osu.Objects
internal int MaxCombo = 1;
private float scalingFactor;
private readonly float scalingFactor;
private float lazySliderLength;
private Vector2 startPosition;
private Vector2 endPosition;
private readonly Vector2 startPosition;
private readonly Vector2 endPosition;
internal OsuHitObjectDifficulty(OsuHitObject baseHitObject)
{

View File

@ -20,7 +20,7 @@ namespace osu.Game.Modes.Osu
private const float spin_radius = 50;
private Beatmap<OsuHitObject> beatmap;
private readonly Beatmap<OsuHitObject> beatmap;
public OsuAutoReplay(Beatmap<OsuHitObject> beatmap)
{
@ -37,11 +37,11 @@ namespace osu.Game.Modes.Osu
}
}
private static IComparer<LegacyReplayFrame> replayFrameComparer = new LegacyReplayFrameComparer();
private static readonly IComparer<LegacyReplayFrame> replay_frame_comparer = new LegacyReplayFrameComparer();
private int findInsertionIndex(LegacyReplayFrame frame)
{
int index = Frames.BinarySearch(frame, replayFrameComparer);
int index = Frames.BinarySearch(frame, replay_frame_comparer);
if (index < 0)
{

View File

@ -17,9 +17,9 @@ namespace osu.Game.Modes.Osu.UI
{
public class OsuPlayfield : Playfield<OsuHitObject, OsuJudgementInfo>
{
private Container approachCircles;
private Container judgementLayer;
private ConnectionRenderer<OsuHitObject> connectionLayer;
private readonly Container approachCircles;
private readonly Container judgementLayer;
private readonly ConnectionRenderer<OsuHitObject> connectionLayer;
public override Vector2 Size
{
@ -85,7 +85,11 @@ namespace osu.Game.Modes.Osu.UI
public override void OnJudgement(DrawableHitObject<OsuHitObject, OsuJudgementInfo> judgedObject)
{
HitExplosion explosion = new HitExplosion(judgedObject.Judgement, judgedObject.HitObject);
DrawableOsuJudgementInfo explosion = new DrawableOsuJudgementInfo(judgedObject.Judgement)
{
Origin = Anchor.Centre,
Position = judgedObject.HitObject.StackedEndPosition + judgedObject.Judgement.PositionOffset
};
judgementLayer.Add(explosion);
}

View File

@ -58,7 +58,7 @@
<Compile Include="Objects\Drawables\Pieces\ExplodePiece.cs" />
<Compile Include="Objects\Drawables\Pieces\FlashPiece.cs" />
<Compile Include="Objects\Drawables\Pieces\GlowPiece.cs" />
<Compile Include="Objects\Drawables\HitExplosion.cs" />
<Compile Include="Objects\Drawables\DrawableOsuJudgementInfo.cs" />
<Compile Include="Objects\Drawables\Pieces\NumberPiece.cs" />
<Compile Include="Objects\Drawables\DrawableSliderTick.cs" />
<Compile Include="Objects\Drawables\Pieces\RingPiece.cs" />

View File

@ -2,18 +2,74 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Legacy;
using osu.Game.Modes.Objects;
using osu.Game.Modes.Objects.Types;
using osu.Game.Modes.Taiko.Objects;
using System.Collections.Generic;
using System.Linq;
namespace osu.Game.Modes.Taiko.Beatmaps
{
internal class TaikoBeatmapConverter : IBeatmapConverter<TaikoHitObject>
{
private const float legacy_velocity_scale = 1.4f;
private const float bash_convert_factor = 1.65f;
public Beatmap<TaikoHitObject> Convert(Beatmap original)
{
if (original is LegacyBeatmap)
original.TimingInfo.ControlPoints.ForEach(c => c.VelocityAdjustment /= legacy_velocity_scale);
return new Beatmap<TaikoHitObject>(original)
{
HitObjects = new List<TaikoHitObject>() // Todo: Implement
HitObjects = convertHitObjects(original.HitObjects)
};
}
private List<TaikoHitObject> convertHitObjects(List<HitObject> hitObjects)
{
return hitObjects.Select(convertHitObject).ToList();
}
private TaikoHitObject convertHitObject(HitObject original)
{
// Check if this HitObject is already a TaikoHitObject, and return it if so
TaikoHitObject originalTaiko = original as TaikoHitObject;
if (originalTaiko != null)
return originalTaiko;
IHasDistance distanceData = original as IHasDistance;
IHasRepeats repeatsData = original as IHasRepeats;
IHasEndTime endTimeData = original as IHasEndTime;
if (distanceData != null)
{
return new DrumRoll
{
StartTime = original.StartTime,
Sample = original.Sample,
Distance = distanceData.Distance * (repeatsData?.RepeatCount ?? 1)
};
}
if (endTimeData != null)
{
// We compute the end time manually to add in the Bash convert factor
return new Bash
{
StartTime = original.StartTime,
Sample = original.Sample,
EndTime = original.StartTime + endTimeData.Duration * bash_convert_factor
};
}
return new Hit
{
StartTime = original.StartTime,
Sample = original.Sample,
};
}
}

View File

@ -1,11 +1,15 @@
// 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.ComponentModel;
namespace osu.Game.Modes.Taiko.Judgements
{
public enum TaikoHitResult
{
[Description("GOOD")]
Good,
[Description("GREAT")]
Great
}
}

View File

@ -2,6 +2,7 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Modes.Judgements;
using osu.Framework.Extensions;
namespace osu.Game.Modes.Taiko.Judgements
{
@ -37,6 +38,10 @@ namespace osu.Game.Modes.Taiko.Judgements
/// </summary>
public int MaxAccuracyScoreValue => NumericResultForAccuracy(MAX_HIT_RESULT);
public override string ScoreString => TaikoResult.GetDescription();
public override string MaxScoreString => MAX_HIT_RESULT.GetDescription();
/// <summary>
/// Whether this Judgement has a secondary hit in the case of finishers.
/// </summary>

View File

@ -0,0 +1,30 @@
// 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.Beatmaps.Timing;
using osu.Game.Database;
using osu.Game.Modes.Objects.Types;
namespace osu.Game.Modes.Taiko.Objects
{
public class Bash : TaikoHitObject, IHasEndTime
{
public double EndTime { get; set; }
public double Duration => EndTime - StartTime;
/// <summary>
/// The number of hits required to complete the bash successfully.
/// </summary>
public int RequiredHits { get; protected set; }
public override void ApplyDefaults(TimingInfo timing, BeatmapDifficulty difficulty)
{
base.ApplyDefaults(timing, difficulty);
double spinnerRotationRatio = BeatmapDifficulty.DifficultyRange(difficulty.OverallDifficulty, 3, 5, 7.5);
RequiredHits = (int)Math.Max(1, Duration / 1000f * spinnerRotationRatio);
}
}
}

View File

@ -1,41 +1,33 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK.Graphics;
using osu.Framework.Graphics;
using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Taiko.Judgements;
namespace osu.Game.Modes.Taiko.Objects.Drawable
{
public class DrawableTaikoHitObject : DrawableHitObject<TaikoHitObject, TaikoJudgementInfo>
public abstract class DrawableTaikoHitObject : DrawableHitObject<TaikoHitObject, TaikoJudgementInfo>
{
/// <summary>
/// The colour used for various elements of this DrawableHitObject.
/// </summary>
public virtual Color4 AccentColour { get; }
public DrawableTaikoHitObject(TaikoHitObject hitObject)
protected DrawableTaikoHitObject(TaikoHitObject hitObject)
: base(hitObject)
{
Anchor = Anchor.CentreLeft;
Origin = Anchor.Centre;
RelativePositionAxes = Axes.X;
}
protected override void LoadComplete()
{
LifetimeStart = HitObject.StartTime - HitObject.PreEmpt * 2;
LifetimeEnd = HitObject.StartTime + HitObject.PreEmpt;
// Todo: Remove (suppresses Resharper)
AccentColour = Color4.White;
base.LoadComplete();
}
protected override TaikoJudgementInfo CreateJudgementInfo() => new TaikoJudgementInfo();
protected override void UpdateState(ArmedState state)
{
}
/// <summary>
/// Sets the scroll position of the DrawableHitObject relative to the offset between
/// a time value and the HitObject's StartTime.

View File

@ -25,41 +25,33 @@ namespace osu.Game.Modes.Taiko.Objects
/// <summary>
/// Velocity of the drum roll in positional length units per millisecond.
/// </summary>
public double Velocity;
public double Velocity { get; protected set; }
/// <summary>
/// The distance between ticks of this drumroll.
/// <para>Half of this value is the hit window of the ticks.</para>
/// </summary>
public double TickTimeDistance;
public double TickTimeDistance { get; protected set; }
/// <summary>
/// Number of drum roll ticks required for a "Good" hit.
/// </summary>
public double RequiredGoodHits;
public double RequiredGoodHits { get; protected set; }
/// <summary>
/// Number of drum roll ticks required for a "Great" hit.
/// </summary>
public double RequiredGreatHits;
public double RequiredGreatHits { get; protected set; }
/// <summary>
/// Total number of drum roll ticks.
/// </summary>
public int TotalTicks;
public int TotalTicks => Ticks.Count();
/// <summary>
/// Initializes the drum roll ticks if not initialized and returns them.
/// </summary>
public IEnumerable<DrumRollTick> Ticks
{
get
{
if (ticks == null)
createTicks();
return ticks;
}
}
public IEnumerable<DrumRollTick> Ticks => ticks ?? (ticks = createTicks());
private List<DrumRollTick> ticks;
@ -70,27 +62,27 @@ namespace osu.Game.Modes.Taiko.Objects
Velocity = timing.SliderVelocityAt(StartTime) * difficulty.SliderMultiplier / 1000;
TickTimeDistance = timing.BeatLengthAt(StartTime);
//TODO: move this to legacy conversion code to allow for direct division without special case.
if (difficulty.SliderTickRate == 3)
TickTimeDistance /= 3;
else
TickTimeDistance /= 4;
TotalTicks = Ticks.Count();
RequiredGoodHits = TotalTicks * Math.Min(0.15, 0.05 + 0.10 / 6 * difficulty.OverallDifficulty);
RequiredGreatHits = TotalTicks * Math.Min(0.30, 0.10 + 0.20 / 6 * difficulty.OverallDifficulty);
}
private void createTicks()
private List<DrumRollTick> createTicks()
{
ticks = new List<DrumRollTick>();
var ret = new List<DrumRollTick>();
if (TickTimeDistance == 0)
return;
return ret;
bool first = true;
for (double t = StartTime; t < EndTime + (int)TickTimeDistance; t += TickTimeDistance)
{
ticks.Add(new DrumRollTick
ret.Add(new DrumRollTick
{
FirstTick = first,
PreEmpt = PreEmpt,
@ -105,6 +97,8 @@ namespace osu.Game.Modes.Taiko.Objects
first = false;
}
return ret;
}
}
}

View File

@ -0,0 +1,35 @@
// 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.Timing;
using osu.Game.Database;
namespace osu.Game.Modes.Taiko.Objects
{
public class Hit : TaikoHitObject
{
/// <summary>
/// The hit window that results in a "GREAT" hit.
/// </summary>
public double HitWindowGreat = 35;
/// <summary>
/// The hit window that results in a "GOOD" hit.
/// </summary>
public double HitWindowGood = 80;
/// <summary>
/// The hit window that results in a "MISS".
/// </summary>
public double HitWindowMiss = 95;
public override void ApplyDefaults(TimingInfo timing, BeatmapDifficulty difficulty)
{
base.ApplyDefaults(timing, difficulty);
HitWindowGreat = BeatmapDifficulty.DifficultyRange(difficulty.OverallDifficulty, 50, 35, 20);
HitWindowGood = BeatmapDifficulty.DifficultyRange(difficulty.OverallDifficulty, 120, 80, 50);
HitWindowMiss = BeatmapDifficulty.DifficultyRange(difficulty.OverallDifficulty, 135, 95, 70);
}
}
}

View File

@ -7,28 +7,13 @@ using osu.Game.Modes.Objects;
namespace osu.Game.Modes.Taiko.Objects
{
public class TaikoHitObject : HitObject
public abstract class TaikoHitObject : HitObject
{
/// <summary>
/// HitCircle radius.
/// </summary>
public const float CIRCLE_RADIUS = 64;
/// <summary>
/// The hit window that results in a "GREAT" hit.
/// </summary>
public double HitWindowGreat = 35;
/// <summary>
/// The hit window that results in a "GOOD" hit.
/// </summary>
public double HitWindowGood = 80;
/// <summary>
/// The hit window that results in a "MISS".
/// </summary>
public double HitWindowMiss = 95;
/// <summary>
/// The time to scroll in the HitObject.
/// </summary>
@ -37,7 +22,7 @@ namespace osu.Game.Modes.Taiko.Objects
/// <summary>
/// Whether this HitObject is in Kiai time.
/// </summary>
public bool Kiai;
public bool Kiai { get; protected set; }
public override void ApplyDefaults(TimingInfo timing, BeatmapDifficulty difficulty)
{
@ -50,10 +35,6 @@ namespace osu.Game.Modes.Taiko.Objects
if (overridePoint != null)
Kiai |= overridePoint.KiaiMode;
HitWindowGreat = BeatmapDifficulty.DifficultyRange(difficulty.OverallDifficulty, 50, 35, 20);
HitWindowGood = BeatmapDifficulty.DifficultyRange(difficulty.OverallDifficulty, 120, 80, 50);
HitWindowMiss = BeatmapDifficulty.DifficultyRange(difficulty.OverallDifficulty, 135, 95, 70);
}
}
}

View File

@ -0,0 +1,57 @@
// 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.Modes.Taiko.Judgements;
using osu.Game.Modes.Objects.Drawables;
using osu.Framework.Allocation;
using osu.Game.Graphics;
using osu.Game.Modes.Judgements;
namespace osu.Game.Modes.Taiko.UI
{
/// <summary>
/// Text that is shown as judgement when a hit object is hit or missed.
/// </summary>
public class DrawableTaikoJudgementInfo : DrawableJudgementInfo<TaikoJudgementInfo>
{
/// <summary>
/// Creates a new judgement text.
/// </summary>
/// <param name="judgement">The judgement to visualise.</param>
public DrawableTaikoJudgementInfo(TaikoJudgementInfo judgement)
: base(judgement)
{
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
switch (Judgement.Result)
{
case HitResult.Hit:
switch (Judgement.TaikoResult)
{
case TaikoHitResult.Good:
Colour = colours.GreenLight;
break;
case TaikoHitResult.Great:
Colour = colours.BlueLight;
break;
}
break;
}
}
protected override void LoadComplete()
{
switch (Judgement.Result)
{
case HitResult.Hit:
MoveToY(-100, 500);
break;
}
base.LoadComplete();
}
}
}

View File

@ -0,0 +1,78 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Transforms;
using osu.Game.Graphics;
using osu.Game.Modes.Taiko.Judgements;
using osu.Game.Modes.Taiko.Objects;
namespace osu.Game.Modes.Taiko.UI
{
/// <summary>
/// A circle explodes from the hit target to indicate a hitobject has been hit.
/// </summary>
internal class HitExplosion : CircularContainer
{
private readonly TaikoJudgementInfo judgement;
private readonly Box innerFill;
public HitExplosion(TaikoJudgementInfo judgement)
{
this.judgement = judgement;
Size = new Vector2(TaikoHitObject.CIRCLE_RADIUS * 2);
Anchor = Anchor.Centre;
Origin = Anchor.Centre;
RelativePositionAxes = Axes.Both;
BorderColour = Color4.White;
BorderThickness = 1;
Alpha = 0.15f;
Masking = true;
Children = new[]
{
innerFill = new Box
{
RelativeSizeAxes = Axes.Both,
}
};
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
if (judgement.SecondHit)
Size *= 1.5f;
switch (judgement.TaikoResult)
{
case TaikoHitResult.Good:
innerFill.Colour = colours.Green;
break;
case TaikoHitResult.Great:
innerFill.Colour = colours.Blue;
break;
}
}
protected override void LoadComplete()
{
base.LoadComplete();
ScaleTo(5f, 1000, EasingTypes.OutQuint);
FadeOut(500);
Expire();
}
}
}

View File

@ -0,0 +1,105 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Game.Modes.Taiko.Objects;
namespace osu.Game.Modes.Taiko.UI
{
/// <summary>
/// A component that is displayed at the hit position in the taiko playfield.
/// </summary>
internal class HitTarget : Container
{
/// <summary>
/// Diameter of normal hit object circles.
/// </summary>
private const float normal_diameter = TaikoHitObject.CIRCLE_RADIUS * 2 * TaikoPlayfield.PLAYFIELD_SCALE;
/// <summary>
/// Diameter of finisher hit object circles.
/// </summary>
private const float finisher_diameter = normal_diameter * 1.5f;
/// <summary>
/// The 1px inner border of the taiko playfield.
/// </summary>
private const float border_offset = 1;
/// <summary>
/// Thickness of all drawn line pieces.
/// </summary>
private const float border_thickness = 2.5f;
public HitTarget()
{
RelativeSizeAxes = Axes.Y;
Children = new Drawable[]
{
new Box
{
Name = "Bar Upper",
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Y = border_offset,
Size = new Vector2(border_thickness, (TaikoPlayfield.PlayfieldHeight - finisher_diameter) / 2f - border_offset),
Alpha = 0.1f
},
new CircularContainer
{
Name = "Finisher Ring",
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(finisher_diameter),
Masking = true,
BorderColour = Color4.White,
BorderThickness = border_thickness,
Alpha = 0.1f,
Children = new[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Alpha = 0,
AlwaysPresent = true
}
}
},
new CircularContainer
{
Name = "Normal Ring",
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(normal_diameter),
Masking = true,
BorderColour = Color4.White,
BorderThickness = border_thickness,
Alpha = 0.5f,
Children = new[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Alpha = 0,
AlwaysPresent = true
}
}
},
new Box
{
Name = "Bar Lower",
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
Y = -border_offset,
Size = new Vector2(border_thickness, (TaikoPlayfield.PlayfieldHeight - finisher_diameter) / 2f - border_offset),
Alpha = 0.1f
},
};
}
}
}

View File

@ -0,0 +1,149 @@
// 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 OpenTK;
using OpenTK.Input;
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.Graphics.Transforms;
using osu.Framework.Input;
using osu.Game.Graphics;
namespace osu.Game.Modes.Taiko.UI
{
/// <summary>
/// A component of the playfield that captures input and displays input as a drum.
/// </summary>
internal class InputDrum : Container
{
public InputDrum()
{
Size = new Vector2(TaikoPlayfield.PlayfieldHeight);
const float middle_split = 10;
Children = new Drawable[]
{
new TaikoHalfDrum(false)
{
Name = "Left Half",
Anchor = Anchor.Centre,
Origin = Anchor.CentreRight,
RelativeSizeAxes = Axes.Both,
X = -middle_split / 2,
RimKey = Key.D,
CentreKey = Key.F
},
new TaikoHalfDrum(true)
{
Name = "Right Half",
Anchor = Anchor.Centre,
Origin = Anchor.CentreLeft,
RelativeSizeAxes = Axes.Both,
X = middle_split / 2,
Position = new Vector2(-1f, 0),
RimKey = Key.K,
CentreKey = Key.J
}
};
}
/// <summary>
/// A half-drum. Contains one centre and one rim hit.
/// </summary>
private class TaikoHalfDrum : Container
{
/// <summary>
/// The key to be used for the rim of the half-drum.
/// </summary>
public Key RimKey;
/// <summary>
/// The key to be used for the centre of the half-drum.
/// </summary>
public Key CentreKey;
private readonly Sprite rim;
private readonly Sprite rimHit;
private readonly Sprite centre;
private readonly Sprite centreHit;
public TaikoHalfDrum(bool flipped)
{
Masking = true;
Children = new Drawable[]
{
rim = new Sprite
{
Anchor = flipped ? Anchor.CentreLeft : Anchor.CentreRight,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both
},
rimHit = new Sprite
{
Anchor = flipped ? Anchor.CentreLeft : Anchor.CentreRight,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Alpha = 0,
BlendingMode = BlendingMode.Additive,
},
centre = new Sprite
{
Anchor = flipped ? Anchor.CentreLeft : Anchor.CentreRight,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Size = new Vector2(0.7f)
},
centreHit = new Sprite
{
Anchor = flipped ? Anchor.CentreLeft : Anchor.CentreRight,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Size = new Vector2(0.7f),
Alpha = 0,
BlendingMode = BlendingMode.Additive
}
};
}
[BackgroundDependencyLoader]
private void load(TextureStore textures, OsuColour colours)
{
rim.Texture = textures.Get(@"Play/Taiko/taiko-drum-outer");
rimHit.Texture = textures.Get(@"Play/Taiko/taiko-drum-outer-hit");
centre.Texture = textures.Get(@"Play/Taiko/taiko-drum-inner");
centreHit.Texture = textures.Get(@"Play/Taiko/taiko-drum-inner-hit");
rimHit.Colour = colours.Blue;
centreHit.Colour = colours.Pink;
}
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
{
if (args.Repeat)
return false;
Drawable target = null;
if (args.Key == CentreKey)
target = centreHit;
else if (args.Key == RimKey)
target = rimHit;
if (target != null)
{
target.FadeTo(Math.Min(target.Alpha + 0.4f, 1), 40, EasingTypes.OutQuint);
target.Delay(40);
target.FadeOut(600, EasingTypes.OutQuint);
}
return false;
}
}
}
}

View File

@ -4,38 +4,192 @@
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Game.Modes.Taiko.Objects;
using osu.Game.Modes.UI;
using OpenTK;
using OpenTK.Graphics;
using osu.Game.Modes.Taiko.Judgements;
using osu.Game.Modes.Objects.Drawables;
using osu.Game.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics.Primitives;
namespace osu.Game.Modes.Taiko.UI
{
public class TaikoPlayfield : Playfield<TaikoHitObject, TaikoJudgementInfo>
{
/// <summary>
/// The default play field height.
/// </summary>
public const float PLAYFIELD_BASE_HEIGHT = 242;
/// <summary>
/// The play field height scale.
/// </summary>
public const float PLAYFIELD_SCALE = 0.65f;
/// <summary>
/// The play field height after scaling.
/// </summary>
public static float PlayfieldHeight => PLAYFIELD_BASE_HEIGHT * PLAYFIELD_SCALE;
/// <summary>
/// The offset from <see cref="left_area_size"/> which the center of the hit target lies at.
/// </summary>
private const float hit_target_offset = 80;
/// <summary>
/// The size of the left area of the playfield. This area contains the input drum.
/// </summary>
private const float left_area_size = 240;
protected override Container<Drawable> Content => hitObjectContainer;
private readonly Container<HitExplosion> hitExplosionContainer;
//private Container<DrawableBarLine> barLineContainer;
private readonly Container<DrawableTaikoJudgementInfo> judgementContainer;
private readonly Container hitObjectContainer;
//private Container topLevelHitContainer;
private readonly Container leftBackgroundContainer;
private readonly Container rightBackgroundContainer;
private readonly Box leftBackground;
private readonly Box rightBackground;
public TaikoPlayfield()
{
RelativeSizeAxes = Axes.X;
Size = new Vector2(1, 100);
Anchor = Anchor.Centre;
Origin = Anchor.Centre;
Height = PlayfieldHeight;
AddInternal(new Drawable[]
{
rightBackgroundContainer = new Container
{
RelativeSizeAxes = Axes.Both,
BorderThickness = 2,
Masking = true,
EdgeEffect = new EdgeEffect
{
Type = EdgeEffectType.Shadow,
Colour = Color4.Black.Opacity(0.2f),
Radius = 5,
},
Children = new Drawable[]
{
rightBackground = new Box
{
RelativeSizeAxes = Axes.Both,
Alpha = 0.6f
},
}
},
new Container
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Left = left_area_size },
Children = new Drawable[]
{
new Container
{
Padding = new MarginPadding { Left = hit_target_offset },
RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
{
hitExplosionContainer = new Container<HitExplosion>
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.Centre,
Size = new Vector2(TaikoHitObject.CIRCLE_RADIUS * 2),
Scale = new Vector2(PLAYFIELD_SCALE),
BlendingMode = BlendingMode.Additive
},
//barLineContainer = new Container<DrawableBarLine>
//{
// RelativeSizeAxes = Axes.Both,
//},
new HitTarget
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.Centre,
},
hitObjectContainer = new Container
{
RelativeSizeAxes = Axes.Both,
},
judgementContainer = new Container<DrawableTaikoJudgementInfo>
{
RelativeSizeAxes = Axes.Both,
BlendingMode = BlendingMode.Additive
},
},
},
}
},
leftBackgroundContainer = new Container
{
Size = new Vector2(left_area_size, PlayfieldHeight),
BorderThickness = 1,
Children = new Drawable[]
{
leftBackground = new Box
{
RelativeSizeAxes = Axes.Both,
},
new InputDrum
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativePositionAxes = Axes.X,
Position = new Vector2(0.10f, 0),
Scale = new Vector2(0.9f)
},
new Box
{
Anchor = Anchor.TopRight,
RelativeSizeAxes = Axes.Y,
Width = 10,
ColourInfo = Framework.Graphics.Colour.ColourInfo.GradientHorizontal(Color4.Black.Opacity(0.6f), Color4.Black.Opacity(0)),
},
}
},
//topLevelHitContainer = new Container
//{
// RelativeSizeAxes = Axes.Both,
//}
});
}
[BackgroundDependencyLoader]
private void load(TextureStore textures)
private void load(OsuColour colours)
{
Add(new Box { RelativeSizeAxes = Axes.Both, Alpha = 0.5f });
leftBackgroundContainer.BorderColour = colours.Gray0;
leftBackground.Colour = colours.Gray1;
Add(new Sprite
rightBackgroundContainer.BorderColour = colours.Gray1;
rightBackground.Colour = colours.Gray0;
}
public override void Add(DrawableHitObject<TaikoHitObject, TaikoJudgementInfo> h)
{
h.Depth = (float)h.HitObject.StartTime;
base.Add(h);
}
public override void OnJudgement(DrawableHitObject<TaikoHitObject, TaikoJudgementInfo> judgedObject)
{
bool wasHit = judgedObject.Judgement.Result == HitResult.Hit;
if (wasHit)
hitExplosionContainer.Add(new HitExplosion(judgedObject.Judgement));
judgementContainer.Add(new DrawableTaikoJudgementInfo(judgedObject.Judgement)
{
Texture = textures.Get(@"Menu/logo"),
Origin = Anchor.Centre,
Scale = new Vector2(0.2f),
RelativePositionAxes = Axes.Both,
Position = new Vector2(0.1f, 0.5f),
Colour = Color4.Gray
Anchor = wasHit ? Anchor.TopLeft : Anchor.CentreLeft,
Origin = wasHit ? Anchor.BottomCentre : Anchor.Centre,
RelativePositionAxes = Axes.X,
X = wasHit ? judgedObject.Position.X : 0,
});
}
}

View File

@ -55,12 +55,18 @@
<Compile Include="Objects\Drawable\DrawableDrumRoll.cs" />
<Compile Include="Objects\Drawable\DrawableDrumRollTick.cs" />
<Compile Include="Objects\Drawable\DrawableTaikoHitObject.cs" />
<Compile Include="Objects\Bash.cs" />
<Compile Include="Objects\DrumRoll.cs" />
<Compile Include="Objects\DrumRollTick.cs" />
<Compile Include="Objects\Hit.cs" />
<Compile Include="TaikoDifficultyCalculator.cs" />
<Compile Include="Objects\TaikoHitObject.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="TaikoScoreProcessor.cs" />
<Compile Include="UI\HitTarget.cs" />
<Compile Include="UI\InputDrum.cs" />
<Compile Include="UI\DrawableTaikoJudgementInfo.cs" />
<Compile Include="UI\HitExplosion.cs" />
<Compile Include="UI\TaikoHitRenderer.cs" />
<Compile Include="UI\TaikoPlayfield.cs" />
<Compile Include="TaikoRuleset.cs" />
@ -78,10 +84,6 @@
<Project>{C76BF5B3-985E-4D39-95FE-97C9C879B83A}</Project>
<Name>osu.Framework</Name>
</ProjectReference>
<ProjectReference Include="..\osu.Game.Modes.Osu\osu.Game.Modes.Osu.csproj">
<Project>{C92A607B-1FDD-4954-9F92-03FF547D9080}</Project>
<Name>osu.Game.Modes.Osu</Name>
</ProjectReference>
<ProjectReference Include="..\osu.Game\osu.Game.csproj">
<Project>{0D3FBF8A-7464-4CF7-8C90-3E7886DF2D4D}</Project>
<Name>osu.Game</Name>

View File

@ -70,7 +70,7 @@ namespace osu.Game.Tests.Beatmaps.IO
Assert.IsTrue(File.Exists(temp));
var importer = new BeatmapIPCChannel(client);
if (!importer.ImportAsync(temp).Wait(1000))
if (!importer.ImportAsync(temp).Wait(5000))
Assert.Fail(@"IPC took too long to send");
ensureLoaded(osu);

View File

@ -15,8 +15,8 @@ namespace osu.Game.Beatmaps
private void loadTiming()
{
// TODO: Handle mods
int audioRate = 100;
TimeRate = audioRate / 100.0;
const int audio_rate = 100;
TimeRate = audio_rate / 100.0;
}
public double Calculate(Dictionary<string, string> categoryDifficulty = null)

View File

@ -21,12 +21,12 @@ namespace osu.Game.Beatmaps.Drawables
public class BeatmapPanel : Panel
{
public BeatmapInfo Beatmap;
private Sprite background;
private readonly Sprite background;
public Action<BeatmapPanel> GainedSelection;
public Action<BeatmapPanel> StartRequested;
private Triangles triangles;
private StarCounter starCounter;
private readonly Triangles triangles;
private readonly StarCounter starCounter;
protected override void Selected()
{

View File

@ -20,11 +20,12 @@ namespace osu.Game.Beatmaps.Drawables
public class BeatmapSetHeader : Panel
{
public Action<BeatmapSetHeader> GainedSelection;
private SpriteText title, artist;
private readonly SpriteText title;
private readonly SpriteText artist;
private OsuConfigManager config;
private Bindable<bool> preferUnicode;
private WorkingBeatmap beatmap;
private FillFlowContainer difficultyIcons;
private readonly WorkingBeatmap beatmap;
private readonly FillFlowContainer difficultyIcons;
public BeatmapSetHeader(WorkingBeatmap beatmap)
{

View File

@ -18,7 +18,7 @@ namespace osu.Game.Beatmaps.Drawables
public override bool RemoveWhenNotAlive => false;
private Container nestedContainer;
private readonly Container nestedContainer;
protected override Container<Drawable> Content => nestedContainer;

View File

@ -21,9 +21,9 @@ namespace osu.Game.Beatmaps.IO
OsuLegacyDecoder.Register();
}
private Stream archiveStream;
private ZipFile archive;
private Beatmap firstMap;
private readonly Stream archiveStream;
private readonly ZipFile archive;
private readonly Beatmap firstMap;
public OszArchiveReader(Stream archiveStream)
{

View File

@ -4,14 +4,11 @@
using osu.Framework.Audio.Track;
using osu.Framework.Configuration;
using osu.Framework.Graphics.Textures;
using osu.Game.Beatmaps.Formats;
using osu.Game.Beatmaps.IO;
using osu.Game.Database;
using osu.Game.Modes;
using osu.Game.Modes.Mods;
using System;
using System.Collections.Generic;
using System.IO;
namespace osu.Game.Beatmaps
{
@ -27,14 +24,12 @@ namespace osu.Game.Beatmaps
/// </summary>
public PlayMode? PreferredPlayMode;
public PlayMode PlayMode => beatmap?.BeatmapInfo?.Mode > PlayMode.Osu ? beatmap.BeatmapInfo.Mode : PreferredPlayMode ?? PlayMode.Osu;
public PlayMode PlayMode => Beatmap?.BeatmapInfo?.Mode > PlayMode.Osu ? Beatmap.BeatmapInfo.Mode : PreferredPlayMode ?? PlayMode.Osu;
public readonly Bindable<IEnumerable<Mod>> Mods = new Bindable<IEnumerable<Mod>>();
public readonly bool WithStoryboard;
protected abstract ArchiveReader GetReader();
protected WorkingBeatmap(BeatmapInfo beatmapInfo, BeatmapSetInfo beatmapSetInfo, bool withStoryboard = false)
{
BeatmapInfo = beatmapInfo;
@ -42,116 +37,63 @@ namespace osu.Game.Beatmaps
WithStoryboard = withStoryboard;
}
private Texture background;
private object backgroundLock = new object();
public Texture Background
{
get
{
lock (backgroundLock)
{
if (background != null) return background;
if (BeatmapInfo?.Metadata?.BackgroundFile == null) return null;
try
{
using (var reader = GetReader())
background = new TextureStore(new RawTextureLoaderStore(reader), false).Get(BeatmapInfo.Metadata.BackgroundFile);
}
catch { }
return background;
}
}
set { lock (backgroundLock) background = value; }
}
protected abstract Beatmap GetBeatmap();
protected abstract Texture GetBackground();
protected abstract Track GetTrack();
private Beatmap beatmap;
private object beatmapLock = new object();
private readonly object beatmapLock = new object();
public Beatmap Beatmap
{
get
{
lock (beatmapLock)
{
if (beatmap != null) return beatmap;
try
{
using (var reader = GetReader())
{
BeatmapDecoder decoder;
using (var stream = new StreamReader(reader.GetStream(BeatmapInfo.Path)))
{
decoder = BeatmapDecoder.GetDecoder(stream);
beatmap = decoder?.Decode(stream);
}
if (WithStoryboard && beatmap != null && BeatmapSetInfo.StoryboardFile != null)
using (var stream = new StreamReader(reader.GetStream(BeatmapSetInfo.StoryboardFile)))
decoder?.Decode(stream, beatmap);
}
}
catch { }
return beatmap;
return beatmap ?? (beatmap = GetBeatmap());
}
}
}
private readonly object backgroundLock = new object();
private Texture background;
public Texture Background
{
get
{
lock (backgroundLock)
{
return background ?? (background = GetBackground());
}
}
set { lock (beatmapLock) beatmap = value; }
}
private ArchiveReader trackReader;
private Track track;
private object trackLock = new object();
private readonly object trackLock = new object();
public Track Track
{
get
{
lock (trackLock)
{
if (track != null) return track;
try
{
//store a reference to the reader as we may continue accessing the stream in the background.
trackReader = GetReader();
var trackData = trackReader?.GetStream(BeatmapInfo.Metadata.AudioFile);
if (trackData != null)
track = new TrackBass(trackData);
}
catch { }
return track;
return track ?? (track = GetTrack());
}
}
set { lock (trackLock) track = value; }
}
public bool TrackLoaded => track != null;
private bool isDisposed;
protected virtual void Dispose(bool disposing)
public void TransferTo(WorkingBeatmap other)
{
if (!isDisposed)
{
track?.Dispose();
background?.Dispose();
isDisposed = true;
}
if (track != null && BeatmapInfo.AudioEquals(other.BeatmapInfo))
other.track = track;
}
public void Dispose()
public virtual void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
public void TransferTo(WorkingBeatmap working)
{
if (track != null && BeatmapInfo.AudioEquals(working.BeatmapInfo))
working.track = track;
track?.Dispose();
track = null;
background?.Dispose();
background = null;
}
}
}

View File

@ -23,7 +23,8 @@ namespace osu.Game.Configuration
Set(OsuConfig.SavePassword, false);
Set(OsuConfig.SaveUsername, true);
Set(OsuConfig.CursorSize, 1.0, 0.5f, 2);
Set(OsuConfig.MenuCursorSize, 1.0, 0.5f, 2);
Set(OsuConfig.GameplayCursorSize, 1.0, 0.5f, 2);
Set(OsuConfig.DimLevel, 30, 0, 100);
Set(OsuConfig.MouseDisableButtons, false);
@ -175,11 +176,11 @@ namespace osu.Game.Configuration
ConfineMouseMode.Fullscreen : ConfineMouseMode.Never).Disabled = true;
GetBindable<bool>(OsuConfig.SavePassword).ValueChanged += delegate
GetOriginalBindable<bool>(OsuConfig.SavePassword).ValueChanged += delegate
{
if (Get<bool>(OsuConfig.SavePassword)) Set(OsuConfig.SaveUsername, true);
};
GetBindable<bool>(OsuConfig.SaveUsername).ValueChanged += delegate
GetOriginalBindable<bool>(OsuConfig.SaveUsername).ValueChanged += delegate
{
if (!Get<bool>(OsuConfig.SaveUsername)) Set(OsuConfig.SavePassword, false);
};
@ -223,7 +224,8 @@ namespace osu.Game.Configuration
ComboFireHeight,
ConfirmExit,
AutoSendNowPlaying,
CursorSize,
MenuCursorSize,
GameplayCursorSize,
AutomaticCursorSizing,
DimLevel,
Display,

View File

@ -21,7 +21,7 @@ namespace osu.Game.Database
public class BeatmapDatabase
{
private SQLiteConnection connection { get; }
private Storage storage;
private readonly Storage storage;
public event Action<BeatmapSetInfo> BeatmapSetAdded;
public event Action<BeatmapSetInfo> BeatmapSetRemoved;
@ -342,18 +342,5 @@ namespace osu.Game.Database
}
public bool Exists(BeatmapSetInfo beatmapSet) => storage.Exists(beatmapSet.Path);
private class DatabaseWorkingBeatmap : WorkingBeatmap
{
private readonly BeatmapDatabase database;
public DatabaseWorkingBeatmap(BeatmapDatabase database, BeatmapInfo beatmapInfo, BeatmapSetInfo beatmapSetInfo, bool withStoryboard = false)
: base(beatmapInfo, beatmapSetInfo, withStoryboard)
{
this.database = database;
}
protected override ArchiveReader GetReader() => database?.GetReader(BeatmapSetInfo);
}
}
}

View File

@ -0,0 +1,73 @@
// 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.IO;
using osu.Framework.Audio.Track;
using osu.Framework.Graphics.Textures;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Formats;
using osu.Game.Beatmaps.IO;
namespace osu.Game.Database
{
internal class DatabaseWorkingBeatmap : WorkingBeatmap
{
private readonly BeatmapDatabase database;
public DatabaseWorkingBeatmap(BeatmapDatabase database, BeatmapInfo beatmapInfo, BeatmapSetInfo beatmapSetInfo, bool withStoryboard = false)
: base(beatmapInfo, beatmapSetInfo, withStoryboard)
{
this.database = database;
}
private ArchiveReader getReader() => database?.GetReader(BeatmapSetInfo);
protected override Beatmap GetBeatmap()
{
try
{
Beatmap beatmap;
using (var reader = getReader())
{
BeatmapDecoder decoder;
using (var stream = new StreamReader(reader.GetStream(BeatmapInfo.Path)))
{
decoder = BeatmapDecoder.GetDecoder(stream);
beatmap = decoder?.Decode(stream);
}
if (WithStoryboard && beatmap != null && BeatmapSetInfo.StoryboardFile != null)
using (var stream = new StreamReader(reader.GetStream(BeatmapSetInfo.StoryboardFile)))
decoder.Decode(stream, beatmap);
}
return beatmap;
}
catch { return null; }
}
protected override Texture GetBackground()
{
if (BeatmapInfo?.Metadata?.BackgroundFile == null)
return null;
try
{
using (var reader = getReader())
return new TextureStore(new RawTextureLoaderStore(reader), false).Get(BeatmapInfo.Metadata.BackgroundFile);
}
catch { return null; }
}
protected override Track GetTrack()
{
try
{
var trackData = getReader()?.GetStream(BeatmapInfo.Metadata.AudioFile);
return trackData == null ? null : new TrackBass(trackData);
}
catch { return null; }
}
}
}

View File

@ -14,7 +14,7 @@ namespace osu.Game.Graphics.Backgrounds
{
public Sprite Sprite;
private string textureName;
private readonly string textureName;
public Background(string textureName = @"")
{

View File

@ -89,25 +89,24 @@ namespace osu.Game.Graphics.Backgrounds
protected virtual Triangle CreateTriangle()
{
float stdDev = 0.16f;
float mean = 0.5f;
const float std_dev = 0.16f;
const float mean = 0.5f;
float u1 = 1 - RNG.NextSingle(); //uniform(0,1] random floats
float u2 = 1 - RNG.NextSingle();
float randStdNormal = (float)(Math.Sqrt(-2.0 * Math.Log(u1)) * Math.Sin(2.0 * Math.PI * u2)); //random normal(0,1)
var scale = Math.Max(triangleScale * (mean + stdDev * randStdNormal), 0.1f); //random normal(mean,stdDev^2)
var scale = Math.Max(triangleScale * (mean + std_dev * randStdNormal), 0.1f); //random normal(mean,stdDev^2)
const float size = 100;
return new Triangle
return new EquilateralTriangle
{
Origin = Anchor.TopCentre,
RelativePositionAxes = Axes.Both,
Size = new Vector2(size),
Scale = new Vector2(scale),
EdgeSmoothness = new Vector2(1),
Colour = GetTriangleShade(),
// Scaling height by 0.866 results in equiangular triangles (== 60° and equal side length)
Size = new Vector2(size, 0.866f * size),
Depth = scale,
};
}

View File

@ -31,7 +31,7 @@ namespace osu.Game.Graphics.Containers
});
}
private Container content;
private readonly Container content;
private InputManager input;
protected override Container<Drawable> Content => content;

View File

@ -31,10 +31,10 @@ namespace osu.Game.Graphics.Cursor
private float time;
private TrailDrawNodeSharedData trailDrawNodeSharedData = new TrailDrawNodeSharedData();
private readonly TrailDrawNodeSharedData trailDrawNodeSharedData = new TrailDrawNodeSharedData();
private const int max_sprites = 2048;
private TrailPart[] parts = new TrailPart[max_sprites];
private readonly TrailPart[] parts = new TrailPart[max_sprites];
private Vector2? lastPosition;
@ -88,10 +88,10 @@ namespace osu.Game.Graphics.Cursor
Invalidate(Invalidation.DrawNode, shallPropagate: false);
int fadeClockResetThreshold = 1000000;
const int fade_clock_reset_threshold = 1000000;
time = (float)(Time.Current - timeOffset) / 500f;
if (time > fadeClockResetThreshold)
if (time > fade_clock_reset_threshold)
resetTime();
}
@ -163,7 +163,7 @@ namespace osu.Game.Graphics.Cursor
public float Time;
public TrailDrawNodeSharedData Shared;
public TrailPart[] Parts = new TrailPart[max_sprites];
public readonly TrailPart[] Parts = new TrailPart[max_sprites];
public Vector2 Size;
public TrailDrawNode()

View File

@ -54,8 +54,6 @@ namespace osu.Game.Graphics.Cursor
[BackgroundDependencyLoader]
private void load(OsuConfigManager config)
{
cursorScale = config.GetBindable<double>(OsuConfig.CursorSize);
Children = new Drawable[]
{
cursorContainer = new CircularContainer
@ -63,7 +61,6 @@ namespace osu.Game.Graphics.Cursor
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Scale = new Vector2((float)cursorScale),
Masking = true,
BorderThickness = Size.X / 6,
BorderColour = Color4.White,
@ -119,7 +116,9 @@ namespace osu.Game.Graphics.Cursor
},
};
cursorScale = config.GetBindable<double>(OsuConfig.GameplayCursorSize);
cursorScale.ValueChanged += scaleChanged;
cursorScale.TriggerChange();
}
private void scaleChanged(object sender, EventArgs e)

View File

@ -97,8 +97,6 @@ namespace osu.Game.Graphics.Cursor
[BackgroundDependencyLoader]
private void load(OsuConfigManager config, TextureStore textures, OsuColour colour)
{
cursorScale = config.GetBindable<double>(OsuConfig.CursorSize);
Children = new Drawable[]
{
cursorContainer = new Container
@ -122,7 +120,10 @@ namespace osu.Game.Graphics.Cursor
}
}
};
cursorScale = config.GetBindable<double>(OsuConfig.MenuCursorSize);
cursorScale.ValueChanged += scaleChanged;
cursorScale.TriggerChange();
}
private void scaleChanged(object sender, EventArgs e)

View File

@ -81,9 +81,14 @@ namespace osu.Game.Graphics.UserInterface
public SampleChannel SampleClick, SampleHover;
private Container backgroundContainer, colourContainer, glowContainer;
private Box leftGlow, centerGlow, rightGlow, background;
private SpriteText spriteText;
private readonly Container backgroundContainer;
private readonly Container colourContainer;
private readonly Container glowContainer;
private readonly Box leftGlow;
private readonly Box centerGlow;
private readonly Box rightGlow;
private readonly Box background;
private readonly SpriteText spriteText;
private Vector2 hoverSpacing => new Vector2(3f, 0f);
private bool didClick; // Used for making sure that the OnMouseDown animation can call instead of OnHoverLost's when clicking

View File

@ -18,7 +18,7 @@ namespace osu.Game.Graphics.UserInterface
public const float COLLAPSED_SIZE = 20;
public const float EXPANDED_SIZE = 40;
private Box fill;
private readonly Box fill;
private const float border_width = 3;
private Color4 glowingColour, idleColour;
@ -30,6 +30,8 @@ namespace osu.Game.Graphics.UserInterface
BorderColour = Color4.White;
BorderThickness = border_width;
Masking = true;
Children = new[]
{
fill = new Box

View File

@ -64,8 +64,8 @@ namespace osu.Game.Graphics.UserInterface
}
}
private Nub nub;
private SpriteText labelSpriteText;
private readonly Nub nub;
private readonly SpriteText labelSpriteText;
private SampleChannel sampleChecked;
private SampleChannel sampleUnchecked;

View File

@ -1,69 +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.Primitives;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
using osu.Game.Graphics.Sprites;
using OpenTK.Graphics;
using osu.Framework.Extensions.Color4Extensions;
namespace osu.Game.Graphics.UserInterface
{
public class OsuDropDownHeader : DropDownHeader
{
private SpriteText label;
protected override string Label
{
get { return label.Text; }
set { label.Text = value; }
}
private Color4? accentColour;
public virtual Color4 AccentColour
{
get { return accentColour.GetValueOrDefault(); }
set
{
accentColour = value;
BackgroundColourHover = value;
}
}
public OsuDropDownHeader()
{
Foreground.Padding = new MarginPadding(4);
AutoSizeAxes = Axes.None;
Margin = new MarginPadding { Bottom = 4 };
CornerRadius = 4;
Height = 40;
Foreground.Children = new Drawable[]
{
label = new OsuSpriteText
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
},
new TextAwesome
{
Icon = FontAwesome.fa_chevron_down,
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
Margin = new MarginPadding { Right = 4 },
TextSize = 20
}
};
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
BackgroundColour = Color4.Black.Opacity(0.5f);
BackgroundColourHover = accentColour ?? colours.PinkDarker;
}
}
}

View File

@ -1,61 +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 System.Linq;
using osu.Framework.Allocation;
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Graphics.Transforms;
using osu.Framework.Graphics.UserInterface;
namespace osu.Game.Graphics.UserInterface
{
public class OsuDropDownMenu<T> : DropDownMenu<T>
{
protected override DropDownHeader CreateHeader() => new OsuDropDownHeader { AccentColour = AccentColour };
private Color4? accentColour;
public virtual Color4 AccentColour
{
get { return accentColour.GetValueOrDefault(); }
set
{
accentColour = value;
if (Header != null)
((OsuDropDownHeader)Header).AccentColour = value;
foreach (var item in ItemList.OfType<OsuDropDownMenuItem<T>>())
item.AccentColour = value;
}
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
if (accentColour == null)
AccentColour = colours.PinkDarker;
}
public OsuDropDownMenu()
{
ContentContainer.CornerRadius = 4;
ContentBackground.Colour = Color4.Black.Opacity(0.5f);
DropDownItemsContainer.Padding = new MarginPadding(5);
}
protected override void AnimateOpen() => ContentContainer.FadeIn(300, EasingTypes.OutQuint);
protected override void AnimateClose() => ContentContainer.FadeOut(300, EasingTypes.OutQuint);
protected override void UpdateContentHeight()
{
var actualHeight = (RelativeSizeAxes & Axes.Y) > 0 ? 1 : ContentHeight;
ContentContainer.ResizeTo(new Vector2(1, State == DropDownMenuState.Opened ? actualHeight : 0), 300, EasingTypes.OutQuint);
}
protected override DropDownMenuItem<T> CreateDropDownItem(string key, T value) => new OsuDropDownMenuItem<T>(key, value) { AccentColour = AccentColour };
}
}

View File

@ -1,85 +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.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Graphics.UserInterface;
using osu.Game.Graphics.Sprites;
using OpenTK.Graphics;
namespace osu.Game.Graphics.UserInterface
{
public class OsuDropDownMenuItem<U> : DropDownMenuItem<U>
{
public OsuDropDownMenuItem(string text, U value) : base(text, value)
{
Foreground.Padding = new MarginPadding(2);
Masking = true;
CornerRadius = 6;
Children = new[]
{
new FillFlowContainer
{
Direction = FillDirection.Horizontal,
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Children = new Drawable[]
{
chevron = new TextAwesome
{
AlwaysPresent = true,
Icon = FontAwesome.fa_chevron_right,
UseFullGlyphHeight = false,
Colour = Color4.Black,
Alpha = 0.5f,
TextSize = 8,
Margin = new MarginPadding { Left = 3, Right = 3 },
Origin = Anchor.CentreLeft,
Anchor = Anchor.CentreLeft,
},
new OsuSpriteText {
Text = text,
Origin = Anchor.CentreLeft,
Anchor = Anchor.CentreLeft,
}
}
}
};
}
private Color4? accentColour;
private TextAwesome chevron;
protected override void FormatForeground(bool hover = false)
{
base.FormatForeground(hover);
chevron.Alpha = hover ? 1 : 0;
}
public Color4 AccentColour
{
get { return accentColour.GetValueOrDefault(); }
set
{
accentColour = value;
BackgroundColourHover = BackgroundColourSelected = value;
FormatBackground();
FormatForeground();
}
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
BackgroundColour = Color4.Transparent;
BackgroundColourHover = accentColour ?? colours.PinkDarker;
BackgroundColourSelected = Color4.Black.Opacity(0.5f);
}
}
}

View File

@ -0,0 +1,172 @@
// 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.Linq;
using OpenTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
using osu.Game.Graphics.Sprites;
namespace osu.Game.Graphics.UserInterface
{
public class OsuDropdown<T> : Dropdown<T>
{
protected override DropdownHeader CreateHeader() => new OsuDropdownHeader { AccentColour = AccentColour };
protected override Menu CreateMenu() => new OsuMenu();
private Color4? accentColour;
public virtual Color4 AccentColour
{
get { return accentColour.GetValueOrDefault(); }
set
{
accentColour = value;
if (Header != null)
((OsuDropdownHeader)Header).AccentColour = value;
foreach (var item in MenuItems.OfType<OsuDropdownMenuItem>())
item.AccentColour = value;
}
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
if (accentColour == null)
AccentColour = colours.PinkDarker;
}
protected override DropdownMenuItem<T> CreateMenuItem(string text, T value) => new OsuDropdownMenuItem(text, value) { AccentColour = AccentColour };
private class OsuDropdownMenuItem : DropdownMenuItem<T>
{
public OsuDropdownMenuItem(string text, T value) : base(text, value)
{
Foreground.Padding = new MarginPadding(2);
Masking = true;
CornerRadius = 6;
Children = new[]
{
new FillFlowContainer
{
Direction = FillDirection.Horizontal,
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Children = new Drawable[]
{
chevron = new TextAwesome
{
AlwaysPresent = true,
Icon = FontAwesome.fa_chevron_right,
UseFullGlyphHeight = false,
Colour = Color4.Black,
Alpha = 0.5f,
TextSize = 8,
Margin = new MarginPadding { Left = 3, Right = 3 },
Origin = Anchor.CentreLeft,
Anchor = Anchor.CentreLeft,
},
new OsuSpriteText {
Text = text,
Origin = Anchor.CentreLeft,
Anchor = Anchor.CentreLeft,
}
}
}
};
}
private Color4? accentColour;
private readonly TextAwesome chevron;
protected override void FormatForeground(bool hover = false)
{
base.FormatForeground(hover);
chevron.Alpha = hover ? 1 : 0;
}
public Color4 AccentColour
{
get { return accentColour.GetValueOrDefault(); }
set
{
accentColour = value;
BackgroundColourHover = BackgroundColourSelected = value;
FormatBackground();
FormatForeground();
}
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
BackgroundColour = Color4.Transparent;
BackgroundColourHover = accentColour ?? colours.PinkDarker;
BackgroundColourSelected = Color4.Black.Opacity(0.5f);
}
}
protected class OsuDropdownHeader : DropdownHeader
{
private readonly SpriteText label;
protected override string Label
{
get { return label.Text; }
set { label.Text = value; }
}
private Color4? accentColour;
public virtual Color4 AccentColour
{
get { return accentColour.GetValueOrDefault(); }
set
{
accentColour = value;
BackgroundColourHover = value;
}
}
public OsuDropdownHeader()
{
Foreground.Padding = new MarginPadding(4);
AutoSizeAxes = Axes.None;
Margin = new MarginPadding { Bottom = 4 };
CornerRadius = 4;
Height = 40;
Foreground.Children = new Drawable[]
{
label = new OsuSpriteText
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
},
new TextAwesome
{
Icon = FontAwesome.fa_chevron_down,
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
Margin = new MarginPadding { Right = 4 },
TextSize = 20
}
};
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
BackgroundColour = Color4.Black.Opacity(0.5f);
BackgroundColourHover = accentColour ?? colours.PinkDarker;
}
}
}
}

View File

@ -0,0 +1,34 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Graphics.Transforms;
using osu.Framework.Graphics.UserInterface;
namespace osu.Game.Graphics.UserInterface
{
public class OsuMenu : Menu
{
public OsuMenu()
{
CornerRadius = 4;
Background.Colour = Color4.Black.Opacity(0.5f);
ItemsContainer.Padding = new MarginPadding(5);
}
protected override void AnimateOpen() => FadeIn(300, EasingTypes.OutQuint);
protected override void AnimateClose() => FadeOut(300, EasingTypes.OutQuint);
protected override void UpdateContentHeight()
{
var actualHeight = (RelativeSizeAxes & Axes.Y) > 0 ? 1 : ContentHeight;
ResizeTo(new Vector2(1, State == MenuState.Opened ? actualHeight : 0), 300, EasingTypes.OutQuint);
}
}
}

View File

@ -18,7 +18,7 @@ namespace osu.Game.Graphics.UserInterface
public class PasswordMaskChar : Container
{
private CircularContainer circle;
private readonly CircularContainer circle;
public PasswordMaskChar(float size)
{
@ -28,6 +28,8 @@ namespace osu.Game.Graphics.UserInterface
circle = new CircularContainer
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Masking = true,
Alpha = 0,
RelativeSizeAxes = Axes.Both,
Size = new Vector2(0.8f, 0),

View File

@ -19,8 +19,9 @@ namespace osu.Game.Graphics.UserInterface
private SampleChannel sample;
private double lastSampleTime;
private Nub nub;
private Box leftBox, rightBox;
private readonly Nub nub;
private readonly Box leftBox;
private readonly Box rightBox;
public OsuSliderBar()
{

View File

@ -6,24 +6,30 @@ using System.Linq;
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Extensions;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Transforms;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input;
using osu.Game.Graphics.Sprites;
namespace osu.Game.Graphics.UserInterface
{
public class OsuTabControl<T> : TabControl<T>
{
protected override DropDownMenu<T> CreateDropDownMenu() => new OsuTabDropDownMenu<T>();
protected override Dropdown<T> CreateDropdown() => new OsuTabDropdown();
protected override TabItem<T> CreateTabItem(T value) => new OsuTabItem<T> { Value = value };
protected override TabItem<T> CreateTabItem(T value) => new OsuTabItem { Value = value };
protected override bool InternalContains(Vector2 screenSpacePos) => base.InternalContains(screenSpacePos) || DropDown.Contains(screenSpacePos);
protected override bool InternalContains(Vector2 screenSpacePos) => base.InternalContains(screenSpacePos) || Dropdown.Contains(screenSpacePos);
public OsuTabControl()
{
TabContainer.Spacing = new Vector2(10f, 0f);
if (!typeof(T).IsEnum)
throw new InvalidOperationException("OsuTabControl only supports enums as the generic type argument");
@ -45,42 +51,146 @@ namespace osu.Game.Graphics.UserInterface
set
{
accentColour = value;
var dropDown = DropDown as OsuTabDropDownMenu<T>;
var dropDown = Dropdown as OsuTabDropdown;
if (dropDown != null)
dropDown.AccentColour = value;
foreach (var item in TabContainer.Children.OfType<OsuTabItem<T>>())
foreach (var item in TabContainer.Children.OfType<OsuTabItem>())
item.AccentColour = value;
}
}
public class OsuTabDropDownMenu<T1> : OsuDropDownMenu<T1>
private class OsuTabItem : TabItem<T>
{
protected override DropDownHeader CreateHeader() => new OsuTabDropDownHeader
private readonly SpriteText text;
private readonly Box box;
private Color4? accentColour;
public Color4 AccentColour
{
get { return accentColour.GetValueOrDefault(); }
set
{
accentColour = value;
if (!Active)
text.Colour = value;
}
}
public new T Value
{
get { return base.Value; }
set
{
base.Value = value;
text.Text = (value as Enum)?.GetDescription();
}
}
public override bool Active
{
get { return base.Active; }
set
{
if (Active == value) return;
if (value)
fadeActive();
else
fadeInactive();
base.Active = value;
}
}
private const float transition_length = 500;
private void fadeActive()
{
box.FadeIn(transition_length, EasingTypes.OutQuint);
text.FadeColour(Color4.White, transition_length, EasingTypes.OutQuint);
}
private void fadeInactive()
{
box.FadeOut(transition_length, EasingTypes.OutQuint);
text.FadeColour(AccentColour, transition_length, EasingTypes.OutQuint);
}
protected override bool OnHover(InputState state)
{
if (!Active)
fadeActive();
return true;
}
protected override void OnHoverLost(InputState state)
{
if (!Active)
fadeInactive();
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
if (accentColour == null)
AccentColour = colours.Blue;
}
public OsuTabItem()
{
AutoSizeAxes = Axes.X;
RelativeSizeAxes = Axes.Y;
Children = new Drawable[]
{
text = new OsuSpriteText
{
Margin = new MarginPadding { Top = 5, Bottom = 5 },
Origin = Anchor.BottomLeft,
Anchor = Anchor.BottomLeft,
TextSize = 14,
Font = @"Exo2.0-Bold", // Font should only turn bold when active?
},
box = new Box
{
RelativeSizeAxes = Axes.X,
Height = 1,
Alpha = 0,
Colour = Color4.White,
Origin = Anchor.BottomLeft,
Anchor = Anchor.BottomLeft,
}
};
}
}
private class OsuTabDropdown : OsuDropdown<T>
{
protected override DropdownHeader CreateHeader() => new OsuTabDropdownHeader
{
AccentColour = AccentColour,
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
};
protected override DropDownMenuItem<T1> CreateDropDownItem(string key, T1 value)
protected override DropdownMenuItem<T> CreateMenuItem(string text, T value)
{
var item = base.CreateDropDownItem(key, value);
var item = base.CreateMenuItem(text, value);
item.ForegroundColourHover = Color4.Black;
return item;
}
public OsuTabDropDownMenu()
public OsuTabDropdown()
{
ContentContainer.Anchor = Anchor.TopRight;
ContentContainer.Origin = Anchor.TopRight;
DropdownMenu.Anchor = Anchor.TopRight;
DropdownMenu.Origin = Anchor.TopRight;
RelativeSizeAxes = Axes.X;
ContentBackground.Colour = Color4.Black.Opacity(0.7f);
MaxDropDownHeight = 400;
DropdownMenu.Background.Colour = Color4.Black.Opacity(0.7f);
DropdownMenu.MaxHeight = 400;
}
public class OsuTabDropDownHeader : OsuDropDownHeader
protected class OsuTabDropdownHeader : OsuDropdownHeader
{
public override Color4 AccentColour
{
@ -104,7 +214,7 @@ namespace osu.Game.Graphics.UserInterface
base.OnHoverLost(state);
}
public OsuTabDropDownHeader()
public OsuTabDropdownHeader()
{
RelativeSizeAxes = Axes.None;
AutoSizeAxes = Axes.X;

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 OpenTK;
using OpenTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Transforms;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input;
using osu.Game.Graphics.Sprites;
namespace osu.Game.Graphics.UserInterface
{
/// <summary>
/// A checkbox styled to be placed in line with an <see cref="OsuTabControl{T}"/>
/// </summary>
public class OsuTabControlCheckBox : CheckBox
{
private readonly Box box;
private readonly SpriteText text;
private readonly TextAwesome icon;
public event EventHandler<CheckBoxState> Action;
private Color4? accentColour;
public Color4 AccentColour
{
get { return accentColour.GetValueOrDefault(); }
set
{
accentColour = value;
if (State != CheckBoxState.Checked)
{
text.Colour = AccentColour;
icon.Colour = AccentColour;
}
}
}
public string Text
{
get { return text.Text; }
set { text.Text = value; }
}
protected override void OnChecked()
{
fadeIn();
icon.Icon = FontAwesome.fa_check_circle_o;
Action?.Invoke(this, State);
}
protected override void OnUnchecked()
{
fadeOut();
icon.Icon = FontAwesome.fa_circle_o;
Action?.Invoke(this, State);
}
private const float transition_length = 500;
private void fadeIn()
{
box.FadeIn(transition_length, EasingTypes.OutQuint);
text.FadeColour(Color4.White, transition_length, EasingTypes.OutQuint);
}
private void fadeOut()
{
box.FadeOut(transition_length, EasingTypes.OutQuint);
text.FadeColour(AccentColour, transition_length, EasingTypes.OutQuint);
}
protected override bool OnHover(InputState state)
{
fadeIn();
return base.OnHover(state);
}
protected override void OnHoverLost(InputState state)
{
if (State == CheckBoxState.Unchecked)
fadeOut();
base.OnHoverLost(state);
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
if (accentColour == null)
AccentColour = colours.Blue;
}
public OsuTabControlCheckBox()
{
AutoSizeAxes = Axes.Both;
Children = new Drawable[]
{
new FillFlowContainer
{
AutoSizeAxes = Axes.Both,
Margin = new MarginPadding { Top = 5, Bottom = 5, },
Spacing = new Vector2(5f, 0f),
Direction = FillDirection.Horizontal,
Children = new Drawable[]
{
text = new OsuSpriteText
{
TextSize = 14,
Font = @"Exo2.0-Bold",
},
icon = new TextAwesome
{
TextSize = 14,
Icon = FontAwesome.fa_circle_o,
Shadow = true,
},
},
},
box = new Box
{
RelativeSizeAxes = Axes.X,
Height = 1,
Alpha = 0,
Colour = Color4.White,
Origin = Anchor.BottomLeft,
Anchor = Anchor.BottomLeft,
}
};
}
}
}

View File

@ -1,121 +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 System;
using OpenTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Transforms;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input;
using osu.Game.Graphics.Sprites;
namespace osu.Game.Graphics.UserInterface
{
public class OsuTabItem<T> : TabItem<T>
{
private SpriteText text;
private Box box;
private Color4? accentColour;
public Color4 AccentColour
{
get { return accentColour.GetValueOrDefault(); }
set
{
accentColour = value;
if (!Active)
text.Colour = value;
}
}
public new T Value
{
get { return base.Value; }
set
{
base.Value = value;
text.Text = (value as Enum)?.GetDescription();
}
}
public override bool Active
{
get { return base.Active; }
set
{
if (Active == value) return;
if (value)
fadeActive();
else
fadeInactive();
base.Active = value;
}
}
private const float transition_length = 500;
private void fadeActive()
{
box.FadeIn(transition_length, EasingTypes.OutQuint);
text.FadeColour(Color4.White, transition_length, EasingTypes.OutQuint);
}
private void fadeInactive()
{
box.FadeOut(transition_length, EasingTypes.OutQuint);
text.FadeColour(AccentColour, transition_length, EasingTypes.OutQuint);
}
protected override bool OnHover(InputState state)
{
if (!Active)
fadeActive();
return true;
}
protected override void OnHoverLost(InputState state)
{
if (!Active)
fadeInactive();
}
public OsuTabItem()
{
AutoSizeAxes = Axes.X;
RelativeSizeAxes = Axes.Y;
Children = new Drawable[]
{
text = new OsuSpriteText
{
Margin = new MarginPadding(5),
Origin = Anchor.BottomLeft,
Anchor = Anchor.BottomLeft,
TextSize = 14,
Font = @"Exo2.0-Bold", // Font should only turn bold when active?
},
box = new Box
{
RelativeSizeAxes = Axes.X,
Height = 1,
Alpha = 0,
Colour = Color4.White,
Origin = Anchor.BottomLeft,
Anchor = Anchor.BottomLeft,
}
};
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
if (accentColour == null)
AccentColour = colours.Blue;
}
}
}

View File

@ -147,7 +147,7 @@ namespace osu.Game.Graphics.UserInterface
private class Star : Container
{
public TextAwesome Icon;
public readonly TextAwesome Icon;
public Star()
{
Size = new Vector2(star_size);

View File

@ -16,7 +16,7 @@ namespace osu.Game.Graphics.UserInterface
{
public class TwoLayerButton : ClickableContainer
{
private TextAwesome icon;
private readonly TextAwesome icon;
public Box IconLayer;
public Box TextLayer;
@ -29,11 +29,11 @@ namespace osu.Game.Graphics.UserInterface
public static readonly Vector2 SIZE_EXTENDED = new Vector2(140, 50);
public static readonly Vector2 SIZE_RETRACTED = new Vector2(100, 50);
public SampleChannel ActivationSound;
private SpriteText text;
private readonly SpriteText text;
public Color4 HoverColour;
private Container c1;
private Container c2;
private readonly Container c1;
private readonly Container c2;
public Color4 BackgroundColour
{
@ -171,7 +171,7 @@ namespace osu.Game.Graphics.UserInterface
IconLayer.FadeColour(HoverColour, transform_time, EasingTypes.OutElastic);
double offset = 0; //(1 - Game.Audio.SyncBeatProgress) * duration;
const double offset = 0; //(1 - Game.Audio.SyncBeatProgress) * duration;
double startTime = Time.Current + offset;
// basic pulse
@ -200,7 +200,7 @@ namespace osu.Game.Graphics.UserInterface
int duration = 0; //(int)(Game.Audio.BeatLength);
if (duration == 0) duration = pulse_length * 2;
double offset = 0; //(1 - Game.Audio.SyncBeatProgress) * duration;
const double offset = 0; //(1 - Game.Audio.SyncBeatProgress) * duration;
double startTime = Time.Current + offset;
// slow pulse

View File

@ -15,7 +15,7 @@ namespace osu.Game.Graphics.UserInterface.Volume
{
internal class VolumeControl : OverlayContainer
{
private VolumeMeter volumeMeterMaster;
private readonly VolumeMeter volumeMeterMaster;
protected override bool HideOnEscape => false;
@ -89,8 +89,8 @@ namespace osu.Game.Graphics.UserInterface.Volume
private ScheduledDelegate popOutDelegate;
private VolumeMeter volumeMeterEffect;
private VolumeMeter volumeMeterMusic;
private readonly VolumeMeter volumeMeterEffect;
private readonly VolumeMeter volumeMeterMusic;
protected override void PopIn()
{

View File

@ -15,7 +15,7 @@ namespace osu.Game.Graphics.UserInterface.Volume
{
internal class VolumeMeter : Container
{
private Box meterFill;
private readonly Box meterFill;
public BindableDouble Bindable { get; } = new BindableDouble();
public VolumeMeter(string meterName)

View File

@ -18,7 +18,7 @@ namespace osu.Game.IO.Legacy
/// handle null strings and simplify use with ISerializable. </summary>
public class SerializationReader : BinaryReader
{
private Stream stream;
private readonly Stream stream;
public SerializationReader(Stream s)
: base(s, Encoding.UTF8)

View File

@ -10,7 +10,7 @@ namespace osu.Game.IPC
{
public class BeatmapIPCChannel : IpcChannel<BeatmapImportMessage>
{
private BeatmapDatabase beatmaps;
private readonly BeatmapDatabase beatmaps;
public BeatmapIPCChannel(IIpcHost host, BeatmapDatabase beatmaps = null)
: base(host)

View File

@ -10,7 +10,7 @@ namespace osu.Game.IPC
{
public class ScoreIPCChannel : IpcChannel<ScoreImportMessage>
{
private ScoreDatabase scores;
private readonly ScoreDatabase scores;
public ScoreIPCChannel(IIpcHost host, ScoreDatabase scores = null)
: base(host)

View File

@ -0,0 +1,94 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using osu.Framework.Allocation;
using osu.Framework.Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Transforms;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Modes.Objects.Drawables;
namespace osu.Game.Modes.Judgements
{
/// <summary>
/// A drawable object which visualises the hit result of a <see cref="JudgementInfo"/>.
/// </summary>
/// <typeparam name="TJudgement">The type of judgement to visualise.</typeparam>
public class DrawableJudgementInfo<TJudgement> : Container
where TJudgement : JudgementInfo
{
protected readonly TJudgement Judgement;
protected readonly SpriteText JudgementText;
/// <summary>
/// Creates a drawable which visualises a <see cref="JudgementInfo"/>.
/// </summary>
/// <param name="judgement">The judgement to visualise.</param>
public DrawableJudgementInfo(TJudgement judgement)
{
Judgement = judgement;
AutoSizeAxes = Axes.Both;
string scoreString = judgement.Result == HitResult.Hit ? judgement.ScoreString : judgement.Result.GetDescription();
Children = new[]
{
JudgementText = new OsuSpriteText
{
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
Text = scoreString.ToUpper(),
Font = @"Venera",
TextSize = 16
}
};
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
switch (Judgement.Result)
{
case HitResult.Miss:
Colour = colours.Red;
break;
}
}
protected override void LoadComplete()
{
base.LoadComplete();
FadeInFromZero(100, EasingTypes.OutQuint);
switch (Judgement.Result)
{
case HitResult.Miss:
ScaleTo(1.6f);
ScaleTo(1, 100, EasingTypes.In);
MoveToOffset(new Vector2(0, 100), 800, EasingTypes.InQuint);
RotateTo(40, 800, EasingTypes.InQuint);
Delay(600);
FadeOut(200);
break;
case HitResult.Hit:
ScaleTo(0.9f);
ScaleTo(1, 500, EasingTypes.OutElastic);
Delay(250);
FadeOut(250, EasingTypes.OutQuint);
break;
}
Expire();
}
}
}

View File

@ -5,10 +5,31 @@ using osu.Game.Modes.Objects.Drawables;
namespace osu.Game.Modes.Judgements
{
public class JudgementInfo
public abstract class JudgementInfo
{
public ulong? ComboAtHit;
/// <summary>
/// Whether this judgement is the result of a hit or a miss.
/// </summary>
public HitResult? Result;
/// <summary>
/// The offset at which this judgement occurred.
/// </summary>
public double TimeOffset;
/// <summary>
/// The combo after this judgement was processed.
/// </summary>
public ulong? ComboAtHit;
/// <summary>
/// The string representation for the score achieved.
/// </summary>
public abstract string ScoreString { get; }
/// <summary>
/// The string representation for the max score achievable.
/// </summary>
public abstract string MaxScoreString { get; }
}
}

View File

@ -8,10 +8,10 @@ namespace osu.Game.Modes.Objects
{
public class BezierApproximator
{
private int count;
private List<Vector2> controlPoints;
private Vector2[] subdivisionBuffer1;
private Vector2[] subdivisionBuffer2;
private readonly int count;
private readonly List<Vector2> controlPoints;
private readonly Vector2[] subdivisionBuffer1;
private readonly Vector2[] subdivisionBuffer2;
private const float tolerance = 0.25f;
private const float tolerance_sq = tolerance * tolerance;

View File

@ -10,9 +10,9 @@ namespace osu.Game.Modes.Objects
{
public class CircularArcApproximator
{
private Vector2 a;
private Vector2 b;
private Vector2 c;
private readonly Vector2 a;
private readonly Vector2 b;
private readonly Vector2 c;
private int amountPoints;

View File

@ -11,6 +11,7 @@ using osu.Game.Beatmaps.Samples;
using osu.Game.Modes.Judgements;
using Container = osu.Framework.Graphics.Containers.Container;
using osu.Game.Modes.Objects.Types;
using OpenTK.Graphics;
namespace osu.Game.Modes.Objects.Drawables
{
@ -38,6 +39,9 @@ namespace osu.Game.Modes.Objects.Drawables
return;
state = value;
if (!IsLoaded)
return;
UpdateState(state);
if (State == ArmedState.Hit)
@ -73,6 +77,11 @@ namespace osu.Game.Modes.Objects.Drawables
public TObject HitObject;
/// <summary>
/// The colour used for various elements of this DrawableHitObject.
/// </summary>
public Color4 AccentColour { get; protected set; }
protected DrawableHitObject(TObject hitObject)
{
HitObject = hitObject;

View File

@ -19,8 +19,8 @@ namespace osu.Game.Modes.Objects
public Vector2 Offset;
private List<Vector2> calculatedPath = new List<Vector2>();
private List<double> cumulativeLength = new List<double>();
private readonly List<Vector2> calculatedPath = new List<Vector2>();
private readonly List<double> cumulativeLength = new List<double>();
private List<Vector2> calculateSubpath(List<Vector2> subControlPoints)
{

View File

@ -21,9 +21,9 @@ namespace osu.Game.Modes
public abstract class Ruleset
{
private static ConcurrentDictionary<PlayMode, Type> availableRulesets = new ConcurrentDictionary<PlayMode, Type>();
private static readonly ConcurrentDictionary<PlayMode, Type> available_rulesets = new ConcurrentDictionary<PlayMode, Type>();
public static IEnumerable<PlayMode> PlayModes => availableRulesets.Keys;
public static IEnumerable<PlayMode> PlayModes => available_rulesets.Keys;
public virtual IEnumerable<BeatmapStatistic> GetBeatmapStatistics(WorkingBeatmap beatmap) => new BeatmapStatistic[] { };
@ -35,7 +35,7 @@ namespace osu.Game.Modes
public abstract ScoreProcessor CreateScoreProcessor();
public static void Register(Ruleset ruleset) => availableRulesets.TryAdd(ruleset.PlayMode, ruleset.GetType());
public static void Register(Ruleset ruleset) => available_rulesets.TryAdd(ruleset.PlayMode, ruleset.GetType());
protected abstract PlayMode PlayMode { get; }
@ -49,7 +49,7 @@ namespace osu.Game.Modes
{
Type type;
if (!availableRulesets.TryGetValue(mode, out type))
if (!available_rulesets.TryGetValue(mode, out type))
return null;
return Activator.CreateInstance(type) as Ruleset;

View File

@ -1,19 +1,63 @@
// 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 Newtonsoft.Json;
using osu.Game.Users;
using osu.Game.Database;
using osu.Game.Modes.Mods;
namespace osu.Game.Modes
{
public class Score
{
[JsonProperty(@"rank")]
public ScoreRank Rank { get; set; }
[JsonProperty(@"score")]
public double TotalScore { get; set; }
public double Accuracy { get; set; }
public double Health { get; set; }
[JsonProperty(@"maxcombo")]
public int MaxCombo { get; set; }
public int Combo { get; set; }
public Mod[] Mods { get; set; }
public User User { get; set; }
[JsonProperty(@"replay_data")]
public Replay Replay;
public BeatmapInfo Beatmap;
[JsonProperty(@"score_id")]
public long OnlineScoreID;
[JsonProperty(@"username")]
public string Username;
[JsonProperty(@"user_id")]
public long UserID;
[JsonProperty(@"date")]
public DateTime Date;
// [JsonProperty(@"count50")] 0,
//[JsonProperty(@"count100")] 0,
//[JsonProperty(@"count300")] 100,
//[JsonProperty(@"countmiss")] 0,
//[JsonProperty(@"countkatu")] 0,
//[JsonProperty(@"countgeki")] 31,
//[JsonProperty(@"perfect")] true,
//[JsonProperty(@"enabled_mods")] [
// "DT",
// "FL",
// "HD",
// "HR"
//],
//[JsonProperty(@"rank")] "XH",
//[JsonProperty(@"pp")] 26.1816,
//[JsonProperty(@"replay")] true
}
}

View File

@ -0,0 +1,29 @@
// 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.ComponentModel;
namespace osu.Game.Modes
{
public enum ScoreRank
{
[Description(@"F")]
F,
[Description(@"F")]
D,
[Description(@"C")]
C,
[Description(@"B")]
B,
[Description(@"A")]
A,
[Description(@"S")]
S,
[Description(@"SPlus")]
SH,
[Description(@"SS")]
X,
[Description(@"SSPlus")]
XH,
}
}

View File

@ -155,7 +155,7 @@ namespace osu.Game.Modes.UI
/// </summary>
protected Playfield<TObject, TJudgement> Playfield;
private Container content;
private readonly Container content;
protected HitRenderer(WorkingBeatmap beatmap)
: base(beatmap)

Some files were not shown because too many files have changed in this diff Show More