osu icon indicating copy to clipboard operation
osu copied to clipboard

Allow hitobject placement while song is playing (live mapping)

Open nodingneu opened this issue 6 years ago • 8 comments

In addition to the current beatmap editor, allow beatmap creators to play the song over a blank beatmap, and when they click it puts a circle there, and when they click and drag it puts a slider there.

I think this could be a much more fun and easy way to create beatmaps, definitely in the beginning.

Maybe once all the sliders and circles are put using this method, their positions can be fine-tuned (and combos can be chosen etc.) in the traditional editor.

Also, alternatively/additionally, combos etc. and other features could be handled via key binds in this "fast" editor.


Basic features I think would be useful:

  • quantization (and you can choose the timings)
  • setting for "smoothness" of sliders
  • based on the setting, automatically place sharp bends and reverse arrows
  • also provided key binds, for sharp bends in sliders, and reverse arrows

nodingneu avatar Oct 25 '19 16:10 nodingneu

I support this.

TsavyPrince avatar Oct 25 '19 16:10 TsavyPrince

This is called live mapping. I believe it is supported in stable and will also come to lazer eventually.

peppy avatar Oct 25 '19 22:10 peppy

Will this be standard only?

enoslayd avatar Oct 26 '19 05:10 enoslayd

Editor features will be present in all bundled rulesets.

peppy avatar Oct 26 '19 05:10 peppy

Has this been added to Lazer yet? Was trying to map a song and wanted to see if it made it in before I opened a request for it.

ViRiXDreamcore avatar Aug 11 '23 06:08 ViRiXDreamcore

Has this been added to Lazer yet? Was trying to map a song and wanted to see if it made it in before I opened a request for it.

Doesn't seem like it.

D-Maxwell avatar Jan 31 '24 19:01 D-Maxwell

IMO this is more important than any other type of editor. If osu! only had one way to create maps, it should be live mapping.

nodingneu avatar Feb 14 '24 07:02 nodingneu

You can basically do this now? Have you tried?

peppy avatar Feb 14 '24 19:02 peppy

I think this should be closed, live mapping is possible.

https://github.com/ppy/osu/assets/104220939/b878b15e-2e9f-4f73-8905-f3e33bae68c4

snalgae avatar Jul 06 '24 15:07 snalgae

