init push 0.2.4
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace SesothoLine
|
||||
{
|
||||
public class AGVSettingsManager : MonoBehaviour
|
||||
{
|
||||
// Start is called before the first frame update
|
||||
void Start()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void Update()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,132 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
using XericLibrary.Runtime.CustomEditor;
|
||||
using XericLibrary.Runtime.MacroLibrary;
|
||||
using XericLibrary.Runtime.Type;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
public class ShowMyNameInScene : MonoBehaviour
|
||||
{
|
||||
[Rename("启用")] public bool Enable = false;
|
||||
[Rename("仅选中时显示")] public bool OnlyShowOnSelect = false;
|
||||
[Rename("目标是子项")] public bool ShowAllChindName = true;
|
||||
[Rename("显示名称")] public bool ShowGameObjectName = false;
|
||||
[Rename("显示模型名称")] public bool ShowMeshFilter_MeshName = false;
|
||||
|
||||
public bool RandomEachObjectColor = false;
|
||||
public Color TextColor = Color.white;
|
||||
public RectOffset TextBorder = new RectOffset(0,0,0,0);
|
||||
public RectOffset TextMargin = new RectOffset(0,0,0,0);
|
||||
public RectOffset TextPadding = new RectOffset(0,0,0,0);
|
||||
public RectOffset TextOverflow = new RectOffset(0,0,0,0);
|
||||
public Font font;
|
||||
public int fontSize = 0;
|
||||
public FontStyle fontStyle = FontStyle.Normal;
|
||||
public TextClipping TextClipping = TextClipping.Overflow;
|
||||
public ImagePosition ImagePosition = ImagePosition.ImageLeft;
|
||||
public Vector2 ContentOffset = Vector2.zero;
|
||||
public Vector2 FixedSize = Vector2.zero;
|
||||
public Bool2 Stretch = new Bool2();
|
||||
|
||||
private GUIStyle TextStyle;
|
||||
private StringBuilder _sb = new StringBuilder();
|
||||
|
||||
#if UNITY_EDITOR
|
||||
private void OnDrawGizmos()
|
||||
{
|
||||
if (!Enable)
|
||||
return;
|
||||
if (OnlyShowOnSelect && !ReferenceEquals(Selection.activeGameObject, this))
|
||||
return;
|
||||
|
||||
TextStyle = new GUIStyle()
|
||||
{
|
||||
normal = new GUIStyleState()
|
||||
{
|
||||
textColor = TextColor,
|
||||
// background =
|
||||
},
|
||||
border = TextBorder,
|
||||
margin = TextMargin,
|
||||
padding = TextPadding,
|
||||
overflow = TextOverflow,
|
||||
font = font,
|
||||
fontSize = fontSize,
|
||||
fontStyle = fontStyle,
|
||||
richText = true,
|
||||
clipping = TextClipping,
|
||||
imagePosition = ImagePosition,
|
||||
contentOffset = ContentOffset,
|
||||
fixedHeight = FixedSize.y,
|
||||
fixedWidth = FixedSize.x,
|
||||
stretchHeight = Stretch.y,
|
||||
stretchWidth = Stretch.x,
|
||||
};
|
||||
|
||||
if (ShowAllChindName)
|
||||
{
|
||||
foreach (var item in transform.GetChildren())
|
||||
{
|
||||
if (!item.gameObject.activeInHierarchy)
|
||||
continue;
|
||||
SwitchFilter(item);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawGameObjectNameInScene(transform, transform.name);
|
||||
}
|
||||
}
|
||||
|
||||
private void SwitchFilter(Transform target)
|
||||
{
|
||||
if (_sb == null)
|
||||
_sb = new StringBuilder();
|
||||
_sb.Clear();
|
||||
|
||||
if (RandomEachObjectColor)
|
||||
TextStyle.normal.textColor = MacroColor.RandomHueColor(target.gameObject.GetInstanceID());
|
||||
|
||||
var position = target.position;
|
||||
var mf = target.GetComponent<MeshFilter>();
|
||||
if (mf != null)
|
||||
{
|
||||
var mesh = mf.mesh;
|
||||
if (mesh != null)
|
||||
position += target.rotation * mesh.bounds.center;
|
||||
}
|
||||
|
||||
if (ShowGameObjectName)
|
||||
_sb.AppendLine($"Name: {target.name}");
|
||||
|
||||
if (ShowMeshFilter_MeshName)
|
||||
_sb.AppendLine($"Mesh: {GetComponentName<MeshFilter>(target, a => a.mesh?.name ?? "unknown")}");
|
||||
|
||||
DrawNameInScene(position, _sb.ToString());
|
||||
}
|
||||
|
||||
private void DrawGameObjectNameInScene(Transform obj, string name)
|
||||
{
|
||||
Handles.Label(obj.position, name,TextStyle);
|
||||
}
|
||||
|
||||
private void DrawNameInScene(Vector3 position, string name)
|
||||
{
|
||||
Handles.Label(position, name, TextStyle);
|
||||
}
|
||||
|
||||
private string GetComponentName<T>(Transform target, Func<T, string> getName)
|
||||
where T : Component
|
||||
{
|
||||
return getName(target.GetComponent<T>());
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Deconstruction.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// Xeric 库的运行时辅助类库
|
||||
/// </summary>
|
||||
public static class XericHelper
|
||||
{
|
||||
#region 程序运行
|
||||
|
||||
/// <summary>
|
||||
/// 离开出游戏模式(在编辑模式时仅退出)
|
||||
/// </summary>
|
||||
public static void ExitGameMode()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
UnityEditor.EditorApplication.ExitPlaymode();
|
||||
}
|
||||
#else
|
||||
Application.Quit();
|
||||
#endif
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
|
||||
</project>
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="UserContentModel">
|
||||
<attachedFolders />
|
||||
<explicitIncludes />
|
||||
<explicitExcludes />
|
||||
</component>
|
||||
</project>
|
||||
Generated
+6
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="RiderProjectSettingsUpdater">
|
||||
<option name="vcsConfiguration" value="2" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$/../.." vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="ebb90e97-f354-453f-8b74-0bb83b47e00e" name="更改" comment="">
|
||||
<change beforePath="$PROJECT_DIR$/../../Developer/DLLDev/XericLibrary/MacroLibrary/MacroObject.cs" beforeDir="false" afterPath="$PROJECT_DIR$/../../Developer/DLLDev/XericLibrary/MacroLibrary/MacroObject.cs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../../Developer/DLLDev/XericLibraryEditor/XericLibraryEditor.csproj" beforeDir="false" afterPath="$PROJECT_DIR$/../../Developer/DLLDev/XericLibraryEditor/XericLibraryEditor.csproj" afterDir="false" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||
</component>
|
||||
<component name="Git.Settings">
|
||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$/../.." />
|
||||
</component>
|
||||
<component name="ProjectColorInfo">{
|
||||
"associatedIndex": 7
|
||||
}</component>
|
||||
<component name="ProjectId" id="2tmgRy20ttbG5bPRqK1ymOlCF4G" />
|
||||
<component name="ProjectViewState">
|
||||
<option name="hideEmptyMiddlePackages" value="true" />
|
||||
<option name="showLibraryContents" value="true" />
|
||||
</component>
|
||||
<component name="PropertiesComponent"><![CDATA[{
|
||||
"keyToString": {
|
||||
"RunOnceActivity.OpenProjectViewOnStart": "true",
|
||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||
"WebServerToolWindowFactoryState": "false",
|
||||
"git-widget-placeholder": "master",
|
||||
"ignore.virus.scanning.warn.message": "true",
|
||||
"vue.rearranger.settings.migration": "true"
|
||||
},
|
||||
"keyToStringList": {
|
||||
"rider.external.source.directories": [
|
||||
"C:\\Users\\LRC\\AppData\\Roaming\\JetBrains\\Rider2023.2\\resharper-host\\DecompilerCache",
|
||||
"C:\\Users\\LRC\\AppData\\Roaming\\JetBrains\\Rider2023.2\\resharper-host\\SourcesCache",
|
||||
"C:\\Users\\LRC\\AppData\\Local\\Symbols\\src"
|
||||
]
|
||||
}
|
||||
}]]></component>
|
||||
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="应用程序级" UseSingleDictionary="true" transferred="true" />
|
||||
<component name="TaskManager">
|
||||
<task active="true" id="Default" summary="默认任务">
|
||||
<changelist id="ebb90e97-f354-453f-8b74-0bb83b47e00e" name="更改" comment="" />
|
||||
<created>1740962660807</created>
|
||||
<option name="number" value="Default" />
|
||||
<option name="presentableId" value="Default" />
|
||||
<updated>1740962660807</updated>
|
||||
<workItem from="1740962665165" duration="4000" />
|
||||
<workItem from="1740962676618" duration="24000" />
|
||||
</task>
|
||||
<servers />
|
||||
</component>
|
||||
<component name="TypeScriptGeneratedFilesManager">
|
||||
<option name="version" value="3" />
|
||||
</component>
|
||||
<component name="VcsManagerConfiguration">
|
||||
<option name="CLEAR_INITIAL_COMMIT_MESSAGE" value="true" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -0,0 +1,365 @@
|
||||
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;
|
||||
|
||||
/// <summary>
|
||||
/// 绘制轨迹线的操作
|
||||
/// <code>
|
||||
/// 当从其他WaitForUserInput_OpSlot到达此处时,将创建TerminalLine2T3用于线路的绘制,
|
||||
/// 同时在线路的两端有两个TerminalPoint用于线路的相连。
|
||||
///
|
||||
/// 支持常规的线路连续绘制,起点吸附,终点吸附。
|
||||
/// 不支持首尾相连。
|
||||
/// </code>
|
||||
/// </summary>
|
||||
public class DrawTerminalLine2T3_OpSlot : WaitForUserInput_OpSlot
|
||||
{
|
||||
#region 字段属性
|
||||
|
||||
/// <summary>
|
||||
/// 上一步的坐标
|
||||
/// </summary>
|
||||
private Vector3 _lastPointPosition;
|
||||
|
||||
/// <summary>
|
||||
/// 上一步的对齐轨迹计算器
|
||||
/// </summary>
|
||||
private Vector3 _lastPointNormal;
|
||||
|
||||
/// <summary>
|
||||
/// 下一步的坐标
|
||||
/// </summary>
|
||||
private Vector3 _helperPosition = Vector3.zero;
|
||||
|
||||
/// <summary>
|
||||
/// 下一步的法向
|
||||
/// </summary>
|
||||
private Vector3 _helperNormal = Vector3.zero;
|
||||
|
||||
/// <summary>
|
||||
/// 操作的轨迹线
|
||||
/// </summary>
|
||||
private TerminalLine2T3 _line;
|
||||
|
||||
/// <summary>
|
||||
/// 起点
|
||||
/// </summary>
|
||||
private TerminalPoint _startPoint;
|
||||
|
||||
/// <summary>
|
||||
/// 操作的点,也是终点
|
||||
/// </summary>
|
||||
private TerminalPoint _endPoint;
|
||||
|
||||
/// <summary>
|
||||
/// 在场上找到的其他的点
|
||||
/// </summary>
|
||||
private TerminalPoint _otherPoint;
|
||||
|
||||
/// <summary>
|
||||
/// 起点是用上一步的终点替代的
|
||||
/// </summary>
|
||||
private bool _isStartPointSubstitute = false;
|
||||
|
||||
/// <summary>
|
||||
/// 绘制时,终点是自由点
|
||||
/// </summary>
|
||||
private bool _isFreeEndPoint;
|
||||
|
||||
// public SesothoArrangementWiresTool myWiresTool;
|
||||
// myWiresTool = targetTool as SesothoArrangementWiresTool;
|
||||
|
||||
#endregion
|
||||
|
||||
#region 引用封装
|
||||
|
||||
/// <summary>
|
||||
/// 创建自己的工具
|
||||
/// </summary>
|
||||
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 方法
|
||||
|
||||
/// <summary>
|
||||
/// 设置先决属性
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 结束清理属性
|
||||
/// </summary>
|
||||
private void EndPrecondition()
|
||||
{
|
||||
selfWiresTool.DeleteElement(_line);
|
||||
// 不能把别人的东西给回收了
|
||||
if (!_isStartPointSubstitute)
|
||||
selfWiresTool.DeleteElement(_startPoint);
|
||||
selfWiresTool.DeleteElement(_endPoint);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 线路绘制过程
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取光标下的起点
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private bool GetCurrentObject()
|
||||
{
|
||||
// SesothoPeManager.
|
||||
return false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace SesothoLine
|
||||
{
|
||||
/// <summary>
|
||||
/// 可链接的对象,表示此成员内包含一个链表的节点,可用于链表跟踪
|
||||
/// </summary>
|
||||
public interface ILinkconfident<T>
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取链接点
|
||||
/// </summary>
|
||||
/// <param name="node"></param>
|
||||
/// <returns></returns>
|
||||
public bool GetLinkedNode(out LinkedListNode<T> node);
|
||||
/// <summary>
|
||||
/// 设置连接点
|
||||
/// </summary>
|
||||
/// <param name="node"></param>
|
||||
public void SetLinkedNode(LinkedListNode<T> node);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Deconstruction.Element;
|
||||
using UnityEngine;
|
||||
|
||||
namespace SesothoLine
|
||||
{
|
||||
/// <summary>
|
||||
/// 可链接的对象,表示此成员内包含一个链表的节点,可用于链表跟踪
|
||||
/// </summary>
|
||||
public interface ILinkconfidentPe : ILinkconfident<PlacementBase>
|
||||
{ }
|
||||
}
|
||||
@@ -0,0 +1,558 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Deconstruction.Element;
|
||||
using Deconstruction.Interface;
|
||||
using Deconstruction.Manager;
|
||||
using Deconstruction.Tool;
|
||||
using Deconstruction.Type;
|
||||
using Deconstruction.Type.DMToolSlot;
|
||||
using Deconstruction.Type.Linkable;
|
||||
using SerializerHelper.Type;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Pool;
|
||||
using XericLibrary.Runtime.MacroLibrary;
|
||||
using XericLibrary.Runtime.Nav;
|
||||
|
||||
namespace SesothoLine
|
||||
{
|
||||
/// <summary>
|
||||
/// 线路绘制工具类
|
||||
/// </summary>
|
||||
public class SesothoArrangementWiresTool : DecisionMakerToolBase
|
||||
{
|
||||
#region 事件委托
|
||||
|
||||
/// <summary>
|
||||
/// 工具中成员变更委托
|
||||
/// </summary>
|
||||
public delegate void ToolMemberChange(PlacementBase obj);
|
||||
|
||||
/// <summary>
|
||||
/// 工具中成员添加事件
|
||||
/// </summary>
|
||||
public event ToolMemberChange OnAdditional;
|
||||
|
||||
/// <summary>
|
||||
/// 工具中成员移除事件
|
||||
/// </summary>
|
||||
public event ToolMemberChange OnDecreasing;
|
||||
|
||||
/// <summary>
|
||||
/// 当任意元素苏醒
|
||||
/// </summary>
|
||||
public event ToolMemberChange OnAnyVivification;
|
||||
|
||||
/// <summary>
|
||||
/// 当任意元素休眠
|
||||
/// </summary>
|
||||
public event ToolMemberChange OnAnyDormancy;
|
||||
|
||||
#endregion
|
||||
|
||||
#region 快捷键
|
||||
|
||||
/*
|
||||
* 1 控制强制直线
|
||||
* 2,3 控制圆弧的角度为90和180度
|
||||
* R 反转圆弧
|
||||
* shift+b 忽略对象吸附
|
||||
* shift+n 忽略网格吸附
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// 强制直线
|
||||
/// </summary>
|
||||
public static KeyPack OpKey_ForceStr = new KeyPack(KeyCode.Alpha1);
|
||||
/// <summary>
|
||||
/// 强制90度圆弧
|
||||
/// </summary>
|
||||
public static KeyPack OpKey_90Arc = new KeyPack(KeyCode.Alpha2);
|
||||
/// <summary>
|
||||
/// 强制180度圆弧
|
||||
/// </summary>
|
||||
public static KeyPack OpKey_180Arc = new KeyPack(KeyCode.Alpha3);
|
||||
/// <summary>
|
||||
/// 反转顺向,比如单圆弧的方向翻转。
|
||||
/// 话说shift+alt+r是英伟达的一个快捷键呢,有点冲突
|
||||
/// </summary>
|
||||
public static KeyPack OpKey_RevCisoid = new KeyPack(KeyCode.R);
|
||||
/// <summary>
|
||||
/// 忽略吸附功能
|
||||
/// </summary>
|
||||
public static KeyPack OpKey_IgnoreNeighborAdsorption = new KeyPack(KeyCode.LeftShift, KeyCode.B);
|
||||
/// <summary>
|
||||
/// 忽略网格吸附
|
||||
/// </summary>
|
||||
public static KeyPack OpKey_IgnoreGridAdsorption = new KeyPack(KeyCode.LeftShift, KeyCode.N);
|
||||
|
||||
#endregion
|
||||
|
||||
#region 字段属性
|
||||
|
||||
private ObjectPool<TerminalLine2T3> _linePool;
|
||||
private ObjectPool<TerminalPoint> _pointPool;
|
||||
|
||||
#endregion
|
||||
|
||||
#region 获取转换
|
||||
|
||||
/// <summary>
|
||||
/// 获取光标下最近的对象为点
|
||||
/// </summary>
|
||||
/// <param name="point"></param>
|
||||
/// <returns></returns>
|
||||
public static bool GetNearestObjectAsPoint(out TerminalPoint point)
|
||||
{
|
||||
if (SesothoPeManager.NearestObject is not null &&
|
||||
SesothoPeManager.NearestObject is TerminalPoint terminalPoint)
|
||||
{
|
||||
point = terminalPoint;
|
||||
return true;
|
||||
}
|
||||
point = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取光标下最近的对象为线
|
||||
/// </summary>
|
||||
/// <param name="line"></param>
|
||||
/// <returns></returns>
|
||||
public static bool GetNearestObjectAsLine(out TerminalLine2T3 line)
|
||||
{
|
||||
if (SesothoPeManager.NearestObject is not null &&
|
||||
SesothoPeManager.NearestObject is TerminalPoint terminalPoint &&
|
||||
terminalPoint.LinkedData.GetOpposite(LinkType.Export) is TerminalLine2T3 terminalLine)
|
||||
{
|
||||
line = terminalLine;
|
||||
return true;
|
||||
}
|
||||
line = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取以给定点上与最近的相切线相对
|
||||
/// </summary>
|
||||
/// <param name="point"></param>
|
||||
/// <param name="line"></param>
|
||||
/// <param name="normal"></param>
|
||||
/// <returns></returns>
|
||||
public static bool GetNearestObjectAsLine(TerminalPoint point, out TerminalLine2T3 line, out Vector3 normal)
|
||||
{
|
||||
if (point is null)
|
||||
goto End;
|
||||
// 检查最近线切线是否有效,是否相连
|
||||
if (SesothoPeManager.NearestLineTangentObject is TerminalLine2T3 otherLine &&
|
||||
point.TryGetLinkLineNormal(otherLine, out normal))
|
||||
{
|
||||
line = otherLine;
|
||||
return true;
|
||||
}
|
||||
|
||||
End:
|
||||
line = null;
|
||||
normal = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 生命周期
|
||||
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
|
||||
_linePool = new ObjectPool<TerminalLine2T3>(
|
||||
createFunc: CreatElement<TerminalLine2T3>,
|
||||
actionOnGet: ElementActive,
|
||||
actionOnRelease: ElementInactive,
|
||||
actionOnDestroy: a =>
|
||||
{ },
|
||||
collectionCheck: true,
|
||||
defaultCapacity: 10,
|
||||
maxSize: 10000);
|
||||
|
||||
_pointPool = new ObjectPool<TerminalPoint>(
|
||||
createFunc: CreatElement<TerminalPoint>,
|
||||
actionOnGet: ElementActive,
|
||||
actionOnRelease: ElementInactive,
|
||||
actionOnDestroy: a =>
|
||||
{ },
|
||||
collectionCheck: true,
|
||||
defaultCapacity: 10,
|
||||
maxSize: 10000);
|
||||
|
||||
}
|
||||
|
||||
protected override void OnEnableTool()
|
||||
{
|
||||
// 启用时创建一个输入等待行为,随后进入绘制行为
|
||||
var target = GenerateOperateSlot<WaitForUserInput_OpSlot>();
|
||||
target.InitializeNextTodo(() => new DrawTerminalLine2T3_OpSlot());
|
||||
|
||||
Debug.Log("激活线路绘制工具");
|
||||
}
|
||||
|
||||
protected override void OnDisableTool()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override void OnFinalEnd()
|
||||
{
|
||||
base.OnFinalEnd();
|
||||
EnableTool = false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 序列化
|
||||
|
||||
public override SerializeUnion ToolSerializeDispost()
|
||||
{
|
||||
base.ToolSerializeDispost();
|
||||
foreach (var element in PlaceElementManager.Inst.StructuralLinkedList)
|
||||
{
|
||||
var union = element.SerializedOccurs();
|
||||
// 索引是后面用来标识类的
|
||||
union.Index = TypeConsignMap.AddMapIndex(element.GetType());
|
||||
union.RefreshSerializedContext();
|
||||
SerializeTemp.Add(union);
|
||||
}
|
||||
SerializeTemp.RefreshSerializedContext();
|
||||
return SerializeTemp;
|
||||
}
|
||||
|
||||
public override bool ToolDiserializDispost(SerializeUnion context)
|
||||
{
|
||||
if (!base.ToolDiserializDispost(context))
|
||||
return false;
|
||||
|
||||
var deserializeList = new List<(PlacementBase, SerializeUnion)>();
|
||||
var safeCount = ushort.MaxValue;
|
||||
Debug.Log("反序列化过程开始创建对象");
|
||||
while (0 <-- safeCount && SerializeTemp.IndexMoveToNext(out var block))
|
||||
{
|
||||
var union = SerializeTemp.GetDeserializeObject<SerializeUnion>();
|
||||
var type = TypeConsignMap.GetMapType(union.Index);
|
||||
if (GetElement(type, out var obj))
|
||||
{
|
||||
deserializeList.Add((obj, union));
|
||||
union.RefreshDeserializeContext();
|
||||
union.IndexMoveToStart();
|
||||
obj.DeserializeOccurs(union);
|
||||
// switch (obj)
|
||||
// {
|
||||
// case TerminalLine2T3 line:
|
||||
// line.DeserializeOccurs(union);
|
||||
// break;
|
||||
// case TerminalPoint point:
|
||||
// point.DeserializeOccurs(union);
|
||||
// break;
|
||||
// }
|
||||
}
|
||||
else
|
||||
Debug.LogError($"无法创建序列化元素,原因是类型不支持{type}");
|
||||
|
||||
if (block) break;
|
||||
}
|
||||
Debug.Log("反序列化过程开始恢复链接关系");
|
||||
foreach (var item in deserializeList)
|
||||
item.Item1.DeserializeHysteresisOccurs(item.Item2);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 方法
|
||||
|
||||
/// <summary>
|
||||
/// 创建元素
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private T CreatElement<T>()
|
||||
where T : PlacementBase, ILinkconfidentPe
|
||||
{
|
||||
var obj = CreatPlacementObject<T>();
|
||||
obj.OnPlancementDestory += a =>
|
||||
{
|
||||
if (a is null)
|
||||
{
|
||||
Debug.LogError("元素已经被销毁,无法回收链表元素");
|
||||
return;
|
||||
}
|
||||
if (a is T b &&
|
||||
b.GetLinkedNode(out var node))
|
||||
SesothoPeManager.Inst.RemoveLinkedTarget(node);
|
||||
else
|
||||
Debug.LogError("元素并非工具元素类型,或者其中的链表节点已丢失,导致无法回收链表元素");
|
||||
};
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 池对象激活
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
private void ElementActive<T>(T obj)
|
||||
where T : PlacementBase, ILinkconfidentPe
|
||||
{
|
||||
obj.gameObject.SetActive(true);
|
||||
OnAnyVivification?.Invoke(obj);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 池对象取消激活
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
private void ElementInactive<T>(T obj)
|
||||
where T : PlacementBase, ILinkconfidentPe
|
||||
{
|
||||
obj.gameObject.SetActive(false);
|
||||
OnAnyDormancy?.Invoke(obj);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取元素
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool GetElement<T>(out T obj)
|
||||
where T : PlacementBase, ILinkconfidentPe
|
||||
{
|
||||
var name = typeof(T).Name;
|
||||
switch (name)
|
||||
{
|
||||
case nameof(TerminalLine2T3):
|
||||
obj = _linePool.Get() as T;
|
||||
return true;
|
||||
case nameof(TerminalPoint):
|
||||
obj = _pointPool.Get() as T;
|
||||
return true;
|
||||
default:
|
||||
Debug.LogError($"给定的元素类型({name})并非预期,这将跳过对象池过程");
|
||||
break;
|
||||
}
|
||||
obj = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取元素
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <param name="obj"></param>
|
||||
/// <returns></returns>
|
||||
public bool GetElement(Type type, out PlacementBase obj)
|
||||
{
|
||||
var name = type.Name;
|
||||
switch (name)
|
||||
{
|
||||
case nameof(TerminalLine2T3):
|
||||
obj = _linePool.Get();
|
||||
return true;
|
||||
case nameof(TerminalPoint):
|
||||
obj = _pointPool.Get();
|
||||
return true;
|
||||
default:
|
||||
Debug.LogError($"给定的元素类型({name})并非预期,这将跳过对象池过程");
|
||||
break;
|
||||
}
|
||||
obj = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 删除元素
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public void DeleteElement<T>(T obj)
|
||||
where T : PlacementBase,
|
||||
ILinkconfidentPe
|
||||
{
|
||||
var name = typeof(T).Name;
|
||||
switch (name)
|
||||
{
|
||||
case nameof(TerminalLine2T3):
|
||||
_linePool.Release(obj as TerminalLine2T3);
|
||||
break;
|
||||
case nameof(TerminalPoint):
|
||||
_pointPool.Release(obj as TerminalPoint);
|
||||
break;
|
||||
default:
|
||||
Debug.LogError($"给定的元素类型({name})并非预期,这将跳过对象池过程");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 保存元素链,在创建并常态化元素后都需要执行的操作 (注意不是在创建后立刻保存)
|
||||
/// <code>
|
||||
/// 如果这是一个线,那么还应该调用 AddBulkLineToNeighborGrid;
|
||||
/// 如果这是一个点,那么应该调用 AddPeToNeighborGrid。
|
||||
/// </code>
|
||||
/// </summary>
|
||||
public void PersistentElement<T>(T obj)
|
||||
where T : PlacementBase,
|
||||
ILinkconfidentPe
|
||||
{
|
||||
// 保存链表结构,反过来也持有这个节点,便于后续查找
|
||||
var lineNode = SesothoPeManager.Inst.AddLinkedTarget(obj);
|
||||
obj.SetLinkedNode(lineNode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 移除元素链
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public void ExcisionElement<T>(T obj)
|
||||
where T : PlacementBase,
|
||||
ILinkconfidentPe
|
||||
{
|
||||
if (obj.GetLinkedNode(out var node))
|
||||
SesothoPeManager.Inst.RemoveLinkedTarget(node);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 添加小型元素到网格中
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public void AddPeToNeighborGrid<T>(T obj)
|
||||
where T : PlacementBase,
|
||||
ILinkconfidentPe
|
||||
{
|
||||
if (obj.NeighborGridIndex != null)
|
||||
{
|
||||
Debug.LogError("无法重复插入元素:当前向管理器中插入的的元素,可能已经存在于其他管理器内,请先退出其他管理器后重试。");
|
||||
return;
|
||||
}
|
||||
SesothoPeManager.Inst.InsertNeighbor(obj, out var index);
|
||||
obj.NeighborGridIndex = index;
|
||||
|
||||
// 回调事件
|
||||
OnAdditional?.Invoke(obj);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加大型元素到网格中
|
||||
/// </summary>
|
||||
public void AddBulkPeToNeighborGrid<T>(T obj)
|
||||
where T : PlacementBase,
|
||||
ILinkconfidentPe,
|
||||
IPossessorTrajectory2
|
||||
{
|
||||
if (obj.NeighborGridIndex != null)
|
||||
{
|
||||
Debug.LogError("无法重复插入元素:当前向管理器中插入的的元素,可能已经存在于其他管理器内,请先退出其他管理器后重试。");
|
||||
return;
|
||||
}
|
||||
SesothoPeManager.Inst.InsertGiantNeighbor<T>(obj, out var index);
|
||||
obj.NeighborGridIndex = index;
|
||||
|
||||
// 回调事件
|
||||
OnAdditional?.Invoke(obj);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 移除这个小元素
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public void RemovePeToNeighborGrid<T>(T obj)
|
||||
where T : PlacementBase,
|
||||
ILinkconfidentPe
|
||||
{
|
||||
if (obj.NeighborGridIndex != null &&
|
||||
obj.NeighborGridIndex.GetAsIndex(out var index))
|
||||
SesothoPeManager.Inst.RemoveNeighbor(index);
|
||||
else
|
||||
SesothoPeManager.Inst.RemoveNeighbor(obj);
|
||||
ExcisionElement(obj);
|
||||
// 回调事件
|
||||
OnDecreasing?.Invoke(obj);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 移除这个大型元素
|
||||
/// </summary>
|
||||
public void RemoveBulkPeFormNeighborGrid<T>(T obj)
|
||||
where T : PlacementBase,
|
||||
ILinkconfidentPe,
|
||||
IPossessorTrajectory2
|
||||
{
|
||||
if (obj.NeighborGridIndex != null &&
|
||||
obj.NeighborGridIndex.GetAsMappingIndex(out var index))
|
||||
SesothoPeManager.Inst.RemoveGiantNeighbor(index);
|
||||
else
|
||||
SesothoPeManager.Inst.RemoveGiantNeighbor<T>(obj);
|
||||
ExcisionElement(obj);
|
||||
// 回调事件
|
||||
OnDecreasing?.Invoke(obj);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 绘制寻路
|
||||
|
||||
/*
|
||||
* 没写完,如果不嫌麻烦可以看看Astart类,或者自己实现。
|
||||
*
|
||||
* 主要提供绘制线路时的多段线拟合,障碍物避让
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// 获取一个可以通过的路径
|
||||
/// <code>
|
||||
/// 这是一个只在向上的二维平面上有效的路径。
|
||||
/// 寻路的规则是仅避开建筑物,贪婪算法。
|
||||
/// </code>
|
||||
/// </summary>
|
||||
/// <param name="startPoint">起点</param>
|
||||
/// <param name="endPoint">终点</param>
|
||||
/// <param name="avoidRadius">避让半径,在遭遇碰撞时将沿法向退回这个距离</param>
|
||||
public DrawWayPoints GetPassThroughRouteShortcut(Vector3 startPoint, Vector3 endPoint, float avoidRadius)
|
||||
{
|
||||
var result = new DrawWayPoints();
|
||||
Debug.LogError("此方法未完成");
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取一个可以通过的路径的迭代器;
|
||||
/// </summary>
|
||||
/// <param name="startPoint">起点</param>
|
||||
/// <param name="endPoint">终点</param>
|
||||
/// <param name="avoidRadius">避让半径,在遭遇障碍时将沿法向退回这个距离</param>
|
||||
/// <param name="layer">检查碰撞对象的层</param>
|
||||
/// <returns></returns>
|
||||
protected IEnumerable<Vector3> GetPassThroughRoute(Vector3 startPoint, Vector3 endPoint, float avoidRadius, LayerMask layer)
|
||||
{
|
||||
yield return Vector3.zero;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使用给定的路径创建一段工具拟合的路径
|
||||
/// </summary>
|
||||
/// <param name="wayPoints">一段路径</param>
|
||||
public void BuildPaths(DrawWayPoints wayPoints)
|
||||
{
|
||||
new AStart2();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
#define _DEBUG_
|
||||
// #undef _DEBUG_
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Deconstruction.Element;
|
||||
using UnityEngine;
|
||||
|
||||
using Deconstruction.Manager;
|
||||
using Deconstruction.Tool;
|
||||
using Deconstruction.Type.Area;
|
||||
using Deconstruction.Type.Serialize;
|
||||
using Newtonsoft.Json;
|
||||
using SerializerHelper.Type;
|
||||
using UnityEngine.UI;
|
||||
using XericLibrary.Runtime.Debuger;
|
||||
using XericLibrary.Runtime.MacroLibrary;
|
||||
|
||||
namespace SesothoLine
|
||||
{
|
||||
/// <summary>
|
||||
/// 主要管理器
|
||||
/// <code>
|
||||
/// 不建议继续封装管理器类
|
||||
/// </code>
|
||||
/// </summary>
|
||||
public sealed class SesothoPeManager : PlaceElementManager
|
||||
{
|
||||
#region 静态成员
|
||||
|
||||
/// <summary>
|
||||
/// 此处提供的单例与父类单例是独立的
|
||||
/// </summary>
|
||||
public new static SesothoPeManager Inst => _inst;
|
||||
private static SesothoPeManager _inst;
|
||||
|
||||
/// <summary>
|
||||
/// 线路绘制工具
|
||||
/// </summary>
|
||||
public static SesothoArrangementWiresTool WiresTool => _wiresTool;
|
||||
private static SesothoArrangementWiresTool _wiresTool;
|
||||
|
||||
/// <summary>
|
||||
/// 光标下最近的线上交点
|
||||
/// </summary>
|
||||
public static Vector3 NearestLineTangentPoint => _lineTangentTraceTool.NearsetPoint;
|
||||
/// <summary>
|
||||
/// 光标下最近的线
|
||||
/// </summary>
|
||||
public static PlacementBase NearestLineTangentObject => _lineTangentTraceTool.NearsetObject;
|
||||
/// <summary>
|
||||
/// 光标下最近的对象原点
|
||||
/// </summary>
|
||||
public static Vector3 NearestPoint => TrackingTool.TrackingCurrentPosition;
|
||||
/// <summary>
|
||||
/// 光标下最近的对象
|
||||
/// </summary>
|
||||
public static PlacementBase NearestObject => TrackingTool.TrackingCurrentTarget;
|
||||
|
||||
private static TrajectoryTrackingTool.TrackPersistentCommunicate _lineTangentTraceTool;
|
||||
|
||||
#endregion
|
||||
|
||||
#region 调试功能
|
||||
|
||||
#if UNITY_EDITOR
|
||||
|
||||
public bool EnableGridDebugDraw = false;
|
||||
|
||||
|
||||
public void DebugFunc()
|
||||
{
|
||||
if (EnableGridDebugDraw)
|
||||
{
|
||||
PlacementNeighbor.DebugDrawGrid();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endregion
|
||||
|
||||
#region 生命周期
|
||||
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
_inst = this;
|
||||
|
||||
if (LineMaterial == null)
|
||||
Debug.LogError("需要给管理器提供一个线段材质");
|
||||
if (PointMaterial == null)
|
||||
Debug.LogError("需要给管理器提供一个点材质");
|
||||
|
||||
// 初始化画线工具
|
||||
_wiresTool = new SesothoArrangementWiresTool();
|
||||
_wiresTool.InitializeParent(transform);
|
||||
|
||||
_lineTangentTraceTool = TrackingTool.InstantiationTrackCaculate(PlaceholdersAreaType.LinearContinuity);
|
||||
|
||||
// 手动开启代理更新
|
||||
EnableUpdate = true;
|
||||
|
||||
|
||||
}
|
||||
|
||||
protected override void Start()
|
||||
{
|
||||
base.Start();
|
||||
}
|
||||
|
||||
private NeighborGrid<PlacementBase>.NeighborGridIndex index;
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
#if UNITY_EDITOR
|
||||
DebugFunc();
|
||||
#endif
|
||||
if (Input.GetMouseButtonDown(2))
|
||||
{
|
||||
index = PlacementNeighbor.GetNeighborIndex(null);
|
||||
index.SetDrivenAsWorld(InputHelper.CurrentPosition);
|
||||
Debug.Log($"{index.GetDrivenAsLinear()} => {index.GetNeighbor().FirstOrDefault()}");
|
||||
}
|
||||
|
||||
// new SerializeUnion();
|
||||
}
|
||||
|
||||
private string serializeContext = null;
|
||||
protected override void LateUpdate()
|
||||
{
|
||||
base.LateUpdate();
|
||||
// if (DecisionMakerToolBase.ActiveDecisionMaker == null ||
|
||||
// !DecisionMakerToolBase.ActiveDecisionMaker.EnableTool)
|
||||
#if !UNITY_EDITOR || !_DEBUG_
|
||||
return;
|
||||
#endif
|
||||
// 工具功能测试
|
||||
if (Input.GetKeyDown(KeyCode.L))
|
||||
{
|
||||
_wiresTool.EnableTool = !_wiresTool.EnableTool;
|
||||
Debug.Log($"{(_wiresTool.EnableTool ? "绘制工具已激活" : "工具已取消激活")}");
|
||||
}
|
||||
|
||||
// 存档功能测试
|
||||
if (Input.GetKeyDown(KeyCode.S))
|
||||
{
|
||||
var obj = _wiresTool.ToolSerializeDispost();
|
||||
serializeContext = JsonConvert.SerializeObject(obj);
|
||||
Debug.Log(obj.ToString());
|
||||
}
|
||||
if (Input.GetKeyDown(KeyCode.D))
|
||||
{
|
||||
if (serializeContext == null)
|
||||
{
|
||||
Debug.Log("反序列化内容为空");
|
||||
return;
|
||||
}
|
||||
|
||||
var obj = JsonConvert.DeserializeObject<SerializeUnion>(serializeContext);
|
||||
_wiresTool.ToolDiserializDispost(obj);
|
||||
}
|
||||
|
||||
if (Input.GetKeyDown(KeyCode.A))
|
||||
{
|
||||
_wiresTool.EnableCompress = !_wiresTool.EnableCompress;
|
||||
if (_wiresTool.EnableCompress )
|
||||
Debug.Log("开启压缩");
|
||||
else
|
||||
Debug.Log("关闭压缩");
|
||||
}
|
||||
|
||||
|
||||
// 绘制一下吸附的目标位置
|
||||
if (TrackingTool.EnableTool || TrackingTool._enableAuxiliaryTool)
|
||||
{
|
||||
MacroDebugDraw.DrawDownArrow(NearestPoint, Color.magenta);
|
||||
MacroDebugDraw.DrawDownArrow(NearestLineTangentPoint, Color.green);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,224 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
using System.Text;
|
||||
using Deconstruction.Element;
|
||||
using Deconstruction.Interface;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
using XericLibrary.Runtime.Debuger;
|
||||
using XericLibrary.Runtime.MacroLibrary;
|
||||
using XericLibrary.Runtime.Type;
|
||||
|
||||
namespace SesothoLine
|
||||
{
|
||||
|
||||
using LineSegment2 = Deconstruction.Element.PromptLine2.LineSegment2;
|
||||
|
||||
/// <summary>
|
||||
/// 线终端执行脚本,使用二维线计算器,驱动三维线渲染器。
|
||||
/// </summary>
|
||||
public class TerminalLine2T3 : PromptLine2,
|
||||
ILinkconfidentPe // 链表跟踪
|
||||
{
|
||||
#region 字段属性
|
||||
|
||||
private LinkedListNode<PlacementBase> _linkNode;
|
||||
|
||||
/// <summary>
|
||||
/// 本地缓存
|
||||
/// </summary>
|
||||
private LineSegment2 _lineSegment = new LineSegment2();
|
||||
|
||||
public bool DebugDrawGrid = false;
|
||||
|
||||
#endregion
|
||||
|
||||
#region 生命周期
|
||||
|
||||
protected override void Start()
|
||||
{
|
||||
base.Start();
|
||||
InitPromptLine<LineRendererUnbodied>();
|
||||
}
|
||||
|
||||
protected override void OnEnable()
|
||||
{
|
||||
base.OnEnable();
|
||||
SesothoPeManager.Inst.AddEmbedded(this);
|
||||
}
|
||||
|
||||
protected override void OnDisable()
|
||||
{
|
||||
base.OnDisable();
|
||||
SesothoPeManager.Inst.RemoveEmbedded(this);
|
||||
}
|
||||
|
||||
protected virtual void OnDestroy()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override void AgencyOnEnable()
|
||||
{
|
||||
base.AgencyOnEnable();
|
||||
}
|
||||
|
||||
protected override void AgencyOnDisable()
|
||||
{
|
||||
base.AgencyOnDisable();
|
||||
}
|
||||
|
||||
protected override void AgencyMainUpdate()
|
||||
{
|
||||
base.AgencyMainUpdate();
|
||||
|
||||
// 绘制线路本身在网格中的索引位置
|
||||
if (DebugDrawGrid &&
|
||||
NeighborGridIndex.SafeGetAsMappingIndex(out var indexs))
|
||||
{
|
||||
foreach (var index in indexs.Indexs)
|
||||
{
|
||||
MacroDebugDraw.DrawDownArrow(
|
||||
index.GetCellWorldIndexPosition() + MacroMath.RandomVector3(0.1f, Identifier),
|
||||
Color.red);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected override void AgencyAsyncBeforeUpdate()
|
||||
{
|
||||
base.AgencyAsyncBeforeUpdate();
|
||||
}
|
||||
|
||||
protected override void AgencyAsyncUpdate()
|
||||
{
|
||||
base.AgencyAsyncUpdate();
|
||||
}
|
||||
|
||||
protected override void AgencyAsyncAfterUpdate()
|
||||
{
|
||||
base.AgencyAsyncAfterUpdate();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 线路构建
|
||||
|
||||
/// <summary>
|
||||
/// 创建合理坐标空间
|
||||
/// </summary>
|
||||
/// <param name="a"></param>
|
||||
/// <param name="b"></param>
|
||||
/// <param name="ah"></param>
|
||||
/// <param name="bh"></param>
|
||||
/// <returns></returns>
|
||||
public LineSegment2 SetLineSegment(Vector3 a, Vector3 b, Vector3 ah = default, Vector3 bh = default)
|
||||
{
|
||||
_lineSegment.SetValue(
|
||||
a.UpwardPlaneToVector2(),
|
||||
b.UpwardPlaneToVector2(),
|
||||
ah.UpwardPlaneToVector2(),
|
||||
bh.UpwardPlaneToVector2());
|
||||
// ah?.GetEndPointNormal ?? default,
|
||||
// bh?.GetStartPointNormal ?? default);
|
||||
return _lineSegment;
|
||||
}
|
||||
|
||||
public void AutomaticDrawCircularLine(float constraintAngle = -1, bool fullArc = false)
|
||||
{
|
||||
AutomaticDrawCircularLine(_lineSegment, constraintAngle, fullArc);
|
||||
}
|
||||
|
||||
private LineSegment2 straightLine = new LineSegment2();
|
||||
public void DrawStraightLine()
|
||||
{
|
||||
straightLine.SetValue(_lineSegment.pointA, _lineSegment.pointB);
|
||||
AutomaticDrawCircularLine(straightLine);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 重新计算原点
|
||||
/// <code>
|
||||
/// 如果此轨迹的原点在零点,那么通过此方法可以将原点设置到起点和终点之间。
|
||||
/// 注意:使用前需要将轨迹设为本地坐标
|
||||
/// </code>
|
||||
/// </summary>
|
||||
public void ReapplyOrigin()
|
||||
{
|
||||
if (TrajectoryRenderer == null || TrajectoryCalculator == null)
|
||||
{
|
||||
Debug.LogError("当前轨迹或线渲染器无效,无法计算原点");
|
||||
return;
|
||||
}
|
||||
|
||||
// 假定其中的轨迹是本地坐标的
|
||||
|
||||
// 期望的本地零点
|
||||
var center = ((TrajectoryCalculator.GetStartPointPosition + TrajectoryCalculator.GetEndPointPosition) / 2).UpwardPlaneToVector3();
|
||||
// 本地原点
|
||||
var local = TrajectoryCalculator.Origin.UpwardPlaneToVector3();
|
||||
// 期望偏移
|
||||
var offset = local - center;
|
||||
|
||||
TrajectoryCalculator.Origin = offset.UpwardPlaneToVector2();
|
||||
transform.position += center;
|
||||
|
||||
// 更新
|
||||
UpdateRender();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 实现 - ILinkconfidentPe
|
||||
|
||||
public bool GetLinkedNode(out LinkedListNode<PlacementBase> node)
|
||||
{
|
||||
if (_linkNode == null)
|
||||
{
|
||||
node = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
node = _linkNode;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void SetLinkedNode(LinkedListNode<PlacementBase> node)
|
||||
{
|
||||
_linkNode = node;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 重写 - ISerializablePost
|
||||
|
||||
public override SerializerHelper.Type.SerializeUnion SerializedOccurs()
|
||||
{
|
||||
return base.SerializedOccurs();
|
||||
}
|
||||
public override bool CheckDeserializeUnion(SerializerHelper.Type.SerializeUnion context)
|
||||
{
|
||||
return base.CheckDeserializeUnion(context);
|
||||
}
|
||||
public override void DeserializeOccurs(SerializerHelper.Type.SerializeUnion context)
|
||||
{
|
||||
base.DeserializeOccurs(context);
|
||||
}
|
||||
public override void DeserializeHysteresisOccurs(SerializerHelper.Type.SerializeUnion context)
|
||||
{
|
||||
base.DeserializeHysteresisOccurs(context);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Deconstruction.Element;
|
||||
using UnityEngine;
|
||||
using XericLibrary.Runtime.Debuger;
|
||||
using XericLibrary.Runtime.MacroLibrary;
|
||||
using Random = System.Random;
|
||||
|
||||
namespace SesothoLine
|
||||
{
|
||||
/// <summary>
|
||||
/// 点,承担连接的责任
|
||||
/// </summary>
|
||||
public class TerminalPoint : Deconstruction.Element.ContactPoint,
|
||||
ILinkconfidentPe // 链表跟踪
|
||||
{
|
||||
private LinkedListNode<PlacementBase> _linkNode;
|
||||
|
||||
#region 生命周期
|
||||
|
||||
// 调试绘制一下位置
|
||||
// private void Update()
|
||||
// {
|
||||
// MacroDebugDraw.DrawDownArrow(transform.position + MacroMath.RandomVector3(0.1f, Identifier), Color.green);
|
||||
// }
|
||||
|
||||
#endregion
|
||||
|
||||
#region 实现 - ILinkconfidentPe
|
||||
|
||||
public bool GetLinkedNode(out LinkedListNode<PlacementBase> node)
|
||||
{
|
||||
if (_linkNode == null)
|
||||
{
|
||||
node = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
node = _linkNode;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void SetLinkedNode(LinkedListNode<PlacementBase> node)
|
||||
{
|
||||
_linkNode = node;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 重写 - ISerializablePost
|
||||
|
||||
public override SerializerHelper.Type.SerializeUnion SerializedOccurs()
|
||||
{
|
||||
return base.SerializedOccurs();
|
||||
}
|
||||
public override bool CheckDeserializeUnion(SerializerHelper.Type.SerializeUnion context)
|
||||
{
|
||||
return base.CheckDeserializeUnion(context);
|
||||
}
|
||||
public override void DeserializeOccurs(SerializerHelper.Type.SerializeUnion context)
|
||||
{
|
||||
base.DeserializeOccurs(context);
|
||||
}
|
||||
public override void DeserializeHysteresisOccurs(SerializerHelper.Type.SerializeUnion context)
|
||||
{
|
||||
base.DeserializeHysteresisOccurs(context);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "Lrss3.Deconstruction",
|
||||
"rootNamespace": "Deconstruction",
|
||||
"references": [
|
||||
"GUID:6055be8ebefd69e48b49212b09b47b2f"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,293 @@
|
||||
#if CREST_UNITY_INPUT && ENABLE_INPUT_SYSTEM
|
||||
#define INPUT_SYSTEM_ENABLED
|
||||
#endif
|
||||
|
||||
using System;
|
||||
using UnityEngine;
|
||||
#if INPUT_SYSTEM_ENABLED
|
||||
using UnityEngine.InputSystem;
|
||||
#endif
|
||||
#if ENABLE_VR && ENABLE_VR_MODULE
|
||||
using UnityEngine.XR;
|
||||
#endif
|
||||
|
||||
namespace Deconstruction.Runtime.Player
|
||||
{
|
||||
/// <summary>
|
||||
/// 一个简单且功能有限的摄像机脚本,可通过 WASD 键和鼠标进行控制。
|
||||
/// </summary>
|
||||
public class CameraController : MonoBehaviour
|
||||
{
|
||||
/// <summary>
|
||||
/// 此资产的版本。可用于不同版本之间的迁移。只有在编辑器升级版本时才应更改此值。
|
||||
/// </summary>
|
||||
[SerializeField, HideInInspector]
|
||||
#pragma warning disable 414
|
||||
int _version = 0;
|
||||
#pragma warning restore 414
|
||||
|
||||
public float linSpeed = 10f;
|
||||
public float rotSpeed = 70f;
|
||||
|
||||
public bool simForwardInput = false;
|
||||
public bool _requireLMBToMove = false;
|
||||
|
||||
public bool enableWalkMode = false;
|
||||
|
||||
Vector2 _lastMousePos = -Vector2.one;
|
||||
bool _dragging = false;
|
||||
|
||||
public float _fixedDt = 1 / 60f;
|
||||
|
||||
Transform _targetTransform;
|
||||
|
||||
public CharacterController _moveComponent;
|
||||
|
||||
[Space(10)]
|
||||
|
||||
[SerializeField]
|
||||
DebugFields _debug = new DebugFields();
|
||||
|
||||
#pragma warning disable CS0108
|
||||
// 在编辑器中,我们需要使用“new”来屏蔽警告,但在构建时会再次给出警告,所以应该使用“pragma”来替代。
|
||||
private Camera camera;
|
||||
#pragma warning restore CS0108
|
||||
|
||||
[System.Serializable]
|
||||
class DebugFields
|
||||
{
|
||||
[Tooltip("Allows the camera to roll (rotating on the z axis).")]
|
||||
public bool _enableCameraRoll = false;
|
||||
|
||||
[Tooltip("Disables the XR occlusion mesh for debugging purposes. Only works with legacy XR.")]
|
||||
public bool _disableOcclusionMesh = false;
|
||||
|
||||
[Tooltip("Sets the XR occlusion mesh scale. Useful for debugging refractions. Only works with legacy XR."), UnityEngine.Range(1f, 2f)]
|
||||
public float _occlusionMeshScale = 1f;
|
||||
}
|
||||
|
||||
private void OnValidate()
|
||||
{
|
||||
if (_moveComponent == null)
|
||||
{
|
||||
_moveComponent = GetComponent<CharacterController>();
|
||||
}
|
||||
else if (Application.isEditor)
|
||||
{
|
||||
_moveComponent.enabled = enableWalkMode;
|
||||
}
|
||||
}
|
||||
|
||||
void Awake()
|
||||
{
|
||||
_targetTransform = transform;
|
||||
|
||||
if (!TryGetComponent(out camera))
|
||||
{
|
||||
enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (_moveComponent != null)
|
||||
{
|
||||
_moveComponent.enabled = enableWalkMode;
|
||||
}
|
||||
#if ENABLE_VR && ENABLE_VR_MODULE
|
||||
if (XRSettings.enabled)
|
||||
{
|
||||
// Seems like the best place to put this for now. Most XR debugging happens using this component.
|
||||
// @FixMe: useOcclusionMesh doesn't work anymore. Might be a Unity bug.
|
||||
XRSettings.useOcclusionMesh = !_debug._disableOcclusionMesh;
|
||||
XRSettings.occlusionMaskScale = _debug._occlusionMeshScale;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
float dt = Time.deltaTime;
|
||||
if (_fixedDt > 0f)
|
||||
dt = _fixedDt;
|
||||
|
||||
UpdateMovement(dt);
|
||||
|
||||
#if ENABLE_VR && ENABLE_VR_MODULE
|
||||
// These aren't useful and can break for XR hardware.
|
||||
if (!XRSettings.enabled || XRSettings.loadedDeviceName.Contains("MockHMD"))
|
||||
#endif
|
||||
{
|
||||
UpdateDragging(dt);
|
||||
UpdateKillRoll();
|
||||
}
|
||||
|
||||
#if ENABLE_VR && ENABLE_VR_MODULE
|
||||
if (XRSettings.enabled)
|
||||
{
|
||||
// Check if property has changed.
|
||||
if (XRSettings.useOcclusionMesh == _debug._disableOcclusionMesh)
|
||||
{
|
||||
// @FixMe: useOcclusionMesh doesn't work anymore. Might be a Unity bug.
|
||||
XRSettings.useOcclusionMesh = !_debug._disableOcclusionMesh;
|
||||
}
|
||||
|
||||
XRSettings.occlusionMaskScale = _debug._occlusionMeshScale;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void UpdateMovement(float dt)
|
||||
{
|
||||
// New input system works even when game view is not focused.
|
||||
if (!Application.isFocused)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#if INPUT_SYSTEM_ENABLED
|
||||
if (!Mouse.current.leftButton.isPressed && _requireLMBToMove) return;
|
||||
float forward = (Keyboard.current.wKey.isPressed ? 1 : 0) - (Keyboard.current.sKey.isPressed ? 1 : 0);
|
||||
#else
|
||||
if (!Input.GetMouseButton(1) && _requireLMBToMove) return;
|
||||
float forward = (Input.GetKey(KeyCode.W) ? 1 : 0) - (Input.GetKey(KeyCode.S) ? 1 : 0);
|
||||
#endif
|
||||
if (simForwardInput)
|
||||
{
|
||||
forward = 1f;
|
||||
}
|
||||
|
||||
_targetTransform.position += linSpeed * _targetTransform.forward * forward * dt;
|
||||
var speed = linSpeed;
|
||||
|
||||
#if INPUT_SYSTEM_ENABLED
|
||||
if (Keyboard.current.leftShiftKey.isPressed)
|
||||
#else
|
||||
if (Input.GetKey(KeyCode.LeftShift))
|
||||
#endif
|
||||
{
|
||||
speed *= 3f;
|
||||
}
|
||||
|
||||
var offset = _targetTransform.forward * forward;
|
||||
// _targetTransform.position += speed * _targetTransform.forward * forward * dt;
|
||||
//_transform.position += linSpeed * _transform.right * Input.GetAxis( "Horizontal" ) * dt;
|
||||
#if INPUT_SYSTEM_ENABLED
|
||||
offset += _targetTransform.up * (Keyboard.current.eKey.isPressed ? 1 : 0);
|
||||
offset -= _targetTransform.up * (Keyboard.current.qKey.isPressed ? 1 : 0);
|
||||
offset -= _targetTransform.right * (Keyboard.current.aKey.isPressed ? 1 : 0);
|
||||
offset += _targetTransform.right * (Keyboard.current.dKey.isPressed ? 1 : 0);
|
||||
#else
|
||||
offset += _targetTransform.up * (Input.GetKey(KeyCode.E) ? 1 : 0);
|
||||
offset -= _targetTransform.up * (Input.GetKey(KeyCode.Q) ? 1 : 0);
|
||||
offset -= _targetTransform.right * (Input.GetKey(KeyCode.A) ? 1 : 0);
|
||||
offset += _targetTransform.right * (Input.GetKey(KeyCode.D) ? 1 : 0);
|
||||
#endif
|
||||
offset *= speed * dt;
|
||||
|
||||
// 使用控制器移动
|
||||
if (enableWalkMode)
|
||||
{
|
||||
UpdateWalk(offset);
|
||||
}
|
||||
// 直接设置坐标移动
|
||||
else
|
||||
{
|
||||
_targetTransform.position += offset;
|
||||
}
|
||||
{
|
||||
float rotate = 0f;
|
||||
#if INPUT_SYSTEM_ENABLED
|
||||
rotate += (Keyboard.current.rightArrowKey.isPressed ? 1 : 0);
|
||||
rotate -= (Keyboard.current.leftArrowKey.isPressed ? 1 : 0);
|
||||
#else
|
||||
rotate += (Input.GetKey(KeyCode.RightArrow) ? 1 : 0);
|
||||
rotate -= (Input.GetKey(KeyCode.LeftArrow) ? 1 : 0);
|
||||
#endif
|
||||
|
||||
rotate *= 5f;
|
||||
Vector3 ea = _targetTransform.eulerAngles;
|
||||
ea.y += 0.1f * rotSpeed * rotate * dt;
|
||||
_targetTransform.eulerAngles = ea;
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateDragging(float dt)
|
||||
{
|
||||
// New input system works even when game view is not focused.
|
||||
if (!Application.isFocused)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Vector2 mousePos =
|
||||
#if INPUT_SYSTEM_ENABLED
|
||||
Mouse.current.position.ReadValue();
|
||||
#else
|
||||
Input.mousePosition;
|
||||
#endif
|
||||
|
||||
var wasLeftMouseButtonPressed =
|
||||
#if INPUT_SYSTEM_ENABLED
|
||||
Mouse.current.leftButton.wasPressedThisFrame;
|
||||
#else
|
||||
Input.GetMouseButtonDown(1);
|
||||
#endif
|
||||
|
||||
if (!_dragging && wasLeftMouseButtonPressed && camera.rect.Contains(camera.ScreenToViewportPoint(mousePos)) )
|
||||
//!Crest.OceanDebugGUI.OverGUI(mousePos))
|
||||
{
|
||||
_dragging = true;
|
||||
_lastMousePos = mousePos;
|
||||
}
|
||||
#if INPUT_SYSTEM_ENABLED
|
||||
if (_dragging && Mouse.current.leftButton.wasReleasedThisFrame)
|
||||
#else
|
||||
if (_dragging && Input.GetMouseButtonUp(1))
|
||||
#endif
|
||||
{
|
||||
_dragging = false;
|
||||
_lastMousePos = -Vector2.one;
|
||||
}
|
||||
|
||||
if (_dragging)
|
||||
{
|
||||
Vector2 delta = mousePos - _lastMousePos;
|
||||
|
||||
Vector3 ea = _targetTransform.eulerAngles;
|
||||
ea.x += -0.1f * rotSpeed * delta.y * dt;
|
||||
ea.y += 0.1f * rotSpeed * delta.x * dt;
|
||||
_targetTransform.eulerAngles = ea;
|
||||
|
||||
_lastMousePos = mousePos;
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateKillRoll()
|
||||
{
|
||||
if (_debug._enableCameraRoll) return;
|
||||
Vector3 ea = _targetTransform.eulerAngles;
|
||||
ea.z = 0f;
|
||||
transform.eulerAngles = ea;
|
||||
}
|
||||
|
||||
private float gravity = 0;
|
||||
void UpdateWalk(Vector3 offset)
|
||||
{
|
||||
if (_moveComponent != null)
|
||||
{
|
||||
_moveComponent.enabled = enableWalkMode;
|
||||
if (enableWalkMode)
|
||||
{
|
||||
if (offset.y > 0)
|
||||
gravity = 0;
|
||||
else
|
||||
{
|
||||
gravity -= 0.01f;
|
||||
gravity = Mathf.Max(gravity, -0.98f);
|
||||
}
|
||||
offset.y = offset.y <= 0 ? gravity : offset.y;
|
||||
_moveComponent.Move(offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 37 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
@@ -0,0 +1,109 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Sirenix.OdinInspector;
|
||||
using UnityEngine;
|
||||
using XericLibrary.Runtime.MacroLibrary;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
namespace XericLibrary.Runtime.Type.Base
|
||||
{
|
||||
/// <summary>
|
||||
/// 游戏对象与软引用 (gameobject with soft refrence)。
|
||||
/// 将游戏对象引用保存为软引用,这对于经常替换模型的场景来说比较有用。
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class GowSoftRef
|
||||
{
|
||||
public readonly string interval = "/";
|
||||
|
||||
/// <summary>
|
||||
/// 对象
|
||||
/// </summary>
|
||||
[HorizontalGroup("SoftRef")]
|
||||
[HideLabel]
|
||||
public GameObject targetObejct;
|
||||
|
||||
/// <summary>
|
||||
/// 路径
|
||||
/// </summary>
|
||||
[HorizontalGroup("SoftRef")]
|
||||
[HideLabel]
|
||||
public string targetPath;
|
||||
|
||||
/// <summary>
|
||||
/// 获取对象
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public GameObject GetObject()
|
||||
{
|
||||
if (targetObejct == null)
|
||||
UpdateGameobjectByPath();
|
||||
return targetObejct;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将对象制作成路径
|
||||
/// </summary>
|
||||
public void UpdatePathByGameobject()
|
||||
{
|
||||
if (targetObejct == null)
|
||||
{
|
||||
Debug.LogError("对象引用为空,无法获取软引用");
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsPrefab(targetObejct))
|
||||
{
|
||||
targetPath = "I Dont Know"; // todo 获取预制体路径
|
||||
return;
|
||||
}
|
||||
|
||||
if (targetObejct.transform == null)
|
||||
{
|
||||
Debug.LogError("对象引用为空,无法获取软引用");
|
||||
return;
|
||||
}
|
||||
|
||||
targetPath = targetObejct.transform.GetFamilyName().Join(a => a, interval: interval);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将路径制作成对象
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool UpdateGameobjectByPath()
|
||||
{
|
||||
if (MacroObject.FindFamilyMemberExact(null, targetPath.Split(interval), out var target))
|
||||
{
|
||||
targetObejct = target.gameObject;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前的对象是预制体吗
|
||||
/// </summary>
|
||||
public bool IsPrefab(Object target)
|
||||
#if UNITY_EDITOR
|
||||
{
|
||||
#if UNITY_6000_0_OR_NEWER
|
||||
var type = PrefabUtility.GetPrefabAssetType(target);
|
||||
return type is PrefabAssetType.Regular or PrefabAssetType.Variant;
|
||||
#else
|
||||
return PrefabUtility.GetPrefabType(target) == PrefabType.PrefabInstance;
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
=> false;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using XericLibrary.Runtime.CustomEditor;
|
||||
|
||||
namespace Deconstruction.Runtime.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取屏幕缩放
|
||||
/// </summary>
|
||||
public class AutoCanvasScale : MonoBehaviour
|
||||
{
|
||||
#region 字段属性
|
||||
|
||||
public CanvasScaler canvasScaler;
|
||||
|
||||
[Rename("设计尺寸")]
|
||||
public Vector2 StandardSize = new Vector2(1920,1080);
|
||||
|
||||
public Vector2 ScaleMinMax = new Vector2(0.5f, 2);
|
||||
|
||||
#endregion
|
||||
|
||||
#region 生命周期
|
||||
|
||||
private void OnValidate()
|
||||
{
|
||||
FindCanvasScaler();
|
||||
GetScreenScale();
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
FindCanvasScaler();
|
||||
}
|
||||
|
||||
private void LateUpdate()
|
||||
{
|
||||
canvasScaler.scaleFactor = GetScreenScale();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 方法
|
||||
|
||||
private void FindCanvasScaler()
|
||||
{
|
||||
if (canvasScaler == null)
|
||||
canvasScaler = transform.GetComponent<CanvasScaler>();
|
||||
}
|
||||
|
||||
private float GetScreenScale()
|
||||
{
|
||||
Vector2 screenSize = new Vector2(Screen.width, Screen.height);
|
||||
// Debug.Log(canvasScaler.referenceResolution);
|
||||
var sf = screenSize / StandardSize;
|
||||
return Mathf.Clamp(Mathf.Min(sf.x, sf.y), ScaleMinMax.x, ScaleMinMax.y);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,429 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Deconstruction.Runtime.UI
|
||||
{
|
||||
public class CircleSlider : Selectable, IDragHandler, IEndDragHandler, IBeginDragHandler
|
||||
{
|
||||
[SerializeField] private RectTransform m_HandleRect;
|
||||
|
||||
public RectTransform handleRect
|
||||
{
|
||||
get { return m_HandleRect; }
|
||||
set
|
||||
{
|
||||
if (SetPropertyUtility.SetClass(ref m_HandleRect, value))
|
||||
{
|
||||
UpdateCachedReferences();
|
||||
UpdateVisuals();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField] private RectTransform m_FillRect;
|
||||
|
||||
public RectTransform fillrect
|
||||
{
|
||||
get { return m_FillRect; }
|
||||
set
|
||||
{
|
||||
if (SetPropertyUtility.SetClass(ref m_FillRect, value))
|
||||
{
|
||||
UpdateCachedReferences();
|
||||
UpdateVisuals();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField] private float m_MinValue = 0;
|
||||
|
||||
public float minValue
|
||||
{
|
||||
get => m_MinValue;
|
||||
set
|
||||
{
|
||||
if (SetPropertyUtility.SetStruct(ref m_MinValue, value))
|
||||
{
|
||||
Set(m_Value);
|
||||
UpdateVisuals();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField] private float m_MaxValue = 1;
|
||||
|
||||
public float maxValue
|
||||
{
|
||||
get { return m_MaxValue; }
|
||||
set
|
||||
{
|
||||
if (SetPropertyUtility.SetStruct(ref m_MaxValue, value))
|
||||
{
|
||||
Set(m_Value);
|
||||
UpdateVisuals();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField] private float m_Value;
|
||||
|
||||
public float value
|
||||
{
|
||||
get
|
||||
{
|
||||
if (wholeNumbers)
|
||||
return Mathf.Round(m_Value);
|
||||
return m_Value;
|
||||
}
|
||||
set { Set(value); }
|
||||
}
|
||||
|
||||
[SerializeField] private Image.Origin360 m_FillOrigin;
|
||||
|
||||
public Image.Origin360 fillOrigin
|
||||
{
|
||||
get { return m_FillOrigin; }
|
||||
set
|
||||
{
|
||||
if (SetPropertyUtility.SetStruct(ref m_FillOrigin, value))
|
||||
{
|
||||
Set(m_Value);
|
||||
UpdateVisuals();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField] private float m_Radius;
|
||||
|
||||
public float radius
|
||||
{
|
||||
get { return m_Radius; }
|
||||
set
|
||||
{
|
||||
if (SetPropertyUtility.SetStruct(ref m_Radius, value))
|
||||
{
|
||||
UpdateVisuals();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField] private bool m_ClockWise;
|
||||
|
||||
public bool clockWise
|
||||
{
|
||||
get { return m_ClockWise; }
|
||||
set
|
||||
{
|
||||
if (SetPropertyUtility.SetStruct(ref m_ClockWise, value))
|
||||
{
|
||||
UpdateCachedReferences();
|
||||
UpdateVisuals();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField] private bool m_WholeNumbers = false;
|
||||
|
||||
public bool wholeNumbers
|
||||
{
|
||||
get { return m_WholeNumbers; }
|
||||
set
|
||||
{
|
||||
if (SetPropertyUtility.SetStruct(ref m_WholeNumbers, value))
|
||||
{
|
||||
Set(m_Value);
|
||||
UpdateVisuals();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public float normalizedValue
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Mathf.Approximately(m_MinValue, m_MaxValue))
|
||||
return 0;
|
||||
return Mathf.InverseLerp(m_MinValue, m_MaxValue, value);
|
||||
}
|
||||
|
||||
set { this.value = Mathf.Lerp(m_MinValue, m_MaxValue, value); }
|
||||
}
|
||||
|
||||
private Action<float> m_OnValueChanged;
|
||||
private Action m_OnDragEnd;
|
||||
private Action m_OnTweenComplete;
|
||||
private Image m_FillImage;
|
||||
private bool m_DelayedUpdateVisuals = false;
|
||||
private bool m_dragHandler;
|
||||
private Camera m_eventCamera;
|
||||
private Coroutine m_TweenCor;
|
||||
|
||||
|
||||
protected override void OnEnable()
|
||||
{
|
||||
UpdateCachedReferences();
|
||||
Set(m_Value);
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
protected override void OnValidate()
|
||||
{
|
||||
base.OnValidate();
|
||||
if (IsActive())
|
||||
{
|
||||
UpdateCachedReferences();
|
||||
Set(m_Value, false);
|
||||
m_DelayedUpdateVisuals = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (m_DelayedUpdateVisuals)
|
||||
{
|
||||
m_DelayedUpdateVisuals = false;
|
||||
UpdateVisuals();
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateCachedReferences()
|
||||
{
|
||||
if (m_FillRect != null)
|
||||
{
|
||||
m_FillImage = m_FillRect.GetComponent<Image>();
|
||||
m_FillImage.fillMethod = Image.FillMethod.Radial360;
|
||||
m_FillImage.fillOrigin = (int)m_FillOrigin;
|
||||
m_FillImage.fillClockwise = m_ClockWise;
|
||||
}
|
||||
}
|
||||
|
||||
private bool MayDrag(PointerEventData eventData)
|
||||
{
|
||||
return IsActive() && IsInteractable() && eventData.button == PointerEventData.InputButton.Left;
|
||||
}
|
||||
|
||||
public void OnDrag(PointerEventData eventData)
|
||||
{
|
||||
if (!MayDrag(eventData))
|
||||
return;
|
||||
if (m_dragHandler)
|
||||
{
|
||||
Vector2 localCursor;
|
||||
if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(m_FillRect, eventData.position,
|
||||
eventData.pressEventCamera, out localCursor))
|
||||
return;
|
||||
float angle = CalAngle(localCursor);
|
||||
normalizedValue = (angle / 360);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void OnEndDrag(PointerEventData eventData)
|
||||
{
|
||||
m_dragHandler = false;
|
||||
if (m_OnDragEnd != null)
|
||||
{
|
||||
m_OnDragEnd();
|
||||
}
|
||||
}
|
||||
|
||||
public void OnBeginDrag(PointerEventData eventData)
|
||||
{
|
||||
if (m_HandleRect != null)
|
||||
{
|
||||
if (RectTransformUtility.RectangleContainsScreenPoint(m_HandleRect, eventData.position,
|
||||
eventData.enterEventCamera))
|
||||
{
|
||||
m_dragHandler = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_dragHandler = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private float CalAngle(Vector2 pos)
|
||||
{
|
||||
float angle = 0;
|
||||
float rad = Mathf.Atan2(pos.y, pos.x) * Mathf.Rad2Deg;
|
||||
switch (m_FillOrigin)
|
||||
{
|
||||
case Image.Origin360.Top:
|
||||
angle = m_ClockWise ? 90 - rad : rad + 270;
|
||||
break;
|
||||
case Image.Origin360.Left:
|
||||
angle = m_ClockWise ? 180 - rad : rad + 180;
|
||||
break;
|
||||
case Image.Origin360.Right:
|
||||
angle = m_ClockWise ? -rad : rad;
|
||||
break;
|
||||
case Image.Origin360.Bottom:
|
||||
angle = m_ClockWise ? 270 - rad : rad + 90;
|
||||
break;
|
||||
}
|
||||
|
||||
if (angle > 360)
|
||||
{
|
||||
angle -= 360;
|
||||
}
|
||||
|
||||
if (angle < 0)
|
||||
{
|
||||
angle += 360;
|
||||
}
|
||||
|
||||
return angle;
|
||||
}
|
||||
|
||||
private void UpdateVisuals()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (!Application.isPlaying)
|
||||
UpdateCachedReferences();
|
||||
#endif
|
||||
if (m_FillImage != null)
|
||||
{
|
||||
m_FillImage.fillAmount = normalizedValue;
|
||||
}
|
||||
|
||||
if (m_HandleRect != null)
|
||||
{
|
||||
m_HandleRect.transform.localPosition = CalPos(normalizedValue * 360);
|
||||
}
|
||||
}
|
||||
|
||||
private Vector2 CalPos(float angle)
|
||||
{
|
||||
Vector2 pos = Vector2.zero;
|
||||
switch (m_FillOrigin)
|
||||
{
|
||||
case Image.Origin360.Left:
|
||||
angle = m_ClockWise ? 180 - angle : angle + 180;
|
||||
break;
|
||||
case Image.Origin360.Top:
|
||||
angle = m_ClockWise ? 90 - angle : angle + 90;
|
||||
break;
|
||||
case Image.Origin360.Right:
|
||||
angle = m_ClockWise ? -angle : angle;
|
||||
break;
|
||||
case Image.Origin360.Bottom:
|
||||
angle = m_ClockWise ? 270 - angle : angle - 90;
|
||||
break;
|
||||
}
|
||||
|
||||
angle = Mathf.Deg2Rad * angle;
|
||||
pos.y = Mathf.Sin(angle) * m_Radius;
|
||||
pos.x = Mathf.Cos(angle) * m_Radius;
|
||||
return pos;
|
||||
}
|
||||
|
||||
|
||||
private void Set(float input, bool sendCallback = true)
|
||||
{
|
||||
float newValue = ClampValue(input);
|
||||
if (m_Value == newValue)
|
||||
return;
|
||||
|
||||
m_Value = newValue;
|
||||
UpdateVisuals();
|
||||
if (sendCallback)
|
||||
{
|
||||
if (m_OnValueChanged != null)
|
||||
{
|
||||
m_OnValueChanged.Invoke(newValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float ClampValue(float input)
|
||||
{
|
||||
float newValue = Mathf.Clamp(input, m_MinValue, m_MaxValue);
|
||||
if (wholeNumbers)
|
||||
newValue = Mathf.Round(newValue);
|
||||
return newValue;
|
||||
}
|
||||
|
||||
public void OnValueChange(Action<float> call)
|
||||
{
|
||||
m_OnValueChanged = call;
|
||||
}
|
||||
|
||||
public void OnDragEnd(Action call)
|
||||
{
|
||||
m_OnDragEnd = call;
|
||||
}
|
||||
|
||||
public void TweenValue(float val, float time, Action call = null)
|
||||
{
|
||||
m_TweenCor = StartCoroutine(_tweenValue(val, time));
|
||||
m_OnTweenComplete = call;
|
||||
}
|
||||
|
||||
public void StopTween()
|
||||
{
|
||||
if (m_TweenCor != null)
|
||||
{
|
||||
StopCoroutine(m_TweenCor);
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator _tweenValue(float val, float time)
|
||||
{
|
||||
float t = 0;
|
||||
float oldValue = value;
|
||||
float interval = val - oldValue;
|
||||
|
||||
while (t < time)
|
||||
{
|
||||
t += Time.deltaTime;
|
||||
value = oldValue + (t / time) * interval;
|
||||
yield return 0;
|
||||
}
|
||||
|
||||
if (m_OnTweenComplete != null)
|
||||
{
|
||||
m_OnTweenComplete();
|
||||
}
|
||||
|
||||
value = val;
|
||||
}
|
||||
}
|
||||
|
||||
internal static class SetPropertyUtility
|
||||
{
|
||||
public static bool SetColor(ref Color currentValue, Color newValue)
|
||||
{
|
||||
if (currentValue.r == newValue.r && currentValue.g == newValue.g && currentValue.b == newValue.b &&
|
||||
currentValue.a == newValue.a)
|
||||
return false;
|
||||
|
||||
currentValue = newValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool SetStruct<T>(ref T currentValue, T newValue) where T : struct
|
||||
{
|
||||
if (EqualityComparer<T>.Default.Equals(currentValue, newValue))
|
||||
return false;
|
||||
|
||||
currentValue = newValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool SetClass<T>(ref T currentValue, T newValue) where T : class
|
||||
{
|
||||
if ((currentValue == null && newValue == null) || (currentValue != null && currentValue.Equals(newValue)))
|
||||
return false;
|
||||
|
||||
currentValue = newValue;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,494 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.UI;
|
||||
using XericLibrary.Runtime.CustomEditor;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
using Sirenix.OdinInspector;
|
||||
#if UNITY_EDITOR
|
||||
using Sirenix.Utilities.Editor;
|
||||
#endif
|
||||
|
||||
namespace XericLibrary.Runtime.MacroLibrary
|
||||
{
|
||||
/// <summary>
|
||||
/// UI相关的扩展
|
||||
/// </summary>
|
||||
public static class MacroUI
|
||||
{
|
||||
#region toggle 扩展
|
||||
|
||||
private static FieldInfo togglesFieldInfo = typeof(ToggleGroup).GetField("m_Toggles", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
|
||||
|
||||
public static List<Toggle> GetToggles(this ToggleGroup toggleGroup)
|
||||
{
|
||||
if (toggleGroup == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(toggleGroup));
|
||||
}
|
||||
|
||||
if (togglesFieldInfo == null)
|
||||
{
|
||||
throw new InvalidOperationException("Unable to access the 'm_Toggles' field.");
|
||||
}
|
||||
|
||||
var toggles = togglesFieldInfo.GetValue(toggleGroup) as List<Toggle>;
|
||||
if (toggles == null)
|
||||
{
|
||||
throw new InvalidCastException("The 'm_Toggles' field is not of type List<Toggle>.");
|
||||
}
|
||||
|
||||
return toggles;
|
||||
// return (List<Toggle>)togglesFieldInfo.GetValue(toggleGroup);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前单选项组中激活的索引
|
||||
/// </summary>
|
||||
/// <param name="toggleGroup"></param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("索引依赖单选项自身在大纲中的顺序,在运行时顺序可能与编辑时不一致,请使用ToggleMapping")]
|
||||
public static int GetActiveToggleIndex(this ToggleGroup toggleGroup)
|
||||
{
|
||||
var index = -1;
|
||||
foreach (var toggle in toggleGroup.GetToggles())
|
||||
{
|
||||
index++;
|
||||
if (toggle.isOn)
|
||||
return index;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前单选项组的数量
|
||||
/// </summary>
|
||||
/// <param name="toggleGroup"></param>
|
||||
/// <returns></returns>
|
||||
public static int GetToggleCount(this ToggleGroup toggleGroup)
|
||||
{
|
||||
return toggleGroup.GetToggles().Count;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 在单选项组上注册一个事件,当组中的任意成员变成激活状态时调用(其他的不会发生调用)。
|
||||
/// </summary>
|
||||
/// <param name="toggleGroup"></param>
|
||||
/// <param name="onToggleChange"></param>
|
||||
public static void OnToggleGroupChangeEvent(this ToggleGroup toggleGroup, Action<Toggle> onToggleChange)
|
||||
{
|
||||
foreach (var toggle in toggleGroup.GetToggles())
|
||||
{
|
||||
toggle.onValueChanged.AddListener(a =>
|
||||
{
|
||||
if (!a) return;
|
||||
onToggleChange?.Invoke(toggle);
|
||||
});
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 清空单选项组中的所有事件(与注册所有事件对应,但那个事件没法单独注销)
|
||||
/// </summary>
|
||||
/// <param name="toggleGroup"></param>
|
||||
public static void RemoveToggleGroupChangeEvent(this ToggleGroup toggleGroup)
|
||||
{
|
||||
foreach (var toggle in toggleGroup.GetToggles())
|
||||
{
|
||||
toggle.onValueChanged.RemoveAllListeners();
|
||||
}
|
||||
}
|
||||
|
||||
#region toggle 索引
|
||||
|
||||
/// <summary>
|
||||
/// toggle映射集
|
||||
/// <code>
|
||||
/// toggle映射集必须使用unity序列化管理,否则和直接使用toggleGroup没区别,目的是解决toggleGroup在打包后大纲视图的索引可能发生错位的问题。
|
||||
/// </code>
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class ToggleMapping : IEnumerable<Toggle>
|
||||
{
|
||||
#region 事件委托
|
||||
|
||||
/// <summary>
|
||||
/// 在单选项目切换时产生回调,返回选中的单选项目在组中的引用
|
||||
/// </summary>
|
||||
public Action<Toggle> OnAnyToggleSwitchOn;
|
||||
|
||||
/// <summary>
|
||||
/// 在单选项目切换时产生回调,返回选中的单选项目在组中的索引
|
||||
/// </summary>
|
||||
public Action<int> OnAnyToggleIndexSwitchOn;
|
||||
|
||||
#endregion
|
||||
|
||||
#region 字段属性
|
||||
|
||||
[LabelText("单选组")] public ToggleGroup ToggleGroup;
|
||||
|
||||
[SerializeField, LabelText("编辑单选项目顺序")]
|
||||
[ListDrawerSettings(OnTitleBarGUI = "GetAndSortToggle")]
|
||||
private List<Toggle> toggleList = new List<Toggle>();
|
||||
|
||||
// 当前选中的项目
|
||||
private int nowSelectToggleIndex = 0;
|
||||
private Toggle nowSelectToggle = null;
|
||||
|
||||
|
||||
public Transform TogglesContext => ToggleGroup.transform;
|
||||
|
||||
/// <summary>
|
||||
/// 当前选中的toggle索引
|
||||
/// </summary>
|
||||
public int NowSelectToggleIndex => nowSelectToggleIndex;
|
||||
|
||||
/// <summary>
|
||||
/// 当前选中的toggle
|
||||
/// </summary>
|
||||
public Toggle NowSelectToggle => nowSelectToggle;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取并给列表排序(顺序不一定与拼音有关)
|
||||
/// </summary>
|
||||
public void GetAndSortToggle()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
// 自动获取并排序
|
||||
if (SirenixEditorGUI.ToolbarButton(EditorIcons.Refresh))
|
||||
{
|
||||
var newToggleList = MacroSort.FullCharacterOrderSort(ToggleGroup.GetToggles(), a => a.name).ToList();
|
||||
if (newToggleList.Count <= 0 || newToggleList == null)
|
||||
Debug.LogError("如果无法更新获取自动排序toggle,可能是因为toggleGroup被隐藏了,手动将其激活后再获取即可。");
|
||||
else
|
||||
toggleList = newToggleList;
|
||||
}
|
||||
// 反转顺序
|
||||
if (SirenixEditorGUI.ToolbarButton(EditorIcons.TriangleDown))
|
||||
{
|
||||
toggleList.Reverse();
|
||||
}
|
||||
#else
|
||||
var newToggleList = MacroSort.FullCharacterOrderSort(ToggleGroup.GetToggles(), a => a.name).ToList();
|
||||
if (newToggleList.Count <= 0 || newToggleList == null)
|
||||
Debug.LogError("如果无法更新获取自动排序toggle,可能是因为toggleGroup被隐藏了,手动将其激活后再获取即可。");
|
||||
else
|
||||
toggleList = newToggleList;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 接口
|
||||
|
||||
/// <summary>
|
||||
/// 获取索引下的单选项组件
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
public Toggle this[int index] => toggleList[index];
|
||||
|
||||
public int Count => toggleList.Count;
|
||||
|
||||
public IEnumerator<Toggle> GetEnumerator()
|
||||
{
|
||||
return toggleList.GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 方法
|
||||
|
||||
/// <summary>
|
||||
/// 初始化
|
||||
/// <code>
|
||||
/// 自动将所有的按键绑定回调事件;如果作为刷新函数调用,请确保已经完全组索引。
|
||||
/// 或者可以直接清空旧项目(CleanToggle),然后逐个添加(AddToggle)
|
||||
/// </code>
|
||||
/// </summary>
|
||||
public void Initialize()
|
||||
{
|
||||
// 未指定组时,说明压根没用这部分功能,用不着初始化。
|
||||
if (ToggleGroup == null)
|
||||
return;
|
||||
|
||||
// 防呆警告
|
||||
if (toggleList.Count <= 0)
|
||||
{
|
||||
var toggles = ToggleGroup.GetToggles();
|
||||
if (toggles.Count != toggleList.Count)
|
||||
{
|
||||
toggleList = toggles;
|
||||
Debug.LogWarning($"在初始化单选项组时,{ToggleGroup.name}并未预先指定索引顺序,将默认使用大纲顺序。");
|
||||
}
|
||||
}
|
||||
// 事件初始化
|
||||
for (int i = 0; i < toggleList.Count; i++)
|
||||
{
|
||||
var toggle = toggleList[i];
|
||||
|
||||
ToggleAddEvent(toggle);
|
||||
|
||||
if (toggle.isOn)
|
||||
{
|
||||
nowSelectToggleIndex = i;
|
||||
nowSelectToggle = toggle;
|
||||
}
|
||||
}
|
||||
|
||||
if (nowSelectToggle == null)
|
||||
SetToggleOn(0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加一个toggle
|
||||
/// </summary>
|
||||
/// <param name="t"></param>
|
||||
/// <returns>返回toggle的索引</returns>
|
||||
public int AddToggle(Toggle t)
|
||||
{
|
||||
ToggleAddEvent(t);
|
||||
|
||||
var resultIndex = toggleList.Count;
|
||||
toggleList.Add(t);
|
||||
return resultIndex;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 移除一个toggle,这不会影响其他toggle的索引,但此处移除的位置会为空。
|
||||
/// <code>
|
||||
/// 注 :这不会销毁toggle。
|
||||
/// </code>
|
||||
/// </summary>
|
||||
/// <param name="t"></param>
|
||||
/// <returns>是否成功移除toggle</returns>
|
||||
public bool RemoveToggle(Toggle t)
|
||||
{
|
||||
var index = toggleList.IndexOf(t);
|
||||
if (index < 0)
|
||||
return false;
|
||||
|
||||
t.onValueChanged.RemoveAllListeners();
|
||||
toggleList[index] = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清除toggle
|
||||
/// </summary>
|
||||
/// <param name="allowDestroy">是否同时销毁所有toggle</param>
|
||||
public void CleanToggle(bool allowDestroy)
|
||||
{
|
||||
foreach (var t in toggleList)
|
||||
{
|
||||
t.onValueChanged.RemoveAllListeners();
|
||||
if (allowDestroy)
|
||||
Object.Destroy(t);
|
||||
}
|
||||
toggleList.Clear();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// toggle注册的事件,只有当按下时才需要调用此事件。
|
||||
/// </summary>
|
||||
/// <param name="t"></param>
|
||||
private void ToggleAddEvent(Toggle t)
|
||||
{
|
||||
t.onValueChanged.AddListener(a =>
|
||||
{
|
||||
if (a) ToggleRegister(t);
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// toggle注册的事件,只有当按下时才需要调用此事件。
|
||||
/// </summary>
|
||||
/// <param name="t"></param>
|
||||
private void ToggleRegister(Toggle t)
|
||||
{
|
||||
nowSelectToggle = t;
|
||||
nowSelectToggleIndex = GetIndex(t);
|
||||
OnAnyToggleSwitchOn?.Invoke(t);
|
||||
OnAnyToggleIndexSwitchOn?.Invoke(nowSelectToggleIndex);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取toggle代表的索引
|
||||
/// </summary>
|
||||
/// <param name="target"></param>
|
||||
/// <returns>如果这个toggle不存在于当前的单选项组中,返回-1</returns>
|
||||
public int GetIndex(Toggle target)
|
||||
{
|
||||
return toggleList.IndexOf(target);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取toggle代表的索引, 如果toggle不存在于这个映射集中,将返回否
|
||||
/// </summary>
|
||||
/// <param name="target"></param>
|
||||
/// <param name="index"></param>
|
||||
/// <returns></returns>
|
||||
public bool TryGetIndex(Toggle target, out int index)
|
||||
{
|
||||
index = toggleList.IndexOf(target);
|
||||
return index >= 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置单选项激活
|
||||
/// </summary>
|
||||
/// <param name="target"></param>
|
||||
public void SetToggleOn(Toggle target)
|
||||
{
|
||||
target.isOn = true;
|
||||
}
|
||||
/// <summary>
|
||||
/// 设置单选项激活
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
public void SetToggleOn(int index)
|
||||
{
|
||||
if (0 < index && index < toggleList.Count)
|
||||
{
|
||||
SetToggleOn(toggleList[index]);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 设置单选项激活
|
||||
/// </summary>
|
||||
/// <param name="target"></param>
|
||||
public void SetToggleOnWithoutNotify(Toggle target)
|
||||
{
|
||||
target.SetIsOnWithoutNotify(true);
|
||||
}
|
||||
/// <summary>
|
||||
/// 设置单选项激活
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
public void SetToggleOnWithoutNotify(int index)
|
||||
{
|
||||
if (0 < index && index < toggleList.Count)
|
||||
{
|
||||
SetToggleOnWithoutNotify(toggleList[index]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 清除映射结构(不会清除toggle实例)
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
ToggleGroup.RemoveToggleGroupChangeEvent();
|
||||
toggleList.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清除映射结构,并销毁所有toggle组件
|
||||
/// </summary>
|
||||
public void RemoveAllToggle()
|
||||
{
|
||||
for (int i = toggleList.Count - 1; i >= 0; i--)
|
||||
{
|
||||
Object.Destroy(toggleList[i]);
|
||||
}
|
||||
Clear();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#region 按钮扩展
|
||||
|
||||
/// <summary>
|
||||
/// 所有按钮注册一个事件
|
||||
/// </summary>
|
||||
/// <param name="buttons"></param>
|
||||
/// <param name="targetEvent"></param>
|
||||
public static void RegisterOnClickEvent(this IEnumerable<Button> buttons, UnityAction targetEvent)
|
||||
{
|
||||
foreach (var button in buttons)
|
||||
{
|
||||
button.onClick.AddListener(targetEvent);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 所有按钮注销一个事件
|
||||
/// </summary>
|
||||
/// <param name="buttons"></param>
|
||||
/// <param name="targetEvent"></param>
|
||||
public static void LogoutOnClickEvent(this IEnumerable<Button> buttons, UnityAction targetEvent)
|
||||
{
|
||||
foreach (var button in buttons)
|
||||
{
|
||||
button.onClick.RemoveListener(targetEvent);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置所有按钮的可交互性
|
||||
/// </summary>
|
||||
/// <param name="buttons"></param>
|
||||
/// <param name="interactable"></param>
|
||||
public static void SetButtonInteractable(this IEnumerable<Button> buttons, bool interactable)
|
||||
{
|
||||
foreach (var button in buttons)
|
||||
{
|
||||
button.interactable = interactable;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 文本组件扩展
|
||||
|
||||
public static void SetText(this IEnumerable<TextMeshProUGUI> texts, string text)
|
||||
{
|
||||
foreach (var t in texts)
|
||||
{
|
||||
t.text = text;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region UI变换获取扩展
|
||||
|
||||
/// <summary>
|
||||
/// 获取一个组件的矩形变换组件
|
||||
/// </summary>
|
||||
/// <param name="target"></param>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public static RectTransform RectTransform<T>(this T target)
|
||||
where T : Component
|
||||
=> target.transform as RectTransform;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using XericLibrary.Runtime.MacroLibrary;
|
||||
|
||||
namespace Deconstruction.Runtime.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// 提供ui界面上的脚本
|
||||
/// </summary>
|
||||
public class WeaklyUIBehaviour : MonoBehaviour
|
||||
{
|
||||
#region 字段属性
|
||||
|
||||
/// <summary>
|
||||
/// 此处的矩形变换组件
|
||||
/// </summary>
|
||||
public RectTransform rectTransform { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 此组件所在的Canvas
|
||||
/// </summary>
|
||||
public Canvas CanvasRoot { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 此组件所在的Canvas下的CanvasScaler
|
||||
/// </summary>
|
||||
public CanvasScaler CanvasRootScaler { get; private set; }
|
||||
|
||||
private bool isFirstOnEnable = false;
|
||||
private bool isFirstOnEnableStart = false;
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// 在加载脚本实例时调用
|
||||
/// </summary>
|
||||
protected virtual void Awake()
|
||||
{
|
||||
rectTransform = transform as RectTransform;
|
||||
CanvasRoot = transform.GetParents()
|
||||
.Select(t => t.GetComponent<Canvas>())
|
||||
.FirstOrDefault(a => a != null);
|
||||
if (CanvasRoot != null)
|
||||
CanvasRootScaler = CanvasRoot.GetComponent<CanvasScaler>();
|
||||
else
|
||||
{
|
||||
Debug.LogError($"成员{name}不是一个有效的ui成员,或没有放置在canvas上,致使其无法找到ui根组件");
|
||||
}
|
||||
|
||||
isFirstOnEnable = true;
|
||||
isFirstOnEnableStart = true;
|
||||
}
|
||||
|
||||
protected virtual void OnEnable()
|
||||
{
|
||||
if (isFirstOnEnable)
|
||||
{
|
||||
isFirstOnEnable = false;
|
||||
OnFirstEnable();
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnDisable()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 首次行为激活时调用(用于界面类型元素在运行期间首次初始化)
|
||||
/// </summary>
|
||||
protected virtual void OnFirstEnable()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected virtual void Start()
|
||||
{
|
||||
if (isFirstOnEnableStart)
|
||||
{
|
||||
isFirstOnEnableStart = false;
|
||||
OnFirstEnableStart();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 首次行为激活开始时调用(用于界面类型元素在运行期间首次初始化)
|
||||
/// </summary>
|
||||
protected virtual void OnFirstEnableStart()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user