2019-01-24 16:43:03 +08:00
// 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.
2018-11-12 17:32:44 +08:00
using osu.Framework.Allocation ;
using osu.Framework.Graphics ;
2018-11-29 18:29:36 +08:00
using osu.Framework.Input ;
2018-11-13 13:13:29 +08:00
using osu.Framework.Input.Events ;
2018-11-12 17:32:44 +08:00
using osu.Game.Rulesets.Edit ;
using osu.Game.Rulesets.Mania.Objects ;
2018-11-19 17:40:16 +08:00
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces ;
2018-11-12 17:32:44 +08:00
using osu.Game.Rulesets.Mania.UI ;
using osu.Game.Rulesets.UI.Scrolling ;
2018-11-26 09:44:48 +08:00
using osuTK ;
2020-05-13 13:43:50 +08:00
using osuTK.Input ;
2018-11-12 17:32:44 +08:00
namespace osu.Game.Rulesets.Mania.Edit.Blueprints
{
2018-11-29 18:29:36 +08:00
public abstract class ManiaPlacementBlueprint < T > : PlacementBlueprint ,
IRequireHighFrequencyMousePosition // the playfield could be moving behind us
2018-11-12 17:32:44 +08:00
where T : ManiaHitObject
{
protected new T HitObject = > ( T ) base . HitObject ;
2018-11-29 18:29:36 +08:00
protected Column Column ;
2018-11-13 13:13:29 +08:00
/// <summary>
/// The current mouse position, snapped to the closest column.
/// </summary>
protected Vector2 SnappedMousePosition { get ; private set ; }
2018-11-19 17:40:16 +08:00
/// <summary>
/// The width of the closest column to the current mouse position.
/// </summary>
protected float SnappedWidth { get ; private set ; }
2018-11-12 17:32:44 +08:00
[Resolved]
2018-11-12 18:41:06 +08:00
private IManiaHitObjectComposer composer { get ; set ; }
2018-11-12 17:32:44 +08:00
[Resolved]
private IScrollingInfo scrollingInfo { get ; set ; }
2018-11-19 16:59:52 +08:00
protected ManiaPlacementBlueprint ( T hitObject )
2018-11-12 17:32:44 +08:00
: base ( hitObject )
{
RelativeSizeAxes = Axes . None ;
}
2018-11-29 18:29:36 +08:00
protected override bool OnMouseDown ( MouseDownEvent e )
{
2020-05-13 13:43:50 +08:00
if ( e . Button ! = MouseButton . Left )
return false ;
2018-11-29 18:29:36 +08:00
if ( Column = = null )
return base . OnMouseDown ( e ) ;
HitObject . Column = Column . Index ;
2020-04-23 11:05:34 +08:00
BeginPlacement ( TimeAt ( e . ScreenSpaceMousePosition ) , true ) ;
2018-11-29 18:29:36 +08:00
return true ;
}
2019-10-03 15:14:42 +08:00
public override void UpdatePosition ( Vector2 screenSpacePosition )
2018-11-13 13:13:29 +08:00
{
2020-02-13 08:03:48 +08:00
if ( ! PlacementActive )
2019-10-03 15:14:42 +08:00
Column = ColumnAt ( screenSpacePosition ) ;
2018-11-19 17:02:01 +08:00
2019-10-03 15:14:42 +08:00
if ( Column = = null ) return ;
2018-11-19 17:05:21 +08:00
2018-11-29 18:29:36 +08:00
SnappedWidth = Column . DrawWidth ;
2018-11-19 16:59:52 +08:00
2018-11-29 13:15:23 +08:00
// Snap to the column
2018-11-29 18:29:36 +08:00
var parentPos = Parent . ToLocalSpace ( Column . ToScreenSpace ( new Vector2 ( Column . DrawWidth / 2 , 0 ) ) ) ;
2019-10-03 15:14:42 +08:00
SnappedMousePosition = new Vector2 ( parentPos . X , Parent . ToLocalSpace ( screenSpacePosition ) . Y ) ;
2018-11-13 13:13:29 +08:00
}
2018-11-12 17:32:44 +08:00
protected double TimeAt ( Vector2 screenSpacePosition )
{
2018-11-29 18:29:36 +08:00
if ( Column = = null )
2018-11-12 17:32:44 +08:00
return 0 ;
2018-11-29 18:29:36 +08:00
var hitObjectContainer = Column . HitObjectContainer ;
2018-11-12 18:40:57 +08:00
// If we're scrolling downwards, a position of 0 is actually further away from the hit target
// so we need to flip the vertical coordinate in the hitobject container's space
2019-10-03 17:27:39 +08:00
var hitObjectPos = mouseToHitObjectPosition ( Column . HitObjectContainer . ToLocalSpace ( screenSpacePosition ) ) . Y ;
2018-11-12 18:40:57 +08:00
if ( scrollingInfo . Direction . Value = = ScrollingDirection . Down )
hitObjectPos = hitObjectContainer . DrawHeight - hitObjectPos ;
return scrollingInfo . Algorithm . TimeAt ( hitObjectPos ,
2018-11-12 17:32:44 +08:00
EditorClock . CurrentTime ,
scrollingInfo . TimeRange . Value ,
2018-11-12 18:40:57 +08:00
hitObjectContainer . DrawHeight ) ;
2018-11-12 17:32:44 +08:00
}
2018-11-29 18:29:36 +08:00
protected float PositionAt ( double time )
{
var pos = scrollingInfo . Algorithm . PositionAt ( time ,
EditorClock . CurrentTime ,
scrollingInfo . TimeRange . Value ,
Column . HitObjectContainer . DrawHeight ) ;
2019-10-03 17:23:13 +08:00
if ( scrollingInfo . Direction . Value = = ScrollingDirection . Down )
pos = Column . HitObjectContainer . DrawHeight - pos ;
2019-10-03 17:27:39 +08:00
return hitObjectToMousePosition ( Column . HitObjectContainer . ToSpaceOfOtherDrawable ( new Vector2 ( 0 , pos ) , Parent ) ) . Y ;
2018-11-29 18:29:36 +08:00
}
2018-11-12 17:32:44 +08:00
protected Column ColumnAt ( Vector2 screenSpacePosition )
2019-10-03 17:22:06 +08:00
= > composer . ColumnAt ( screenSpacePosition ) ;
2018-11-12 17:32:44 +08:00
2019-10-03 17:27:39 +08:00
/// <summary>
/// Converts a mouse position to a hitobject position.
/// </summary>
/// <remarks>
/// Blueprints are centred on the mouse position, such that the hitobject position is anchored at the top or bottom of the blueprint depending on the scroll direction.
/// </remarks>
/// <param name="mousePosition">The mouse position.</param>
/// <returns>The resulting hitobject position, acnhored at the top or bottom of the blueprint depending on the scroll direction.</returns>
private Vector2 mouseToHitObjectPosition ( Vector2 mousePosition )
2018-11-12 17:32:44 +08:00
{
2019-10-03 17:21:50 +08:00
switch ( scrollingInfo . Direction . Value )
{
case ScrollingDirection . Up :
2020-03-31 14:29:25 +08:00
mousePosition . Y - = DefaultNotePiece . NOTE_HEIGHT / 2 ;
2019-10-03 17:21:50 +08:00
break ;
case ScrollingDirection . Down :
2020-03-31 14:29:25 +08:00
mousePosition . Y + = DefaultNotePiece . NOTE_HEIGHT / 2 ;
2019-10-03 17:21:50 +08:00
break ;
}
2019-10-03 17:27:39 +08:00
return mousePosition ;
}
/// <summary>
/// Converts a hitobject position to a mouse position.
/// </summary>
/// <param name="hitObjectPosition">The hitobject position.</param>
/// <returns>The resulting mouse position, anchored at the centre of the hitobject.</returns>
private Vector2 hitObjectToMousePosition ( Vector2 hitObjectPosition )
{
switch ( scrollingInfo . Direction . Value )
{
case ScrollingDirection . Up :
2020-03-31 14:29:25 +08:00
hitObjectPosition . Y + = DefaultNotePiece . NOTE_HEIGHT / 2 ;
2019-10-03 17:27:39 +08:00
break ;
case ScrollingDirection . Down :
2020-03-31 14:29:25 +08:00
hitObjectPosition . Y - = DefaultNotePiece . NOTE_HEIGHT / 2 ;
2019-10-03 17:27:39 +08:00
break ;
}
2019-10-03 17:21:50 +08:00
2019-10-03 17:27:39 +08:00
return hitObjectPosition ;
2018-11-12 17:32:44 +08:00
}
}
}