The title is kind of misleading. "Live mapping" in stable uses keyboard bindings (instead of mouse) to place circles (ref: https://osu.ppy.sh/wiki/en/Client/Beatmap_editor/Menu#compose). Stable also doesn't support slider placement, which OP also wanted and can be exclusive to lazer.

TL;DR (or in a different way to say it):

  • use keyboard bindings to place circles, and when holding key and dragging, place a slider instead (i.e. automatically switch to slider mode drawing)
  • probably also add the hold and drag behavior to mouse
  • decide whether this should be a toggle (to not conflict existing editor keybinds) or make it work and have it always default behavior

Joehuu avatar Jul 06 '24 19:07 Joehuu

Tried to do a barebones implementation of this for taiko and hit a few walls.

diff --git a/osu.Game.Rulesets.Taiko/Edit/DrawableTaikoEditorRuleset.cs b/osu.Game.Rulesets.Taiko/Edit/DrawableTaikoEditorRuleset.cs
index 217bb8139c..f206130dd2 100644
--- a/osu.Game.Rulesets.Taiko/Edit/DrawableTaikoEditorRuleset.cs
+++ b/osu.Game.Rulesets.Taiko/Edit/DrawableTaikoEditorRuleset.cs
@@ -2,6 +2,7 @@
 // See the LICENCE file in the repository root for full licence text.
 
 using System.Collections.Generic;
+using osu.Framework.Allocation;
 using osu.Framework.Bindables;
 using osu.Game.Beatmaps;
 using osu.Game.Configuration;
@@ -20,6 +21,12 @@ public DrawableTaikoEditorRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyLi
         {
         }
 
+        [BackgroundDependencyLoader]
+        private void load()
+        {
+            KeyBindingInputManager.Add(new TaikoLiveMapper());
+        }
+
         protected override void LoadComplete()
         {
             base.LoadComplete();
diff --git a/osu.Game.Rulesets.Taiko/Edit/TaikoLiveMapper.cs b/osu.Game.Rulesets.Taiko/Edit/TaikoLiveMapper.cs
new file mode 100644
index 0000000000..c3a0092695
--- /dev/null
+++ b/osu.Game.Rulesets.Taiko/Edit/TaikoLiveMapper.cs
@@ -0,0 +1,68 @@
+// Copyright (c) ppy Pty Ltd <[email protected]>. Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System.Linq;
+using osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Framework.Input.Bindings;
+using osu.Framework.Input.Events;
+using osu.Game.Rulesets.Edit;
+using osu.Game.Rulesets.Taiko.Objects;
+using osu.Game.Screens.Edit;
+
+namespace osu.Game.Rulesets.Taiko.Edit
+{
+    public partial class TaikoLiveMapper : Component, IKeyBindingHandler<TaikoAction>
+    {
+        [Resolved]
+        private EditorBeatmap editorBeatmap { get; set; } = null!;
+
+        [Resolved]
+        private IBeatSnapProvider beatSnapProvider { get; set; } = null!;
+
+        [Resolved]
+        private EditorClock editorClock { get; set; } = null!;
+
+        public bool OnPressed(KeyBindingPressEvent<TaikoAction> e)
+        {
+            if (e.Repeat)
+                return false;
+
+            double quantisedTime = beatSnapProvider.SnapTime(editorClock.CurrentTime);
+
+            var existing = editorBeatmap.HitObjects.FirstOrDefault(h => h.StartTime == quantisedTime);
+
+            switch (existing)
+            {
+                case Hit hit:
+                {
+                    if ((hit.Type == HitType.Centre && (e.Action == TaikoAction.LeftCentre || e.Action == TaikoAction.RightCentre)) ||
+                        (hit.Type == HitType.Rim && (e.Action == TaikoAction.LeftRim || e.Action == TaikoAction.RightRim)))
+                    {
+                        hit.IsStrong = true;
+                    }
+
+                    return true;
+                }
+
+                case null:
+                {
+                    editorBeatmap.Add(new Hit
+                    {
+                        Type = e.Action == TaikoAction.LeftCentre || e.Action == TaikoAction.RightCentre ? HitType.Centre : HitType.Rim,
+                        StartTime = quantisedTime
+                    });
+
+                    return true;
+                }
+
+                default:
+                    return false;
+            }
+        }
+
+        public void OnReleased(KeyBindingReleaseEvent<TaikoAction> e)
+        {
+        }
+    }
+}
diff --git a/osu.Game/Rulesets/Edit/DrawableEditorRulesetWrapper.cs b/osu.Game/Rulesets/Edit/DrawableEditorRulesetWrapper.cs
index 174b278d89..04fcad4262 100644
--- a/osu.Game/Rulesets/Edit/DrawableEditorRulesetWrapper.cs
+++ b/osu.Game/Rulesets/Edit/DrawableEditorRulesetWrapper.cs
@@ -68,7 +68,7 @@ protected override void LoadComplete()
         private void regenerateAutoplay()
         {
             var autoplayMod = drawableRuleset.Mods.OfType<ModAutoplay>().Single();
-            drawableRuleset.SetReplayScore(autoplayMod.CreateScoreFromReplayData(drawableRuleset.Beatmap, drawableRuleset.Mods));
+            //drawableRuleset.SetReplayScore(autoplayMod.CreateScoreFromReplayData(drawableRuleset.Beatmap, drawableRuleset.Mods));
         }
 
         private void addHitObject(HitObject hitObject)
@@ -85,7 +85,7 @@ private void removeHitObject(HitObject hitObject)
 
         public override bool PropagatePositionalInputSubTree => false;
 
-        public override bool PropagateNonPositionalInputSubTree => false;
+        //public override bool PropagateNonPositionalInputSubTree => false;
 
         public PlayfieldAdjustmentContainer CreatePlayfieldAdjustmentContainer() => drawableRuleset.CreatePlayfieldAdjustmentContainer();
 
  • To listen to user bindings the TaikoLiveMapper has to be under a RulesetInputManager. Instantiating one is currently not obvious, and attempting to reuse existing...
  • requires both autoplay replays (which power simulation of gameplay during playback) to be disabled and for the PropagateNonPositionalInput override to be gone.
  • Also there are keybinding priority conflicts; with this patch only the left default bindings work, the right ones are eaten by timeline.

The play here is probably to make instantiating the ruleset input manager easier. I can't imagine trying to jam the live mapper in the only current viable place is going to be nice or easy.

bdach avatar Jul 24 '24 21:07 bdach