优化hierarchyab和consolemethod,然后是粒子追踪
Signed-off-by: TRADER_FOER <lhf190@outlook.com>
This commit is contained in:
@@ -48,21 +48,14 @@ namespace Ichni.Editor
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重命名选中元素
|
||||
/// </summary>
|
||||
public static void ReName(string message)
|
||||
{
|
||||
inspector.connectedGameElement.elementName = message;
|
||||
inspector.connectedGameElement.Refresh();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region PathNode Generation (路径节点生成)
|
||||
/// <summary>
|
||||
/// 直线路径节点生成 (Line PathNode Generator)
|
||||
/// </summary>
|
||||
public static void Lgp(int loop, Vector3 start, Vector3 end, bool Clear = false, bool offsetOrigin = false)
|
||||
public static void Lgp(int loop, Vector3 start, Vector3 end, bool Clear = false)
|
||||
{
|
||||
if (inspector.connectedGameElement == null || inspector.connectedGameElement.GetType() != typeof(Track))
|
||||
{
|
||||
@@ -80,17 +73,10 @@ namespace Ichni.Editor
|
||||
// 如果 Clear 且有旧节点,迁移变换
|
||||
|
||||
if (Clear)
|
||||
{
|
||||
if (offsetOrigin && oldNodes.Count > 0 && newNodes.Count > 0)
|
||||
{
|
||||
AdjustPathNodesToNearest(track, newNodes, oldNodes);
|
||||
}
|
||||
// 清除之前的PathNode
|
||||
foreach (var node in oldNodes)
|
||||
{
|
||||
EditorManager.instance.operationManager.CopyPasteDeleteModule.DeleteElement(node);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < loop; i++)
|
||||
{
|
||||
float t = (float)i / (loop - 1); // 修正插值
|
||||
@@ -186,33 +172,7 @@ namespace Ichni.Editor
|
||||
|
||||
#region PathNode/Track Utilities (路径节点/轨道工具)
|
||||
|
||||
/// <summary>
|
||||
/// 将原有 PathNode 的变换(位置、旋转、缩放)迁移到新生成的最近 PathNode 上
|
||||
/// </summary>
|
||||
public static bool AdjustPathNodesToNearest(Track track, List<PathNode> newNodes, List<PathNode> oldNodes)
|
||||
{
|
||||
foreach (var oldNode in oldNodes)
|
||||
{
|
||||
// 找到距离 oldNode 最近的新节点
|
||||
PathNode nearest = newNodes
|
||||
.OrderBy(n => Vector3.Distance(n.transformSubmodule.originalPosition, oldNode.transformSubmodule.originalPosition))
|
||||
.FirstOrDefault();
|
||||
|
||||
if (nearest != null)
|
||||
{
|
||||
// 计算 oldNode 的变换(直接用欧拉角,不用四元数)
|
||||
Vector3 deltaPos = oldNode.transformSubmodule.originalPosition - oldNode.transformSubmodule.originalPosition;
|
||||
Vector3 deltaEuler = oldNode.transformSubmodule.originalEulerAngles - oldNode.transformSubmodule.originalEulerAngles;
|
||||
Vector3 deltaScale = oldNode.transformSubmodule.originalScale - oldNode.transformSubmodule.originalScale;
|
||||
|
||||
// 将变换应用到新节点
|
||||
nearest.transformSubmodule.originalPosition += deltaPos;
|
||||
nearest.transformSubmodule.originalEulerAngles += deltaEuler;
|
||||
nearest.transformSubmodule.originalScale += deltaScale;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除父元素下所有与当前选中元素类型相同的其他元素,最后删除当前选中元素
|
||||
|
||||
@@ -57,7 +57,7 @@ namespace Ichni.Editor
|
||||
this.isSelected = false;
|
||||
if (BgImage != null)
|
||||
{
|
||||
BgImage.color = new Color(0.5f, 0.5f, 0.5f, 0);
|
||||
BgImage.color = new Color(0, 0, 0, 0);
|
||||
}
|
||||
this.childTabList = new List<HierarchyTab>();
|
||||
|
||||
@@ -157,17 +157,17 @@ namespace Ichni.Editor
|
||||
}
|
||||
}
|
||||
|
||||
public void SelectGameElement()
|
||||
{
|
||||
if (Keyboard.current.shiftKey.isPressed)
|
||||
{
|
||||
EditorManager.instance.operationManager.AddSelectRangeToElement(connectedGameElement);
|
||||
}
|
||||
else if (Keyboard.current.leftCtrlKey.isPressed)
|
||||
{
|
||||
if (!isSelected)
|
||||
{
|
||||
EditorManager.instance.operationManager.AddSelectElement(connectedGameElement);
|
||||
public void SelectGameElement()
|
||||
{
|
||||
if (Keyboard.current.shiftKey.isPressed)
|
||||
{
|
||||
EditorManager.instance.operationManager.AddSelectRangeToElement(connectedGameElement);
|
||||
}
|
||||
else if (Keyboard.current.leftCtrlKey.isPressed)
|
||||
{
|
||||
if (!isSelected)
|
||||
{
|
||||
EditorManager.instance.operationManager.AddSelectElement(connectedGameElement);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Dreamteck.Splines;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Ichni.RhythmGame.Beatmap
|
||||
@@ -22,6 +23,7 @@ namespace Ichni.RhythmGame.Beatmap
|
||||
|
||||
public string materialThemeBundleName = string.Empty;
|
||||
public string materialName = string.Empty;
|
||||
public ParticleController.PathNodeSizeMode pathNodeSizeMode = ParticleController.PathNodeSizeMode.LegacyOffset;
|
||||
|
||||
public ParticleTracker_BM()
|
||||
{
|
||||
@@ -33,7 +35,8 @@ namespace Ichni.RhythmGame.Beatmap
|
||||
bool is3D, float width, Vector3 extendDirection,
|
||||
float density, float lifeTime,
|
||||
bool isAutoOrient, Vector3 particleRotation,
|
||||
string materialThemeBundleName, string materialName) : base(elementName, elementGuid, tags, attachedElement)
|
||||
string materialThemeBundleName, string materialName,
|
||||
ParticleController.PathNodeSizeMode pathNodeSizeMode = ParticleController.PathNodeSizeMode.LegacyOffset) : base(elementName, elementGuid, tags, attachedElement)
|
||||
{
|
||||
this.prewarm = prewarm;
|
||||
this.playTime = playTime;
|
||||
@@ -48,6 +51,7 @@ namespace Ichni.RhythmGame.Beatmap
|
||||
|
||||
this.materialThemeBundleName = materialThemeBundleName;
|
||||
this.materialName = materialName;
|
||||
this.pathNodeSizeMode = pathNodeSizeMode;
|
||||
}
|
||||
|
||||
public override void ExecuteBM()
|
||||
@@ -55,7 +59,8 @@ namespace Ichni.RhythmGame.Beatmap
|
||||
matchedElement = ParticleTracker.GenerateElement(
|
||||
elementName, elementGuid, tags, false,
|
||||
GetElement(attachedElementGuid) as Track, materialThemeBundleName, materialName,
|
||||
prewarm, playTime, stopTime, is3D, width, extendDirection, density, lifeTime, isAutoOrient, particleRotation);
|
||||
prewarm, playTime, stopTime, is3D, width, extendDirection, density, lifeTime, isAutoOrient, particleRotation,
|
||||
pathNodeSizeMode);
|
||||
}
|
||||
|
||||
#region [Editor 独有接口] Editor Interfaces
|
||||
@@ -64,7 +69,8 @@ namespace Ichni.RhythmGame.Beatmap
|
||||
return ParticleTracker.GenerateElement(
|
||||
elementName, Guid.NewGuid(), tags, false,
|
||||
attached as Track, materialThemeBundleName, materialName,
|
||||
prewarm, playTime, stopTime, is3D, width, extendDirection, density, lifeTime, isAutoOrient, particleRotation);
|
||||
prewarm, playTime, stopTime, is3D, width, extendDirection, density, lifeTime, isAutoOrient, particleRotation,
|
||||
pathNodeSizeMode);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -110,7 +110,8 @@ namespace Ichni.RhythmGame
|
||||
.Button("Particle Tracker", () =>
|
||||
{
|
||||
CommandManager.ExecuteCreate(() => ParticleTracker.GenerateElement("New Particle Tracker", Guid.NewGuid(), new List<string>(), true, this,
|
||||
string.Empty, string.Empty, false, 0, 1, false, 10, Vector3.right, 10, 5, true, Vector3.zero));
|
||||
string.Empty, string.Empty, false, 0, 1, false, 10, Vector3.right, 10, 5, true, Vector3.zero,
|
||||
Dreamteck.Splines.ParticleController.PathNodeSizeMode.ApplyPathNodeSize));
|
||||
})
|
||||
.Button("Object Tracker", () =>
|
||||
{
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace Ichni.RhythmGame
|
||||
matchedBM = new ParticleTracker_BM(elementName, elementGuid, tags,
|
||||
parentElement.matchedBM as GameElement_BM,
|
||||
prewarm, playTime, stopTime, is3D, width, extendDirection, density, lifeTime, isAutoOrient, particleRotation,
|
||||
themeBundleName, materialName);
|
||||
themeBundleName, materialName, pathNodeSizeMode);
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -45,6 +45,8 @@ namespace Ichni.RhythmGame
|
||||
.OnChanged(SetShape)
|
||||
.Vector3Field(nameof(extendDirection), "Extend Direction")
|
||||
.OnChanged(SetShape)
|
||||
.Dropdown(nameof(pathNodeSizeMode), typeof(Dreamteck.Splines.ParticleController.PathNodeSizeMode), "PathNode Size Mode")
|
||||
.OnChanged(SetShape)
|
||||
.Section("Emission")
|
||||
.InputField(nameof(density), "Density")
|
||||
.OnChanged(() => particlesContainer.SetDensity(density))
|
||||
|
||||
@@ -35,6 +35,7 @@ namespace Ichni.RhythmGame
|
||||
|
||||
public bool isAutoOrient;
|
||||
public Vector3 particleRotation;
|
||||
public ParticleController.PathNodeSizeMode pathNodeSizeMode;
|
||||
#endregion
|
||||
|
||||
#region [生成与初始化] Generation & Initialization
|
||||
@@ -43,7 +44,8 @@ namespace Ichni.RhythmGame
|
||||
bool prewarm, float playTime, float stopTime,
|
||||
bool is3D, float width, Vector3 extendDirection,
|
||||
float density, float lifeTime,
|
||||
bool isAutoOrient, Vector3 particleRotation)
|
||||
bool isAutoOrient, Vector3 particleRotation,
|
||||
ParticleController.PathNodeSizeMode pathNodeSizeMode = ParticleController.PathNodeSizeMode.LegacyOffset)
|
||||
{
|
||||
ParticleTracker particleTracker = Instantiate(EditorManager.instance.basePrefabs.particleTracker, track.transform)
|
||||
.GetComponent<ParticleTracker>();
|
||||
@@ -57,6 +59,7 @@ namespace Ichni.RhythmGame
|
||||
particleTracker.materialNameList = new List<string>();
|
||||
particleTracker.themeBundleName = themeBundleName;
|
||||
particleTracker.materialName = materialName;
|
||||
particleTracker.pathNodeSizeMode = pathNodeSizeMode;
|
||||
particleTracker.particlesContainer.SetParticleMaterial(themeBundleName, materialName);
|
||||
particleTracker.SetParticleSettings(prewarm, is3D, width, extendDirection, density, lifeTime, isAutoOrient, particleRotation);
|
||||
|
||||
@@ -88,16 +91,17 @@ namespace Ichni.RhythmGame
|
||||
this.prewarm = prewarm;
|
||||
this.isAutoOrient = isAutoOrient;
|
||||
this.particleRotation = particleRotation;
|
||||
particlesContainer.SetParticleSettings(prewarm, ParticleSystemSimulationSpace.Local, density,
|
||||
particlesContainer.SetParticleSettings(prewarm, ParticleSystemSimulationSpace.Local, density,
|
||||
lifeTime, 0, 1, isAutoOrient, particleRotation);
|
||||
SetShape();
|
||||
}
|
||||
|
||||
|
||||
private void SetShape()
|
||||
{
|
||||
particleController.is3D = is3D;
|
||||
particleController.width = width;
|
||||
particleController.extendDirection = extendDirection;
|
||||
particleController.pathNodeSizeMode = pathNodeSizeMode;
|
||||
particleController.Rebuild();
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -2,40 +2,41 @@ using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using DG.Tweening;
|
||||
using Ichni.Editor.Commands;
|
||||
using Ichni.RhythmGame;
|
||||
using Ichni.RhythmGame.Beatmap;
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
namespace Ichni.Editor
|
||||
{
|
||||
public class OperationManager
|
||||
{
|
||||
public List<GameElement> currentSelectedElements { get; private set; }
|
||||
public TempOutlineModule TempOutlineModule = new TempOutlineModule();
|
||||
public CopyPasteDeleteModule CopyPasteDeleteModule;
|
||||
|
||||
public FindingModule FindingModule;
|
||||
|
||||
public OperationManager()
|
||||
{
|
||||
currentSelectedElements = new List<GameElement>();
|
||||
CopyPasteDeleteModule = new CopyPasteDeleteModule();
|
||||
FindingModule = new FindingModule();
|
||||
}
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
namespace Ichni.Editor
|
||||
{
|
||||
public class OperationManager
|
||||
{
|
||||
public List<GameElement> currentSelectedElements { get; private set; }
|
||||
public TempOutlineModule TempOutlineModule = new TempOutlineModule();
|
||||
public CopyPasteDeleteModule CopyPasteDeleteModule;
|
||||
|
||||
public FindingModule FindingModule;
|
||||
|
||||
public OperationManager()
|
||||
{
|
||||
currentSelectedElements = new List<GameElement>();
|
||||
CopyPasteDeleteModule = new CopyPasteDeleteModule();
|
||||
FindingModule = new FindingModule();
|
||||
}
|
||||
|
||||
public void AddSelectElement(GameElement gameElement)
|
||||
{
|
||||
if (gameElement == null || gameElement.connectedTab == null) return;
|
||||
if (currentSelectedElements.Contains(gameElement)) return;
|
||||
|
||||
currentSelectedElements.Add(gameElement);
|
||||
|
||||
gameElement.connectedTab.isSelected = true;
|
||||
if (gameElement.connectedTab.BgImage != null)
|
||||
{
|
||||
gameElement.connectedTab.BgImage.color = new Color(0f, 0f, 0f, 0.8f);
|
||||
|
||||
currentSelectedElements.Add(gameElement);
|
||||
|
||||
gameElement.connectedTab.isSelected = true;
|
||||
if (gameElement.connectedTab.BgImage != null)
|
||||
{
|
||||
gameElement.connectedTab.BgImage.DOColor(new Color(0f, 0f, 0f, 0.8f), 0.2f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,75 +94,78 @@ namespace Ichni.Editor
|
||||
public void RemoveSelectElement(GameElement gameElement)
|
||||
{
|
||||
if (gameElement == null) return;
|
||||
|
||||
currentSelectedElements.Remove(gameElement);
|
||||
|
||||
if (gameElement.connectedTab == null) return;
|
||||
|
||||
gameElement.connectedTab.isSelected = false;
|
||||
if (gameElement.connectedTab.BgImage != null)
|
||||
{
|
||||
gameElement.connectedTab.BgImage.color = new Color(0.5f, 0.5f, 0.5f, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearSelectedElements()
|
||||
{
|
||||
currentSelectedElements.RemoveAll(gameElement => gameElement == null);
|
||||
currentSelectedElements.ForEach(gameElement =>
|
||||
{
|
||||
if (gameElement == null || gameElement.connectedTab == null) return;
|
||||
gameElement.connectedTab.isSelected = false;
|
||||
if (gameElement.connectedTab.BgImage != null)
|
||||
{
|
||||
gameElement.connectedTab.BgImage.color = new Color(0.5f, 0.5f, 0.5f, 0);
|
||||
}
|
||||
});
|
||||
|
||||
currentSelectedElements.Clear();
|
||||
}
|
||||
}
|
||||
public class TempOutlineModule
|
||||
{
|
||||
public List<GameElement> outlinedElements;
|
||||
public Material outlineMaterial => EditorManager.instance.basePrefabs.outlineShaderMaterial;
|
||||
public TempOutlineModule()
|
||||
{
|
||||
outlinedElements = new List<GameElement>();
|
||||
}
|
||||
|
||||
public void AddOutline(GameElement gameElement)
|
||||
{
|
||||
outlinedElements.Add(gameElement);
|
||||
}
|
||||
|
||||
public void RemoveOutline(GameElement gameElement)
|
||||
{
|
||||
outlinedElements.Remove(gameElement);
|
||||
}
|
||||
|
||||
public void ClearOutline()
|
||||
{
|
||||
outlinedElements.Clear();
|
||||
}
|
||||
}
|
||||
public class FindingModule
|
||||
{
|
||||
public GameElement FindGameElementByName(string elementName)
|
||||
{
|
||||
foreach (GameElement element in EditorManager.instance.beatmapContainer.gameElementList)
|
||||
{
|
||||
if (element.elementName == elementName)
|
||||
{
|
||||
return element;
|
||||
}
|
||||
}
|
||||
|
||||
LogWindow.Log("Element not found: " + elementName, Color.red);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
currentSelectedElements.Remove(gameElement);
|
||||
|
||||
if (gameElement.connectedTab == null) return;
|
||||
|
||||
gameElement.connectedTab.isSelected = false;
|
||||
if (gameElement.connectedTab.BgImage != null)
|
||||
{
|
||||
gameElement.connectedTab.BgImage.DOColor(new Color(0, 0, 0, 0), 0.2f);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearSelectedElements()
|
||||
{
|
||||
currentSelectedElements.RemoveAll(gameElement => gameElement == null);
|
||||
currentSelectedElements.ForEach(gameElement =>
|
||||
{
|
||||
if (gameElement == null || gameElement.connectedTab == null) return;
|
||||
gameElement.connectedTab.isSelected = false;
|
||||
if (gameElement.connectedTab.BgImage != null)
|
||||
{
|
||||
gameElement.connectedTab.BgImage.DOColor(new Color(0, 0, 0, 0), 0.2f);
|
||||
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
currentSelectedElements.Clear();
|
||||
}
|
||||
}
|
||||
public class TempOutlineModule
|
||||
{
|
||||
public List<GameElement> outlinedElements;
|
||||
public Material outlineMaterial => EditorManager.instance.basePrefabs.outlineShaderMaterial;
|
||||
public TempOutlineModule()
|
||||
{
|
||||
outlinedElements = new List<GameElement>();
|
||||
}
|
||||
|
||||
public void AddOutline(GameElement gameElement)
|
||||
{
|
||||
outlinedElements.Add(gameElement);
|
||||
}
|
||||
|
||||
public void RemoveOutline(GameElement gameElement)
|
||||
{
|
||||
outlinedElements.Remove(gameElement);
|
||||
}
|
||||
|
||||
public void ClearOutline()
|
||||
{
|
||||
outlinedElements.Clear();
|
||||
}
|
||||
}
|
||||
public class FindingModule
|
||||
{
|
||||
public GameElement FindGameElementByName(string elementName)
|
||||
{
|
||||
foreach (GameElement element in EditorManager.instance.beatmapContainer.gameElementList)
|
||||
{
|
||||
if (element.elementName == elementName)
|
||||
{
|
||||
return element;
|
||||
}
|
||||
}
|
||||
|
||||
LogWindow.Log("Element not found: " + elementName, Color.red);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public class CopyPasteDeleteModule
|
||||
{
|
||||
public GameElement copiedElement;
|
||||
@@ -220,8 +224,8 @@ namespace Ichni.Editor
|
||||
public void PasteElement(GameElement parentElement)
|
||||
{
|
||||
if (parentElement == null)
|
||||
{
|
||||
LogWindow.Log("No parent element selected to paste.", Color.red);
|
||||
{
|
||||
LogWindow.Log("No parent element selected to paste.", Color.red);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user