@@ -1,5 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using Ichni.Editor;
|
||||
using Ichni.Editor.Commands;
|
||||
using Ichni.RhythmGame.ThemeBundles.DepartureToMultiverse;
|
||||
using UnityEngine;
|
||||
|
||||
@@ -7,7 +9,7 @@ namespace Ichni.RhythmGame
|
||||
{
|
||||
public partial class ElementFolder
|
||||
{
|
||||
private void QuickCopy(Vector3 unitPositionOffset, Vector3 unitRotationOffset, Vector3 unitScaleOffset, float unitTimeOffset, int iteration = 1)
|
||||
private void QuickCopy(Vector3 unitPositionOffset, Vector3 unitRotationOffset, Vector3 unitScaleOffset, float unitTimeOffset, int iteration = 1, QuickCopyDisturbanceSettings disturbance = default)
|
||||
{
|
||||
if (iteration <= 0) return;
|
||||
|
||||
@@ -17,6 +19,14 @@ namespace Ichni.RhythmGame
|
||||
return;
|
||||
}
|
||||
|
||||
CommandManager.ExecuteCommand(new CreateElementsCommand(() =>
|
||||
QuickCopyRaw(unitPositionOffset, unitRotationOffset, unitScaleOffset, unitTimeOffset, iteration, disturbance)));
|
||||
}
|
||||
|
||||
private List<GameElement> QuickCopyRaw(Vector3 unitPositionOffset, Vector3 unitRotationOffset, Vector3 unitScaleOffset, float unitTimeOffset, int iteration, QuickCopyDisturbanceSettings disturbance)
|
||||
{
|
||||
disturbance = disturbance ?? QuickCopyDisturbanceSettings.None;
|
||||
List<GameElement> createdFolders = new List<GameElement>();
|
||||
CopyPasteDeleteModule cpd = EditorManager.instance.operationManager.CopyPasteDeleteModule;
|
||||
cpd.CopyElement(this);
|
||||
|
||||
@@ -24,11 +34,12 @@ namespace Ichni.RhythmGame
|
||||
{
|
||||
ElementFolder newFolder = cpd.PasteElementRaw(this, parentElement) as ElementFolder;
|
||||
if (newFolder == null) continue;
|
||||
createdFolders.Add(newFolder);
|
||||
|
||||
Vector3 positionOffset = unitPositionOffset * i;
|
||||
Vector3 rotationOffset = unitRotationOffset * i;
|
||||
Vector3 scaleOffset = unitScaleOffset * i;
|
||||
float timeOffset = unitTimeOffset * i;
|
||||
Vector3 positionOffset = unitPositionOffset * i + disturbance.SamplePosition();
|
||||
Vector3 rotationOffset = unitRotationOffset * i + disturbance.SampleRotation();
|
||||
Vector3 scaleOffset = unitScaleOffset * i + disturbance.SampleScale();
|
||||
float timeOffset = unitTimeOffset * i + disturbance.SampleTime();
|
||||
|
||||
newFolder.ApplyFolderPositionOffset(positionOffset);
|
||||
newFolder.ApplyFolderRotationOffset(rotationOffset);
|
||||
@@ -38,6 +49,7 @@ namespace Ichni.RhythmGame
|
||||
}
|
||||
|
||||
cpd.pastedElementList?.Clear();
|
||||
return createdFolders;
|
||||
}
|
||||
|
||||
private void ApplyFolderPositionOffset(Vector3 positionOffset)
|
||||
@@ -196,4 +208,120 @@ namespace Ichni.RhythmGame
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class QuickCopyDisturbanceSettings
|
||||
{
|
||||
public static QuickCopyDisturbanceSettings None => new QuickCopyDisturbanceSettings();
|
||||
|
||||
public Vector3 positionLower;
|
||||
public Vector3 positionUpper;
|
||||
public Vector3 rotationLower;
|
||||
public Vector3 rotationUpper;
|
||||
public Vector3 scaleLower;
|
||||
public Vector3 scaleUpper;
|
||||
public float timeLower;
|
||||
public float timeUpper;
|
||||
|
||||
public Vector3 SamplePosition() => SampleVector(positionLower, positionUpper);
|
||||
public Vector3 SampleRotation() => SampleVector(rotationLower, rotationUpper);
|
||||
public Vector3 SampleScale() => SampleVector(scaleLower, scaleUpper);
|
||||
public float SampleTime() => SampleFloat(timeLower, timeUpper);
|
||||
|
||||
private static Vector3 SampleVector(Vector3 lower, Vector3 upper)
|
||||
{
|
||||
return new Vector3(
|
||||
SampleFloat(lower.x, upper.x),
|
||||
SampleFloat(lower.y, upper.y),
|
||||
SampleFloat(lower.z, upper.z));
|
||||
}
|
||||
|
||||
private static float SampleFloat(float lower, float upper)
|
||||
{
|
||||
float min = Mathf.Min(lower, upper);
|
||||
float max = Mathf.Max(lower, upper);
|
||||
return Mathf.Approximately(min, max) ? min : UnityEngine.Random.Range(min, max);
|
||||
}
|
||||
}
|
||||
|
||||
internal static class QuickCopyDisturbanceWindow
|
||||
{
|
||||
public static void Show(GameElement owner, string title, QuickCopyDisturbanceSettings settings)
|
||||
{
|
||||
InspectorSecondaryWindow window = EditorManager.instance.uiManager.inspector.GenerateSecondaryWindow(owner, title);
|
||||
IHaveInspection windowInspection = window;
|
||||
DynamicUIContainer container = windowInspection.GenerateContainer("Settings");
|
||||
|
||||
settings ??= QuickCopyDisturbanceSettings.None;
|
||||
|
||||
DynamicUIVector3InputField positionLower = windowInspection.GenerateVector3InputField(container.GenerateSubcontainer(1), "Position Lower", settings.positionLower);
|
||||
DynamicUIVector3InputField positionUpper = windowInspection.GenerateVector3InputField(container.GenerateSubcontainer(1), "Position Upper", settings.positionUpper);
|
||||
DynamicUIVector3InputField rotationLower = windowInspection.GenerateVector3InputField(container.GenerateSubcontainer(1), "Rotation Lower", settings.rotationLower);
|
||||
DynamicUIVector3InputField rotationUpper = windowInspection.GenerateVector3InputField(container.GenerateSubcontainer(1), "Rotation Upper", settings.rotationUpper);
|
||||
DynamicUIVector3InputField scaleLower = windowInspection.GenerateVector3InputField(container.GenerateSubcontainer(1), "Scale Lower", settings.scaleLower);
|
||||
DynamicUIVector3InputField scaleUpper = windowInspection.GenerateVector3InputField(container.GenerateSubcontainer(1), "Scale Upper", settings.scaleUpper);
|
||||
|
||||
DynamicUISubcontainer timeSub = container.GenerateSubcontainer(2);
|
||||
DynamicUIInputField timeLower = windowInspection.GenerateInputField(timeSub, "Time Lower", settings.timeLower.ToString());
|
||||
DynamicUIInputField timeUpper = windowInspection.GenerateInputField(timeSub, "Time Upper", settings.timeUpper.ToString());
|
||||
|
||||
BindVector3(positionLower, value => settings.positionLower = value);
|
||||
BindVector3(positionUpper, value => settings.positionUpper = value);
|
||||
BindVector3(rotationLower, value => settings.rotationLower = value);
|
||||
BindVector3(rotationUpper, value => settings.rotationUpper = value);
|
||||
BindVector3(scaleLower, value => settings.scaleLower = value);
|
||||
BindVector3(scaleUpper, value => settings.scaleUpper = value);
|
||||
BindFloat(timeLower, value => settings.timeLower = value);
|
||||
BindFloat(timeUpper, value => settings.timeUpper = value);
|
||||
}
|
||||
|
||||
private static void BindVector3(DynamicUIVector3InputField field, Action<Vector3> applyValue)
|
||||
{
|
||||
void UpdateValue(string _)
|
||||
{
|
||||
if (TryGetVector3(field, out Vector3 value))
|
||||
{
|
||||
applyValue(value);
|
||||
}
|
||||
}
|
||||
|
||||
field.inputFieldX.onEndEdit.RemoveAllListeners();
|
||||
field.inputFieldY.onEndEdit.RemoveAllListeners();
|
||||
field.inputFieldZ.onEndEdit.RemoveAllListeners();
|
||||
field.inputFieldX.onValueChanged.RemoveAllListeners();
|
||||
field.inputFieldY.onValueChanged.RemoveAllListeners();
|
||||
field.inputFieldZ.onValueChanged.RemoveAllListeners();
|
||||
field.inputFieldX.onValueChanged.AddListener(UpdateValue);
|
||||
field.inputFieldY.onValueChanged.AddListener(UpdateValue);
|
||||
field.inputFieldZ.onValueChanged.AddListener(UpdateValue);
|
||||
}
|
||||
|
||||
private static void BindFloat(DynamicUIInputField field, Action<float> applyValue)
|
||||
{
|
||||
void UpdateValue(string text)
|
||||
{
|
||||
if (float.TryParse(text, out float value))
|
||||
{
|
||||
applyValue(value);
|
||||
}
|
||||
}
|
||||
|
||||
field.inputField.onEndEdit.RemoveAllListeners();
|
||||
field.inputField.onValueChanged.RemoveAllListeners();
|
||||
field.inputField.onValueChanged.AddListener(UpdateValue);
|
||||
}
|
||||
|
||||
private static bool TryGetVector3(DynamicUIVector3InputField field, out Vector3 value)
|
||||
{
|
||||
if (float.TryParse(field.inputFieldX.text, out float x) &&
|
||||
float.TryParse(field.inputFieldY.text, out float y) &&
|
||||
float.TryParse(field.inputFieldZ.text, out float z))
|
||||
{
|
||||
value = new Vector3(x, y, z);
|
||||
return true;
|
||||
}
|
||||
|
||||
value = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,6 +58,7 @@ namespace Ichni.RhythmGame
|
||||
var inspectorMain = EditorManager.instance.uiManager.inspector;
|
||||
IHaveInspection qcWindow = inspectorMain.GenerateSecondaryWindow(this, elementName + "'s Quick Copy");
|
||||
var qcContainer = qcWindow.GenerateContainer();
|
||||
QuickCopyDisturbanceSettings disturbance = QuickCopyDisturbanceSettings.None;
|
||||
|
||||
var positionSub = qcContainer.GenerateSubcontainer(3);
|
||||
var xField = qcWindow.GenerateInputField(positionSub, "X offset", "0");
|
||||
@@ -78,14 +79,19 @@ namespace Ichni.RhythmGame
|
||||
var timeField = qcWindow.GenerateInputField(timeSub, "Time offset", "0");
|
||||
var iterationField = qcWindow.GenerateInputField(timeSub, "Iteration", "1");
|
||||
|
||||
qcWindow.GenerateButton(this, timeSub, "Copy", () =>
|
||||
var actionSub = qcContainer.GenerateSubcontainer(2);
|
||||
qcWindow.GenerateButton(this, actionSub, "Copy", () =>
|
||||
{
|
||||
Vector3 positionOffset = new Vector3(xField.GetValue<float>(), yField.GetValue<float>(), zField.GetValue<float>());
|
||||
Vector3 rotationOffset = new Vector3(rxField.GetValue<float>(), ryField.GetValue<float>(), rzField.GetValue<float>());
|
||||
Vector3 scaleOffset = new Vector3(sxField.GetValue<float>(), syField.GetValue<float>(), szField.GetValue<float>());
|
||||
float timeOffset = timeField.GetValue<float>();
|
||||
int iteration = iterationField.GetValue<int>();
|
||||
QuickCopy(positionOffset, rotationOffset, scaleOffset, timeOffset, iteration);
|
||||
QuickCopy(positionOffset, rotationOffset, scaleOffset, timeOffset, iteration, disturbance);
|
||||
});
|
||||
qcWindow.GenerateButton(this, actionSub, "Disturbance", () =>
|
||||
{
|
||||
QuickCopyDisturbanceWindow.Show(this, elementName + "'s Quick Copy Disturbance", disturbance);
|
||||
});
|
||||
})
|
||||
.Span(3)
|
||||
|
||||
@@ -2,6 +2,7 @@ using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Ichni.Editor;
|
||||
using Ichni.Editor.Commands;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Ichni.RhythmGame
|
||||
@@ -17,20 +18,30 @@ namespace Ichni.RhythmGame
|
||||
/// <param name="unitRotationOffset">单位旋转偏移(欧拉角)</param>
|
||||
/// <param name="unitScaleOffset">单位缩放偏移</param>
|
||||
/// <param name="iteration">迭代次数,即产生几个粘贴的Track</param>
|
||||
private void QuickCopy(Vector3 unitPositionOffset, float unitTimeOffset, bool includeAnimations = true, int iteration = 1, bool MovingTrack = false, Vector3 unitRotationOffset = default, Vector3 unitScaleOffset = default)
|
||||
private void QuickCopy(Vector3 unitPositionOffset, float unitTimeOffset, bool includeAnimations = true, int iteration = 1, bool MovingTrack = false, Vector3 unitRotationOffset = default, Vector3 unitScaleOffset = default, QuickCopyDisturbanceSettings disturbance = default)
|
||||
{
|
||||
if (iteration <= 0) return;
|
||||
|
||||
CommandManager.ExecuteCommand(new CreateElementsCommand(() =>
|
||||
QuickCopyRaw(unitPositionOffset, unitTimeOffset, includeAnimations, iteration, MovingTrack, unitRotationOffset, unitScaleOffset, disturbance)));
|
||||
}
|
||||
|
||||
private List<GameElement> QuickCopyRaw(Vector3 unitPositionOffset, float unitTimeOffset, bool includeAnimations, int iteration, bool MovingTrack, Vector3 unitRotationOffset, Vector3 unitScaleOffset, QuickCopyDisturbanceSettings disturbance)
|
||||
{
|
||||
disturbance = disturbance ?? QuickCopyDisturbanceSettings.None;
|
||||
List<GameElement> createdTracks = new List<GameElement>();
|
||||
CopyPasteDeleteModule cpd = EditorManager.instance.operationManager.CopyPasteDeleteModule;
|
||||
cpd.CopyElement(this);
|
||||
for (int i = 1; i <= iteration; i++)
|
||||
{
|
||||
cpd.PasteElementRaw(this, parentElement);
|
||||
Track newTrack = cpd.pastedElementList[0] as Track;
|
||||
Vector3 positionOffset = unitPositionOffset * i;
|
||||
float timeOffset = unitTimeOffset * i;
|
||||
Vector3 rotationOffset = unitRotationOffset * i;
|
||||
Vector3 scaleOffset = unitScaleOffset * i;
|
||||
Track newTrack = cpd.pastedElementList?.FirstOrDefault() as Track;
|
||||
if (newTrack == null) continue;
|
||||
createdTracks.Add(newTrack);
|
||||
Vector3 positionOffset = unitPositionOffset * i + disturbance.SamplePosition();
|
||||
float timeOffset = unitTimeOffset * i + disturbance.SampleTime();
|
||||
Vector3 rotationOffset = unitRotationOffset * i + disturbance.SampleRotation();
|
||||
Vector3 scaleOffset = unitScaleOffset * i + disturbance.SampleScale();
|
||||
|
||||
//以下:对Track的所有有效的Submodule和子GameElement进行偏移 TODO: 需要思考是否有统一时间偏移的方法?
|
||||
if (MovingTrack)
|
||||
@@ -87,6 +98,7 @@ namespace Ichni.RhythmGame
|
||||
}
|
||||
|
||||
cpd.pastedElementList.Clear();
|
||||
return createdTracks;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -135,6 +135,7 @@ namespace Ichni.RhythmGame
|
||||
{
|
||||
IHaveInspection qcWindow = inspectorMain.GenerateSecondaryWindow(this, elementName + "'s Quick Copy");
|
||||
var qcContainer = qcWindow.GenerateContainer();
|
||||
QuickCopyDisturbanceSettings disturbance = QuickCopyDisturbanceSettings.None;
|
||||
|
||||
// 位置偏移
|
||||
var posSub = qcContainer.GenerateSubcontainer(3);
|
||||
@@ -160,10 +161,11 @@ namespace Ichni.RhythmGame
|
||||
var iterationField = qcWindow.GenerateInputField(timeSub, "Iteration", "1");
|
||||
|
||||
// 选项 & 按钮
|
||||
var toggleSub = qcContainer.GenerateSubcontainer(3);
|
||||
var toggleSub = qcContainer.GenerateSubcontainer(2);
|
||||
var includeAnimationToggle = qcWindow.GenerateToggle(null, toggleSub, "Include Animation", string.Empty);
|
||||
var movingTrackToggle = qcWindow.GenerateToggle(null, toggleSub, "Move Track", string.Empty);
|
||||
qcWindow.GenerateButton(this, toggleSub, "Copy", () =>
|
||||
var actionSub = qcContainer.GenerateSubcontainer(2);
|
||||
qcWindow.GenerateButton(this, actionSub, "Copy", () =>
|
||||
{
|
||||
Vector3 positionOffset = new Vector3(xField.GetValue<float>(), yField.GetValue<float>(), zField.GetValue<float>());
|
||||
Vector3 rotationOffset = new Vector3(rotXField.GetValue<float>(), rotYField.GetValue<float>(), rotZField.GetValue<float>());
|
||||
@@ -172,7 +174,11 @@ namespace Ichni.RhythmGame
|
||||
int iteration = iterationField.GetValue<int>();
|
||||
bool includeAnimation = includeAnimationToggle.toggle.isOn;
|
||||
bool movingTrack = movingTrackToggle.toggle.isOn;
|
||||
this.QuickCopy(positionOffset, timeOffset, includeAnimation, iteration, movingTrack, rotationOffset, scaleOffset);
|
||||
this.QuickCopy(positionOffset, timeOffset, includeAnimation, iteration, movingTrack, rotationOffset, scaleOffset, disturbance);
|
||||
});
|
||||
qcWindow.GenerateButton(this, actionSub, "Disturbance", () =>
|
||||
{
|
||||
QuickCopyDisturbanceWindow.Show(this, elementName + "'s Quick Copy Disturbance", disturbance);
|
||||
});
|
||||
})
|
||||
.Button("Whole Track Move", () =>
|
||||
|
||||
@@ -2,6 +2,7 @@ using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
namespace Ichni.RhythmGame
|
||||
{
|
||||
@@ -27,6 +28,13 @@ namespace Ichni.RhythmGame
|
||||
case PathNode pathNode1 when !pathNode1.isShowingSphere:
|
||||
return;
|
||||
}
|
||||
if (Keyboard.current.shiftKey.isPressed && elementToSelect.connectedTab != null)
|
||||
{
|
||||
EditorManager.instance.operationManager.AddSelectRangeToElement(elementToSelect);
|
||||
EditorManager.instance.uiManager.inspector.SetInspector(elementToSelect);
|
||||
return;
|
||||
}
|
||||
|
||||
EditorManager.instance.uiManager.hierarchy.FindTab(elementToSelect);
|
||||
}
|
||||
|
||||
@@ -40,4 +48,4 @@ namespace Ichni.RhythmGame
|
||||
{
|
||||
public SelectSubmodule selectSubmodule { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user