曲线视觉编辑器,初步
This commit is contained in:
@@ -49,10 +49,10 @@ MonoBehaviour:
|
||||
m_addressable:
|
||||
m_atlas:
|
||||
m_fileSize: 26252
|
||||
m_assetChangeTS: 1751289904
|
||||
m_fileInfoReadTS: 1751289905
|
||||
m_fileWriteTS: 1751289904
|
||||
m_cachefileWriteTS: 1751289904
|
||||
m_assetChangeTS: 1751364893
|
||||
m_fileInfoReadTS: 1751364911
|
||||
m_fileWriteTS: 1751364893
|
||||
m_cachefileWriteTS: 1751364893
|
||||
refreshStamp: 2
|
||||
UseGUIDsList:
|
||||
- guid: fc6c02e75b66345c29e8a25e2e2bda9c
|
||||
@@ -108842,15 +108842,15 @@ MonoBehaviour:
|
||||
ids: 73000000
|
||||
- guid: f716a33409746460589eb6305a5ed072
|
||||
type: 2
|
||||
m_fileInfoHash: 16659.cs
|
||||
m_fileInfoHash: 16810.cs
|
||||
m_assetbundle:
|
||||
m_addressable:
|
||||
m_atlas:
|
||||
m_fileSize: 16659
|
||||
m_assetChangeTS: 0
|
||||
m_fileInfoReadTS: 1750510507
|
||||
m_fileWriteTS: 1745084316
|
||||
m_cachefileWriteTS: 1745084316
|
||||
m_fileSize: 16810
|
||||
m_assetChangeTS: 1751352657
|
||||
m_fileInfoReadTS: 1751352674
|
||||
m_fileWriteTS: 1751351894
|
||||
m_cachefileWriteTS: 1751351894
|
||||
refreshStamp: 2
|
||||
UseGUIDsList: []
|
||||
- guid: f776bdd36b750304c8e0de8ee1f31fc0
|
||||
@@ -111247,15 +111247,15 @@ MonoBehaviour:
|
||||
UseGUIDsList: []
|
||||
- guid: 28c134965d47644a98d3ba8a1343674a
|
||||
type: 3
|
||||
m_fileInfoHash: 480091.unity
|
||||
m_fileInfoHash: 1713382.unity
|
||||
m_assetbundle:
|
||||
m_addressable:
|
||||
m_atlas:
|
||||
m_fileSize: 480091
|
||||
m_assetChangeTS: 1750943771
|
||||
m_fileInfoReadTS: 1750943791
|
||||
m_fileWriteTS: 1750943771
|
||||
m_cachefileWriteTS: 1750943771
|
||||
m_fileSize: 1713382
|
||||
m_assetChangeTS: 1751364894
|
||||
m_fileInfoReadTS: 1751364911
|
||||
m_fileWriteTS: 1751364894
|
||||
m_cachefileWriteTS: 1751364894
|
||||
refreshStamp: 2
|
||||
UseGUIDsList:
|
||||
- guid: 0000000000000000f000000000000000
|
||||
@@ -111344,6 +111344,10 @@ MonoBehaviour:
|
||||
ids: 73000000
|
||||
- guid: 3312d7739989d2b4e91e6319e9a96d76
|
||||
ids: 73000000
|
||||
- guid: 5e4743327f32eb24e86090ec474ac91a
|
||||
ids: 73000000
|
||||
- guid: 1344c3c82d62a2a41a3576d8abb8e3ea
|
||||
ids: 73000000
|
||||
- guid: 3f216541647c185428ca5581509954d8
|
||||
ids: e9030000
|
||||
- guid: 344445a89b4f74a0e9a0a766903df87e
|
||||
@@ -115557,15 +115561,15 @@ MonoBehaviour:
|
||||
UseGUIDsList: []
|
||||
- guid: 7847a689c7721eb4dba4344e727ab715
|
||||
type: 2
|
||||
m_fileInfoHash: 3313.cs
|
||||
m_fileInfoHash: 3863.cs
|
||||
m_assetbundle:
|
||||
m_addressable:
|
||||
m_atlas:
|
||||
m_fileSize: 3313
|
||||
m_assetChangeTS: 0
|
||||
m_fileInfoReadTS: 1750510506
|
||||
m_fileWriteTS: 1742680961
|
||||
m_cachefileWriteTS: 1742680961
|
||||
m_fileSize: 3863
|
||||
m_assetChangeTS: 1751352657
|
||||
m_fileInfoReadTS: 1751352674
|
||||
m_fileWriteTS: 1751351539
|
||||
m_cachefileWriteTS: 1751351539
|
||||
refreshStamp: 2
|
||||
UseGUIDsList: []
|
||||
- guid: 785830160e033d24280df9c5b4cec368
|
||||
@@ -143557,15 +143561,15 @@ MonoBehaviour:
|
||||
UseGUIDsList: []
|
||||
- guid: 7ab6cd8f9a2e77c49a158e16014f9cec
|
||||
type: 9
|
||||
m_fileInfoHash: 2049032.json
|
||||
m_fileInfoHash: 2049196.json
|
||||
m_assetbundle:
|
||||
m_addressable:
|
||||
m_atlas:
|
||||
m_fileSize: 2049032
|
||||
m_assetChangeTS: 1751292309
|
||||
m_fileInfoReadTS: 1751292326
|
||||
m_fileWriteTS: 1751292036
|
||||
m_cachefileWriteTS: 1751292036
|
||||
m_fileSize: 2049196
|
||||
m_assetChangeTS: 1751367897
|
||||
m_fileInfoReadTS: 1751367915
|
||||
m_fileWriteTS: 1751367843
|
||||
m_cachefileWriteTS: 1751367843
|
||||
refreshStamp: 2
|
||||
UseGUIDsList: []
|
||||
- guid: 7af6ac3e6b51b8d4aab04adc85b8de2f
|
||||
@@ -183753,15 +183757,15 @@ MonoBehaviour:
|
||||
UseGUIDsList: []
|
||||
- guid: 6d98a93f5b5c14ef5b7b125e407ce17d
|
||||
type: 5
|
||||
m_fileInfoHash: 39073.prefab
|
||||
m_fileInfoHash: 41510.prefab
|
||||
m_assetbundle:
|
||||
m_addressable:
|
||||
m_atlas:
|
||||
m_fileSize: 39073
|
||||
m_assetChangeTS: 0
|
||||
m_fileInfoReadTS: 1750510493
|
||||
m_fileWriteTS: 1742680962
|
||||
m_cachefileWriteTS: 1742680962
|
||||
m_fileSize: 41510
|
||||
m_assetChangeTS: 1751357984
|
||||
m_fileInfoReadTS: 1751358658
|
||||
m_fileWriteTS: 1751357984
|
||||
m_cachefileWriteTS: 1751357984
|
||||
refreshStamp: 2
|
||||
UseGUIDsList:
|
||||
- guid: f4688fdb7df04437aeb418b961361dc5
|
||||
@@ -183788,6 +183792,10 @@ MonoBehaviour:
|
||||
ids: 73000000
|
||||
- guid: 31a19414c41e5ae4aae2af33fee712f6
|
||||
ids: 73000000
|
||||
- guid: 1344c3c82d62a2a41a3576d8abb8e3ea
|
||||
ids: 73000000
|
||||
- guid: 5e4743327f32eb24e86090ec474ac91a
|
||||
ids: 73000000
|
||||
- guid: 30649d3a9faa99c48a7b1166b86bf2a0
|
||||
ids: 73000000
|
||||
- guid: 306cc8c2b49d7114eaa3623786fc2126
|
||||
@@ -193426,15 +193434,15 @@ MonoBehaviour:
|
||||
ids: 73000000
|
||||
- guid: 2e498d1c8094910479dc3e1b768306a4
|
||||
type: 5
|
||||
m_fileInfoHash: 9628.asset
|
||||
m_fileInfoHash: 560939.asset
|
||||
m_assetbundle:
|
||||
m_addressable:
|
||||
m_atlas:
|
||||
m_fileSize: 9628
|
||||
m_assetChangeTS: 1751289920
|
||||
m_fileInfoReadTS: 1751289979
|
||||
m_fileWriteTS: 1751289920
|
||||
m_cachefileWriteTS: 1751289920
|
||||
m_fileSize: 560939
|
||||
m_assetChangeTS: 1751292440
|
||||
m_fileInfoReadTS: 1751292443
|
||||
m_fileWriteTS: 1751292439
|
||||
m_cachefileWriteTS: 1751292439
|
||||
refreshStamp: 2
|
||||
UseGUIDsList:
|
||||
- guid: fe393ace9b354375a9cb14cdbbc28be4
|
||||
@@ -218807,6 +218815,32 @@ MonoBehaviour:
|
||||
m_cachefileWriteTS: 1751289835
|
||||
refreshStamp: 2
|
||||
UseGUIDsList: []
|
||||
- guid: 138c996b947bada4d94d900ca8213f9a
|
||||
type: 1
|
||||
m_fileInfoHash:
|
||||
m_assetbundle:
|
||||
m_addressable:
|
||||
m_atlas:
|
||||
m_fileSize: 0
|
||||
m_assetChangeTS: 0
|
||||
m_fileInfoReadTS: 1751296414
|
||||
m_fileWriteTS: 0
|
||||
m_cachefileWriteTS: 0
|
||||
refreshStamp: 2
|
||||
UseGUIDsList: []
|
||||
- guid: 5e4743327f32eb24e86090ec474ac91a
|
||||
type: 2
|
||||
m_fileInfoHash: 24377.cs
|
||||
m_assetbundle:
|
||||
m_addressable:
|
||||
m_atlas:
|
||||
m_fileSize: 24377
|
||||
m_assetChangeTS: 1751367897
|
||||
m_fileInfoReadTS: 1751367915
|
||||
m_fileWriteTS: 1751367894
|
||||
m_cachefileWriteTS: 1751367894
|
||||
refreshStamp: 2
|
||||
UseGUIDsList: []
|
||||
setting:
|
||||
alternateColor: 1
|
||||
excludeTypes: 0
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
namespace Michsky.MUIP
|
||||
{
|
||||
@@ -8,10 +9,11 @@ namespace Michsky.MUIP
|
||||
[Header("Resources")]
|
||||
public RectTransform dragArea;
|
||||
public RectTransform dragObject;
|
||||
public RectTransform draggerRect;
|
||||
|
||||
[Header("Settings")]
|
||||
public bool topOnDrag = true;
|
||||
|
||||
public bool Lock = false;
|
||||
private Vector2 originalLocalPointerPosition;
|
||||
private Vector3 originalPanelLocalPosition;
|
||||
|
||||
@@ -58,23 +60,29 @@ namespace Michsky.MUIP
|
||||
|
||||
public void OnBeginDrag(PointerEventData data)
|
||||
{
|
||||
originalPanelLocalPosition = DragObjectInternal.localPosition;
|
||||
RectTransformUtility.ScreenPointToLocalPointInRectangle(DragAreaInternal, data.position, data.pressEventCamera, out originalLocalPointerPosition);
|
||||
gameObject.transform.SetAsLastSibling();
|
||||
if (topOnDrag == true) { dragObject.transform.SetAsLastSibling(); }
|
||||
if (!Lock && (draggerRect == null || RectTransformUtility.RectangleContainsScreenPoint(GetComponent<RectTransform>(), Mouse.current.position.ReadValue())))
|
||||
{
|
||||
originalPanelLocalPosition = DragObjectInternal.localPosition;
|
||||
RectTransformUtility.ScreenPointToLocalPointInRectangle(DragAreaInternal, data.position, data.pressEventCamera, out originalLocalPointerPosition);
|
||||
gameObject.transform.SetAsLastSibling();
|
||||
if (topOnDrag == true) { dragObject.transform.SetAsLastSibling(); }
|
||||
}
|
||||
}
|
||||
|
||||
public void OnDrag(PointerEventData data)
|
||||
{
|
||||
Vector2 localPointerPosition;
|
||||
|
||||
if (RectTransformUtility.ScreenPointToLocalPointInRectangle(DragAreaInternal, data.position, data.pressEventCamera, out localPointerPosition))
|
||||
if (!Lock && (draggerRect == null || RectTransformUtility.RectangleContainsScreenPoint(GetComponent<RectTransform>(), Mouse.current.position.ReadValue())))
|
||||
{
|
||||
Vector3 offsetToOriginal = localPointerPosition - originalLocalPointerPosition;
|
||||
DragObjectInternal.localPosition = originalPanelLocalPosition + offsetToOriginal;
|
||||
}
|
||||
Vector2 localPointerPosition;
|
||||
|
||||
ClampToArea();
|
||||
if (RectTransformUtility.ScreenPointToLocalPointInRectangle(DragAreaInternal, data.position, data.pressEventCamera, out localPointerPosition))
|
||||
{
|
||||
Vector3 offsetToOriginal = localPointerPosition - originalLocalPointerPosition;
|
||||
DragObjectInternal.localPosition = originalPanelLocalPosition + offsetToOriginal;
|
||||
}
|
||||
|
||||
ClampToArea();
|
||||
}
|
||||
}
|
||||
|
||||
private void ClampToArea()
|
||||
|
||||
@@ -784,6 +784,136 @@ MonoBehaviour:
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_ShowMaskGraphic: 1
|
||||
--- !u!1 &4955889325830384991
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 810674083073048004}
|
||||
- component: {fileID: 8990101195177178229}
|
||||
- component: {fileID: 4768191335492145245}
|
||||
- component: {fileID: 1028112064287344483}
|
||||
m_Layer: 5
|
||||
m_Name: KeyframeVisualizer
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 0
|
||||
--- !u!224 &810674083073048004
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4955889325830384991}
|
||||
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 2, y: 2, z: 2}
|
||||
m_ConstrainProportionsScale: 1
|
||||
m_Children: []
|
||||
m_Father: {fileID: 70126183804589383}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 400, y: 300}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &8990101195177178229
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4955889325830384991}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &4768191335492145245
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4955889325830384991}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 1344c3c82d62a2a41a3576d8abb8e3ea, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_RaycastTarget: 0
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Texture: {fileID: 0}
|
||||
m_UVRect:
|
||||
serializedVersion: 2
|
||||
x: 0
|
||||
y: 0
|
||||
width: 1
|
||||
height: 1
|
||||
--- !u!114 &1028112064287344483
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4955889325830384991}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 5e4743327f32eb24e86090ec474ac91a, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
curve:
|
||||
serializedVersion: 2
|
||||
m_Curve:
|
||||
- serializedVersion: 3
|
||||
time: 0
|
||||
value: 1
|
||||
inSlope: -0.02690773
|
||||
outSlope: -0.02690773
|
||||
tangentMode: 34
|
||||
weightedMode: 0
|
||||
inWeight: 0
|
||||
outWeight: 0.33333334
|
||||
- serializedVersion: 3
|
||||
time: 0.49971336
|
||||
value: 0.98655385
|
||||
inSlope: -0.0037777494
|
||||
outSlope: -0.0037777494
|
||||
tangentMode: 0
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0.33333334
|
||||
- serializedVersion: 3
|
||||
time: 0.9750061
|
||||
value: 1.0018921
|
||||
inSlope: 0.032753333
|
||||
outSlope: 0.032753333
|
||||
tangentMode: 0
|
||||
weightedMode: 0
|
||||
inWeight: 0.43590096
|
||||
outWeight: 0
|
||||
m_PreInfinity: 2
|
||||
m_PostInfinity: 2
|
||||
m_RotationOrder: 4
|
||||
timeRange: 10
|
||||
valueRange: 10
|
||||
keyframeSize: 0.2
|
||||
tangentLength: 1
|
||||
curveColor: {r: 0, g: 1, b: 0, a: 1}
|
||||
keyframeColor: {r: 1, g: 0, b: 0, a: 1}
|
||||
tangentColor: {r: 0, g: 0, b: 1, a: 1}
|
||||
segments: 5
|
||||
curveRawImage: {fileID: 4768191335492145245}
|
||||
curveTextureSize: {x: 400, y: 300}
|
||||
keyframeImages: []
|
||||
compositeParameterWindow: {fileID: 8591554574042573968}
|
||||
--- !u!1 &5406300460509605192
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -1100,6 +1230,7 @@ RectTransform:
|
||||
- {fileID: 8670700627722813223}
|
||||
- {fileID: 4803002250074383695}
|
||||
- {fileID: 6090386518530065525}
|
||||
- {fileID: 810674083073048004}
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
@@ -1121,7 +1252,9 @@ MonoBehaviour:
|
||||
m_EditorClassIdentifier:
|
||||
dragArea: {fileID: 0}
|
||||
dragObject: {fileID: 70126183804589383}
|
||||
draggerRect: {fileID: 0}
|
||||
topOnDrag: 1
|
||||
Lock: 0
|
||||
--- !u!114 &8591554574042573968
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -1137,11 +1270,11 @@ MonoBehaviour:
|
||||
windowRect: {fileID: 1670114893104377247}
|
||||
closeButton: {fileID: 6180637045729466281}
|
||||
title: {fileID: 1143112183991551266}
|
||||
container: {fileID: 0}
|
||||
addNewUnitButton: {fileID: 3483650628256943973}
|
||||
unitPrefab: {fileID: 0}
|
||||
unitList: []
|
||||
parameterName:
|
||||
keyframeVisualizer: {fileID: 1028112064287344483}
|
||||
--- !u!1 &9104419187492598894
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -23,7 +23,7 @@ namespace Ichni.Editor
|
||||
this.connectedBaseElement = baseElement;
|
||||
this.parameterName = parameterName;
|
||||
unitList = new List<DynamicUICompositeUnit>();
|
||||
|
||||
|
||||
InitializeWindow(titleText, ApplyParameters);
|
||||
|
||||
StartCoroutine(WindowAnim.ShowPanelOnScale(gameObject));
|
||||
@@ -34,7 +34,7 @@ namespace Ichni.Editor
|
||||
unitList.Remove(unit);
|
||||
Destroy(unit.gameObject);
|
||||
}
|
||||
|
||||
|
||||
public CompositeParameterWindow AddListenerFunction(UnityAction action)
|
||||
{
|
||||
onQuit = action;
|
||||
@@ -77,7 +77,7 @@ namespace Ichni.Editor
|
||||
List<string> stringList = unitList.Select(unit => (unit as DynamicUIInputFieldUnit).GetValue<string>()).ToList();
|
||||
connectedBaseElement.GetType().GetField(parameterName).SetValue(connectedBaseElement, stringList);
|
||||
};
|
||||
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -109,7 +109,7 @@ namespace Ichni.Editor
|
||||
List<float> floatList = unitList.Select(unit => (unit as DynamicUIInputFieldUnit).GetValue<float>()).ToList();
|
||||
connectedBaseElement.GetType().GetField(parameterName).SetValue(connectedBaseElement, floatList);
|
||||
};
|
||||
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -146,7 +146,7 @@ namespace Ichni.Editor
|
||||
}
|
||||
connectedBaseElement.GetType().GetField(parameterName).SetValue(connectedBaseElement, newFlexibleFloat);
|
||||
};
|
||||
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -183,7 +183,7 @@ namespace Ichni.Editor
|
||||
}
|
||||
connectedBaseElement.GetType().GetField(parameterName).SetValue(connectedBaseElement, newFlexibleInt);
|
||||
};
|
||||
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -219,12 +219,19 @@ namespace Ichni.Editor
|
||||
}
|
||||
connectedBaseElement.GetType().GetField(parameterName).SetValue(connectedBaseElement, newFlexibleBool);
|
||||
};
|
||||
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public KeyframeVisualizer keyframeVisualizer;
|
||||
public CompositeParameterWindow SetAsCustomCurve()
|
||||
{
|
||||
|
||||
//生成一个预览器先
|
||||
keyframeVisualizer.gameObject.SetActive(true);
|
||||
//
|
||||
void GenerateUnit(Keyframe content)
|
||||
{
|
||||
DynamicUICustomCurveKeyframeUnit unit = Instantiate(unitPrefab, windowRect).GetComponent<DynamicUICustomCurveKeyframeUnit>();
|
||||
@@ -242,6 +249,11 @@ namespace Ichni.Editor
|
||||
Instantiate(EditorManager.instance.basePrefabs.customCurveWrapModeUnit, windowRect).GetComponent<DynamicUICustomCurveWrapModeUnit>();
|
||||
unitList.Add(warpModesUnit);
|
||||
warpModesUnit.SetUnit(this, warpModes);
|
||||
//
|
||||
keyframeVisualizer.curve = curve;
|
||||
keyframeVisualizer.DrawCurveToRawImage();
|
||||
keyframeVisualizer.CreateKeyframeImages();
|
||||
//
|
||||
|
||||
foreach (Keyframe keyframe in keyframes)
|
||||
{
|
||||
@@ -268,8 +280,8 @@ namespace Ichni.Editor
|
||||
newCurve.AddKey(unit.GetValue());
|
||||
}
|
||||
connectedBaseElement.GetType().GetField(parameterName).SetValue(connectedBaseElement, newCurve);
|
||||
|
||||
};
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -281,7 +293,7 @@ namespace Ichni.Editor
|
||||
unitList.Add(unit);
|
||||
unit.SetUnit(this, content);
|
||||
}
|
||||
|
||||
|
||||
unitPrefab = EditorManager.instance.basePrefabs.gradientColorKeyUnit;
|
||||
Gradient gradient = connectedBaseElement.GetType().GetField(parameterName).GetValue(connectedBaseElement) as Gradient;
|
||||
List<GradientColorKey> colorKeys = gradient.colorKeys.ToList();
|
||||
@@ -296,7 +308,7 @@ namespace Ichni.Editor
|
||||
GenerateUnit(new GradientColorKey(Color.white, 1));
|
||||
addNewUnitButton.GetComponent<RectTransform>().SetAsLastSibling();
|
||||
});
|
||||
|
||||
|
||||
ApplyParameters = () =>
|
||||
{
|
||||
List<GradientColorKey> newColorKeys = new List<GradientColorKey>();
|
||||
@@ -306,10 +318,10 @@ namespace Ichni.Editor
|
||||
}
|
||||
(connectedBaseElement.GetType().GetField(parameterName).GetValue(connectedBaseElement) as Gradient).colorKeys = newColorKeys.ToArray();
|
||||
};
|
||||
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public CompositeParameterWindow SetAsGradientAlphaKeys()
|
||||
{
|
||||
void GenerateUnit(GradientAlphaKey content)
|
||||
@@ -318,7 +330,7 @@ namespace Ichni.Editor
|
||||
unitList.Add(unit);
|
||||
unit.SetUnit(this, content);
|
||||
}
|
||||
|
||||
|
||||
unitPrefab = EditorManager.instance.basePrefabs.gradientAlphaKeyUnit;
|
||||
Gradient gradient = connectedBaseElement.GetType().GetField(parameterName).GetValue(connectedBaseElement) as Gradient;
|
||||
List<GradientAlphaKey> alphaKeys = gradient.alphaKeys.ToList();
|
||||
@@ -333,7 +345,7 @@ namespace Ichni.Editor
|
||||
GenerateUnit(new GradientAlphaKey(1, 1));
|
||||
addNewUnitButton.GetComponent<RectTransform>().SetAsLastSibling();
|
||||
});
|
||||
|
||||
|
||||
ApplyParameters = () =>
|
||||
{
|
||||
List<GradientAlphaKey> newAlphaKeys = new List<GradientAlphaKey>();
|
||||
@@ -343,10 +355,10 @@ namespace Ichni.Editor
|
||||
}
|
||||
(connectedBaseElement.GetType().GetField(parameterName).GetValue(connectedBaseElement) as Gradient).alphaKeys = newAlphaKeys.ToArray();
|
||||
};
|
||||
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public CompositeParameterWindow SetAsStringIntDictionary()
|
||||
{
|
||||
//生成Unit
|
||||
@@ -358,13 +370,13 @@ namespace Ichni.Editor
|
||||
}
|
||||
|
||||
unitPrefab = EditorManager.instance.basePrefabs.stringIntPairUnit;
|
||||
|
||||
|
||||
Dictionary<string, int> dictionary = connectedBaseElement.GetType().GetField(parameterName).GetValue(connectedBaseElement) as Dictionary<string, int>;
|
||||
foreach (var pair in dictionary)
|
||||
{
|
||||
GenerateUnit(pair);
|
||||
}
|
||||
|
||||
|
||||
addNewUnitButton.GetComponent<RectTransform>().SetAsLastSibling();
|
||||
|
||||
//为添加新的Unit的按钮设置点击事件
|
||||
@@ -385,7 +397,7 @@ namespace Ichni.Editor
|
||||
}
|
||||
connectedBaseElement.GetType().GetField(parameterName).SetValue(connectedBaseElement, dictionaryList);
|
||||
};
|
||||
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
8
Assets/Scripts/Graphical Tools/Hermite Editor.meta
Normal file
8
Assets/Scripts/Graphical Tools/Hermite Editor.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 138c996b947bada4d94d900ca8213f9a
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,587 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using Sirenix.OdinInspector;
|
||||
using System.Linq;
|
||||
using UnityEngine.InputSystem;
|
||||
using Michsky.MUIP;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
namespace Ichni.Editor
|
||||
{
|
||||
[RequireComponent(typeof(RawImage))]
|
||||
public class KeyframeVisualizer : MonoBehaviour
|
||||
{
|
||||
public AnimationCurve curve;
|
||||
public float timeRange = 10f;
|
||||
public float valueRange = 10f;
|
||||
public float keyframeSize = 0.2f;
|
||||
public float tangentLength = 1f;
|
||||
public Color curveColor = Color.green;
|
||||
public Color keyframeColor = Color.red;
|
||||
public Color tangentColor = Color.blue;
|
||||
public int segments = 5;
|
||||
|
||||
[Header("Curve Preview")]
|
||||
public RawImage curveRawImage;
|
||||
public Vector2Int curveTextureSize = new Vector2Int(256, 128);
|
||||
|
||||
[System.Serializable]
|
||||
public struct KeyframeImageInfo
|
||||
{
|
||||
public Image keyImage;
|
||||
public Image inTangentImage;
|
||||
public Image outTangentImage;
|
||||
}
|
||||
|
||||
public List<KeyframeImageInfo> keyframeImages = new List<KeyframeImageInfo>();
|
||||
|
||||
// 合并min/max到类成员,便于全局一致使用
|
||||
private float minTime, maxTime, minValue = 0f, maxValue = 1f;
|
||||
|
||||
private void UpdateCurveRange()
|
||||
{
|
||||
if (curve == null || curve.length < 2)
|
||||
{
|
||||
minTime = maxTime = valueRange = timeRange = 0;
|
||||
minValue = 0f;
|
||||
maxValue = 1f;
|
||||
return;
|
||||
}
|
||||
minTime = 0f;
|
||||
maxTime = 1f;
|
||||
minValue = 0f; // 固定下界为0
|
||||
maxValue = 1f; // 固定上界为1
|
||||
valueRange = Mathf.Max(0.0001f, maxValue - minValue);
|
||||
timeRange = Mathf.Max(0.0001f, maxTime - minTime);
|
||||
}
|
||||
|
||||
[Button("Draw Curve To RawImage")]
|
||||
public void DrawCurveToRawImage()
|
||||
{
|
||||
UpdateCurveRange();
|
||||
if (curveRawImage == null || curve == null || curve.length < 2) return;
|
||||
|
||||
int texWidth = curveTextureSize.x;
|
||||
int texHeight = curveTextureSize.y;
|
||||
Texture2D tex = new Texture2D(texWidth, texHeight, TextureFormat.ARGB32, false);
|
||||
tex.filterMode = FilterMode.Point;
|
||||
tex.wrapMode = TextureWrapMode.Clamp;
|
||||
|
||||
// 清空
|
||||
for (int i = 0; i < texWidth; i++)
|
||||
for (int j = 0; j < texHeight; j++)
|
||||
tex.SetPixel(i, j, new Color(0, 0, 0, 0));
|
||||
|
||||
// === 新增:绘制网格 ===
|
||||
int gridXCount = 8;
|
||||
int gridYCount = 4;
|
||||
Color gridColor = new Color(0.3f, 0.3f, 0.3f, 0.7f);
|
||||
for (int gx = 1; gx < gridXCount; gx++)
|
||||
{
|
||||
int x = gx * texWidth / gridXCount;
|
||||
DrawVerticalLineOnTexture(tex, x, 0, texHeight - 1, gridColor);
|
||||
}
|
||||
for (int gy = 1; gy < gridYCount; gy++)
|
||||
{
|
||||
int y = gy * texHeight / gridYCount;
|
||||
DrawHorizontalLineOnTexture(tex, 0, texWidth - 1, y, gridColor);
|
||||
}
|
||||
|
||||
// === 新增:绘制边框 ===
|
||||
Color borderColor = Color.white;
|
||||
DrawHorizontalLineOnTexture(tex, 0, texWidth - 1, 0, borderColor);
|
||||
DrawHorizontalLineOnTexture(tex, 0, texWidth - 1, texHeight - 1, borderColor);
|
||||
DrawVerticalLineOnTexture(tex, 0, 0, texHeight - 1, borderColor);
|
||||
DrawVerticalLineOnTexture(tex, texWidth - 1, 0, texHeight - 1, borderColor);
|
||||
|
||||
int lastY = -1;
|
||||
for (int x = 0; x < texWidth; x++)
|
||||
{
|
||||
float t = (float)x / (texWidth - 1);
|
||||
float time = Mathf.Lerp(minTime, maxTime, t);
|
||||
float value = curve.Evaluate(time);
|
||||
float normY = (value - minValue) / valueRange;
|
||||
int y = (int)(normY * (texHeight - 1));
|
||||
|
||||
bool outOfRange = y < 0 || y >= texHeight;
|
||||
int drawY = y;
|
||||
|
||||
Color drawColor = outOfRange
|
||||
? new Color(1f - curveColor.r, 1f - curveColor.g, 1f - curveColor.b, 1f)
|
||||
: curveColor;
|
||||
|
||||
if (lastY >= 0)
|
||||
{
|
||||
int y0 = lastY;
|
||||
int y1 = y;
|
||||
int x0 = x - 1;
|
||||
int x1 = x;
|
||||
// === 修正:补全断点 ===
|
||||
if (x0 >= 0 && x0 < texWidth && x1 >= 0 && x1 < texWidth)
|
||||
{
|
||||
if (Mathf.Abs(y1 - y0) > 1)
|
||||
{
|
||||
int step = y1 > y0 ? 1 : -1;
|
||||
for (int yyy = y0; yyy != y1; yyy += step)
|
||||
{
|
||||
if (yyy >= 0 && yyy < texHeight)
|
||||
tex.SetPixel(x0, yyy, curveColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
int dy = Mathf.Abs(y1 - y0);
|
||||
int sy = y0 < y1 ? 1 : -1;
|
||||
int err = dy / 2;
|
||||
int yy = y0;
|
||||
for (int xx = x0; xx <= x1; xx++)
|
||||
{
|
||||
bool segOutOfRange = yy < 0 || yy >= texHeight;
|
||||
Color segColor = segOutOfRange
|
||||
? new Color(1f - curveColor.r, 1f - curveColor.g, 1f - curveColor.b, 1f)
|
||||
: curveColor;
|
||||
if (xx >= 0 && xx < texWidth)
|
||||
{
|
||||
for (int j = lastY; j < yy; j++) tex.SetPixel(x0, j, curveColor);
|
||||
for (int j = lastY; j > yy; j--) tex.SetPixel(x0, j, curveColor);
|
||||
tex.SetPixel(xx, yy, segColor);
|
||||
}
|
||||
err -= dy;
|
||||
if (err < 0)
|
||||
{
|
||||
yy += sy;
|
||||
err += (x1 - x0);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (x >= 0 && x < texWidth)
|
||||
tex.SetPixel(x, drawY, drawColor);
|
||||
|
||||
lastY = y;
|
||||
}
|
||||
|
||||
foreach (var key in curve.keys)
|
||||
{
|
||||
float tangentScale = (maxTime - minTime) * 0.08f;
|
||||
if (!float.IsInfinity(key.inTangent))
|
||||
{
|
||||
float t0 = key.time;
|
||||
float v0 = key.value;
|
||||
float t1 = t0 - tangentScale;
|
||||
float v1 = v0 - key.inTangent * tangentScale;
|
||||
int x0 = (int)(((t0 - minTime) / timeRange) * (texWidth - 1));
|
||||
int y0 = (int)(((v0 - minValue) / valueRange) * (texHeight - 1));
|
||||
int x1 = (int)(((t1 - minTime) / timeRange) * (texWidth - 1));
|
||||
int y1 = (int)(((v1 - minValue) / valueRange) * (texHeight - 1));
|
||||
DrawLineOnTexture(tex, x0, y0, x1, y1, tangentColor);
|
||||
}
|
||||
if (!float.IsInfinity(key.outTangent))
|
||||
{
|
||||
float t0 = key.time;
|
||||
float v0 = key.value;
|
||||
float t1 = t0 + tangentScale;
|
||||
float v1 = v0 + key.outTangent * tangentScale;
|
||||
int x0 = (int)(((t0 - minTime) / timeRange) * (texWidth - 1));
|
||||
int y0 = (int)(((v0 - minValue) / valueRange) * (texHeight - 1));
|
||||
int x1 = (int)(((t1 - minTime) / timeRange) * (texWidth - 1));
|
||||
int y1 = (int)(((v1 - minValue) / valueRange) * (texHeight - 1));
|
||||
DrawLineOnTexture(tex, x0, y0, x1, y1, tangentColor * 0.8f);
|
||||
}
|
||||
}
|
||||
|
||||
tex.Apply();
|
||||
curveRawImage.texture = tex;
|
||||
}
|
||||
|
||||
private void DrawLineOnTexture(Texture2D tex, int x0, int y0, int x1, int y1, Color color)
|
||||
{
|
||||
int dx = Mathf.Abs(x1 - x0), sx = x0 < x1 ? 1 : -1;
|
||||
int dy = Mathf.Abs(y1 - y0), sy = y0 < y1 ? 1 : -1;
|
||||
int err = (dx > dy ? dx : -dy) / 2, e2;
|
||||
int lastY = y0;
|
||||
while (true)
|
||||
{
|
||||
for (int j = lastY; j < y0; j++) tex.SetPixel(x0, j, color);
|
||||
for (int j = lastY; j > y0; j--) tex.SetPixel(x0, j, color);
|
||||
tex.SetPixel(x0, y0, color);
|
||||
lastY = y0;
|
||||
if (x0 == x1 && y0 == y1) break;
|
||||
e2 = err;
|
||||
if (e2 > -dx) { err -= dy; x0 += sx; }
|
||||
if (e2 < dy) { err += dx; y0 += sy; }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取关键帧在RawImage中的localPosition(以RawImage中心为原点)
|
||||
/// </summary>
|
||||
public Vector2 GetKeyframeLocalPositionInRawImage(Keyframe key, float scale = 1f)
|
||||
{
|
||||
UpdateCurveRange();
|
||||
if (curveRawImage == null || curve == null || curve.length < 2)
|
||||
return Vector2.zero;
|
||||
|
||||
// 这里直接使用固定的minValue/maxValue
|
||||
float normX = (key.time - minTime) / timeRange;
|
||||
float normY = (key.value - 0f) / Mathf.Max(0.0001f, 1f - 0f);
|
||||
|
||||
float px = normX * curveTextureSize.x;
|
||||
float py = normY * curveTextureSize.y;
|
||||
|
||||
Vector2 localPos = new Vector2(
|
||||
px - curveTextureSize.x * 0.5f,
|
||||
py - curveTextureSize.y * 0.5f
|
||||
);
|
||||
return localPos * scale;
|
||||
}
|
||||
|
||||
[Button("Create Keyframe Images")]
|
||||
public void CreateKeyframeImages()
|
||||
{
|
||||
UpdateCurveRange();
|
||||
if (curveRawImage == null || curve == null || curve.length < 1) return;
|
||||
|
||||
for (int i = curveRawImage.transform.childCount - 1; i >= 0; i--)
|
||||
{
|
||||
var child = curveRawImage.transform.GetChild(i);
|
||||
#if UNITY_EDITOR
|
||||
if (!Application.isPlaying)
|
||||
DestroyImmediate(child.gameObject);
|
||||
else
|
||||
#endif
|
||||
Destroy(child.gameObject);
|
||||
}
|
||||
keyframeImages.Clear();
|
||||
|
||||
for (int i = 0; i < curve.length; i++)
|
||||
{
|
||||
Keyframe key = curve.keys[i];
|
||||
Vector2 localPos = GetKeyframeLocalPositionInRawImage(key);
|
||||
|
||||
GameObject go = new GameObject($"KeyframeImage_{i}", typeof(RectTransform), typeof(Image));
|
||||
go.transform.SetParent(curveRawImage.transform, false);
|
||||
|
||||
RectTransform rt = go.GetComponent<RectTransform>();
|
||||
rt.sizeDelta = Vector2.one * 16f;
|
||||
rt.anchoredPosition = localPos;
|
||||
|
||||
Image img = go.GetComponent<Image>();
|
||||
img.color = keyframeColor;
|
||||
img.raycastTarget = false;
|
||||
PointMover pointMover = go.AddComponent<PointMover>();
|
||||
pointMover.parent = this;
|
||||
pointMover.keyIndex = i;
|
||||
|
||||
Image inImg = null;
|
||||
if (!float.IsInfinity(key.inTangent))
|
||||
{
|
||||
Vector2 tangentLocalPos = GetTangentLocalPosition(key, true);
|
||||
GameObject tgo = new GameObject($"TangentInImage_{i}", typeof(RectTransform), typeof(Image));
|
||||
tgo.transform.SetParent(curveRawImage.transform, false);
|
||||
RectTransform trt = tgo.GetComponent<RectTransform>();
|
||||
trt.sizeDelta = Vector2.one * 10f;
|
||||
trt.anchoredPosition = tangentLocalPos;
|
||||
inImg = tgo.GetComponent<Image>();
|
||||
inImg.color = tangentColor;
|
||||
inImg.raycastTarget = false;
|
||||
PointMover pointMover1 = tgo.AddComponent<PointMover>();
|
||||
pointMover1.IO = 1;
|
||||
pointMover1.parent = this;
|
||||
pointMover1.keyIndex = i;
|
||||
pointMover.subpointMover.Add(pointMover1);
|
||||
}
|
||||
|
||||
Image outImg = null;
|
||||
if (!float.IsInfinity(key.outTangent))
|
||||
{
|
||||
Vector2 tangentLocalPos = GetTangentLocalPosition(key, false);
|
||||
GameObject tgo = new GameObject($"TangentOutImage_{i}", typeof(RectTransform), typeof(Image));
|
||||
tgo.transform.SetParent(curveRawImage.transform, false);
|
||||
RectTransform trt = tgo.GetComponent<RectTransform>();
|
||||
trt.sizeDelta = Vector2.one * 10f;
|
||||
trt.anchoredPosition = tangentLocalPos;
|
||||
outImg = tgo.GetComponent<Image>();
|
||||
outImg.color = tangentColor * 0.8f;
|
||||
outImg.raycastTarget = false;
|
||||
PointMover pointMover2 = tgo.AddComponent<PointMover>();
|
||||
pointMover2.IO = -1;
|
||||
pointMover2.parent = this;
|
||||
pointMover2.keyIndex = i;
|
||||
pointMover.subpointMover.Add(pointMover2);
|
||||
}
|
||||
|
||||
keyframeImages.Add(new KeyframeImageInfo
|
||||
{
|
||||
keyImage = img,
|
||||
inTangentImage = inImg,
|
||||
outTangentImage = outImg
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 修复后的切线位置计算方法
|
||||
private Vector2 GetTangentLocalPosition(Keyframe key, bool isIn)
|
||||
{
|
||||
Vector2 keyLocalPos = GetKeyframeLocalPositionInRawImage(key);
|
||||
float tangent = isIn ? key.inTangent : key.outTangent;
|
||||
|
||||
// 计算像素/单位转换比例
|
||||
float pixelsPerTimeUnit = curveTextureSize.x / timeRange;
|
||||
float pixelsPerValueUnit = curveTextureSize.y / valueRange;
|
||||
|
||||
// 处理无穷斜率的情况(垂直切线)
|
||||
if (float.IsInfinity(tangent))
|
||||
{
|
||||
return keyLocalPos + new Vector2(
|
||||
0,
|
||||
isIn ? -tangentLength * 20f : tangentLength * 20f
|
||||
);
|
||||
}
|
||||
|
||||
// 计算方向向量
|
||||
Vector2 direction = new Vector2(
|
||||
isIn ? -1f : 1f,
|
||||
tangent * (pixelsPerValueUnit / pixelsPerTimeUnit)
|
||||
).normalized;
|
||||
|
||||
// 动态计算像素长度
|
||||
float dynamicLength = tangentLength * Mathf.Min(curveTextureSize.x, curveTextureSize.y) * 0.1f;
|
||||
|
||||
return keyLocalPos + direction * dynamicLength;
|
||||
}
|
||||
[Button("Update Curve From Images")]
|
||||
public void UpdateCurveFromImages()
|
||||
{
|
||||
UpdateCurveRange();
|
||||
if (curve == null || keyframeImages == null || keyframeImages.Count < curve.length) return;
|
||||
|
||||
Keyframe[] newKeys = new Keyframe[curve.length];
|
||||
for (int i = 0; i < curve.length; i++)
|
||||
{
|
||||
RectTransform rt = keyframeImages[i].keyImage.rectTransform;
|
||||
Vector2 localPos = rt.anchoredPosition;
|
||||
float px = localPos.x + curveTextureSize.x * 0.5f;
|
||||
float py = localPos.y + curveTextureSize.y * 0.5f;
|
||||
float normX = px / curveTextureSize.x;
|
||||
float normY = py / curveTextureSize.y;
|
||||
float time = Mathf.Lerp(minTime, maxTime, normX);
|
||||
float value = Mathf.Clamp01(0f + normY * Mathf.Max(0.0001f, 1f - 0f));
|
||||
|
||||
float inTangent = curve.keys[i].inTangent;
|
||||
float outTangent = curve.keys[i].outTangent;
|
||||
float timeScale = timeRange / curveTextureSize.x;
|
||||
float valueScale = valueRange / curveTextureSize.y;
|
||||
|
||||
// 修复切线斜率计算
|
||||
if (keyframeImages[i].inTangentImage != null)
|
||||
{
|
||||
Vector2 inLocalPos = keyframeImages[i].inTangentImage.rectTransform.anchoredPosition;
|
||||
Vector2 keyLocalPos = keyframeImages[i].keyImage.rectTransform.anchoredPosition;
|
||||
|
||||
// 使用像素坐标差计算真实斜率
|
||||
float dx = (keyLocalPos.x - inLocalPos.x) * timeScale;
|
||||
float dy = (keyLocalPos.y - inLocalPos.y) * valueScale;
|
||||
|
||||
if (Mathf.Abs(dx) > 0.001f)
|
||||
inTangent = dy / dx;
|
||||
}
|
||||
|
||||
if (keyframeImages[i].outTangentImage != null)
|
||||
{
|
||||
Vector2 outLocalPos = keyframeImages[i].outTangentImage.rectTransform.anchoredPosition;
|
||||
Vector2 keyLocalPos = keyframeImages[i].keyImage.rectTransform.anchoredPosition;
|
||||
|
||||
// 使用像素坐标差计算真实斜率
|
||||
float dx = (outLocalPos.x - keyLocalPos.x) * timeScale;
|
||||
float dy = (outLocalPos.y - keyLocalPos.y) * valueScale;
|
||||
|
||||
if (Mathf.Abs(dx) > 0.001f)
|
||||
outTangent = dy / dx;
|
||||
}
|
||||
|
||||
Keyframe newKey = new Keyframe(time, value, inTangent, outTangent);
|
||||
newKeys[i] = newKey;
|
||||
}
|
||||
curve.keys = newKeys;
|
||||
}
|
||||
|
||||
[Button("Refresh Keyframe Images Position")]
|
||||
public void RefreshKeyframeImagesPosition()
|
||||
{
|
||||
UpdateCurveRange();
|
||||
if (curve == null || keyframeImages == null || keyframeImages.Count < curve.length) return;
|
||||
|
||||
for (int i = 0; i < curve.length; i++)
|
||||
{
|
||||
Keyframe key = curve.keys[i];
|
||||
var info = keyframeImages[i];
|
||||
|
||||
if (info.keyImage != null)
|
||||
{
|
||||
Vector2 localPos = GetKeyframeLocalPositionInRawImage(key);
|
||||
info.keyImage.rectTransform.anchoredPosition = localPos;
|
||||
}
|
||||
|
||||
if (info.inTangentImage != null && !float.IsInfinity(key.inTangent))
|
||||
{
|
||||
Vector2 tangentLocalPos = GetTangentLocalPosition(key, true);
|
||||
info.inTangentImage.rectTransform.anchoredPosition = tangentLocalPos;
|
||||
}
|
||||
|
||||
if (info.outTangentImage != null && !float.IsInfinity(key.outTangent))
|
||||
{
|
||||
Vector2 tangentLocalPos = GetTangentLocalPosition(key, false);
|
||||
info.outTangentImage.rectTransform.anchoredPosition = tangentLocalPos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public CompositeParameterWindow compositeParameterWindow;
|
||||
public void UpadteValue()
|
||||
{
|
||||
compositeParameterWindow.connectedBaseElement.GetType().GetField(compositeParameterWindow.parameterName).SetValue(compositeParameterWindow.connectedBaseElement, curve);
|
||||
}
|
||||
|
||||
// === 新增:绘制水平线辅助方法 ===
|
||||
private void DrawHorizontalLineOnTexture(Texture2D tex, int x0, int x1, int y, Color color)
|
||||
{
|
||||
int width = tex.width;
|
||||
int height = tex.height;
|
||||
if (y < 0 || y >= height) return;
|
||||
int minX = Mathf.Clamp(Mathf.Min(x0, x1), 0, width - 1);
|
||||
int maxX = Mathf.Clamp(Mathf.Max(x0, x1), 0, width - 1);
|
||||
for (int x = minX; x <= maxX; x++)
|
||||
tex.SetPixel(x, y, color);
|
||||
}
|
||||
|
||||
// === 新增:绘制垂直线辅助方法 ===
|
||||
private void DrawVerticalLineOnTexture(Texture2D tex, int x, int y0, int y1, Color color)
|
||||
{
|
||||
int width = tex.width;
|
||||
int height = tex.height;
|
||||
if (x < 0 || x >= width) return;
|
||||
int minY = Mathf.Clamp(Mathf.Min(y0, y1), 0, height - 1);
|
||||
int maxY = Mathf.Clamp(Mathf.Max(y0, y1), 0, height - 1);
|
||||
for (int y = minY; y <= maxY; y++)
|
||||
tex.SetPixel(x, y, color);
|
||||
}
|
||||
}
|
||||
|
||||
public class PointMover : MonoBehaviour
|
||||
{
|
||||
|
||||
public RectTransform rectTransform;
|
||||
public KeyframeVisualizer parent;
|
||||
public int keyIndex = -1; // 记录所属关键帧索引
|
||||
public PointMover parentPointMover;
|
||||
public List<PointMover> subpointMover = new();
|
||||
public bool Pressed;
|
||||
public int IO = 0;//0关键帧 1in -1out
|
||||
|
||||
private Dictionary<PointMover, Vector2> initialOffsets; // 存储切线点初始偏移
|
||||
private Vector2 startPosition; // 拖拽开始位置
|
||||
|
||||
private void Start()
|
||||
{
|
||||
rectTransform = gameObject.GetComponent<RectTransform>();
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (RectTransformUtility.RectangleContainsScreenPoint(rectTransform, Mouse.current.position.ReadValue()))
|
||||
{
|
||||
if (Mouse.current.leftButton.wasPressedThisFrame)
|
||||
{
|
||||
StartCoroutine(Moving());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator Moving()
|
||||
{
|
||||
var windowDragger = parent.compositeParameterWindow.GetComponent<WindowDragger>();
|
||||
if (windowDragger != null)
|
||||
{
|
||||
windowDragger.Lock = true;
|
||||
}
|
||||
|
||||
// 获取边界尺寸
|
||||
float halfWidth = parent.curveTextureSize.x * 0.5f;
|
||||
float halfHeight = parent.curveTextureSize.y * 0.5f;
|
||||
|
||||
// 如果是切线点,记录初始位置和方向
|
||||
Vector2 initialPosition = rectTransform.anchoredPosition;
|
||||
Vector2 initialDirection = Vector2.zero;
|
||||
if (IO != 0)
|
||||
{
|
||||
PointMover keyPoint = parentPointMover != null ? parentPointMover : this;
|
||||
Vector2 keyPos = keyPoint.rectTransform.anchoredPosition;
|
||||
initialDirection = (initialPosition - keyPos).normalized;
|
||||
}
|
||||
|
||||
while (Mouse.current.leftButton.isPressed)
|
||||
{
|
||||
Vector2 mouseDelta = Mouse.current.delta.ReadValue();
|
||||
Vector2 newPos = rectTransform.anchoredPosition + mouseDelta;
|
||||
|
||||
// 边界约束
|
||||
newPos.x = Mathf.Clamp(newPos.x, -halfWidth, halfWidth);
|
||||
newPos.y = Mathf.Clamp(newPos.y, -halfHeight, halfHeight);
|
||||
|
||||
// 如果是切线点,约束移动方向
|
||||
if (IO != 0 && initialDirection != Vector2.zero)
|
||||
{
|
||||
Vector2 keyPos = parentPointMover.rectTransform.anchoredPosition;
|
||||
Vector2 toNewPos = newPos - keyPos;
|
||||
|
||||
// 计算与初始方向的夹角
|
||||
float angle = Vector2.Angle(initialDirection, toNewPos);
|
||||
|
||||
// 如果偏离初始方向超过45度,修正方向
|
||||
if (angle > 45f)
|
||||
{
|
||||
// 投影到初始方向
|
||||
float dot = Vector2.Dot(toNewPos, initialDirection);
|
||||
newPos = keyPos + initialDirection * Mathf.Sign(dot) * toNewPos.magnitude;
|
||||
}
|
||||
}
|
||||
|
||||
rectTransform.anchoredPosition = newPos;
|
||||
|
||||
// 如果是关键帧点,同时移动切线点
|
||||
if (IO == 0)
|
||||
{
|
||||
foreach (PointMover tangentPoint in subpointMover)
|
||||
{
|
||||
if (tangentPoint != null)
|
||||
{
|
||||
tangentPoint.rectTransform.anchoredPosition += mouseDelta;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
yield return null;
|
||||
}
|
||||
|
||||
if (windowDragger != null)
|
||||
{
|
||||
windowDragger.Lock = false;
|
||||
}
|
||||
UpdateParentCurve();
|
||||
}
|
||||
|
||||
public void UpdateParentCurve()
|
||||
{
|
||||
parent.UpdateCurveFromImages();
|
||||
parent.DrawCurveToRawImage();
|
||||
parent.UpadteValue();
|
||||
parent.CreateKeyframeImages();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5e4743327f32eb24e86090ec474ac91a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -65518,6 +65518,12 @@
|
||||
"startTime" : 28.8,
|
||||
"endTime" : 32,
|
||||
"animationCurveType" : 0
|
||||
},{
|
||||
"startValue" : 0,
|
||||
"endValue" : 1,
|
||||
"startTime" : 28.8,
|
||||
"endTime" : 32,
|
||||
"animationCurveType" : 0
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -73541,10 +73547,10 @@
|
||||
"inTangent" : 0,
|
||||
"outTangent" : 0
|
||||
},{
|
||||
"time" : 0.5,
|
||||
"time" : 0.185,
|
||||
"value" : 1,
|
||||
"inTangent" : 0,
|
||||
"outTangent" : 0
|
||||
"outTangent" : -3.43269825
|
||||
},{
|
||||
"time" : 1,
|
||||
"value" : 0,
|
||||
|
||||
@@ -65518,6 +65518,12 @@
|
||||
"startTime" : 28.8,
|
||||
"endTime" : 32,
|
||||
"animationCurveType" : 0
|
||||
},{
|
||||
"startValue" : 0,
|
||||
"endValue" : 1,
|
||||
"startTime" : 28.8,
|
||||
"endTime" : 32,
|
||||
"animationCurveType" : 0
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -73530,7 +73536,7 @@
|
||||
"effectTime" : 0
|
||||
},{
|
||||
"__type" : "Ichni.RhythmGame.Beatmap.PixelateEffect_BM,Assembly-CSharp",
|
||||
"duration" : 5,
|
||||
"duration" : 2.5,
|
||||
"bottomX" : 3,
|
||||
"bottomY" : 180,
|
||||
"intensityCurve" : {
|
||||
@@ -73541,21 +73547,41 @@
|
||||
"inTangent" : 0,
|
||||
"outTangent" : 0
|
||||
},{
|
||||
"time" : 0.5,
|
||||
"value" : 1,
|
||||
"time" : 0.1225,
|
||||
"value" : 0.9933333,
|
||||
"inTangent" : -0.2222226,
|
||||
"outTangent" : 0.2222226
|
||||
},{
|
||||
"time" : 0.1925,
|
||||
"value" : 0.01,
|
||||
"inTangent" : 0,
|
||||
"outTangent" : 0
|
||||
},{
|
||||
"time" : 0.3175,
|
||||
"value" : 0.9833333,
|
||||
"inTangent" : -0.3555552,
|
||||
"outTangent" : 0.3555552
|
||||
},{
|
||||
"time" : 0.405,
|
||||
"value" : 0.006666667,
|
||||
"inTangent" : 0,
|
||||
"outTangent" : 0
|
||||
},{
|
||||
"time" : 0.5175,
|
||||
"value" : 1,
|
||||
"inTangent" : -0.2222226,
|
||||
"outTangent" : -3.592717
|
||||
},{
|
||||
"time" : 1,
|
||||
"value" : 0,
|
||||
"inTangent" : 0,
|
||||
"inTangent" : -0.1006292,
|
||||
"outTangent" : 0
|
||||
}
|
||||
],
|
||||
"preWrapMode" : 8,
|
||||
"postWrapMode" : 8
|
||||
},
|
||||
"effectTime" : 5
|
||||
"effectTime" : 2.5
|
||||
}
|
||||
],"Late":[
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user