using System; using System.Collections; using System.Collections.Generic; using System.Linq; using Deconstruction.Element; using Deconstruction.Interface; using Deconstruction.Manager; using Deconstruction.Tool; using Deconstruction.Trajectory; using Deconstruction.Type.DMToolSlot; using Deconstruction.Type.Linkable; using UnityEngine; using XericLibrary.Runtime.MacroLibrary; namespace SesothoLine { using LineSegment2 = Deconstruction.Element.PromptLine2.LineSegment2; /// /// 绘制轨迹线的操作 /// /// 当从其他WaitForUserInput_OpSlot到达此处时,将创建TerminalLine2T3用于线路的绘制, /// 同时在线路的两端有两个TerminalPoint用于线路的相连。 /// /// 支持常规的线路连续绘制,起点吸附,终点吸附。 /// 不支持首尾相连。 /// /// public class DrawTerminalLine2T3_OpSlot : WaitForUserInput_OpSlot { #region 字段属性 /// /// 上一步的坐标 /// private Vector3 _lastPointPosition; /// /// 上一步的对齐轨迹计算器 /// private Vector3 _lastPointNormal; /// /// 下一步的坐标 /// private Vector3 _helperPosition = Vector3.zero; /// /// 下一步的法向 /// private Vector3 _helperNormal = Vector3.zero; /// /// 操作的轨迹线 /// private TerminalLine2T3 _line; /// /// 起点 /// private TerminalPoint _startPoint; /// /// 操作的点,也是终点 /// private TerminalPoint _endPoint; /// /// 在场上找到的其他的点 /// private TerminalPoint _otherPoint; /// /// 起点是用上一步的终点替代的 /// private bool _isStartPointSubstitute = false; /// /// 绘制时,终点是自由点 /// private bool _isFreeEndPoint; // public SesothoArrangementWiresTool myWiresTool; // myWiresTool = targetTool as SesothoArrangementWiresTool; #endregion #region 引用封装 /// /// 创建自己的工具 /// private SesothoArrangementWiresTool selfWiresTool => SesothoPeManager.WiresTool; #endregion #region 生命周期 protected override void OnStart() { base.OnStart(); // 检查抵达此处的流程是否正确 if (!HasLastNode) { Debug.LogError( $"绘制节点行为树顺序错误,必须从其他任意WaitForUserInput_OpSlot中抵达此处"); RemoveThis(); return; } if (Last is not WaitForUserInput_OpSlot) { Debug.LogError( $"绘制节点行为树顺序错误,应该是 WaitForUserInput_OpSlot -> {nameof(DrawTerminalLine2T3_OpSlot)},而不是{Last.GetType().Name}"); RemoveThis(); return; } // 设置先决条件 InitPrecondition(); } protected override void OnEnd() { base.OnEnd(); } protected override void Update() { // 阻止基类的默认操作 // base.Update(); // 线的绘制计算,包括空间点吸附,链接等 DrawingProcess(); // 计算完毕后执行渲染,这里调用有可能会带来空引用问题 // 但在此之前的阶段已经对此进行过了处理所以没有关系,如果要在其他地方照抄的话需要注意。 _line.UpdateRender(); // 下一步 if (IsReleaseContinueKey()) { _helperNormal = _line.TrajectoryCalculator.GetEndPointNormal.UpwardPlaneToVector3(); // 起点链接 if (_isStartPointSubstitute) { // 在开始时已经做过转换了 // var dtlt_Slot = Last as DrawTerminalLine2T3_OpSlot; _line.LinkedDataAddPolarity(_startPoint, LinkType.Import); } else { _line.LinkedDataAddPolarity(_startPoint, LinkType.Import); selfWiresTool.PersistentElement(_startPoint); selfWiresTool.AddPeToNeighborGrid(_startPoint); } // 终点链接 if (_otherPoint is null) // || _endPoint.gameObject.activeSelf { _line.LinkedDataAddPolarity(_endPoint, LinkType.Export); selfWiresTool.PersistentElement(_endPoint); selfWiresTool.AddPeToNeighborGrid(_endPoint); } // 如果存在吸附目标 else { selfWiresTool.DeleteElement(_endPoint); _line.LinkedDataAddPolarity(_otherPoint, LinkType.Export); } // 保存线 _line.ReapplyOrigin(); selfWiresTool.PersistentElement(_line); selfWiresTool.AddBulkPeToNeighborGrid(_line); // 下一步 ReplaceThis(new DrawTerminalLine2T3_OpSlot()); } // 取消 else if (IsReleaseCanelKey()) { RemoveThis(); EndPrecondition(); } // todo: 回到上一步 /* * 操作栈的结构使得操作与对象的更新可以分离, * 就是撤回的过程可能有点复杂, * 需要分为工具运行期间撤回和常规撤回。 */ } protected override void AsyncBeforeUpdate() { base.AsyncBeforeUpdate(); } protected override void AsyncUpdate() { base.AsyncUpdate(); } protected override void AsyncAfterUpdate() { base.AsyncAfterUpdate(); } #endregion #region 方法 /// /// 设置先决属性 /// private void InitPrecondition() { switch (Last) { // 使用来自前者的元素 case DrawTerminalLine2T3_OpSlot dtlt_Slot: _isStartPointSubstitute = true; _startPoint = dtlt_Slot._endPoint; _lastPointPosition = dtlt_Slot._helperPosition; _lastPointNormal = dtlt_Slot._helperNormal; break; // 新建,或从空间中继承 case WaitForUserInput_OpSlot wfui_Slot: if (SesothoArrangementWiresTool.GetNearestObjectAsPoint(out var terminalPoint)) { _isStartPointSubstitute = true; _startPoint = terminalPoint; _lastPointPosition = terminalPoint.GetPosition3(); if (SesothoArrangementWiresTool.GetNearestObjectAsLine(terminalPoint, out var terminalLine, out var normal)) _lastPointNormal = normal; else { Debug.LogError("错误:当前绘制的线路准备吸附的目标并非一个完整的链路,或类型错误,正在退出。"); RemoveThis(); } } else { _isStartPointSubstitute = false; selfWiresTool.GetElement(out _startPoint); _lastPointPosition = SesothoArrangementWiresTool.OpKey_IgnoreNeighborAdsorption.Getkey() ? wfui_Slot.MouseHelperPosition : CameraMouseInputHelper.Inst.GetGridAdsorb(wfui_Slot.MouseHelperPosition); _lastPointNormal = default; } break; default: break; } selfWiresTool.GetElement(out _line); selfWiresTool.GetElement(out _endPoint); } /// /// 结束清理属性 /// private void EndPrecondition() { selfWiresTool.DeleteElement(_line); // 不能把别人的东西给回收了 if (!_isStartPointSubstitute) selfWiresTool.DeleteElement(_startPoint); selfWiresTool.DeleteElement(_endPoint); } /// /// 线路绘制过程 /// private void DrawingProcess() { // 获取当前的坐标 _helperPosition = PlaceElementManager.Inst.InputHelper.CurrentGridPosition; _startPoint.transform.position = _lastPointPosition; _isFreeEndPoint = true; // 如果吸附到任意物体,或者用按键忽略这一过程 if (SesothoPeManager.NearestObject is not null && SesothoArrangementWiresTool.GetNearestObjectAsPoint(out _otherPoint) && !SesothoArrangementWiresTool.OpKey_IgnoreNeighborAdsorption.Getkey()) { _isFreeEndPoint = false; if (_endPoint.gameObject.activeSelf) _endPoint.gameObject.SetActive(false); _helperPosition = SesothoPeManager.NearestPoint; _endPoint.transform.position = SesothoPeManager.NearestPoint; if (SesothoArrangementWiresTool.GetNearestObjectAsLine(_otherPoint, out var terminalLine, out var normal)) _helperNormal = normal; } // 如果吸附到任意切线 // else if (NearestLineTangentObject != null) // { // NearestLineTangentPoint // } // 否则自由点 if (_isFreeEndPoint) { if (!_endPoint.gameObject.activeSelf) _endPoint.gameObject.SetActive(true); _otherPoint = null; _helperNormal = default; _endPoint.transform.position = _helperPosition; } _line.SetLineSegment( _lastPointPosition, _helperPosition, _lastPointNormal, _helperNormal ); // 如果当前线的线计算器是圆弧计算器,那么获取它的角度 // if (_line.NowCalculator is RoundTrajectory2 arc) // { // Debug.Log($"角度{arc.Angle} {arc.AngleExact}"); // } var forceStr = SesothoArrangementWiresTool.OpKey_ForceStr.Getkey(); if (forceStr) _line.DrawStraightLine(); else { var force90Arc = SesothoArrangementWiresTool.OpKey_90Arc.Getkey(); var force180Arc = SesothoArrangementWiresTool.OpKey_180Arc.Getkey(); var forceRevCisoid = SesothoArrangementWiresTool.OpKey_RevCisoid.Getkey(); var angle = -1; if (force90Arc || force180Arc) { angle = 0; if (force90Arc) angle += 90; if (force180Arc) angle += 180; } _line.AutomaticDrawCircularLine(angle, forceRevCisoid); } } /// /// 获取光标下的起点 /// /// private bool GetCurrentObject() { // SesothoPeManager. return false; } #endregion } }