mirror of
https://github.com/osukey/osukey.git
synced 2025-08-04 07:06:35 +09:00
Merge pull request #13983 from ekrctb/juice-stream-placement
Add initial implementation of juice stream placement
This commit is contained in:
@ -0,0 +1,49 @@
|
||||
// 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 osu.Game.Rulesets.Catch.Objects;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Edit.Blueprints.Components
|
||||
{
|
||||
public class PlacementEditablePath : EditablePath
|
||||
{
|
||||
/// <summary>
|
||||
/// The original position of the last added vertex.
|
||||
/// This is not same as the last vertex of the current path because the vertex ordering can change.
|
||||
/// </summary>
|
||||
private JuiceStreamPathVertex lastVertex;
|
||||
|
||||
public PlacementEditablePath(Func<float, double> positionToDistance)
|
||||
: base(positionToDistance)
|
||||
{
|
||||
}
|
||||
|
||||
public void AddNewVertex()
|
||||
{
|
||||
var endVertex = Vertices[^1];
|
||||
int index = AddVertex(endVertex.Distance, endVertex.X);
|
||||
|
||||
for (int i = 0; i < VertexCount; i++)
|
||||
{
|
||||
VertexStates[i].IsSelected = i == index;
|
||||
VertexStates[i].IsFixed = i != index;
|
||||
VertexStates[i].VertexBeforeChange = Vertices[i];
|
||||
}
|
||||
|
||||
lastVertex = Vertices[index];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Move the vertex added by <see cref="AddNewVertex"/> in the last time.
|
||||
/// </summary>
|
||||
public void MoveLastVertex(Vector2 screenSpacePosition)
|
||||
{
|
||||
Vector2 position = ToRelativePosition(screenSpacePosition);
|
||||
double distanceDelta = PositionToDistance(position.Y) - lastVertex.Distance;
|
||||
float xDelta = position.X - lastVertex.X;
|
||||
MoveSelectedVertices(distanceDelta, xDelta);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,128 @@
|
||||
// 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 osu.Framework.Graphics;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Rulesets.Catch.Edit.Blueprints.Components;
|
||||
using osu.Game.Rulesets.Catch.Objects;
|
||||
using osu.Game.Rulesets.Edit;
|
||||
using osuTK;
|
||||
using osuTK.Input;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Edit.Blueprints
|
||||
{
|
||||
public class JuiceStreamPlacementBlueprint : CatchPlacementBlueprint<JuiceStream>
|
||||
{
|
||||
private readonly ScrollingPath scrollingPath;
|
||||
|
||||
private readonly NestedOutlineContainer nestedOutlineContainer;
|
||||
|
||||
private readonly PlacementEditablePath editablePath;
|
||||
|
||||
private int lastEditablePathId = -1;
|
||||
|
||||
private InputManager inputManager;
|
||||
|
||||
public JuiceStreamPlacementBlueprint()
|
||||
{
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
scrollingPath = new ScrollingPath(),
|
||||
nestedOutlineContainer = new NestedOutlineContainer(),
|
||||
editablePath = new PlacementEditablePath(positionToDistance)
|
||||
};
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
if (PlacementActive == PlacementState.Active)
|
||||
editablePath.UpdateFrom(HitObjectContainer, HitObject);
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
inputManager = GetContainingInputManager();
|
||||
}
|
||||
|
||||
protected override bool OnMouseDown(MouseDownEvent e)
|
||||
{
|
||||
switch (PlacementActive)
|
||||
{
|
||||
case PlacementState.Waiting:
|
||||
if (e.Button != MouseButton.Left) break;
|
||||
|
||||
editablePath.AddNewVertex();
|
||||
BeginPlacement(true);
|
||||
return true;
|
||||
|
||||
case PlacementState.Active:
|
||||
switch (e.Button)
|
||||
{
|
||||
case MouseButton.Left:
|
||||
editablePath.AddNewVertex();
|
||||
return true;
|
||||
|
||||
case MouseButton.Right:
|
||||
EndPlacement(HitObject.Duration > 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return base.OnMouseDown(e);
|
||||
}
|
||||
|
||||
public override void UpdateTimeAndPosition(SnapResult result)
|
||||
{
|
||||
switch (PlacementActive)
|
||||
{
|
||||
case PlacementState.Waiting:
|
||||
if (!(result.Time is double snappedTime)) return;
|
||||
|
||||
HitObject.OriginalX = ToLocalSpace(result.ScreenSpacePosition).X;
|
||||
HitObject.StartTime = snappedTime;
|
||||
break;
|
||||
|
||||
case PlacementState.Active:
|
||||
Vector2 unsnappedPosition = inputManager.CurrentState.Mouse.Position;
|
||||
editablePath.MoveLastVertex(unsnappedPosition);
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure the up-to-date position is used for outlines.
|
||||
Vector2 startPosition = CatchHitObjectUtils.GetStartPosition(HitObjectContainer, HitObject);
|
||||
editablePath.Position = nestedOutlineContainer.Position = scrollingPath.Position = startPosition;
|
||||
|
||||
updateHitObjectFromPath();
|
||||
}
|
||||
|
||||
private void updateHitObjectFromPath()
|
||||
{
|
||||
if (lastEditablePathId == editablePath.PathId)
|
||||
return;
|
||||
|
||||
editablePath.UpdateHitObjectFromPath(HitObject);
|
||||
ApplyDefaultsToHitObject();
|
||||
|
||||
scrollingPath.UpdatePathFrom(HitObjectContainer, HitObject);
|
||||
nestedOutlineContainer.UpdateNestedObjectsFrom(HitObjectContainer, HitObject);
|
||||
|
||||
lastEditablePathId = editablePath.PathId;
|
||||
}
|
||||
|
||||
private double positionToDistance(float relativeYPosition)
|
||||
{
|
||||
double time = HitObjectContainer.TimeAtPosition(relativeYPosition, HitObject.StartTime);
|
||||
return (time - HitObject.StartTime) * HitObject.Velocity;
|
||||
}
|
||||
}
|
||||
}
|
@ -38,6 +38,7 @@ namespace osu.Game.Rulesets.Catch.Edit
|
||||
protected override IReadOnlyList<HitObjectCompositionTool> CompositionTools => new HitObjectCompositionTool[]
|
||||
{
|
||||
new FruitCompositionTool(),
|
||||
new JuiceStreamCompositionTool(),
|
||||
new BananaShowerCompositionTool()
|
||||
};
|
||||
|
||||
|
24
osu.Game.Rulesets.Catch/Edit/JuiceStreamCompositionTool.cs
Normal file
24
osu.Game.Rulesets.Catch/Edit/JuiceStreamCompositionTool.cs
Normal file
@ -0,0 +1,24 @@
|
||||
// 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 osu.Framework.Graphics;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Catch.Edit.Blueprints;
|
||||
using osu.Game.Rulesets.Catch.Objects;
|
||||
using osu.Game.Rulesets.Edit;
|
||||
using osu.Game.Rulesets.Edit.Tools;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Edit
|
||||
{
|
||||
public class JuiceStreamCompositionTool : HitObjectCompositionTool
|
||||
{
|
||||
public JuiceStreamCompositionTool()
|
||||
: base(nameof(JuiceStream))
|
||||
{
|
||||
}
|
||||
|
||||
public override Drawable CreateIcon() => new BeatmapStatisticIcon(BeatmapStatisticsIconType.Sliders);
|
||||
|
||||
public override PlacementBlueprint CreatePlacementBlueprint() => new JuiceStreamPlacementBlueprint();
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user