1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-12 11:42:54 +08:00

Add user interaction and stricter change validation rules

This commit is contained in:
Dean Herbert 2018-08-26 19:11:46 +09:00
parent 041d826396
commit e4ea802c7b
5 changed files with 129 additions and 45 deletions

View File

@ -3,6 +3,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Game.Tests.Visual; using osu.Game.Tests.Visual;
@ -21,6 +23,9 @@ namespace osu.Game.Tournament.Tests
typeof(DrawableTournamentTeam), typeof(DrawableTournamentTeam),
}; };
[Cached]
private Bindable<TournamentConditions> conditions = new Bindable<TournamentConditions>(new TournamentConditions { BestOf = 9 });
public TestCaseMatchPairings() public TestCaseMatchPairings()
{ {
FillFlowContainer<DrawableMatchPairing> level1; FillFlowContainer<DrawableMatchPairing> level1;
@ -30,8 +35,8 @@ namespace osu.Game.Tournament.Tests
new TournamentTeam { FlagName = "AU", FullName = "Australia", }, new TournamentTeam { FlagName = "AU", FullName = "Australia", },
new TournamentTeam { FlagName = "JP", FullName = "Japan", Acronym = "JPN" }) new TournamentTeam { FlagName = "JP", FullName = "Japan", Acronym = "JPN" })
{ {
Team1Score = { Value = 8 }, Team1Score = { Value = 4 },
Team2Score = { Value = 6 }, Team2Score = { Value = 1 },
}; };
var pairing2 = new MatchPairing( var pairing2 = new MatchPairing(
@ -76,21 +81,19 @@ namespace osu.Game.Tournament.Tests
level1.Children[0].Progression = level2.Children[0]; level1.Children[0].Progression = level2.Children[0];
level1.Children[1].Progression = level2.Children[0]; level1.Children[1].Progression = level2.Children[0];
AddStep("mark complete", () => pairing1.Completed.Value = true); AddRepeatStep("change scores", () => pairing1.Team2Score.Value++, 4);
AddRepeatStep("change scores", () => pairing1.Team2Score.Value++, 5);
AddStep("mark complete", () => pairing1.Completed.Value = true);
AddStep("add new team", () => pairing2.Team2.Value = new TournamentTeam { FlagName = "PT", FullName = "Portugal" }); AddStep("add new team", () => pairing2.Team2.Value = new TournamentTeam { FlagName = "PT", FullName = "Portugal" });
AddStep("Add progression", () => level1.Children[2].Progression = level2.Children[1]); AddStep("Add progression", () => level1.Children[2].Progression = level2.Children[1]);
AddStep("start match", () => pairing2.ResetScores()); AddStep("start match", () => pairing2.StartMatch());
AddRepeatStep("change scores", () => pairing2.Team1Score.Value++, 5); AddRepeatStep("change scores", () => pairing2.Team1Score.Value++, 10);
AddStep("mark complete", () => pairing2.Completed.Value = true);
AddStep("start submatch", () => level2.Children[0].Pairing.ResetScores()); AddStep("start submatch", () => level2.Children[0].Pairing.StartMatch());
AddRepeatStep("change scores", () => level2.Children[0].Pairing.Team1Score.Value++, 5); AddRepeatStep("change scores", () => level2.Children[0].Pairing.Team1Score.Value++, 5);
AddStep("mark complete", () => level2.Children[0].Pairing.Completed.Value = true);
AddRepeatStep("change scores", () => level2.Children[0].Pairing.Team2Score.Value++, 4);
} }
} }
} }

View File

@ -2,6 +2,8 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic; using System.Collections.Generic;
using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Lines; using osu.Framework.Graphics.Lines;
@ -14,9 +16,10 @@ namespace osu.Game.Tournament.Screens.Ladder.Components
{ {
public readonly MatchPairing Pairing; public readonly MatchPairing Pairing;
private readonly FillFlowContainer<DrawableMatchTeam> flow; private readonly FillFlowContainer<DrawableMatchTeam> flow;
private DrawableMatchPairing progression; private DrawableMatchPairing progression;
private readonly Bindable<TournamentConditions> conditions = new Bindable<TournamentConditions>();
private readonly Path path; private readonly Path path;
public DrawableMatchPairing Progression public DrawableMatchPairing Progression
@ -39,6 +42,51 @@ namespace osu.Game.Tournament.Screens.Ladder.Components
private const float line_width = 2; private const float line_width = 2;
public DrawableMatchPairing(MatchPairing pairing)
{
Pairing = pairing;
AutoSizeAxes = Axes.Both;
Margin = new MarginPadding(5);
InternalChildren = new Drawable[]
{
flow = new FillFlowContainer<DrawableMatchTeam>
{
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Vertical,
Spacing = new Vector2(2)
},
path = new Path
{
Alpha = 0,
BypassAutoSizeAxes = Axes.Both,
Anchor = Anchor.CentreRight,
PathWidth = line_width,
},
};
pairing.Team1.BindValueChanged(_ => updateTeams());
pairing.Team2.BindValueChanged(_ => updateTeams());
pairing.Team1Score.BindValueChanged(_ => updateWinConditions());
pairing.Team2Score.BindValueChanged(_ => updateWinConditions());
pairing.Completed.BindValueChanged(_ => updateProgression());
updateTeams();
}
[BackgroundDependencyLoader(true)]
private void load(Bindable<TournamentConditions> conditions)
{
this.conditions.BindValueChanged(_ => updateWinConditions());
if (conditions != null)
this.conditions.BindTo(conditions);
}
private void updateProgression() private void updateProgression()
{ {
if (progression == null) if (progression == null)
@ -83,37 +131,11 @@ namespace osu.Game.Tournament.Screens.Ladder.Components
destinationForWinner.Value = Pairing.Winner; destinationForWinner.Value = Pairing.Winner;
} }
public DrawableMatchPairing(MatchPairing pairing) private void updateWinConditions()
{ {
Pairing = pairing; if (conditions.Value == null) return;
AutoSizeAxes = Axes.Both; Pairing.Completed.Value = Pairing.Team1Score.Value + Pairing.Team2Score.Value >= conditions.Value.BestOf;
Margin = new MarginPadding(5);
InternalChildren = new Drawable[]
{
flow = new FillFlowContainer<DrawableMatchTeam>
{
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Vertical,
Spacing = new Vector2(2)
},
path = new Path
{
Alpha = 0,
BypassAutoSizeAxes = Axes.Both,
Anchor = Anchor.CentreRight,
PathWidth = line_width,
},
};
pairing.Team1.BindValueChanged(_ => updateTeams());
pairing.Team2.BindValueChanged(_ => updateTeams());
pairing.Completed.BindValueChanged(_ => updateProgression());
updateTeams();
} }
protected override void LoadComplete() protected override void LoadComplete()
@ -136,6 +158,9 @@ namespace osu.Game.Tournament.Screens.Ladder.Components
// todo: teams may need to be bindable for transitions at a later point. // todo: teams may need to be bindable for transitions at a later point.
if (Pairing.Team1.Value == null || Pairing.Team2.Value == null)
Pairing.CancelMatchStart();
flow.Children = new[] flow.Children = new[]
{ {
new DrawableMatchTeam(Pairing.Team1, Pairing), new DrawableMatchTeam(Pairing.Team1, Pairing),
@ -143,6 +168,7 @@ namespace osu.Game.Tournament.Screens.Ladder.Components
}; };
updateProgression(); updateProgression();
updateWinConditions();
} }
} }
} }

