1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-15 18:45:37 +08:00

Merge pull request #517 from smoogipooo/taiko_playfield_2

Taiko Playfield Implementation
This commit is contained in:
Dan Balasescu 2017-03-23 15:43:59 +09:00 committed by GitHub
commit cb51256bd4
20 changed files with 814 additions and 108 deletions

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 TaikoHitObject())
{
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 TaikoHitObject())
{
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

@ -194,6 +194,7 @@
<Compile Include="Tests\TestCaseReplay.cs" /> <Compile Include="Tests\TestCaseReplay.cs" />
<Compile Include="Tests\TestCaseScoreCounter.cs" /> <Compile Include="Tests\TestCaseScoreCounter.cs" />
<Compile Include="Tests\TestCaseTabControl.cs" /> <Compile Include="Tests\TestCaseTabControl.cs" />
<Compile Include="Tests\TestCaseTaikoPlayfield.cs" />
<Compile Include="Tests\TestCaseTextAwesome.cs" /> <Compile Include="Tests\TestCaseTextAwesome.cs" />
<Compile Include="Tests\TestCasePlaySongSelect.cs" /> <Compile Include="Tests\TestCasePlaySongSelect.cs" />
<Compile Include="Tests\TestCaseTwoLayerButton.cs" /> <Compile Include="Tests\TestCaseTwoLayerButton.cs" />

View File

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

View File

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

View File

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

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

@ -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 readonly SpriteText line1;
private readonly 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

@ -85,7 +85,11 @@ namespace osu.Game.Modes.Osu.UI
public override void OnJudgement(DrawableHitObject<OsuHitObject, OsuJudgementInfo> judgedObject) 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); judgementLayer.Add(explosion);
} }

View File

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

View File

@ -1,11 +1,15 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.ComponentModel;
namespace osu.Game.Modes.Taiko.Judgements namespace osu.Game.Modes.Taiko.Judgements
{ {
public enum TaikoHitResult public enum TaikoHitResult
{ {
[Description("GOOD")]
Good, Good,
[Description("GREAT")]
Great Great
} }
} }

View File

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

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.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Game.Modes.Taiko.Objects; using osu.Game.Modes.Taiko.Objects;
using osu.Game.Modes.UI; using osu.Game.Modes.UI;
using OpenTK; using OpenTK;
using OpenTK.Graphics; using OpenTK.Graphics;
using osu.Game.Modes.Taiko.Judgements; 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 namespace osu.Game.Modes.Taiko.UI
{ {
public class TaikoPlayfield : Playfield<TaikoHitObject, TaikoJudgementInfo> 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() public TaikoPlayfield()
{ {
RelativeSizeAxes = Axes.X; RelativeSizeAxes = Axes.X;
Size = new Vector2(1, 100); Height = PlayfieldHeight;
Anchor = Anchor.Centre;
Origin = Anchor.Centre; 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] [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)
{ {
Texture = textures.Get(@"Menu/logo"), h.Depth = (float)h.HitObject.StartTime;
Origin = Anchor.Centre,
Scale = new Vector2(0.2f), base.Add(h);
RelativePositionAxes = Axes.Both, }
Position = new Vector2(0.1f, 0.5f),
Colour = Color4.Gray 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)
{
Anchor = wasHit ? Anchor.TopLeft : Anchor.CentreLeft,
Origin = wasHit ? Anchor.BottomCentre : Anchor.Centre,
RelativePositionAxes = Axes.X,
X = wasHit ? judgedObject.Position.X : 0,
}); });
} }
} }

View File

@ -59,6 +59,10 @@
<Compile Include="Objects\TaikoHitObject.cs" /> <Compile Include="Objects\TaikoHitObject.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="TaikoScoreProcessor.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\TaikoHitRenderer.cs" />
<Compile Include="UI\TaikoPlayfield.cs" /> <Compile Include="UI\TaikoPlayfield.cs" />
<Compile Include="TaikoRuleset.cs" /> <Compile Include="TaikoRuleset.cs" />
@ -76,10 +80,6 @@
<Project>{C76BF5B3-985E-4D39-95FE-97C9C879B83A}</Project> <Project>{C76BF5B3-985E-4D39-95FE-97C9C879B83A}</Project>
<Name>osu.Framework</Name> <Name>osu.Framework</Name>
</ProjectReference> </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"> <ProjectReference Include="..\osu.Game\osu.Game.csproj">
<Project>{0D3FBF8A-7464-4CF7-8C90-3E7886DF2D4D}</Project> <Project>{0D3FBF8A-7464-4CF7-8C90-3E7886DF2D4D}</Project>
<Name>osu.Game</Name> <Name>osu.Game</Name>

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 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; public HitResult? Result;
/// <summary>
/// The offset at which this judgement occurred.
/// </summary>
public double TimeOffset; 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

@ -96,6 +96,7 @@
<Compile Include="IO\Legacy\SerializationReader.cs" /> <Compile Include="IO\Legacy\SerializationReader.cs" />
<Compile Include="IO\Legacy\SerializationWriter.cs" /> <Compile Include="IO\Legacy\SerializationWriter.cs" />
<Compile Include="IPC\ScoreIPCChannel.cs" /> <Compile Include="IPC\ScoreIPCChannel.cs" />
<Compile Include="Modes\Judgements\DrawableJudgementInfo.cs" />
<Compile Include="Modes\LegacyReplay.cs" /> <Compile Include="Modes\LegacyReplay.cs" />
<Compile Include="Modes\Mods\IApplicableMod.cs" /> <Compile Include="Modes\Mods\IApplicableMod.cs" />
<Compile Include="Modes\Mods\ModType.cs" /> <Compile Include="Modes\Mods\ModType.cs" />