diff --git a/Client/Assets/Editor.meta b/Client/Assets/Editor.meta new file mode 100644 index 0000000..b8a77ba --- /dev/null +++ b/Client/Assets/Editor.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: cfd4e71629ef4332ad3e97a9b19a6574 +timeCreated: 1757414550 \ No newline at end of file diff --git a/Client/Assets/Editor/UIBezierCurveGeneratorEditor.cs b/Client/Assets/Editor/UIBezierCurveGeneratorEditor.cs new file mode 100644 index 0000000..52514a6 --- /dev/null +++ b/Client/Assets/Editor/UIBezierCurveGeneratorEditor.cs @@ -0,0 +1,144 @@ +using UI; +using UnityEditor; +using UnityEngine; + +namespace Editor +{ + +// 告诉 Unity 这个编辑器是为 UIBezierCurveGenerator 组件服务的 + [CustomEditor(typeof(UIBezierCurveGenerator))] + public class UIBezierCurveGeneratorEditor : UnityEditor.Editor + { + // 这个方法用于定义组件在 Inspector 窗口中的显示 + public override void OnInspectorGUI() + { + // 调用基类的 OnInspectorGUI 方法,绘制所有 public 或 [SerializeField] 字段 + // 这意味着我们会看到 P0, P1, P2, P3 和 segmentCount 的默认 Inspector 控件 + base.OnInspectorGUI(); + + // 获取目标组件的引用 + UIBezierCurveGenerator generator = (UIBezierCurveGenerator)target; + + // 可以在这里添加自定义的 Inspector 按钮或信息 + if (GUILayout.Button("Generate Curve Now")) + { + generator.GenerateCurvePoints(); + } + } + + // 这个方法用于在 Scene 视图中绘制 Gizmos 或处理交互 + protected virtual void OnSceneGUI() + { + // 获取当前被选中的 UIBezierCurveGenerator 实例 + UIBezierCurveGenerator generator = (UIBezierCurveGenerator)target; + RectTransform rectTransform = generator.GetComponent(); + + // 如果没有 RectTransform 或 UILineRenderer,则无法操作,直接返回 + if (rectTransform == null || generator.lineRenderer == null) // lineRenderer 现已为 public + { + return; + } + + // 确保在 Scene 视图中显示时重新生成曲线 + // 这有助于在编辑器中实时预览,即使 Inspector 没有变动。 + // 但要注意,频繁调用 GenerateCurvePoints() 可能对性能有轻微影响, + // 但对于贝塞尔曲线这种操作,通常是可以接受的。 + generator.GenerateCurvePoints(); + + + // 设置 Unity Editor Handles 的颜色,方便区分不同的点 + Handles.color = Color.white; + // 修正:使用 HandleUtility.GetHandleSize 方法,并根据 P0 的世界位置计算句柄大小 + float handleSphereSize = + HandleUtility.GetHandleSize(rectTransform.TransformPoint(generator.P0)) * 0.05f; // 调整一个合适的大小比例 + + // ========================================================= + // P0 (起点) 的操作 + // ========================================================= + Handles.color = Color.green; // 绿色表示起点 + Vector3 worldP0 = rectTransform.TransformPoint(generator.P0); // 将 P0 从局部坐标转换为世界坐标 + + EditorGUI.BeginChangeCheck(); // 开始检查是否有改变发生 + // 绘制一个可拖动的 PositionHandle,返回用户拖动后的新世界坐标 + worldP0 = Handles.PositionHandle(worldP0, Quaternion.identity); + if (EditorGUI.EndChangeCheck()) // 如果 PositionHandle 被拖动,检测到改变 + { + Undo.RecordObject(generator, "Move Bezier Point P0"); // 记录操作,支持撤销 + generator.P0 = rectTransform.InverseTransformPoint(worldP0); // 将新的世界坐标转换回局部坐标 + generator.GenerateCurvePoints(); // 立即更新曲线 (调用组件的方法) + EditorUtility.SetDirty(generator); // 标记组件已修改,确保保存到场景 + } + + Handles.DrawSolidDisc(worldP0, Vector3.forward, handleSphereSize * 0.8f); // 绘制一个小圆盘作为点标记 + + + // ========================================================= + // P1 (第一个控制点) 的操作 + // ========================================================= + Handles.color = Color.blue; // 蓝色表示第一个控制点 + Vector3 worldP1 = rectTransform.TransformPoint(generator.P1); + + EditorGUI.BeginChangeCheck(); + worldP1 = Handles.PositionHandle(worldP1, Quaternion.identity); + if (EditorGUI.EndChangeCheck()) + { + Undo.RecordObject(generator, "Move Bezier Point P1"); + generator.P1 = rectTransform.InverseTransformPoint(worldP1); + generator.GenerateCurvePoints(); + EditorUtility.SetDirty(generator); + } + + Handles.DrawSolidDisc(worldP1, Vector3.forward, handleSphereSize * 0.6f); + + + // ========================================================= + // P2 (第二个控制点) 的操作 + // ========================================================= + Handles.color = Color.magenta; // 洋红色表示第二个控制点 + Vector3 worldP2 = rectTransform.TransformPoint(generator.P2); + + EditorGUI.BeginChangeCheck(); + worldP2 = Handles.PositionHandle(worldP2, Quaternion.identity); + if (EditorGUI.EndChangeCheck()) + { + Undo.RecordObject(generator, "Move Bezier Point P2"); + generator.P2 = rectTransform.InverseTransformPoint(worldP2); + generator.GenerateCurvePoints(); + EditorUtility.SetDirty(generator); + } + + Handles.DrawSolidDisc(worldP2, Vector3.forward, handleSphereSize * 0.6f); + + + // ========================================================= + // P3 (终点) 的操作 + // ========================================================= + Handles.color = Color.red; // 红色表示终点 + Vector3 worldP3 = rectTransform.TransformPoint(generator.P3); + + EditorGUI.BeginChangeCheck(); + worldP3 = Handles.PositionHandle(worldP3, Quaternion.identity); + if (EditorGUI.EndChangeCheck()) + { + Undo.RecordObject(generator, "Move Bezier Point P3"); + generator.P3 = rectTransform.InverseTransformPoint(worldP3); + generator.GenerateCurvePoints(); + EditorUtility.SetDirty(generator); + } + + Handles.DrawSolidDisc(worldP3, Vector3.forward, handleSphereSize * 0.8f); + + + // ========================================================= + // 绘制辅助线 (控制杆),连接起点到第一个控制点,终点到第二个控制点 + // ========================================================= + Handles.color = Color.gray; // 灰色辅助线 + Handles.DrawLine(worldP0, worldP1); // P0 -> P1 + Handles.DrawLine(worldP2, worldP3); // P2 -> P3 + + // 刷新 Scene 视图,确保所有 Gizmos 和曲线更新立即显示 + SceneView.RepaintAll(); + } + } + +} \ No newline at end of file diff --git a/Client/Assets/Editor/UIBezierCurveGeneratorEditor.cs.meta b/Client/Assets/Editor/UIBezierCurveGeneratorEditor.cs.meta new file mode 100644 index 0000000..2314a2d --- /dev/null +++ b/Client/Assets/Editor/UIBezierCurveGeneratorEditor.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: c1a4aaa124cb4e6c9d26f54bde32d674 +timeCreated: 1757418725 \ No newline at end of file diff --git a/Client/Assets/Resources/Prefab/Entity/EntityPrefab.prefab b/Client/Assets/Resources/Prefab/Entity/EntityPrefab.prefab index 9076b03..3d9553a 100644 --- a/Client/Assets/Resources/Prefab/Entity/EntityPrefab.prefab +++ b/Client/Assets/Resources/Prefab/Entity/EntityPrefab.prefab @@ -176,7 +176,10 @@ MonoBehaviour: healthBarPrefab: {fileID: 8307348883874536545} entityPrefab: {fileID: 3332598847335032684} weaponAnimator: {fileID: 1007148524615441468} + weaponItem: {fileID: 0} + weaponAttackAnimation: {fileID: 0} direction: {x: 0, y: 0, z: 0} + attackDirection: {x: 0, y: 0, z: 0} body: {fileID: 2838206730318674270} affiliation: canSelect: 1 @@ -246,6 +249,37 @@ Rigidbody2D: m_SleepingMode: 1 m_CollisionDetection: 0 m_Constraints: 4 +--- !u!1 &1007148524615441468 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4504455988891581487} + m_Layer: 0 + m_Name: WeaponTexture + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &4504455988891581487 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1007148524615441468} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 697189026367054479} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &2838206730318674270 GameObject: m_ObjectHideFlags: 0 @@ -366,70 +400,3 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 605f185650fe46d89a6e0d60fb8fb11c, type: 3} m_Name: m_EditorClassIdentifier: ---- !u!1001 &5211884413447499418 -PrefabInstance: - m_ObjectHideFlags: 0 - serializedVersion: 2 - m_Modification: - serializedVersion: 3 - m_TransformParent: {fileID: 697189026367054479} - m_Modifications: - - target: {fileID: 5021031438404678310, guid: ea9af70ce0f4c8b4a9de58ac63074156, type: 3} - propertyPath: m_Name - value: WeaponTexture - objectReference: {fileID: 0} - - target: {fileID: 8563418329714102965, guid: ea9af70ce0f4c8b4a9de58ac63074156, type: 3} - propertyPath: m_LocalPosition.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 8563418329714102965, guid: ea9af70ce0f4c8b4a9de58ac63074156, type: 3} - propertyPath: m_LocalPosition.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 8563418329714102965, guid: ea9af70ce0f4c8b4a9de58ac63074156, type: 3} - propertyPath: m_LocalPosition.z - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 8563418329714102965, guid: ea9af70ce0f4c8b4a9de58ac63074156, type: 3} - propertyPath: m_LocalRotation.w - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 8563418329714102965, guid: ea9af70ce0f4c8b4a9de58ac63074156, type: 3} - propertyPath: m_LocalRotation.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 8563418329714102965, guid: ea9af70ce0f4c8b4a9de58ac63074156, type: 3} - propertyPath: m_LocalRotation.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 8563418329714102965, guid: ea9af70ce0f4c8b4a9de58ac63074156, type: 3} - propertyPath: m_LocalRotation.z - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 8563418329714102965, guid: ea9af70ce0f4c8b4a9de58ac63074156, type: 3} - propertyPath: m_LocalEulerAnglesHint.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 8563418329714102965, guid: ea9af70ce0f4c8b4a9de58ac63074156, type: 3} - propertyPath: m_LocalEulerAnglesHint.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 8563418329714102965, guid: ea9af70ce0f4c8b4a9de58ac63074156, type: 3} - propertyPath: m_LocalEulerAnglesHint.z - value: 0 - objectReference: {fileID: 0} - m_RemovedComponents: [] - m_RemovedGameObjects: [] - m_AddedGameObjects: [] - m_AddedComponents: [] - m_SourcePrefab: {fileID: 100100000, guid: ea9af70ce0f4c8b4a9de58ac63074156, type: 3} ---- !u!1 &1007148524615441468 stripped -GameObject: - m_CorrespondingSourceObject: {fileID: 5021031438404678310, guid: ea9af70ce0f4c8b4a9de58ac63074156, type: 3} - m_PrefabInstance: {fileID: 5211884413447499418} - m_PrefabAsset: {fileID: 0} ---- !u!4 &4504455988891581487 stripped -Transform: - m_CorrespondingSourceObject: {fileID: 8563418329714102965, guid: ea9af70ce0f4c8b4a9de58ac63074156, type: 3} - m_PrefabInstance: {fileID: 5211884413447499418} - m_PrefabAsset: {fileID: 0} diff --git a/Client/Assets/Scenes/Test.unity b/Client/Assets/Scenes/Test.unity index 303940d..54eb16e 100644 --- a/Client/Assets/Scenes/Test.unity +++ b/Client/Assets/Scenes/Test.unity @@ -873,6 +873,303 @@ Transform: m_Children: [] m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1688506932 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1688506936} + - component: {fileID: 1688506935} + - component: {fileID: 1688506934} + - component: {fileID: 1688506933} + m_Layer: 5 + m_Name: Canvas + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1688506933 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1688506932} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreReversedGraphics: 1 + m_BlockingObjects: 0 + m_BlockingMask: + serializedVersion: 2 + m_Bits: 4294967295 +--- !u!114 &1688506934 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1688506932} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UiScaleMode: 0 + m_ReferencePixelsPerUnit: 100 + m_ScaleFactor: 1 + m_ReferenceResolution: {x: 800, y: 600} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 0 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 1 + m_PresetInfoIsWorld: 0 +--- !u!223 &1688506935 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1688506932} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 1 + m_Camera: {fileID: 1057087089} + m_PlaneDistance: 100 + m_PixelPerfect: 0 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_VertexColorAlwaysGammaSpace: 0 + m_AdditionalShaderChannelsFlag: 25 + m_UpdateRectTransformForStandalone: 0 + m_SortingLayerID: 0 + m_SortingOrder: 0 + m_TargetDisplay: 0 +--- !u!224 &1688506936 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1688506932} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0, y: 0, z: 0} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1813565768} + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0, y: 0} +--- !u!1 &1802079591 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1802079592} + m_Layer: 0 + m_Name: SkillTree + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1802079592 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1802079591} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 33.93411, y: 34.43715, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1813565767 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1813565768} + - component: {fileID: 1813565770} + - component: {fileID: 1813565769} + - component: {fileID: 1813565771} + m_Layer: 5 + m_Name: GameObject + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1813565768 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1813565767} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1688506936} + 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: 100, y: 100} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1813565769 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1813565767} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a7c56ce7d0f247639e5fff6ebba2edd6, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + points: + - {x: -133.03534, y: 73.06387} + - {x: -88.07134, y: 68.2778} + - {x: -52.80454, y: 62.199043} + - {x: -25.609941, y: 55.11205} + - {x: -5.077899, y: 47.27628} + - {x: 10.005646, y: 38.927437} + - {x: 20.67804, y: 30.27879} + - {x: 27.817818, y: 21.522396} + - {x: 32.16182, y: 12.830205} + - {x: 34.321438, y: 4.355151} + - {x: 34.797802, y: -3.7678308} + - {x: 33.996346, y: -11.420871} + - {x: 32.2403, y: -18.502266} + - {x: 29.783356, y: -24.925674} + - {x: 26.82156, y: -30.61938} + - {x: 23.504032, y: -35.52555} + - {x: 19.94323, y: -39.599724} + - {x: 16.223877, y: -42.810104} + - {x: 12.411441, y: -45.137222} + - {x: 8.559343, y: -46.57335} + - {x: 4.7155967, y: -47.122353} + - {x: 0.9283457, y: -46.799118} + - {x: -2.7493114, y: -45.6296} + - {x: -6.2555466, y: -43.65044} + - {x: -9.516719, y: -40.909004} + - {x: -12.445361, y: -37.463264} + - {x: -14.938893, y: -33.38188} + - {x: -16.879314, y: -28.744246} + - {x: -18.133726, y: -23.640694} + - {x: -18.555773, y: -18.172682} + - {x: -17.987919, y: -12.453108} + - {x: -16.26463, y: -6.606659} + - {x: -13.216493, y: -0.7702131} + - {x: -8.675069, y: 4.9066596} + - {x: -2.4787803, y: 10.261147} + - {x: 5.5203714, y: 15.116601} + - {x: 15.449296, y: 19.281828} + - {x: 27.405247, y: 22.550373} + - {x: 41.446537, y: 24.699694} + - {x: 57.58231, y: 25.49029} + - {x: 75.76138, y: 24.66478} + - {x: 95.86027, y: 21.946861} + - {x: 117.670395, y: 17.040276} + - {x: 140.8842, y: 9.627667} + - {x: 165.08054, y: -0.6306292} + - {x: 189.70929, y: -14.097839} + lineWidth: 5 + lineGradient: + serializedVersion: 2 + key0: {r: 0.023668766, g: 1, b: 0, a: 1} + key1: {r: 1, g: 1, b: 1, a: 1} + key2: {r: 0, g: 0, b: 0, a: 0} + key3: {r: 0, g: 0, b: 0, a: 0} + key4: {r: 0, g: 0, b: 0, a: 0} + key5: {r: 0, g: 0, b: 0, a: 0} + key6: {r: 0, g: 0, b: 0, a: 0} + key7: {r: 0, g: 0, b: 0, a: 0} + ctime0: 0 + ctime1: 65535 + ctime2: 0 + ctime3: 0 + ctime4: 0 + ctime5: 0 + ctime6: 0 + ctime7: 0 + atime0: 0 + atime1: 65535 + atime2: 0 + atime3: 0 + atime4: 0 + atime5: 0 + atime6: 0 + atime7: 0 + m_Mode: 0 + m_ColorSpace: -1 + m_NumColorKeys: 2 + m_NumAlphaKeys: 2 + startCap: 2 + endCap: 2 +--- !u!222 &1813565770 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1813565767} + m_CullTransparentMesh: 1 +--- !u!114 &1813565771 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1813565767} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 8623ad98baf0495b8c8634232e3cae2e, type: 3} + m_Name: + m_EditorClassIdentifier: + lineRenderer: {fileID: 1813565769} + controlPoints: + - {x: -133.03534, y: 73.06387} + - {x: 245.0557, y: 42.776196} + - {x: -155.57315, y: -95.5988} + - {x: 171.73596, y: -95.63857} + - {x: -196.53432, y: -28.766539} + - {x: 5.0138226, y: 99.89391} + - {x: 189.70929, y: -14.097839} + segmentCount: 45 --- !u!1 &2053271181 GameObject: m_ObjectHideFlags: 0 @@ -988,3 +1285,5 @@ SceneRoots: - {fileID: 1245790017} - {fileID: 593350052837672451} - {fileID: 178349937} + - {fileID: 1802079592} + - {fileID: 1688506936} diff --git a/Client/Assets/Scripts/Base/GradientColor.cs b/Client/Assets/Scripts/Base/GradientColor.cs index f445c77..60d8f35 100644 --- a/Client/Assets/Scripts/Base/GradientColor.cs +++ b/Client/Assets/Scripts/Base/GradientColor.cs @@ -14,7 +14,7 @@ namespace Base } // 自定义梯度效果类,继承自BaseMeshEffect - public class Gradient : BaseMeshEffect + public class ColorBar : BaseMeshEffect { [SerializeField] // 序列化字段,可在Inspector中编辑 private Dir dir = Dir.Vertical; // 渐变方向,默认垂直 diff --git a/Client/Assets/Scripts/Base/Launcher.cs b/Client/Assets/Scripts/Base/Launcher.cs index 9d34ebb..dea63b0 100644 --- a/Client/Assets/Scripts/Base/Launcher.cs +++ b/Client/Assets/Scripts/Base/Launcher.cs @@ -29,7 +29,7 @@ namespace Base /// 用于显示加载进度的自定义进度条组件。 /// 请参阅类注释以了解其声明类型与预期API的差异。 /// - public Gradient progressBar; + public ColorBar progressBar; /// /// 用于显示当前加载步骤描述的文本组件。 diff --git a/Client/Assets/Scripts/Entity/Bullet.cs b/Client/Assets/Scripts/Entity/Bullet.cs index 6789668..9531ab2 100644 --- a/Client/Assets/Scripts/Entity/Bullet.cs +++ b/Client/Assets/Scripts/Entity/Bullet.cs @@ -36,7 +36,7 @@ namespace Entity private void OnTriggerEnter2D(Collider2D other) { var entity = other.GetComponent(); - if (!entity || entity == bulletSource || entity is Pickup) return; + if (IsDead||!entity || entity == bulletSource || entity is Pickup) return; if (Managers.AffiliationManager.Instance.GetRelation(bulletSource.affiliation, entity.affiliation) != Relation.Friendly || Setting.Instance.CurrentSettings.friendlyFire) { entity.OnHit(this); diff --git a/Client/Assets/Scripts/Entity/Entity.cs b/Client/Assets/Scripts/Entity/Entity.cs index 5b18141..3606e61 100644 --- a/Client/Assets/Scripts/Entity/Entity.cs +++ b/Client/Assets/Scripts/Entity/Entity.cs @@ -216,6 +216,7 @@ namespace Entity return; weaponItem=GameObjectCreate.SpriteAnimator(currentWeapon.Icon.ToArray(), weaponAnimator.transform); weaponItem.SetFPS(currentWeapon.FPS); + weaponItem.gameObject.SetActive(true); weaponAttackAnimation = GameObjectCreate.SpriteAnimator(currentWeapon.AttackAnimation.ToArray(), weaponAnimator.transform); @@ -393,7 +394,7 @@ namespace Entity private void StartAttack(WeaponResource weaponResource) { _attackTimer = weaponResource.AttackCooldown; - _attackDetectionTime = weaponResource.AttackDetectionTime; + _attackDetectionTime =Mathf.Max(0,weaponResource.AttackCooldown- weaponResource.AttackDetectionTime); currentAttackWeapon = weaponResource; if (weaponResource.AttackAnimationTime > 0) @@ -594,8 +595,13 @@ namespace Entity { var mousePos = MousePosition.GetWorldPosition(); attackDirection = new Vector3(mousePos.x,mousePos.y) - Position; + RotateTool.RotateTransformToDirection(weaponItem.transform, attackDirection); + } + + if (Input.GetKeyDown(KeyCode.V)) + { + weaponItem.gameObject.SetActive(!weaponItem.gameObject.activeSelf); } - // 获取当前键盘输入状态(2D 移动,只使用 X 和 Y 轴) var inputDirection = Vector2.zero; diff --git a/Client/Assets/Scripts/Prefab/SkillTreeNodeProfab.cs b/Client/Assets/Scripts/Prefab/SkillTreeNodeProfab.cs new file mode 100644 index 0000000..7f4a533 --- /dev/null +++ b/Client/Assets/Scripts/Prefab/SkillTreeNodeProfab.cs @@ -0,0 +1,7 @@ +namespace Prefab +{ + public class SkillTreeNodeProfab + { + + } +} \ No newline at end of file diff --git a/Client/Assets/Scripts/Prefab/SkillTreeNodeProfab.cs.meta b/Client/Assets/Scripts/Prefab/SkillTreeNodeProfab.cs.meta new file mode 100644 index 0000000..f2a8018 --- /dev/null +++ b/Client/Assets/Scripts/Prefab/SkillTreeNodeProfab.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 78843bef7bb2445495588f60349626d9 +timeCreated: 1757395333 \ No newline at end of file diff --git a/Client/Assets/Scripts/UI/UIBezierCurveGenerator.cs b/Client/Assets/Scripts/UI/UIBezierCurveGenerator.cs new file mode 100644 index 0000000..eb7d70b --- /dev/null +++ b/Client/Assets/Scripts/UI/UIBezierCurveGenerator.cs @@ -0,0 +1,148 @@ +using UnityEngine; + +namespace UI +{ + // 需要引用 UILineRenderer 组件 + [RequireComponent(typeof(UILineRenderer))] + // 允许在编辑器模式下实时更新,便于调试 + [ExecuteAlways] + public class UIBezierCurveGenerator : MonoBehaviour + { + // UILineRenderer 组件的引用 + [SerializeField] public UILineRenderer lineRenderer; + + // 控制点 + [Header("Bezier Control Points")] public Vector2 P0; // 起点 + public Vector2 P1; // 第一个控制点 + public Vector2 P2; // 第二个控制点 + public Vector2 P3; // 终点 + + [Header("Curve Settings")] [Range(5, 200)] // 限制段数范围,防止过低导致不平滑,过高导致性能问题 + public int segmentCount = 50; // 曲线的平滑度,即采样的线段数量 + + void Awake() + { + Initialize(); + } + + void OnValidate() + { + Initialize(); + if (lineRenderer != null) + { + GenerateCurvePoints(); // 在编辑器中修改参数时实时更新曲线 + } + } + + /// + /// 初始化组件,获取 UILineRenderer 引用 + /// + private void Initialize() + { + if (lineRenderer == null) + { + lineRenderer = GetComponent(); + if (lineRenderer == null) + { + Debug.LogError("UILineRenderer component not found on this GameObject. Please add one.", this); + enabled = false; // 禁用此组件,防止空引用错误 + } + } + } + + /// + /// 计算三次贝塞尔曲线上的点 + /// B(t) = (1-t)^3 * P0 + 3 * (1-t)^2 * t * P1 + 3 * (1-t) * t^2 * P2 + t^3 * P3 + /// + /// 参数,范围 [0, 1] + /// 起点 + /// 第一个控制点 + /// 第二个控制点 + /// 终点 + /// 在参数 t 处的贝塞尔曲线上点 + private Vector2 CalculateBezierPoint(float t, Vector2 p0, Vector2 p1, Vector2 p2, Vector2 p3) + { + float u = 1 - t; + float tt = t * t; + float uu = u * u; + float uuu = uu * u; + float ttt = tt * t; + + Vector2 p = uuu * p0; // (1-t)^3 * P0 + p += 3 * uu * t * p1; // 3 * (1-t)^2 * t * P1 + p += 3 * u * tt * p2; // 3 * (1-t) * t^2 * P2 + p += ttt * p3; // t^3 * P3 + + return p; + } + + /// + /// 生成贝塞尔曲线的点并更新 UILineRenderer + /// + public void GenerateCurvePoints() + { + if (lineRenderer == null || segmentCount <= 0) + { + Debug.LogWarning("UILineRenderer is null or segmentCount is invalid. Cannot generate curve.", this); + return; + } + + // 清空 UILineRenderer 的点列表,以便重新填充 + lineRenderer.points.Clear(); + + for (int i = 0; i <= segmentCount; i++) + { + float t = i / (float)segmentCount; + Vector2 point = CalculateBezierPoint(t, P0, P1, P2, P3); + lineRenderer.points.Add(point); + } + + // 通知 UILineRenderer 需要重新绘制其几何体 + lineRenderer.SetAllDirty(); + } + + /// + /// 提供了通过代码设置控制点并刷新曲线的方法 + /// + public void SetControlPoints(Vector2 p0, Vector2 p1, Vector2 p2, Vector2 p3) + { + this.P0 = p0; + this.P1 = p1; + this.P2 = p2; + this.P3 = p3; + GenerateCurvePoints(); + } + + /// + /// 提供了通过代码设置曲线段数并刷新曲线的方法 + /// + public void SetSegmentCount(int count) + { + segmentCount = Mathf.Max(5, count); // 至少保留5段,保证一定平滑度 + GenerateCurvePoints(); + } + + // 当组件首次添加或重置时调用 + void Reset() + { + Initialize(); // 确保 lineRenderer 已初始化 + + // 根据 RectTransform 的大小设置默认点,确保在可见范围内 + RectTransform rt = GetComponent(); + float halfWidth = rt.rect.width / 2f; + float halfHeight = rt.rect.height / 2f; + + // 设置一些默认的控制点,让曲线在UI区域内可见 + // 这些是相对于 RectTransform 的局部坐标 + P0 = new Vector2(-halfWidth * 0.8f, -halfHeight * 0.5f); // 左下 + P1 = new Vector2(-halfWidth * 0.4f, halfHeight * 0.8f); // 左上控制点 + P2 = new Vector2(halfWidth * 0.4f, halfHeight * 0.8f); // 右上控制点 + P3 = new Vector2(halfWidth * 0.8f, -halfHeight * 0.5f); // 右下 + + segmentCount = 50; + + GenerateCurvePoints(); // 立即生成曲线 + } + } + +} \ No newline at end of file diff --git a/Client/Assets/Scripts/UI/UIBezierCurveGenerator.cs.meta b/Client/Assets/Scripts/UI/UIBezierCurveGenerator.cs.meta new file mode 100644 index 0000000..276bebb --- /dev/null +++ b/Client/Assets/Scripts/UI/UIBezierCurveGenerator.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 8623ad98baf0495b8c8634232e3cae2e +timeCreated: 1757418458 \ No newline at end of file diff --git a/Client/Assets/Scripts/UI/UILineRenderer.cs b/Client/Assets/Scripts/UI/UILineRenderer.cs new file mode 100644 index 0000000..9982f6c --- /dev/null +++ b/Client/Assets/Scripts/UI/UILineRenderer.cs @@ -0,0 +1,439 @@ +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.UI; +using static UI.UILineRenderer; // 允许LineCapType直接访问 + +// 确保在UI命名空间内 +namespace UI +{ + /// + /// UILineRenderer 是一个用于在UI中绘制自定义线条的Graphic组件。 + /// 它支持设置线条宽度、渐变颜色以及不同类型的线头(方形或圆形)。 + /// 同时支持线段之间的斜切连接,以确保转角平滑。 + /// + [RequireComponent(typeof(CanvasRenderer))] + public class UILineRenderer : Graphic + { + /// + /// 存储构成线条的顶点列表。 + /// + public List points = new List(); + + /// + /// 线的宽度。 + /// + [SerializeField] private float lineWidth = 5f; + + /// + /// 获取或设置线的宽度。 + /// 设置新值时,如果宽度发生改变,将触发UI网格的重新绘制。 + /// + public float LineWidth + { + get => lineWidth; + set + { + // 仅当值发生显著变化时才更新,以避免不必要的重绘。 + // Mathf.Abs(lineWidth - value) > float.Epsilon 是一个更健壮的浮点数比较方式。 + if (Mathf.Abs(lineWidth - value) > float.Epsilon) + { + lineWidth = value; + SetVerticesDirty(); // 标记UI网格需要重新生成。 + } + } + } + + /// + /// 用于线条的渐变颜色。 + /// + public Gradient lineGradient = new Gradient(); + + /// + /// 定义线条两端的线头类型。 + /// + public enum LineCapType + { + /// + /// 无线头。 + /// + None, + /// + /// 方形线头。 + /// + Square, + /// + /// 圆形线头。 + /// + Round + } + + /// + /// 线的起始端线头类型。 + /// + public LineCapType startCap = LineCapType.None; + + /// + /// 线的结束端线头类型。 + /// + public LineCapType endCap = LineCapType.None; + + /// + /// 获取用于UI渲染的相机。 + /// 如果Canvas的渲染模式是Screen Space - Overlay,则返回null,此时不需要相机。 + /// + /// 用于UI渲染的Camera实例,或在Overlay模式下返回null。 + private Camera GetCanvasRenderCamera() + { + Canvas _canvas = GetComponentInParent(); + // 作为Graphic组件,总会有一个Canvas作为父级。 + if (_canvas == null) return null; + // 对于ScreenSpaceOverlay模式,不需要相机来将屏幕点转换为世界点。 + return _canvas.renderMode == RenderMode.ScreenSpaceOverlay ? null : _canvas.worldCamera; + } + + /// + /// 在UI需要被重新绘制时调用,用于生成网格顶点数据。 + /// + /// VertexHelper,用于构建UI元素的网格。 + protected override void OnPopulateMesh(VertexHelper vh) + { + vh.Clear(); + + // 如果点列表为空或点的数量不足以构成线段,则不绘制任何东西。 + if (points == null || points.Count < 2) + return; + + // 如果渐变色对象未设置或颜色键为空,则默认创建一个纯白色渐变。 + if (lineGradient == null || lineGradient.colorKeys.Length == 0) + { + lineGradient = new Gradient(); + lineGradient.SetKeys( + new[] { new GradientColorKey(Color.white, 0f), new GradientColorKey(Color.white, 1f) }, + new[] { new GradientAlphaKey(1f, 0f), new GradientAlphaKey(1f, 1f) } + ); + } + + List segmentLengths = new List(); + float totalLength = 0f; + + // 预计算线条总长度和每段长度,用于渐变色和线头定位 + for (int i = 0; i < points.Count - 1; i++) + { + float len = Vector2.Distance(points[i], points[i + 1]); + segmentLengths.Add(len); + totalLength += len; + } + + // 存储计算出的所有顶点,包括内外侧及颜色信息 + List vertices = new List(); + + float currentRenderedLength = 0f; + float halfWidth = lineWidth / 2f; + const float miterLimit = 4f; // Miter limit to prevent excessively long miters + + for (int i = 0; i < points.Count; i++) + { + Vector2 p = points[i]; + Vector2 currentPerp = Vector2.zero; // 垂直于期望线段方向的偏移向量 + + // 计算当前点的渐变颜色 + float normalizedDistance = (totalLength > 0 && points.Count > 1) ? (currentRenderedLength / totalLength) : 0f; + Color pointColor = lineGradient.Evaluate(normalizedDistance); + + if (i == 0) // 第一个点 (起点) + { + // 使用第一段的法线方向 + Vector2 segmentDir = (points[1] - p).normalized; + currentPerp = new Vector2(-segmentDir.y, segmentDir.x) * halfWidth; + } + else if (i == points.Count - 1) // 最后一个点 (终点) + { + // 使用最后一段的法线方向 + Vector2 segmentDir = (p - points[points.Count - 2]).normalized; + currentPerp = new Vector2(-segmentDir.y, segmentDir.x) * halfWidth; + } + else // 中间点 (转角) + { + Vector2 prevDir = (p - points[i - 1]).normalized; + Vector2 nextDir = (points[i + 1] - p).normalized; + + // 计算两条线段的平均法线 (角平分线方向) + Vector2 angleBisector = (prevDir + nextDir).normalized; + + // 计算垂直于角平分线的向量 + Vector2 bisectorPerp = new Vector2(-angleBisector.y, angleBisector.x); + + // 确定 bisectorPerp 的方向,使其始终指向“外侧” + // 通过检查 prevDir 和 bisectorPerp 的点积来判断方向 + // 如果点积为负,表示 prevDir 的“向左”方向(perp)与 bisectorPerp 方向相反,需要翻转 + // (prevDir.x * bisectorPerp.y - prevDir.y * bisectorPerp.x) > 0 表示 bisectorPerp 在 prevDir 的左侧 + // (prevDir.x * bisectorPerp.y - prevDir.y * bisectorPerp.x) < 0 表示 bisectorPerp 在 prevDir 的右侧 + // 更直观的判断是看prevDir的右向量和bisectorPerp是否同向 + Vector2 prevDirPerp = new Vector2(-prevDir.y, prevDir.x); // prevDir的左侧法线 + if (Vector2.Dot(prevDirPerp, bisectorPerp) < 0) // 如果bisectorPerp不是指向prevDir左侧,则翻转 + { + bisectorPerp *= -1; + } + + // 计算斜切的延伸长度 + // 角度越尖锐,cos(angle/2) 越小,miterFactor 越大 + float angleRad = Vector2.Angle(prevDir, nextDir) * Mathf.Deg2Rad; + float miterLengthFactor = halfWidth / Mathf.Max(0.001f, Mathf.Cos(angleRad / 2f)); // 防止除以0 + + // 应用miter limit,避免极端尖锐角造成过长斜切 + miterLengthFactor = Mathf.Min(miterLengthFactor, lineWidth * miterLimit); + + currentPerp = bisectorPerp * miterLengthFactor; + } + + // 添加内外侧顶点 + // Outer point + vertices.Add(new UIVertex + { + position = p + currentPerp, + color = pointColor, + uv0 = new Vector2(0, normalizedDistance) // Simple UV mapping for gradient, 0 for outer + }); + // Inner point + vertices.Add(new UIVertex + { + position = p - currentPerp, + color = pointColor, + uv0 = new Vector2(1, normalizedDistance) // Simple UV mapping for gradient, 1 for inner + }); + + // 更新已渲染长度,用于下一个点的渐变计算 + if (i < segmentLengths.Count) + { + currentRenderedLength += segmentLengths[i]; + } + } + + // --- 绘制线段网格 --- + for (int i = 0; i < points.Count - 1; i++) + { + int prevOuter = i * 2; // 上一个点的外侧顶点索引 + int prevInner = i * 2 + 1; // 上一个点的内侧顶点索引 + int currentOuter = (i + 1) * 2; // 当前点的外侧顶点索引 + int currentInner = (i + 1) * 2 + 1; // 当前点的内侧顶点索引 + + // 添加顶点到 VertexHelper + // 确保vh.AddVert的顺序与vertices列表中的顺序一致 + if (i == 0) // 为第一个点添加顶点 + { + vh.AddVert(vertices[prevOuter]); + vh.AddVert(vertices[prevInner]); + } + vh.AddVert(vertices[currentOuter]); + vh.AddVert(vertices[currentInner]); + + // 连接当前点和上一个点的顶点,形成一个矩形(两个三角形) + vh.AddTriangle(prevOuter, currentOuter, currentInner); + vh.AddTriangle(prevOuter, currentInner, prevInner); + } + + // --- 绘制线头 --- + if (points.Count >= 2) + { + // 起点线头 + Vector2 firstSegmentDirection = (points[1] - points[0]).normalized; + DrawCap(vh, points[0], -firstSegmentDirection, startCap, lineGradient.Evaluate(0f)); + + // 终点线头 + Vector2 lastSegmentDirection = (points[points.Count - 1] - points[points.Count - 2]).normalized; + DrawCap(vh, points[points.Count - 1], lastSegmentDirection, endCap, lineGradient.Evaluate(1f)); + } + } + + /// + /// 绘制指定类型的线头。 + /// + /// VertexHelper,用于构建线头网格。 + /// 线头的中心(即线条的端点)。 + /// 线头延伸的方向。 + /// 线头类型(无、方形或圆形)。 + /// 线头的颜色。 + private void DrawCap(VertexHelper vh, Vector2 center, Vector2 direction, LineCapType capType, Color capColor) + { + if (capType == LineCapType.None) return; + + // 计算线头垂直于方向的向量,用于确定线头的宽度。 + var perpendicular = new Vector2(-direction.y, direction.x) * lineWidth / 2f; + // 记录当前VertexHelper中的顶点数量。 + var currentVertCount = vh.currentVertCount; + + UIVertex vertexTemplate = UIVertex.simpleVert; + vertexTemplate.color = capColor; + + if (capType == LineCapType.Square) + { + // 绘制方形线头,通过在端点处添加一个与线段垂直的矩形。 + Vector2 p0 = center - perpendicular; // 线段边缘点1 + Vector2 p1 = center + perpendicular; // 线段边缘点2 + Vector2 p2 = center + perpendicular + (direction * (lineWidth / 2f)); // 延伸点1 + Vector2 p3 = center - perpendicular + (direction * (lineWidth / 2f)); // 延伸点2 + + // 添加方形线头的四个顶点。 + // 注意:这里需要确保顶点的顺序正确,形成两个三角形 + vertexTemplate.position = p0; vertexTemplate.uv0 = new Vector2(0f, 0f); vh.AddVert(vertexTemplate); // 0 + vertexTemplate.position = p1; vertexTemplate.uv0 = new Vector2(1f, 0f); vh.AddVert(vertexTemplate); // 1 + vertexTemplate.position = p2; vertexTemplate.uv0 = new Vector2(1f, 1f); vh.AddVert(vertexTemplate); // 2 + vertexTemplate.position = p3; vertexTemplate.uv0 = new Vector2(0f, 1f); vh.AddVert(vertexTemplate); // 3 + + // 添加两个三角形组成方形线头。 + vh.AddTriangle(currentVertCount, currentVertCount + 1, currentVertCount + 2); + vh.AddTriangle(currentVertCount, currentVertCount + 2, currentVertCount + 3); + } + else if (capType == LineCapType.Round) + { + const int segments = 12; // 增加段数使圆形更平滑 + float radius = lineWidth / 2f; // 半圆的半径等于线宽的一半。 + + // 添加扇形中心点。 + vertexTemplate.position = center; + vertexTemplate.uv0 = new Vector2(0.5f, 0.5f); // 中心UV + vh.AddVert(vertexTemplate); + var centerVertIndex = currentVertCount; + currentVertCount++; + + // 计算半圆弧的起始角度 (垂直向量的角度) 和每段的扫过角度。 + float baseAngle = Mathf.Atan2(perpendicular.y, perpendicular.x); + float angleSweepStep = Mathf.PI / segments; // 180度 / 段数。 + + List arcVerticesIndices = new List(); + + // 遍历并添加半圆弧上的点。 + for (int j = 0; j <= segments; j++) + { + float angle = baseAngle - (j * angleSweepStep); // 逆时针扫描。 + Vector2 pointOnArc = new Vector2(Mathf.Cos(angle), Mathf.Sin(angle)) * radius; + + vertexTemplate.position = center + pointOnArc; + // 计算相对中心的UV,使纹理正确映射到圆形。 + vertexTemplate.uv0 = new Vector2(0.5f + pointOnArc.x / (radius * 2), 0.5f + pointOnArc.y / (radius * 2)); + vh.AddVert(vertexTemplate); + arcVerticesIndices.Add(currentVertCount); + currentVertCount++; + } + + // 连接扇形中心和弧上的相邻点形成三角形,构成半圆形线头。 + for (int j = 0; j < arcVerticesIndices.Count - 1; j++) + { + vh.AddTriangle(centerVertIndex, arcVerticesIndices[j], arcVerticesIndices[j + 1]); + } + } + } + + + /// + /// 将一个UI元素的世界坐标转换为此UILineRenderer的局部坐标,并将其作为线条上的一个点添加。 + /// + /// 要作为线条点的RectTransform UI元素。 + public void AppendUIElement(RectTransform uiElement) + { + Vector2 localPoint; // 转换后的局部坐标。 + + // 将UI元素的世界坐标转换为屏幕坐标,再将屏幕坐标转换为当前UILineRenderer的局部坐标。 + RectTransformUtility.ScreenPointToLocalPointInRectangle( + rectTransform, // 当前 UILineRenderer 的 RectTransform。 + RectTransformUtility.WorldToScreenPoint(GetCanvasRenderCamera(), uiElement.position), // UI 元素的世界坐标转换为屏幕坐标。 + GetCanvasRenderCamera(), // 使用正确的相机进行屏幕到局部坐标转换。 + out localPoint // 输出的局部坐标。 + ); + + // 添加转换后的局部坐标到点列表中。 + points.Add(localPoint); + + SetVerticesDirty(); // 标记UI网格需要重新生成。 + } + + /// + /// 将鼠标的当前位置作为线条的末端点。 + /// 该方法支持对已有折线的末端点进行修改,也可用于绘制“橡皮筋”效果。 + /// + public void SetMouse() + { + // 如果点列表为空,则无法设置鼠标位置为末端点,直接返回。 + if (points.Count == 0) + { + return; + } + + var mousePosition = Input.mousePosition; // 获取当前的鼠标屏幕坐标。 + Vector2 localPoint; + + // 将鼠标屏幕坐标转换为当前UILineRenderer的局部坐标。 + RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, mousePosition, GetCanvasRenderCamera(), out localPoint); + + if (points.Count == 1) + { + // 如果只有一个点,则将鼠标位置作为第二点添加到列表,形成第一条线段。 + points.Add(localPoint); + } + else // points.Count >= 2 + { + // 如果已有多个点,则更新列表中的最后一个点为鼠标位置。 + points[points.Count - 1] = localPoint; + } + + SetVerticesDirty(); // 标记UI网格需要重新生成。 + } + + /// + /// 设置线的宽度。 + /// + /// 线条的新宽度。 + public void SetWidth(float width) + { + LineWidth = width; // 调用公共属性,确保 SetVerticesDirty() 被调用。 + } + + /// + /// 设置线条的渐变颜色。 + /// + /// 新的渐变色对象。 + public void SetGradient(Gradient newGradient) + { + // 仅当新的渐变色不同于当前渐变色时才进行更新。 + if (newGradient != null && !newGradient.Equals(lineGradient)) + { + lineGradient = newGradient; + SetVerticesDirty(); // 标记UI网格需要重新生成。 + } + } + + /// + /// 设置线条的起始和结束线头类型。 + /// + /// 新的起始线头类型。 + /// 新的结束线头类型。 + public void SetCaps(LineCapType startCapType, LineCapType endCapType) + { + // 仅当线头类型发生改变时才更新。 + if (startCap != startCapType || endCap != endCapType) + { + startCap = startCapType; + endCap = endCapType; + SetVerticesDirty(); // 标记UI网格需要重新生成。 + } + } + + /// + /// 重置此UILineRenderer组件的状态,包括清空所有点、重置宽度、渐变色和线头类型。 + /// + public void ResetSelf() + { + points.Clear(); // 清空所有线条点。 + // 重置为默认的纯白色渐变。 + lineGradient = new Gradient(); + lineGradient.SetKeys( + new[] { new GradientColorKey(Color.white, 0f), new GradientColorKey(Color.white, 1f) }, + new[] { new GradientAlphaKey(1f, 0f), new GradientAlphaKey(1f, 1f) } + ); + lineWidth = 5f; // 重置线条宽度为默认值。 + startCap = LineCapType.None; // 重置线头类型为无。 + endCap = LineCapType.None; // 重置线头类型为无。 + SetVerticesDirty(); // 标记UI网格需要重新生成。 + } + } +} diff --git a/Client/Assets/Scripts/UI/UILineRenderer.cs.meta b/Client/Assets/Scripts/UI/UILineRenderer.cs.meta new file mode 100644 index 0000000..045f6a3 --- /dev/null +++ b/Client/Assets/Scripts/UI/UILineRenderer.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a7c56ce7d0f247639e5fff6ebba2edd6 +timeCreated: 1757415509 \ No newline at end of file diff --git a/Client/Data/Core/Define/Item/Weapon.xml b/Client/Data/Core/Define/Item/Weapon.xml index 9a2af28..2718ec6 100644 --- a/Client/Data/Core/Define/Item/Weapon.xml +++ b/Client/Data/Core/Define/Item/Weapon.xml @@ -26,7 +26,7 @@ TestGun 10 3 - 3 + 1 10 1 @@ -38,7 +38,7 @@ TestGun Ranged - 2 + 10
  • TestGunItem
  • @@ -54,7 +54,7 @@
  • testGunAttackAnimation_8
  • testGunAttackAnimation_9
  • - 2.5 + 0.5 1 Uncommon 0.3 diff --git a/Client/Data/Core/Define/Pawn/Monster.xml b/Client/Data/Core/Define/Pawn/Monster.xml index f541f70..132b8ca 100644 --- a/Client/Data/Core/Define/Pawn/Monster.xml +++ b/Client/Data/Core/Define/Pawn/Monster.xml @@ -20,7 +20,7 @@ monster 1 - 123 + 2 Claw @@ -46,7 +46,7 @@ monster 1 - 123 + 2 TestGun @@ -72,8 +72,8 @@ BasicMonsterBehavior monster - 4600 - 100 + 60 + 10 2.5 Weapon_MonsterA1 @@ -107,8 +107,8 @@ BasicMonsterBehavior monster - 6000 - 10 + 80 + 1 4 Weapon_MonsterA2 @@ -142,8 +142,8 @@ BasicMonsterBehavior monster - 5000 - 400 + 70 + 40 1 Weapon_MonsterB1 @@ -177,8 +177,8 @@ BasicMonsterBehavior monster - 8000 - 500 + 100 + 50 1.5 Weapon_MonsterB2 @@ -212,8 +212,8 @@ BasicMonsterBehavior monster - 22000 - 800 + 300 + 80 1 Weapon_MonsterC1 @@ -247,8 +247,8 @@ BasicMonsterBehavior monster - 22000 - 450 + 300 + 45 2 Weapon_MonsterC2 @@ -283,8 +283,8 @@ BasicMonsterBehavior monster - 6400 - 50 + 85 + 5 2 Weapon_MonsterD1 @@ -318,8 +318,8 @@ BasicMonsterBehavior monster - 7200 - 0 + 95 + 0 3 Weapon_MonsterD2 @@ -353,8 +353,8 @@ BasicMonsterBehavior monster - 6550 - 240 + 90 + 24 3 Weapon_MonsterE1 @@ -388,8 +388,8 @@ BasicMonsterBehavior monster - 9120 - 320 + 120 + 32 3 Weapon_MonsterE2 @@ -423,8 +423,8 @@ BasicMonsterBehavior monster - 42000 - 770 + 420 + 70 2 Weapon_MonsterF1 @@ -458,8 +458,8 @@ BasicMonsterBehavior monster - 48000 - 560 + 480 + 50 2 Weapon_MonsterF2 @@ -494,8 +494,8 @@ BasicMonsterBehavior monster - 4800 - 66 + 60 + 7 8 Weapon_MaskMonster @@ -529,8 +529,8 @@ BasicMonsterBehavior monster - 9600 - 132 + 120 + 13 8 Weapon_MaskMonsterElite @@ -564,8 +564,8 @@ BasicMonsterBehavior monster - 6666 - -66 + 90 + -7 0 Weapon_HologramMonster @@ -599,8 +599,8 @@ BasicMonsterBehavior monster - 16666 - -166 + 200 + -17 0 Weapon_HologramMonsterElite @@ -634,8 +634,8 @@ BasicMonsterBehavior monster - 5630 - 78 + 75 + 8 2 Weapon_SnakeMonster @@ -669,8 +669,8 @@ BasicMonsterBehavior monster - 11260 - 156 + 150 + 16 2 Weapon_SnakeMonsterElite @@ -704,8 +704,8 @@ BasicMonsterBehavior monster - 111 - 1 + 3 + 0 11 Weapon_RatMonster @@ -739,8 +739,8 @@ BasicMonsterBehavior monster - 222 - 2 + 5 + 0 22 Weapon_RatMonsterElite