1
0
mirror of https://github.com/ppy/osu.git synced 2024-09-22 03:27:24 +08:00
osu-lazer/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs

134 lines
5.6 KiB
C#

// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Collections.Generic;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Input;
using osu.Framework.Input.Bindings;
using osu.Framework.Input.Events;
using osu.Game.Graphics;
using osuTK;
namespace osu.Game.Rulesets.Taiko.UI
{
/// <summary>
/// An overlay that captures and displays Taiko mouse and touch input.
/// The boundaries of this overlay defines the interactable area for touch input.
/// A secondary InputDrum is attached by this overlay, which defines the circulary boundary which distinguishes "centre" from "rim" hits, and also displays input.
/// </summary>
public class DrumTouchInputArea : Container
{
// The percent of the drum that extends past the bottom of the screen (set to 0.0f to show the full drum)
private const float overhangPercent = 0.35f;
private InputDrum touchInputDrum;
private Circle drumBackground;
private KeyBindingContainer<TaikoAction> keyBindingContainer;
// Which Taiko action was pressed by the last OnMouseDown event, so that the corresponding action can be released OnMouseUp even if the cursor position moved
private TaikoAction mouseAction;
// A map of (Finger Index OnTouchDown -> Which Taiko action was pressed), so that the corresponding action can be released OnTouchUp is released even if the touch position moved
private Dictionary<TouchSource, TaikoAction> touchActions = new Dictionary<TouchSource, TaikoAction>(Enum.GetNames(typeof(TouchSource)).Length);
public DrumTouchInputArea() {
RelativeSizeAxes = Axes.Both;
RelativePositionAxes = Axes.Both;
Children = new Drawable[]
{
new Container() {
RelativeSizeAxes = Axes.Both,
RelativePositionAxes = Axes.Both,
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
Children = new Drawable[]
{
drumBackground = new Circle() {
RelativeSizeAxes = Axes.Both,
RelativePositionAxes = Axes.Both,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
FillMode = FillMode.Fit,
Alpha = 0.9f,
},
touchInputDrum = new InputDrum() {
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
},
}
},
};
}
protected override void LoadComplete()
{
Padding = new MarginPadding {
Top = TaikoPlayfield.DEFAULT_HEIGHT * 2f, // Visual elements should start right below the playfield
Bottom = -touchInputDrum.DrawHeight * overhangPercent, // The drum should go past the bottom of the screen so that it can be wider
};
}
[BackgroundDependencyLoader]
private void load(TaikoInputManager taikoInputManager, OsuColour colours)
{
keyBindingContainer = taikoInputManager?.KeyBindingContainer;
drumBackground.Colour = colours.Gray0;
}
protected override bool OnMouseDown(MouseDownEvent e)
{
mouseAction = getTaikoActionFromInput(e.ScreenSpaceMouseDownPosition);
keyBindingContainer?.TriggerPressed(mouseAction);
return true;
}
protected override void OnMouseUp(MouseUpEvent e)
{
keyBindingContainer?.TriggerReleased(mouseAction);
base.OnMouseUp(e);
}
protected override bool OnTouchDown(TouchDownEvent e)
{
TaikoAction taikoAction = getTaikoActionFromInput(e.ScreenSpaceTouchDownPosition);
touchActions.Add(e.Touch.Source, taikoAction);
keyBindingContainer?.TriggerPressed(touchActions[e.Touch.Source]);
return true;
}
protected override void OnTouchUp(TouchUpEvent e)
{
keyBindingContainer?.TriggerReleased(touchActions[e.Touch.Source]);
touchActions.Remove(e.Touch.Source);
base.OnTouchUp(e);
}
private TaikoAction getTaikoActionFromInput(Vector2 inputPosition) {
bool centreHit = inputIsCenterHit(inputPosition);
bool leftSide = inputIsOnLeftSide(inputPosition);
return centreHit ?
(leftSide ? TaikoAction.LeftCentre : TaikoAction.RightCentre) :
(leftSide ? TaikoAction.LeftRim : TaikoAction.RightRim);
}
private bool inputIsOnLeftSide(Vector2 inputPosition) {
Vector2 inputPositionToDrumCentreDelta = touchInputDrum.ToLocalSpace(inputPosition) - touchInputDrum.OriginPosition;
return inputPositionToDrumCentreDelta.X < 0f;
}
private bool inputIsCenterHit(Vector2 inputPosition) {
Vector2 inputPositionToDrumCentreDelta = touchInputDrum.ToLocalSpace(inputPosition) - touchInputDrum.OriginPosition;
float inputDrumRadius = Math.Max(touchInputDrum.Width, touchInputDrum.DrawHeight) / 2f;
float centreRadius = (inputDrumRadius * InputDrum.centre_size);
return inputPositionToDrumCentreDelta.Length <= centreRadius;
}
}
}