View File

@ -7,16 +7,20 @@ using osu.Framework.Configuration;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Input.EventArgs;
using osu.Framework.Input.States;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osu.Game.Tournament.Components; using osu.Game.Tournament.Components;
using OpenTK; using OpenTK;
using OpenTK.Graphics; using OpenTK.Graphics;
using OpenTK.Input;
namespace osu.Game.Tournament.Screens.Ladder.Components namespace osu.Game.Tournament.Screens.Ladder.Components
{ {
public class DrawableMatchTeam : DrawableTournamentTeam public class DrawableMatchTeam : DrawableTournamentTeam
{ {
private readonly MatchPairing pairing;
private OsuSpriteText scoreText; private OsuSpriteText scoreText;
private Box background; private Box background;
@ -31,6 +35,7 @@ namespace osu.Game.Tournament.Screens.Ladder.Components
public DrawableMatchTeam(TournamentTeam team, MatchPairing pairing) public DrawableMatchTeam(TournamentTeam team, MatchPairing pairing)
: base(team) : base(team)
{ {
this.pairing = pairing;
Size = new Vector2(150, 40); Size = new Vector2(150, 40);
Masking = true; Masking = true;
@ -48,7 +53,8 @@ namespace osu.Game.Tournament.Screens.Ladder.Components
isWinner = () => pairing.Winner == Team; isWinner = () => pairing.Winner == Team;
completed.BindTo(pairing.Completed); completed.BindTo(pairing.Completed);
score.BindTo(team == pairing.Team1.Value ? pairing.Team1Score : pairing.Team2Score); if (team != null)
score.BindTo(team == pairing.Team1.Value ? pairing.Team1Score : pairing.Team2Score);
} }
} }
@ -109,6 +115,30 @@ namespace osu.Game.Tournament.Screens.Ladder.Components
}, true); }, true);
} }
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
{
if (Team == null) return true;
if (args.Button == MouseButton.Left)
{
if (score.Value == null)
{
pairing.StartMatch();
}
else if (!pairing.Completed)
score.Value++;
}
else
{
if (score.Value > 0)
score.Value--;
else
pairing.CancelMatchStart();
}
return true;
}
private void updateWinStyle() private void updateWinStyle()
{ {
bool winner = completed && isWinner?.Invoke() == true; bool winner = completed && isWinner?.Invoke() == true;

View File

@ -23,15 +23,27 @@ namespace osu.Game.Tournament.Screens.Ladder.Components
{ {
Team1.Value = team1; Team1.Value = team1;
Team2.Value = team2; Team2.Value = team2;
Team1Score.ValueChanged += _ => Completed.Value = false;
Team2Score.ValueChanged += _ => Completed.Value = false;
} }
public TournamentTeam Winner => !Completed.Value ? null : (Team1Score.Value > Team2Score.Value ? Team1.Value : Team2.Value); public TournamentTeam Winner => !Completed.Value ? null : (Team1Score.Value > Team2Score.Value ? Team1.Value : Team2.Value);
public void ResetScores() /// <summary>
/// Remove scores from the match, in case of a false click or false start.
/// </summary>
public void CancelMatchStart()
{ {
Team1Score.Value = null;
Team2Score.Value = null;
}
/// <summary>
/// Initialise this match with zeroed scores. Will be a noop if either team is not present.
/// </summary>
public void StartMatch()
{
if (Team1.Value == null || Team2.Value == null)
return;
Team1Score.Value = 0; Team1Score.Value = 0;
Team2Score.Value = 0; Team2Score.Value = 0;
} }

View File

@ -0,0 +1,13 @@
namespace osu.Game.Tournament.Screens.Ladder.Components
{
/// <summary>
/// Conditions governing a tournament.
/// </summary>
public class TournamentConditions
{
/// <summary>
/// How many matches before a winner is decided.
/// </summary>
public int BestOf;
}
}