This commit is contained in:
XgC2961 2025-09-02 08:44:00 +08:00
parent 28fe030475
commit 0e2275635c
26 changed files with 10582 additions and 517413 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +0,0 @@
fileFormatVersion: 2
guid: 432f87c529858f04c99d14284b7e0c80
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +0,0 @@
fileFormatVersion: 2
guid: f75d3e676db2e634e92fedae86563f09
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +0,0 @@
fileFormatVersion: 2
guid: 6865c1237a7183346ba17964f39d0609
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +0,0 @@
fileFormatVersion: 2
guid: 8d7d450574a887b489087ae2aca48e5a
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +0,0 @@
fileFormatVersion: 2
guid: f4b338402f11323408587e037729cc71
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +0,0 @@
fileFormatVersion: 2
guid: be28f7874a758b74a8b0af6d3139c00c
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -710,7 +710,7 @@ GameObject:
- component: {fileID: 67960687}
- component: {fileID: 67960686}
m_Layer: 5
m_Name: Button
m_Name: "\u52A8\u7269\u4ED3"
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
@ -967,7 +967,7 @@ GameObject:
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 0
m_IsActive: 1
--- !u!224 &103809607
RectTransform:
m_ObjectHideFlags: 0
@ -1411,7 +1411,7 @@ MonoBehaviour:
- m_Target: {fileID: 2109707620}
m_TargetAssemblyTypeName: TouchClient, Assembly-CSharp
m_MethodName: OnButtonClick_PlayModel
m_Mode: 5
m_Mode: 1
m_Arguments:
m_ObjectArgument: {fileID: 0}
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
@ -1814,7 +1814,7 @@ MonoBehaviour:
- m_Target: {fileID: 2109707620}
m_TargetAssemblyTypeName: TouchClient, Assembly-CSharp
m_MethodName: OnButtonClick_PlayModel
m_Mode: 5
m_Mode: 1
m_Arguments:
m_ObjectArgument: {fileID: 0}
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
@ -2221,7 +2221,7 @@ RectTransform:
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0.0000019073486}
m_SizeDelta: {x: 64.1366, y: 15.9954}
m_Pivot: {x: 0.5, y: 0.5}
@ -2297,7 +2297,7 @@ RectTransform:
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 10, y: 0}
m_Pivot: {x: 0.5, y: 0.5}
@ -2564,7 +2564,7 @@ RectTransform:
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: -481, y: 175.86954}
m_AnchoredPosition: {x: -404, y: -53.323}
m_SizeDelta: {x: 514.5018, y: 206.6469}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &374413652
@ -3095,7 +3095,7 @@ GameObject:
- component: {fileID: 446068281}
- component: {fileID: 446068280}
m_Layer: 5
m_Name: Button
m_Name: "pet\u5355\u4E2A\u7EC4\u4EF6\u7ED3\u6784"
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
@ -3165,7 +3165,19 @@ MonoBehaviour:
m_TargetGraphic: {fileID: 446068281}
m_OnClick:
m_PersistentCalls:
m_Calls: []
m_Calls:
- m_Target: {fileID: 2109707620}
m_TargetAssemblyTypeName: TouchClient, Assembly-CSharp
m_MethodName: OnButtonClick_SingleItem
m_Mode: 5
m_Arguments:
m_ObjectArgument: {fileID: 0}
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
m_IntArgument: 0
m_FloatArgument: 0
m_StringArgument: "pet\u5355\u4E2A\u7EC4\u4EF6\u7ED3\u6784"
m_BoolArgument: 0
m_CallState: 2
--- !u!114 &446068281
MonoBehaviour:
m_ObjectHideFlags: 0
@ -4128,7 +4140,7 @@ GameObject:
- component: {fileID: 547606276}
- component: {fileID: 547606275}
m_Layer: 5
m_Name: Button
m_Name: "SPECT\u63A2\u6D4B\u5668"
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
@ -4673,7 +4685,7 @@ GameObject:
- component: {fileID: 684509595}
- component: {fileID: 684509594}
m_Layer: 5
m_Name: Button
m_Name: "\u627F\u91CD\u7ED3\u6784"
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
@ -5729,7 +5741,7 @@ MonoBehaviour:
- m_Target: {fileID: 2109707620}
m_TargetAssemblyTypeName: TouchClient, Assembly-CSharp
m_MethodName: OnButtonClick_PlayModel
m_Mode: 5
m_Mode: 1
m_Arguments:
m_ObjectArgument: {fileID: 0}
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
@ -6001,7 +6013,7 @@ GameObject:
- component: {fileID: 896665758}
- component: {fileID: 896665757}
m_Layer: 5
m_Name: Button
m_Name: "\u5E8A\u4F53\u652F\u6491\u7CFB\u7EDF"
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
@ -6258,7 +6270,7 @@ GameObject:
- component: {fileID: 911858246}
- component: {fileID: 911858245}
m_Layer: 5
m_Name: Button
m_Name: "PET\u9635\u5217\u5806\u53E0\u6392\u5217"
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
@ -6328,7 +6340,19 @@ MonoBehaviour:
m_TargetGraphic: {fileID: 911858246}
m_OnClick:
m_PersistentCalls:
m_Calls: []
m_Calls:
- m_Target: {fileID: 2109707620}
m_TargetAssemblyTypeName: TouchClient, Assembly-CSharp
m_MethodName: OnButtonClick_SingleItem
m_Mode: 5
m_Arguments:
m_ObjectArgument: {fileID: 0}
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
m_IntArgument: 0
m_FloatArgument: 0
m_StringArgument: "PET\u9635\u5217\u5806\u53E0\u6392\u5217"
m_BoolArgument: 0
m_CallState: 2
--- !u!114 &911858246
MonoBehaviour:
m_ObjectHideFlags: 0
@ -6691,7 +6715,7 @@ RectTransform:
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 10, y: 0}
m_Pivot: {x: 0.5, y: 0.5}
@ -7544,7 +7568,7 @@ MonoBehaviour:
- m_Target: {fileID: 2109707620}
m_TargetAssemblyTypeName: TouchClient, Assembly-CSharp
m_MethodName: OnButtonClick_PlayModel
m_Mode: 5
m_Mode: 1
m_Arguments:
m_ObjectArgument: {fileID: 0}
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
@ -7666,7 +7690,7 @@ RectTransform:
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: -481, y: -115}
m_AnchoredPosition: {x: 350, y: 87}
m_SizeDelta: {x: 514.5018, y: 206.6469}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &1108370711
@ -7689,7 +7713,7 @@ MonoBehaviour:
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 21300000, guid: deb624ce021a69244a5acbd633ee73df, type: 3}
m_Sprite: {fileID: 21300000, guid: a611350a87ed4624abca9ae7e9278a6e, type: 3}
m_Type: 0
m_PreserveAspect: 0
m_FillCenter: 1
@ -8165,7 +8189,7 @@ RectTransform:
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: -481, y: 175.8695}
m_AnchoredPosition: {x: -365.74, y: 333}
m_SizeDelta: {x: 514.5018, y: 206.6469}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &1226287016
@ -8356,7 +8380,7 @@ RectTransform:
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 0, y: 0.0000019073486}
m_SizeDelta: {x: 64.1366, y: 15.9954}
m_Pivot: {x: 0.5, y: 0.5}
@ -8990,7 +9014,7 @@ GameObject:
- component: {fileID: 1476283247}
- component: {fileID: 1476283246}
m_Layer: 5
m_Name: Button
m_Name: "\u653E\u5C04\u6E90"
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
@ -9014,7 +9038,7 @@ RectTransform:
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: 104.15062, y: 72.06}
m_AnchoredPosition: {x: -104.15, y: 72.06}
m_SizeDelta: {x: 306.2091, y: 62.5272}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &1476283246
@ -9112,7 +9136,7 @@ GameObject:
- component: {fileID: 1486855123}
- component: {fileID: 1486855122}
m_Layer: 5
m_Name: Button
m_Name: "\u7535\u5B50\u5143\u5668\u4EF6"
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
@ -9747,7 +9771,7 @@ MonoBehaviour:
- m_Target: {fileID: 2109707620}
m_TargetAssemblyTypeName: TouchClient, Assembly-CSharp
m_MethodName: OnButtonClick_PlayModel
m_Mode: 5
m_Mode: 1
m_Arguments:
m_ObjectArgument: {fileID: 0}
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
@ -10524,7 +10548,7 @@ RectTransform:
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: 363, y: 223}
m_AnchoredPosition: {x: 235, y: 250}
m_SizeDelta: {x: 514.5018, y: 206.6469}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &1699508422
@ -11191,7 +11215,7 @@ GameObject:
- component: {fileID: 1813455974}
- component: {fileID: 1813455973}
m_Layer: 5
m_Name: Button
m_Name: "\u5E73\u677F\u63A2\u6D4B\u5668"
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
@ -11313,7 +11337,7 @@ GameObject:
- component: {fileID: 1820901397}
- component: {fileID: 1820901396}
m_Layer: 5
m_Name: Button
m_Name: "\u5E73\u79FB\u8C03\u7CFB\u7EDF"
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
@ -11337,7 +11361,7 @@ RectTransform:
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: -102.64, y: 72.06016}
m_AnchoredPosition: {x: 102.64, y: 72.06}
m_SizeDelta: {x: 309.2302, y: 62.5272}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &1820901396
@ -11703,7 +11727,7 @@ MonoBehaviour:
- m_Target: {fileID: 2109707620}
m_TargetAssemblyTypeName: TouchClient, Assembly-CSharp
m_MethodName: OnButtonClick_PlayModel
m_Mode: 5
m_Mode: 1
m_Arguments:
m_ObjectArgument: {fileID: 0}
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
@ -11763,7 +11787,7 @@ GameObject:
- component: {fileID: 1871943555}
- component: {fileID: 1871943554}
m_Layer: 5
m_Name: Button
m_Name: "\u6ED1\u53F0"
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
@ -11885,7 +11909,7 @@ GameObject:
- component: {fileID: 1892964834}
- component: {fileID: 1892964833}
m_Layer: 5
m_Name: Button
m_Name: "pet\u6676\u4F53\u7ED3\u6784"
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
@ -12122,7 +12146,7 @@ GameObject:
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
m_IsActive: 0
--- !u!224 &1993840782
RectTransform:
m_ObjectHideFlags: 0
@ -12848,7 +12872,7 @@ GameObject:
- component: {fileID: 2105199688}
- component: {fileID: 2105199687}
m_Layer: 5
m_Name: "\u5E8A\u5934\u652F\u6491\u7CFB\u7EDF"
m_Name: "\u5E8A\u4F53\u652F\u6491\u7CFB\u7EDF"
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
@ -12946,6 +12970,55 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
background: {fileID: 126639093}
pageButtonConfigs:
- pageName: "PET\u7CFB\u7EDF"
singleItemButtons:
- {fileID: 1892964833}
- {fileID: 911858245}
- {fileID: 446068280}
singleItemModelNames:
- "pet\u6676\u4F53\u7ED3\u6784"
- "PET\u9635\u5217\u5806\u53E0\u6392\u5217"
- "pet\u5355\u4E2A\u7EC4\u4EF6\u7ED3\u6784"
defaultModelName: PET
- pageName: "SPECT\u7CFB\u7EDF"
singleItemButtons:
- {fileID: 547606275}
singleItemModelNames:
- "SPECT\u63A2\u6D4B\u5668"
defaultModelName: SPECT
- pageName: "CT\u7CFB\u7EDF"
singleItemButtons:
- {fileID: 1813455973}
- {fileID: 1476283246}
- {fileID: 1820901396}
singleItemModelNames:
- "\u5E73\u677F\u63A2\u6D4B\u5668"
- "\u653E\u5C04\u6E90"
- "\u5E73\u79FB\u8C03\u7CFB\u7EDF"
defaultModelName: "CT\u7CFB\u7EDF"
- pageName: "\u673A\u67B6\u7CFB\u7EDF"
singleItemButtons:
- {fileID: 1486855122}
- {fileID: 684509594}
singleItemModelNames:
- "\u7535\u5B50\u5143\u5668\u4EF6"
- "\u627F\u91CD\u7ED3\u6784"
defaultModelName: "\u673A\u67B6\u7CFB\u7EDF"
- pageName: "\u5E8A\u53F0\u7CFB\u7EDF"
singleItemButtons:
- {fileID: 67960686}
- {fileID: 1871943554}
- {fileID: 896665757}
singleItemModelNames:
- "\u52A8\u7269\u4ED3"
- "\u6ED1\u53F0"
- "\u5E8A\u4F53\u652F\u6491\u7CFB\u7EDF"
defaultModelName: "\u5E8A\u53F0\u7CFB\u7EDF"
udpPort: 9999
tcpPort: 8888
resolutionWidth: 1920
resolutionHeight: 1080
showSprite: {fileID: 21300000, guid: cc008a9708685dd4a91b74ff185ad926, type: 3}
hideSprite: {fileID: 21300000, guid: 23990d42656b4bd4191e7b31135c3f75, type: 3}
--- !u!114 &2109707621
@ -13043,7 +13116,7 @@ GameObject:
- component: {fileID: 2111609300}
- component: {fileID: 2111609299}
m_Layer: 5
m_Name: "\u5C04\u7EBF\u6E90"
m_Name: "\u653E\u5C04\u6E90"
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
@ -13067,7 +13140,7 @@ RectTransform:
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: 363, y: 223}
m_AnchoredPosition: {x: -232, y: 0}
m_SizeDelta: {x: 514.5018, y: 206.6469}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &2111609299
@ -13090,7 +13163,7 @@ MonoBehaviour:
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 21300000, guid: a611350a87ed4624abca9ae7e9278a6e, type: 3}
m_Sprite: {fileID: 21300000, guid: deb624ce021a69244a5acbd633ee73df, type: 3}
m_Type: 0
m_PreserveAspect: 0
m_FillCenter: 1

File diff suppressed because it is too large Load Diff

View File

@ -12,6 +12,15 @@ public class BroadcastServer : MonoBehaviour
private Thread broadcastThread; // 广播线程
private volatile bool isRunning = true; // 线程安全的运行标志
[Header("网络配置")]
[SerializeField] private int broadcastPort = 9999; // UDP广播端口
[SerializeField] private float broadcastInterval = 1f; // 广播间隔(秒)
[SerializeField] private string preferredNetworkInterface = ""; // 优先网络接口(可选)
[Header("日志级别")]
[SerializeField] private LogLevel logLevel = LogLevel.Verbose; // 日志级别控制
public enum LogLevel { None, Minimal, Verbose }
// 脚本启动时调用
void Start()
{
@ -19,10 +28,12 @@ public class BroadcastServer : MonoBehaviour
{
udpClient = new UdpClient();
udpClient.EnableBroadcast = true;
// 启动广播线程
broadcastThread = new Thread(BroadcastIP);
broadcastThread.Start();
Debug.Log("广播服务器已启动,端口: 9999");
if (logLevel != LogLevel.None)
{
Debug.Log($"广播服务器已启动,端口: {broadcastPort}");
}
}
catch (Exception ex)
{
@ -42,20 +53,26 @@ public class BroadcastServer : MonoBehaviour
string message = $"ServerIP:{localIP}";
byte[] data = Encoding.UTF8.GetBytes(message);
IPEndPoint endPoint = new IPEndPoint(IPAddress.Broadcast, 9999); // 修改为9999
IPEndPoint endPoint = new IPEndPoint(IPAddress.Broadcast, broadcastPort);
while (isRunning)
{
try
{
udpClient.Send(data, data.Length, endPoint);
Debug.Log($"广播IP: {message}");
Thread.Sleep(1000); // 每秒广播一次
if (logLevel == LogLevel.Verbose)
{
Debug.Log($"广播IP: {message}");
}
Thread.Sleep((int)(broadcastInterval * 1000));
}
catch (Exception ex)
{
Debug.LogError($"广播错误: {ex.Message}");
Thread.Sleep(5000); // 出错后等待5秒重试
if (logLevel != LogLevel.None)
{
Debug.LogError($"广播错误: {ex.Message}");
}
Thread.Sleep(5000);
}
}
}
@ -67,19 +84,25 @@ public class BroadcastServer : MonoBehaviour
{
foreach (var networkInterface in NetworkInterface.GetAllNetworkInterfaces())
{
if (networkInterface.OperationalStatus == OperationalStatus.Up &&
networkInterface.NetworkInterfaceType != NetworkInterfaceType.Loopback)
if (networkInterface.OperationalStatus != OperationalStatus.Up ||
networkInterface.NetworkInterfaceType == NetworkInterfaceType.Loopback)
continue;
if (!string.IsNullOrEmpty(preferredNetworkInterface) && networkInterface.Name != preferredNetworkInterface)
continue;
foreach (var unicastIPAddress in networkInterface.GetIPProperties().UnicastAddresses)
{
foreach (var unicastIPAddress in networkInterface.GetIPProperties().UnicastAddresses)
if (unicastIPAddress.Address.AddressFamily == AddressFamily.InterNetwork)
{
if (unicastIPAddress.Address.AddressFamily == AddressFamily.InterNetwork)
string ip = unicastIPAddress.Address.ToString();
if (!ip.StartsWith("127."))
{
string ip = unicastIPAddress.Address.ToString();
if (!ip.StartsWith("127."))
if (logLevel == LogLevel.Verbose)
{
Debug.Log($"选择IP: {ip} (接口: {networkInterface.Name})");
return ip;
}
return ip;
}
}
}
@ -101,8 +124,17 @@ public class BroadcastServer : MonoBehaviour
udpClient?.Close();
if (broadcastThread != null && broadcastThread.IsAlive)
{
broadcastThread.Join(1000); // 等待线程结束
broadcastThread.Join(1000);
}
Debug.Log("广播服务器已停止");
if (logLevel != LogLevel.None)
{
Debug.Log("广播服务器已停止");
}
}
// 确保资源在销毁时清理
private void OnDestroy()
{
OnApplicationQuit();
}
}

View File

@ -5,213 +5,266 @@ using System.Net;
using System.Text;
using System.Threading;
using System.Collections.Generic;
using System;
using DG.Tweening;
public class DisplayServer : MonoBehaviour
{
private TcpListener listener; // 用于接受客户端连接的TCP监听器
private Thread listenThread; // 用于接受客户端连接的线程
private CancellationTokenSource listenCts = new CancellationTokenSource(); // 控制线程取消
private volatile bool isRunning = true; // 线程安全的服务器循环标志
private NetworkStream clientStream; // 当前客户端的网络流,用于发送消息
private TcpListener listener;
private Thread listenThread;
private CancellationTokenSource listenCts = new CancellationTokenSource();
private volatile bool isRunning = true;
private NetworkStream clientStream;
public Transform background; // UI页面的父级变换BG包含Image组件
public Transform background;
[System.Serializable]
public class PageModel
{
public string pageName; // 页面名称
public GameObject model; // 与页面关联的模型挂载ModelController
public string pageName;
public GameObject model;
public Vector3 originalPosition;
public List<GameObject> singleItemModels;
}
public List<PageModel> pageModels = new List<PageModel>(); // 页面-模型映射列表
public List<PageModel> pageModels = new List<PageModel>();
private readonly Queue<string> messageQueue = new Queue<string>(); // 线程安全的消息队列
private readonly object queueLock = new object(); // 消息队列访问锁
private readonly Queue<string> messageQueue = new Queue<string>();
private readonly object queueLock = new object();
private string currentPage = ""; // 跟踪当前显示的页面
private Dictionary<string, PageModel> pageModelCache; // 页面-模型映射的缓存
private bool isPlayingAnimation = false; // 跟踪动画播放状态
private bool isClientDragging = false; // 跟踪客户端是否正在拖动Slider
private float lastSendTime = 0f; // 上次发送进度的时间
private float sendInterval = 0.05f; // 进度发送间隔(秒)
private float lastSentProgress = 0f; // 记录上次发送的进度
private string currentPage = "";
private string currentSingleItemModel = "";
private Dictionary<string, PageModel> pageModelCache;
private Dictionary<string, Transform> textPanelCache;
private Dictionary<string, Slider> sliderCache;
private bool isPlayingAnimation = false;
private bool isClientDragging = false;
private float lastSendTime = 0f;
private float lastSentProgress = 0f;
[Header("Background Sprites")]
public Sprite textBackgroundSprite; // 有文字时的背景Sprite
public Sprite noTextBackgroundSprite; // 无文字时的背景Sprite
[SerializeField] private int tcpPort = 8888;
[SerializeField] private float sendInterval = 0.05f;
[SerializeField] private int resolutionWidth = 3328;
[SerializeField] private int resolutionHeight = 1352;
public Sprite textBackgroundSprite;
public Sprite noTextBackgroundSprite;
[SerializeField] private float textHiddenOffset = 33f;
// 脚本启动时调用
void Start()
{
// 设置显示端分辨率为 3328x1352
Screen.SetResolution(3328, 1352, false);
Screen.SetResolution(resolutionWidth, resolutionHeight, false);
// 初始化页面-模型缓存以加快查找
pageModelCache = new Dictionary<string, PageModel>();
textPanelCache = new Dictionary<string, Transform>();
sliderCache = new Dictionary<string, Slider>();
foreach (var pm in pageModels)
{
if (!string.IsNullOrEmpty(pm.pageName) && pm.model != null)
{
pm.originalPosition = pm.model.transform.localPosition;
pageModelCache[pm.pageName] = pm;
}
else
{
Debug.LogWarning($"PageModel 配置错误: pageName={pm.pageName}, model={(pm.model != null ? pm.model.name : "null")}");
if (pm.singleItemModels == null)
pm.singleItemModels = new List<GameObject>();
}
}
// 在端口8888上启动TCP监听
try
CacheUIComponents();
if (background == null)
{
listener = new TcpListener(IPAddress.Any, 8888);
listener.Start();
Debug.Log("TCP监听启动成功端口: 8888");
return;
}
catch (Exception ex)
Image backgroundImage = background.GetComponent<Image>();
if (backgroundImage == null)
{
return;
}
try
{
listener = new TcpListener(IPAddress.Any, tcpPort);
listener.Start();
}
catch
{
Debug.LogError($"TCP监听启动失败: {ex.Message}");
return;
}
// 启动线程以监听客户端连接
listenThread = new Thread(() => ListenForClients(listenCts.Token));
listenThread.Start();
Debug.Log("显示端服务器已启动,等待触摸端连接...");
// 显示初始页面
ShowPage("Ê×Ò³");
SendHasAnimationStatus();
}
private void CacheUIComponents()
{
foreach (Transform child in background)
{
Transform textPanel = FindDeep(child, "TextPanel");
if (textPanel != null)
{
textPanelCache[child.name] = textPanel;
}
Slider slider = child.GetComponentInChildren<Slider>();
if (slider != null)
{
sliderCache[child.name] = slider;
}
}
}
// 监听传入的TCP客户端连接
private void ListenForClients(CancellationToken token)
{
int retryDelayMs = 2000;
while (!token.IsCancellationRequested && isRunning)
{
try
{
TcpClient client = listener.AcceptTcpClient();
Debug.Log($"触摸端已连接!客户端地址: {((IPEndPoint)client.Client.RemoteEndPoint).Address}");
clientStream = client.GetStream(); // 保存客户端流以发送消息
// 为每个客户端启动新线程处理通信
clientStream = client.GetStream();
Thread clientThread = new Thread(() => HandleClientComm(client, token));
clientThread.Start();
retryDelayMs = 2000;
}
catch (Exception ex)
catch
{
Debug.LogError($"接受客户端连接错误: {ex.Message}");
Thread.Sleep(2000); // 等待2秒重试
Thread.Sleep(retryDelayMs);
retryDelayMs = Mathf.Min(retryDelayMs * 2, 10000);
}
}
}
// 处理与单个客户端的通信
private void HandleClientComm(TcpClient tcpClient, CancellationToken token)
{
NetworkStream stream = tcpClient.GetStream();
byte[] message = new byte[4096];
int bytesRead;
// 在未取消或未断开连接的情况下持续读取
while (!token.IsCancellationRequested && isRunning)
{
try
{
bytesRead = stream.Read(message, 0, 4096);
if (bytesRead == 0) break; // 客户端断开连接
if (bytesRead == 0) break;
string data = Encoding.UTF8.GetString(message, 0, bytesRead);
lock (queueLock)
{
messageQueue.Enqueue(data); // 将消息加入队列以供处理
messageQueue.Enqueue(data);
}
}
catch (Exception ex)
catch
{
Debug.LogError($"读取客户端消息错误: {ex.Message}");
break;
}
}
// 清理客户端资源
stream.Close();
tcpClient.Close();
clientStream = null; // 清空客户端流
Debug.Log("客户端断开连接");
clientStream = null;
}
// 在主线程中处理排队的消息并发送动画进度
private void Update()
{
// 处理接收到的消息
string msg = null;
lock (queueLock)
{
if (messageQueue.Count > 0)
{
msg = messageQueue.Dequeue(); // 获取下一条消息
msg = messageQueue.Dequeue();
}
}
if (!string.IsNullOrEmpty(msg))
{
Debug.Log($"收到消息: {msg}");
if (msg.StartsWith("Page:"))
{
string pageName = msg.Replace("Page:", "");
ShowPage(pageName);
isPlayingAnimation = false; // 重置播放状态
isClientDragging = false; // 重置拖动状态
lastSentProgress = 0f; // 重置进度
isPlayingAnimation = false;
isClientDragging = false;
lastSentProgress = 0f;
SendHasAnimationStatus();
}
else if (msg.StartsWith("Model:"))
{
string modelName = msg.Replace("Model:", "");
PlayModelAnimation(modelName);
lastSentProgress = 0f; // 重置进度
lastSentProgress = 0f;
}
else if (msg.StartsWith("SingleItemModel:"))
{
string modelName = msg.Replace("SingleItemModel:", "");
ShowSingleItemModel(modelName);
isPlayingAnimation = false;
isClientDragging = false;
lastSentProgress = 0f;
SendHasAnimationStatus();
}
else if (msg.StartsWith("Progress:"))
{
if (float.TryParse(msg.Replace("Progress:", ""), out float progress))
{
SetAnimationProgress(progress);
isPlayingAnimation = false; // 拖动时停止播放
isClientDragging = true; // 标记客户端正在拖动
lastSentProgress = progress; // 更新最后发送的进度
Debug.Log($"处理进度消息: Progress:{progress:F2}");
isPlayingAnimation = false;
isClientDragging = true;
lastSentProgress = progress;
}
}
else if (msg == "EndDrag")
{
isClientDragging = false; // 客户端拖动结束
Debug.Log("客户端Slider拖动结束");
isClientDragging = false;
}
else if (msg.StartsWith("TextPanel:"))
{
string command = msg.Replace("TextPanel:", "");
SetTextPanelVisibility(command == "Show");
Debug.Log($"处理文字面板消息: {msg}");
}
else if (msg.StartsWith("Background:"))
{
string command = msg.Replace("Background:", "");
SetBackgroundSprite(command == "Text");
Debug.Log($"处理背景消息: {msg}");
}
else if (msg.StartsWith("ModelMove:"))
{
string command = msg.Replace("ModelMove:", "");
if (command == "Reset")
{
ResetModelPosition();
}
else if (float.TryParse(command, out float offset))
{
MoveModel(offset);
}
}
else if (msg == "RequestHasAnimation")
{
SendHasAnimationStatus();
}
}
// 仅当动画播放且客户端未拖动时发送进度,且限制发送频率
if (isPlayingAnimation && !isClientDragging && clientStream != null && clientStream.CanWrite)
{
if (Time.time - lastSendTime >= sendInterval)
{
if (pageModelCache.TryGetValue(currentPage, out PageModel pm) && pm != null && pm.model != null)
if (pageModelCache.TryGetValue(currentPage, out PageModel pm) && pm != null)
{
ModelController mc = pm.model.GetComponent<ModelController>();
ModelController mc = null;
if (!string.IsNullOrEmpty(currentSingleItemModel))
{
GameObject singleItemModel = pm.singleItemModels.Find(m => m != null && m.name == currentSingleItemModel);
if (singleItemModel != null)
{
mc = singleItemModel.GetComponent<ModelController>();
}
}
else if (pm.model != null)
{
mc = pm.model.GetComponent<ModelController>();
}
if (mc != null && mc.IsPlayingAnimation())
{
float progress = mc.GetAnimationProgress();
// 仅当进度有效且变化显著时发送
if (progress > 0f && Mathf.Abs(progress - lastSentProgress) > 0.005f)
{
try
@ -219,20 +272,17 @@ public class DisplayServer : MonoBehaviour
string progressMsg = $"Progress:{progress:F2}";
byte[] data = Encoding.UTF8.GetBytes(progressMsg);
clientStream.Write(data, 0, data.Length);
Debug.Log($"发送动画进度: {progressMsg}");
lastSentProgress = progress; // 更新最后发送的进度
lastSendTime = Time.time; // 更新发送时间
lastSentProgress = progress;
lastSendTime = Time.time;
}
catch (Exception ex)
catch
{
Debug.LogError($"发送动画进度失败: {ex.Message}");
clientStream = null; // 标记流失效
clientStream = null;
}
}
}
else
{
// 动画已停止,更新状态
isPlayingAnimation = false;
}
}
@ -240,12 +290,49 @@ public class DisplayServer : MonoBehaviour
}
}
// 切换激活的UI页面并更新模型
private void SendHasAnimationStatus()
{
if (clientStream == null || !clientStream.CanWrite) return;
bool hasAnimation = false;
if (pageModelCache.TryGetValue(currentPage, out PageModel pm) && pm != null)
{
ModelController mc = null;
if (!string.IsNullOrEmpty(currentSingleItemModel))
{
GameObject singleItemModel = pm.singleItemModels.Find(m => m != null && m.name == currentSingleItemModel);
if (singleItemModel != null)
{
mc = singleItemModel.GetComponent<ModelController>();
}
}
else if (pm.model != null)
{
mc = pm.model.GetComponent<ModelController>();
}
if (mc != null)
{
hasAnimation = mc.GetHasAnimation();
}
}
try
{
string msg = $"HasAnimation:{(hasAnimation ? "True" : "False")}";
byte[] data = Encoding.UTF8.GetBytes(msg);
clientStream.Write(data, 0, data.Length);
}
catch
{
clientStream = null;
}
}
private void ShowPage(string pageName)
{
if (background == null)
{
Debug.LogError("背景Transform未设置");
return;
}
@ -253,153 +340,266 @@ public class DisplayServer : MonoBehaviour
{
bool isActive = child.name == pageName;
child.gameObject.SetActive(isActive);
Debug.Log($"页面 {child.name} 设置为 {(isActive ? "" : "")}");
}
currentPage = pageName;
currentSingleItemModel = "";
// 更新模型可见性并重置动画
foreach (var pageModel in pageModels)
{
bool isActive = pageModel.pageName == pageName;
if (pageModel.model != null)
{
bool isActive = pageModel.pageName == pageName;
pageModel.model.SetActive(isActive);
pageModel.model.SetActive(isActive && string.IsNullOrEmpty(currentSingleItemModel));
pageModel.originalPosition = pageModel.model.transform.localPosition;
ModelController mc = pageModel.model.GetComponent<ModelController>();
if (mc != null)
{
// 取消订阅旧事件
mc.OnAnimationFinished -= OnModelAnimationFinished;
// 订阅动画结束事件
if (isActive)
{
mc.OnAnimationFinished += OnModelAnimationFinished;
}
mc.ResetAnimation();
Debug.Log($"模型 {pageModel.model.name} 重置,页面: {pageName}");
mc.ResetModelPosition();
}
}
foreach (var singleItemModel in pageModel.singleItemModels)
{
if (singleItemModel != null)
{
singleItemModel.SetActive(false);
ModelController mc = singleItemModel.GetComponent<ModelController>();
if (mc != null)
{
mc.OnAnimationFinished -= OnModelAnimationFinished;
mc.ResetAnimation();
mc.ResetModelPosition();
}
}
}
}
SetTextPanelVisibility(pageName != "Ê×Ò³");
SetBackgroundSprite(pageName != "Ê×Ò³");
}
private void ShowSingleItemModel(string modelName)
{
if (pageModelCache.TryGetValue(currentPage, out PageModel pm) && pm != null)
{
if (pm.model != null)
{
pm.model.SetActive(false);
ModelController mc = pm.model.GetComponent<ModelController>();
if (mc != null)
{
mc.OnAnimationFinished -= OnModelAnimationFinished;
mc.ResetAnimation();
}
}
bool modelFound = false;
foreach (var singleItemModel in pm.singleItemModels)
{
if (singleItemModel != null)
{
bool isActive = singleItemModel.name == modelName;
singleItemModel.SetActive(isActive);
ModelController mc = singleItemModel.GetComponent<ModelController>();
if (mc != null)
{
mc.OnAnimationFinished -= OnModelAnimationFinished;
if (isActive)
{
mc.OnAnimationFinished += OnModelAnimationFinished;
mc.ResetAnimation();
mc.ResetModelPosition();
currentSingleItemModel = modelName;
modelFound = true;
}
}
else if (isActive)
{
currentSingleItemModel = modelName;
modelFound = true;
}
}
}
SetTextPanelVisibility(currentPage != "Ê×Ò³");
SetBackgroundSprite(currentPage != "Ê×Ò³");
}
}
private void PlayModelAnimation(string modelName)
{
if (string.IsNullOrEmpty(modelName))
{
return;
}
if (pageModelCache.TryGetValue(currentPage, out PageModel pm) && pm != null)
{
ModelController mc = null;
GameObject targetModel = null;
if (!string.IsNullOrEmpty(currentSingleItemModel) && modelName == currentSingleItemModel)
{
targetModel = pm.singleItemModels.Find(m => m != null && m.name == modelName);
if (targetModel != null)
{
mc = targetModel.GetComponent<ModelController>();
}
}
else if (pm.model != null && pm.model.name == modelName)
{
targetModel = pm.model;
mc = pm.model.GetComponent<ModelController>();
}
if (mc != null)
{
Animator animator = mc.GetComponent<Animator>();
if (animator != null && animator.runtimeAnimatorController != null && mc.GetHasAnimation())
{
mc.OnAnimationFinished -= OnModelAnimationFinished;
mc.OnAnimationFinished += OnModelAnimationFinished;
mc.PlayAnimation();
isPlayingAnimation = true;
}
else
{
Debug.LogWarning($"模型 {pageModel.model.name} 未找到ModelController");
isPlayingAnimation = false;
}
}
}
// 初始化文字面板为显示
SetTextPanelVisibility(true);
// 初始化背景为有文字背景
SetBackgroundSprite(true);
Debug.Log($"显示端切换到页面: {pageName}");
}
// 为指定模型播放动画
private void PlayModelAnimation(string modelName)
{
PageModel pm = pageModels.Find(p => p.model != null && p.model.name == modelName);
if (pm != null)
{
ModelController mc = pm.model.GetComponent<ModelController>();
if (mc != null)
{
// 取消旧订阅,添加新订阅
mc.OnAnimationFinished -= OnModelAnimationFinished;
mc.OnAnimationFinished += OnModelAnimationFinished;
mc.PlayAnimation();
isPlayingAnimation = true; // 确认动画开始播放
Debug.Log($"播放模型动画: {modelName}");
}
else
{
isPlayingAnimation = false; // 动画未启动
Debug.LogWarning($"模型 {modelName} 未找到ModelController");
isPlayingAnimation = false;
}
}
else
{
isPlayingAnimation = false; // 动画未启动
Debug.LogWarning($"未找到模型 {modelName}");
isPlayingAnimation = false;
}
}
// 设置当前页面模型的动画进度
private void SetAnimationProgress(float progress)
{
if (pageModelCache.TryGetValue(currentPage, out PageModel pm) && pm != null && pm.model != null)
if (pageModelCache.TryGetValue(currentPage, out PageModel pm) && pm != null)
{
ModelController mc = pm.model.GetComponent<ModelController>();
ModelController mc = null;
if (!string.IsNullOrEmpty(currentSingleItemModel))
{
GameObject singleItemModel = pm.singleItemModels.Find(m => m != null && m.name == currentSingleItemModel);
if (singleItemModel != null)
{
mc = singleItemModel.GetComponent<ModelController>();
}
}
else if (pm.model != null)
{
mc = pm.model.GetComponent<ModelController>();
}
if (mc != null)
{
mc.SetAnimationProgress(progress);
Debug.Log($"设置模型 {pm.model.name} 进度: {progress:F2}");
}
else
{
Debug.LogWarning($"模型 {pm.model.name} 未找到ModelController");
}
}
else
{
Debug.LogWarning($"未找到页面 {currentPage} 的模型或ModelController");
}
}
// 设置当前页面文字面板的显隐
private void MoveModel(float xOffset)
{
if (pageModelCache.TryGetValue(currentPage, out PageModel pm) && pm != null)
{
ModelController mc = null;
GameObject targetModel = null;
if (!string.IsNullOrEmpty(currentSingleItemModel))
{
targetModel = pm.singleItemModels.Find(m => m != null && m.name == currentSingleItemModel);
if (targetModel != null)
{
mc = targetModel.GetComponent<ModelController>();
}
}
else if (pm.model != null)
{
targetModel = pm.model;
mc = pm.model.GetComponent<ModelController>();
}
if (mc != null && targetModel.activeSelf)
{
mc.MoveModel(xOffset);
}
else if (targetModel != null && targetModel.activeSelf)
{
Vector3 originalPosition = pm.originalPosition;
Vector3 targetPosition = originalPosition + new Vector3(xOffset, 0f, 0f);
targetModel.transform.DOLocalMoveX(targetPosition.x, 1f).SetEase(Ease.InOutSine);
}
}
}
private void ResetModelPosition()
{
if (pageModelCache.TryGetValue(currentPage, out PageModel pm) && pm != null)
{
ModelController mc = null;
GameObject targetModel = null;
if (!string.IsNullOrEmpty(currentSingleItemModel))
{
targetModel = pm.singleItemModels.Find(m => m != null && m.name == currentSingleItemModel);
if (targetModel != null)
{
mc = targetModel.GetComponent<ModelController>();
}
}
else if (pm.model != null)
{
targetModel = pm.model;
mc = pm.model.GetComponent<ModelController>();
}
if (mc != null && targetModel.activeSelf)
{
mc.ResetModelPosition();
}
else if (targetModel != null && targetModel.activeSelf)
{
Vector3 originalPosition = pm.originalPosition;
targetModel.transform.DOLocalMoveX(originalPosition.x, 1f).SetEase(Ease.InOutSine);
}
}
}
private void SetTextPanelVisibility(bool isVisible)
{
if (background == null || string.IsNullOrEmpty(currentPage) || currentPage == "Ê×Ò³")
{
Debug.Log($"跳过文字面板显隐设置: background={(background != null ? "" : "null")}, currentPage={currentPage}");
return;
}
Transform pageTransform = background.Find(currentPage);
if (pageTransform != null)
if (textPanelCache.TryGetValue(currentPage, out Transform textPanel))
{
Transform textPanel = pageTransform.Find("ItemInfo/TextPanel");
if (textPanel != null)
textPanel.gameObject.SetActive(isVisible);
if (isVisible)
{
textPanel.gameObject.SetActive(isVisible);
Debug.Log($"设置页面 {currentPage} 文字面板显隐: {isVisible}");
ResetModelPosition();
}
else
{
Debug.LogWarning($"未在页面 {currentPage}/ItemInfo 找到TextPanel");
// 尝试递归查找
textPanel = FindDeep(pageTransform, "TextPanel");
if (textPanel != null)
{
textPanel.gameObject.SetActive(isVisible);
Debug.Log($"通过递归查找设置页面 {currentPage} 文字面板显隐: {isVisible}");
}
else
{
Debug.LogWarning($"递归查找仍未找到 {currentPage}/TextPanel");
Debug.Log($"页面 {currentPage} 子物体: {string.Join(", ", GetChildNames(pageTransform))}");
Transform itemInfo = pageTransform.Find("ItemInfo");
if (itemInfo != null)
{
Debug.Log($"ItemInfo 子物体: {string.Join(", ", GetChildNames(itemInfo))}");
}
else
{
Debug.LogWarning($"未在页面 {currentPage} 找到ItemInfo");
}
}
MoveModel(textHiddenOffset);
}
}
else
{
Debug.LogWarning($"未找到页面 {currentPage}背景Transform子物体: {string.Join(", ", GetChildNames(background))}");
}
}
// 设置公共背景的Sprite
private void SetBackgroundSprite(bool hasText)
{
if (background == null)
{
Debug.LogError($"背景Transform未设置无法切换背景");
return;
}
@ -410,32 +610,10 @@ public class DisplayServer : MonoBehaviour
if (newSprite != null)
{
backgroundImage.sprite = newSprite;
Debug.Log($"设置公共背景: {newSprite.name}");
}
else
{
Debug.LogWarning($"背景Sprite未设置: hasText={hasText}");
}
}
else
{
Debug.LogWarning($"BG GameObject未找到Image组件");
Debug.Log($"BG 子物体: {string.Join(", ", GetChildNames(background))}");
}
}
// 辅助方法获取Transform的子物体名称
private string[] GetChildNames(Transform parent)
{
List<string> names = new List<string>();
foreach (Transform child in parent)
{
names.Add(child.name);
}
return names.ToArray();
}
// 辅助方法:递归查找子物体
private Transform FindDeep(Transform parent, string name)
{
Transform result = parent.Find(name);
@ -451,12 +629,9 @@ public class DisplayServer : MonoBehaviour
return null;
}
// 处理动画结束事件
private void OnModelAnimationFinished()
{
isPlayingAnimation = false;
Debug.Log("模型动画播放完成,停止发送进度");
// 发送最终进度 1.0
if (clientStream != null && clientStream.CanWrite)
{
try
@ -464,27 +639,23 @@ public class DisplayServer : MonoBehaviour
string progressMsg = "Progress:1.00";
byte[] data = Encoding.UTF8.GetBytes(progressMsg);
clientStream.Write(data, 0, data.Length);
Debug.Log($"发送最终动画进度: {progressMsg}");
lastSentProgress = 1f;
lastSendTime = Time.time;
}
catch (Exception ex)
catch
{
Debug.LogError($"发送最终进度失败: {ex.Message}");
clientStream = null;
}
}
}
// 应用程序退出时清理资源
private void OnApplicationQuit()
{
isRunning = false;
listenCts.Cancel();
listener.Stop();
listener?.Stop();
clientStream?.Close();
// 取消所有动画结束事件订阅
foreach (var pm in pageModels)
{
if (pm.model != null)
@ -495,12 +666,27 @@ public class DisplayServer : MonoBehaviour
mc.OnAnimationFinished -= OnModelAnimationFinished;
}
}
foreach (var singleItemModel in pm.singleItemModels)
{
if (singleItemModel != null)
{
ModelController mc = singleItemModel.GetComponent<ModelController>();
if (mc != null)
{
mc.OnAnimationFinished -= OnModelAnimationFinished;
}
}
}
}
if (listenThread != null && listenThread.IsAlive)
{
listenThread.Join(1000); // 等待线程结束
listenThread.Join(1000);
}
Debug.Log("显示端服务器已停止");
}
private void OnDestroy()
{
OnApplicationQuit();
}
}

View File

@ -1,151 +1,229 @@
using UnityEngine;
using System.Collections.Generic;
using DG.Tweening;
using System;
public class ModelController : MonoBehaviour
{
private Animator animator; // 控制动画的Animator组件
private string currentAnim = ""; // 跟踪当前播放的动画
private bool isPlaying = false; // 跟踪动画播放状态
private Animator animator;
private string currentAnim = "";
private bool isPlaying = false;
private Vector3 originalPosition;
private Vector3 originalScale;
[Header("默认动画状态名称")]
public string defaultAnimName = "Take 001"; // 默认动画状态名称
[SerializeField] private string defaultAnimName = "Take 001";
[SerializeField] private bool hasAnimation = true;
private Dictionary<string, int> stateHashes = new Dictionary<string, int>(); // 动画状态哈希缓存
private float lastLoggedProgress = -1f; // 记录上次日志的进度值
private float lastWarningTime = 0f; // 记录上次警告日志时间
private const float warningInterval = 1f; // 警告日志间隔(秒)
private Dictionary<string, int> stateHashes = new Dictionary<string, int>();
private float lastLoggedProgress = -1f;
private float lastWarningTime = 0f;
private const float warningInterval = 1f;
// 动画结束事件
public event Action OnAnimationFinished;
// 脚本初始化时调用
void Awake()
{
animator = GetComponent<Animator>();
// 缓存默认动画状态的哈希值以提高性能
originalPosition = transform.localPosition;
originalScale = transform.localScale;
if (hasAnimation)
{
if (animator == null)
{
hasAnimation = false;
}
else
{
CacheAnimationStates();
}
}
else
{
if (animator != null)
{
animator.enabled = false;
}
}
}
private void CacheAnimationStates()
{
if (!hasAnimation) return;
stateHashes.Clear();
if (!string.IsNullOrEmpty(defaultAnimName))
{
stateHashes[defaultAnimName] = Animator.StringToHash(defaultAnimName);
}
}
// 在Update中更新动画状态
void Update()
{
if (isPlaying && animator != null && !string.IsNullOrEmpty(currentAnim))
if (animator.runtimeAnimatorController != null)
{
if (!animator.enabled)
foreach (var clip in animator.runtimeAnimatorController.animationClips)
{
animator.enabled = true; // 确保Animator启用
Debug.Log($"重新启用Animator: {currentAnim}");
}
AnimatorStateInfo stateInfo = animator.GetCurrentAnimatorStateInfo(0);
if (stateInfo.IsName(currentAnim) && stateInfo.normalizedTime >= 1f)
{
// 动画播放完成,暂停并标记
animator.enabled = false;
isPlaying = false;
OnAnimationFinished?.Invoke(); // 通知动画结束
Debug.Log($"动画 {currentAnim} 播放完成,暂停");
if (!stateHashes.ContainsKey(clip.name))
{
stateHashes[clip.name] = Animator.StringToHash(clip.name);
}
}
}
else
{
hasAnimation = false;
animator.enabled = false;
}
}
void Update()
{
if (!hasAnimation || !isPlaying || animator == null || string.IsNullOrEmpty(currentAnim)) return;
if (!animator.enabled)
{
animator.enabled = true;
}
transform.localScale = originalScale;
transform.localPosition = originalPosition;
AnimatorStateInfo stateInfo = animator.GetCurrentAnimatorStateInfo(0);
if (stateInfo.IsName(currentAnim) && stateInfo.normalizedTime >= 1f && !animator.IsInTransition(0))
{
isPlaying = false;
animator.enabled = false;
transform.localScale = originalScale;
transform.localPosition = originalPosition;
OnAnimationFinished?.Invoke();
}
}
/// <summary>
/// 从头播放默认动画
/// </summary>
public void PlayAnimation()
{
if (animator == null || string.IsNullOrEmpty(defaultAnimName)) return;
if (!hasAnimation)
{
return;
}
if (animator == null || string.IsNullOrEmpty(defaultAnimName) || !gameObject.activeSelf)
{
return;
}
if (!AnimatorHasState(defaultAnimName))
{
Debug.LogWarning($"Animator上不存在状态: {defaultAnimName}");
return;
}
currentAnim = defaultAnimName;
animator.enabled = true;
animator.Play(currentAnim, 0, 0f); // 从头播放动画
animator.Update(0f); // 强制立即更新
isPlaying = true; // 标记动画正在播放
Debug.Log($"开始播放动画: {currentAnim}");
animator.Play(stateHashes[currentAnim], 0, 0f);
animator.Update(0f);
isPlaying = true;
transform.localScale = originalScale;
transform.localPosition = originalPosition;
}
/// <summary>
/// 设置动画进度0到1
/// </summary>
public void SetAnimationProgress(float normalizedTime)
{
if (animator == null || string.IsNullOrEmpty(defaultAnimName)) return;
if (!gameObject.activeSelf) return;
if (!hasAnimation)
{
return;
}
if (animator == null || string.IsNullOrEmpty(defaultAnimName) || !gameObject.activeSelf)
{
return;
}
// 确保currentAnim已设置
if (string.IsNullOrEmpty(currentAnim))
{
currentAnim = defaultAnimName;
Debug.Log($"设置动画进度前初始化currentAnim: {currentAnim}");
}
if (!AnimatorHasState(currentAnim))
{
Debug.LogWarning($"Animator上不存在状态: {currentAnim}");
return;
}
// 停止播放状态
isPlaying = false;
animator.enabled = true;
float clampedTime = Mathf.Clamp01(normalizedTime);
animator.Play(currentAnim, 0, clampedTime); // 设置动画到指定时间
animator.Update(0f); // 强制立即更新
animator.enabled = false; // 暂停动画
Debug.Log($"设置动画 {currentAnim} 进度: {clampedTime:F2}");
animator.Play(stateHashes[currentAnim], 0, clampedTime);
animator.Update(0f);
animator.enabled = false;
transform.localScale = originalScale;
transform.localPosition = originalPosition;
}
/// <summary>
/// 重置动画到初始状态
/// </summary>
public void ResetAnimation()
{
if (animator == null) return;
if (!gameObject.activeSelf) return;
if (!hasAnimation)
{
return;
}
if (animator == null || !gameObject.activeSelf)
{
return;
}
string animToReset = !string.IsNullOrEmpty(defaultAnimName) ? defaultAnimName : "";
if (string.IsNullOrEmpty(animToReset)) return;
if (string.IsNullOrEmpty(animToReset))
{
return;
}
currentAnim = animToReset; // 确保currentAnim已设置
if (!AnimatorHasState(animToReset))
{
return;
}
currentAnim = animToReset;
animator.enabled = true;
animator.Play(currentAnim, 0, 0f); // 重置到开始
animator.Update(0f); // 强制立即更新
animator.enabled = false; // 暂停动画
isPlaying = false; // 标记动画暂停
Debug.Log($"重置动画: {currentAnim}");
animator.Play(stateHashes[currentAnim], 0, 0f);
animator.Update(0f);
animator.enabled = false;
isPlaying = false;
transform.localScale = originalScale;
transform.localPosition = originalPosition;
}
public void MoveModel(float xOffset)
{
if (!gameObject.activeSelf)
{
return;
}
Vector3 targetPosition = originalPosition + new Vector3(xOffset, 0f, 0f);
transform.DOLocalMoveX(targetPosition.x, 1f).SetEase(Ease.InOutSine).OnComplete(() =>
{
transform.localScale = originalScale;
});
}
public void ResetModelPosition()
{
if (!gameObject.activeSelf)
{
return;
}
transform.DOLocalMoveX(originalPosition.x, 1f).SetEase(Ease.InOutSine).OnComplete(() =>
{
transform.localScale = originalScale;
});
}
/// <summary>
/// 获取当前动画的标准化时间0到1
/// </summary>
/// <returns>当前动画进度若无动画则返回0</returns>
public float GetAnimationProgress()
{
if (!hasAnimation)
{
return 0f;
}
if (animator == null || !animator.enabled || string.IsNullOrEmpty(currentAnim) || !gameObject.activeSelf)
{
if (Time.time - lastWarningTime >= warningInterval)
{
Debug.LogWarning($"无法获取动画进度: animator={animator}, enabled={animator?.enabled}, currentAnim={currentAnim}, active={gameObject.activeSelf}");
lastWarningTime = Time.time;
}
return 0f;
}
if (!AnimatorHasState(currentAnim))
{
if (Time.time - lastWarningTime >= warningInterval)
{
Debug.LogWarning($"Animator上不存在状态: {currentAnim}");
lastWarningTime = Time.time;
}
return 0f;
}
@ -153,38 +231,44 @@ public class ModelController : MonoBehaviour
if (stateInfo.IsName(currentAnim))
{
float progress = Mathf.Clamp01(stateInfo.normalizedTime % 1f);
// 仅当进度变化超过0.01时记录日志
if (Mathf.Abs(progress - lastLoggedProgress) > 0.01f)
{
Debug.Log($"获取动画 {currentAnim} 进度: {progress:F2}");
lastLoggedProgress = progress;
}
return progress;
}
if (Time.time - lastWarningTime >= warningInterval)
{
Debug.LogWarning($"动画状态不匹配: currentAnim={currentAnim}, state={stateInfo.fullPathHash}");
lastWarningTime = Time.time;
}
return 0f;
}
// 检查指定的动画状态是否存在于Animator中
private bool AnimatorHasState(string stateName)
{
if (stateHashes.TryGetValue(stateName, out int hash))
if (!hasAnimation)
{
for (int i = 0; i < animator.layerCount; i++)
return false;
}
if (string.IsNullOrEmpty(stateName) || !stateHashes.TryGetValue(stateName, out int hash))
{
return false;
}
for (int i = 0; i < animator.layerCount; i++)
{
if (animator.HasState(i, hash))
{
if (animator.HasState(i, hash)) return true;
return true;
}
}
return false;
}
// 获取动画播放状态
public bool IsPlayingAnimation()
{
if (!hasAnimation)
{
return false;
}
return isPlaying;
}
public bool GetHasAnimation()
{
return hasAnimation;
}
}

View File

@ -10,56 +10,118 @@ using UnityEngine.UI;
public class TouchClient : MonoBehaviour
{
private TcpClient client; // 用于与显示端通信的TCP客户端
private NetworkStream stream; // 用于发送/接收数据的流
private volatile bool isConnected = false; // 线程安全的连接状态标志
private TcpClient client;
private NetworkStream stream;
private volatile bool isConnected = false;
private UdpClient udpListener; // 用于接收广播IP的UDP客户端
private Thread udpThread; // 监听广播的线程
private CancellationTokenSource udpCts = new CancellationTokenSource(); // 控制UDP线程取消
private UdpClient udpListener;
private Thread udpThread;
private CancellationTokenSource udpCts = new CancellationTokenSource();
private Thread receiveThread; // 接收服务器消息的线程
private CancellationTokenSource receiveCts = new CancellationTokenSource(); // 控制接收线程取消
private Thread receiveThread;
private CancellationTokenSource receiveCts = new CancellationTokenSource();
public Transform background; // UI页面的父级变换
private string currentPage = "首页"; // 跟踪当前显示的页面
public Transform background;
private string currentPage = "Ê×Ò³";
private string currentSingleItemModel = "";
private readonly Queue<float> progressQueue = new Queue<float>(); // 线程安全的进度队列
private readonly object queueLock = new object(); // 进度队列访问锁
private bool isDraggingSlider = false; // 标记是否正在拖动Slider
private float lastSentProgress = 0f; // 记录最后发送的进度
private readonly Queue<float> progressQueue = new Queue<float>();
private readonly Queue<bool> hasAnimationQueue = new Queue<bool>();
private readonly object queueLock = new object();
private bool isDraggingSlider = false;
private float lastSentProgress = 0f;
[Header("Text Panel Toggle Sprites")]
public Sprite showSprite; // 显示状态的Sprite
public Sprite hideSprite; // 隐藏状态的Sprite
private Dictionary<string, Slider> sliderCache;
private Dictionary<string, Toggle> toggleCache;
private Dictionary<string, Button> playButtonCache;
private Dictionary<string, List<Button>> singleItemButtonCache;
[System.Serializable]
public class PageButtonConfig
{
public string pageName;
public List<Button> singleItemButtons;
public List<string> singleItemModelNames;
public string defaultModelName;
}
[SerializeField] private List<PageButtonConfig> pageButtonConfigs = new List<PageButtonConfig>();
[SerializeField] private int udpPort = 9999;
[SerializeField] private int tcpPort = 8888;
[SerializeField] private int resolutionWidth = 1920;
[SerializeField] private int resolutionHeight = 1080;
public Sprite showSprite;
public Sprite hideSprite;
// 脚本启动时调用
void Start()
{
// 设置触摸控制端分辨率为 1920x1080
Screen.SetResolution(1920, 1080, false);
Screen.SetResolution(resolutionWidth, resolutionHeight, false);
sliderCache = new Dictionary<string, Slider>();
toggleCache = new Dictionary<string, Toggle>();
playButtonCache = new Dictionary<string, Button>();
singleItemButtonCache = new Dictionary<string, List<Button>>();
CacheUIComponents();
foreach (var config in pageButtonConfigs)
{
if (!string.IsNullOrEmpty(config.pageName) && config.singleItemButtons != null && config.singleItemModelNames != null)
{
if (config.singleItemButtons.Count == config.singleItemModelNames.Count)
{
singleItemButtonCache[config.pageName] = config.singleItemButtons;
for (int i = 0; i < config.singleItemButtons.Count; i++)
{
if (config.singleItemButtons[i] != null)
{
int index = i;
config.singleItemButtons[i].onClick.RemoveAllListeners();
config.singleItemButtons[i].onClick.AddListener(() => OnButtonClick_SingleItemModel(config.pageName, config.singleItemModelNames[index]));
}
}
}
}
}
try
{
// 在端口9999上初始化UDP监听
udpListener = new UdpClient(9999);
udpListener = new UdpClient(udpPort);
udpThread = new Thread(() => ListenForBroadcast(udpCts.Token));
udpThread.Start();
Debug.Log("触摸端等待显示端广播,监听端口: 9999");
}
catch (Exception ex)
catch
{
Debug.LogError($"初始化UDP监听失败: {ex.Message}");
}
// 显示初始页面
ShowPage("首页");
}
// 监听UDP广播以发现显示端IP
private void CacheUIComponents()
{
foreach (Transform child in background)
{
Slider slider = child.GetComponentInChildren<Slider>();
if (slider != null)
{
sliderCache[child.name] = slider;
}
Toggle toggle = child.GetComponentInChildren<Toggle>();
if (toggle != null)
{
toggleCache[child.name] = toggle;
}
Button playButton = FindDeep(child, "PlayButton")?.GetComponent<Button>();
if (playButton != null)
{
playButtonCache[child.name] = playButton;
}
}
}
private void ListenForBroadcast(CancellationToken token)
{
IPEndPoint endPoint = new IPEndPoint(IPAddress.Any, 9999);
IPEndPoint endPoint = new IPEndPoint(IPAddress.Any, udpPort);
int retryDelayMs = 2000;
while (!isConnected && !token.IsCancellationRequested)
{
@ -67,69 +129,54 @@ public class TouchClient : MonoBehaviour
{
byte[] data = udpListener.Receive(ref endPoint);
string message = Encoding.UTF8.GetString(data);
Debug.Log($"收到UDP广播: {message},来源: {endPoint.Address}:{endPoint.Port}");
// 提取IP地址
string serverIp = message.StartsWith("ServerIP:") ? message.Replace("ServerIP:", "").Trim() : message.Trim();
if (IPAddress.TryParse(serverIp, out IPAddress ipAddress))
{
Debug.Log($"解析到有效IP: {serverIp}");
ConnectToServer(serverIp, 8888); // 尝试连接到服务器
}
else
{
Debug.LogWarning($"无效IP地址: {serverIp}");
ConnectToServer(serverIp, tcpPort);
retryDelayMs = 2000;
}
}
catch (Exception ex)
catch
{
Debug.LogError($"UDP接收错误: {ex.Message}");
Thread.Sleep(2000); // 等待2秒重试
Thread.Sleep(retryDelayMs);
retryDelayMs = Mathf.Min(retryDelayMs * 2, 10000);
}
}
}
// 通过TCP连接到显示端服务器
private void ConnectToServer(string ip, int port)
{
int retryCount = 0;
const int maxRetries = 5;
const int retryDelayMs = 2000;
int retryDelayMs = 2000;
while (!isConnected && retryCount < maxRetries)
{
try
{
Debug.Log($"尝试连接显示端: {ip}:{port} (尝试 {retryCount + 1}/{maxRetries})");
client = new TcpClient();
client.Connect(ip, port); // 连接到服务器
client.Connect(ip, port);
stream = client.GetStream();
isConnected = true;
udpCts.Cancel(); // 连接成功后停止UDP监听线程
udpListener?.Close(); // 关闭UDP监听器
Debug.Log($"触摸端已连接到显示端: {ip}:{port}");
// 启动接收线程以处理服务器消息
udpCts.Cancel();
udpListener?.Close();
receiveThread = new Thread(() => ReceiveMessages(receiveCts.Token));
receiveThread.Start();
return;
}
catch (Exception ex)
catch
{
Debug.LogError($"连接显示端失败: {ex.Message}");
retryCount++;
if (retryCount < maxRetries)
{
Debug.Log($"将在{retryDelayMs / 1000f}秒后重试...");
Thread.Sleep(retryDelayMs);
retryDelayMs = Mathf.Min(retryDelayMs * 2, 10000);
}
}
}
Debug.LogError($"连接显示端失败,已达到最大重试次数 ({maxRetries})");
}
// 接收服务器发送的消息
private void ReceiveMessages(CancellationToken token)
{
byte[] message = new byte[4096];
@ -140,62 +187,48 @@ public class TouchClient : MonoBehaviour
try
{
bytesRead = stream.Read(message, 0, 4096);
if (bytesRead == 0)
{
Debug.Log("服务器断开连接");
break;
}
if (bytesRead == 0) break;
string data = Encoding.UTF8.GetString(message, 0, bytesRead);
if (data.StartsWith("Progress:") && float.TryParse(data.Replace("Progress:", ""), out float progress))
lock (queueLock)
{
lock (queueLock)
if (data.StartsWith("Progress:") && float.TryParse(data.Replace("Progress:", ""), out float progress))
{
progressQueue.Enqueue(progress); // 将进度加入队列
Debug.Log($"收到进度: {progress:F2}");
progressQueue.Enqueue(progress);
}
else if (data.StartsWith("HasAnimation:"))
{
bool hasAnimation = data.Replace("HasAnimation:", "") == "True";
hasAnimationQueue.Enqueue(hasAnimation);
}
}
else
{
Debug.LogWarning($"收到未知消息: {data}");
}
}
catch (Exception ex)
catch
{
Debug.LogError($"接收服务器消息错误: {ex.Message}");
isConnected = false;
break;
}
}
// 清理连接
stream?.Close();
client?.Close();
isConnected = false;
Debug.Log("TCP连接已断开将重新启动UDP监听");
// 重启UDP监听
RestartUdpListener();
}
// 重启UDP监听
private void RestartUdpListener()
{
try
{
udpCts = new CancellationTokenSource();
udpListener = new UdpClient(9999);
udpListener = new UdpClient(udpPort);
udpThread = new Thread(() => ListenForBroadcast(udpCts.Token));
udpThread.Start();
Debug.Log("重启UDP监听端口: 9999");
}
catch (Exception ex)
catch
{
Debug.LogError($"重启UDP监听失败: {ex.Message}");
}
}
// 向显示端服务器发送消息
private void SendMessageToServer(string msg)
{
if (isConnected && stream != null)
@ -204,38 +237,28 @@ public class TouchClient : MonoBehaviour
{
byte[] data = Encoding.UTF8.GetBytes(msg);
stream.Write(data, 0, data.Length);
Debug.Log($"发送指令: {msg}");
}
catch (Exception ex)
catch
{
Debug.LogError($"发送消息失败: {ex.Message}");
isConnected = false;
RestartUdpListener();
}
}
else
{
Debug.LogWarning($"无法发送消息,未连接到服务器: {msg}");
}
}
// 页面按钮点击时调用
public void OnButtonClick_Page(string pageName)
{
ShowPage(pageName); // 切换到指定页面
SendMessageToServer("Page:" + pageName); // 通知服务器
ShowPage(pageName);
SendMessageToServer("Page:" + pageName);
}
// 模型播放按钮点击时调用
public void OnButtonClick_PlayModel(string modelName)
public void OnButtonClick_PlayModel()
{
// 清空进度队列,防止旧进度干扰
lock (queueLock)
{
progressQueue.Clear();
}
// 重置Slider到0
Slider slider = GetCurrentPageSlider();
if (slider != null)
{
@ -243,27 +266,64 @@ public class TouchClient : MonoBehaviour
slider.onValueChanged = new Slider.SliderEvent();
slider.value = 0f;
slider.onValueChanged = onValueChanged;
lastSentProgress = 0f; // 重置最后发送的进度
Debug.Log($"播放模型 {modelName} 前重置Slider到0");
lastSentProgress = 0f;
}
SendMessageToServer("Model:" + modelName); // 通知服务器播放模型
string modelName = "";
var config = pageButtonConfigs.Find(c => c.pageName == currentPage);
if (config != null && !string.IsNullOrEmpty(config.defaultModelName))
{
modelName = string.IsNullOrEmpty(currentSingleItemModel) ? config.defaultModelName : currentSingleItemModel;
}
else if (currentPage == "Ê×Ò³")
{
modelName = "ÕûÌå½á¹¹Õ¹Ê¾";
}
if (!string.IsNullOrEmpty(modelName))
{
SendMessageToServer("Model:" + modelName);
}
}
public void OnButtonClick_SingleItemModel(string pageName, string modelName)
{
if (pageName != currentPage)
{
ShowPage(pageName);
SendMessageToServer("Page:" + pageName);
}
currentSingleItemModel = modelName;
lock (queueLock)
{
progressQueue.Clear();
}
Slider slider = GetCurrentPageSlider();
if (slider != null)
{
var onValueChanged = slider.onValueChanged;
slider.onValueChanged = new Slider.SliderEvent();
slider.value = 0f;
slider.onValueChanged = onValueChanged;
lastSentProgress = 0f;
}
SendMessageToServer("SingleItemModel:" + modelName);
}
// 滑块值改变时调用
public void OnSliderChanged(Slider slider)
{
isDraggingSlider = true; // 标记正在拖动
float progress = slider.value / 100f; // 转换为0-1
if (progress > 0.01f) // 忽略接近0的值以避免异常
isDraggingSlider = true;
float progress = slider.value / 100f;
if (progress > 0.01f)
{
SendMessageToServer("Progress:" + progress.ToString("F2")); // 发送进度
lastSentProgress = progress; // 记录最后发送的进度
Debug.Log($"Slider拖动到: {progress:F2}");
SendMessageToServer("Progress:" + progress.ToString("F2"));
lastSentProgress = progress;
}
}
// 滑块拖动结束时调用需在Inspector中绑定
public void OnSliderEndDrag()
{
Slider slider = GetCurrentPageSlider();
@ -272,17 +332,14 @@ public class TouchClient : MonoBehaviour
float progress = slider.value / 100f;
if (progress > 0.01f)
{
SendMessageToServer("Progress:" + progress.ToString("F2")); // 发送最终进度
lastSentProgress = progress; // 更新最后发送的进度
Debug.Log($"Slider拖动结束发送最终进度: {progress:F2}");
SendMessageToServer("Progress:" + progress.ToString("F2"));
lastSentProgress = progress;
}
}
isDraggingSlider = false; // 结束拖动
SendMessageToServer("EndDrag"); // 通知服务器拖动结束
Debug.Log("Slider拖动结束");
isDraggingSlider = false;
SendMessageToServer("EndDrag");
}
// 文字面板Toggle状态改变时调用
public void OnTextPanelToggleChanged(Toggle toggle)
{
if (toggle == null) return;
@ -294,186 +351,162 @@ public class TouchClient : MonoBehaviour
if (toggleImage != null)
{
Sprite newSprite = isTextPanelVisible ? showSprite : hideSprite;
toggleImage.sprite = newSprite;
Debug.Log($"Toggle sprite 切换: {currentPage}, isOn={isTextPanelVisible}, sprite={(newSprite != null ? newSprite.name : "null")}");
}
else
{
Debug.LogWarning($"Toggle {toggle.name} 未找到Background的Image组件");
toggleImage.sprite = isTextPanelVisible ? showSprite : hideSprite;
}
if (toggleText != null)
{
toggleText.text = isTextPanelVisible ? "显示文字" : "隐藏文字";
Debug.Log($"Toggle 文本更新: {currentPage}, text={toggleText.text}");
}
else
{
Debug.LogWarning($"Toggle {toggle.name} 未找到Text(TMP)组件");
}
// 验证Toggle的Graphic字段
if (toggle.graphic != null && toggle.graphic is Image graphicImage)
{
Debug.Log($"Toggle Graphic验证: {currentPage}, graphic sprite={graphicImage.sprite?.name ?? "null"}");
}
else
{
Debug.LogWarning($"Toggle {toggle.name} 的Graphic字段未正确配置或为空");
}
string textPanelMessage = isTextPanelVisible ? "TextPanel:Show" : "TextPanel:Hide";
SendMessageToServer(textPanelMessage);
// 发送显隐消息到显示端
string message = isTextPanelVisible ? "TextPanel:Show" : "TextPanel:Hide";
SendMessageToServer(message);
Debug.Log($"文字面板Toggle切换: {message}");
string backgroundMessage = isTextPanelVisible ? "Background:Text" : "Background:NoText";
SendMessageToServer(backgroundMessage);
string modelMoveMessage = isTextPanelVisible ? "ModelMove:Reset" : $"ModelMove:33";
SendMessageToServer(modelMoveMessage);
SendMessageToServer("RequestHasAnimation");
}
private void UpdatePlayButtonVisibility(bool hasAnimation)
{
if (playButtonCache.TryGetValue(currentPage, out Button playButton) && playButton != null)
{
playButton.gameObject.SetActive(hasAnimation);
}
}
// 获取当前页面的Slider组件
private Slider GetCurrentPageSlider()
{
if (background == null || currentPage == "首页") return null;
Transform pageTransform = background.Find(currentPage);
if (pageTransform != null)
if (sliderCache.TryGetValue(currentPage, out Slider slider))
{
Slider slider = pageTransform.GetComponentInChildren<Slider>();
if (slider != null)
if (!slider.interactable)
{
if (!slider.interactable)
{
slider.interactable = true; // 确保Slider可交互
Debug.Log($"启用Slider交互: {currentPage}");
}
return slider;
slider.interactable = true;
}
Debug.LogWarning($"未在页面 {currentPage} 找到Slider");
return null;
return slider;
}
Debug.LogWarning($"未找到页面 {currentPage}");
return null;
}
// 获取当前页面的TextPanelToggle组件
private Toggle GetCurrentPageTextPanelToggle()
{
if (background == null || currentPage == "首页") return null;
Transform pageTransform = background.Find(currentPage);
if (pageTransform != null)
if (toggleCache.TryGetValue(currentPage, out Toggle toggle))
{
Toggle toggle = pageTransform.GetComponentInChildren<Toggle>();
if (toggle != null)
if (!toggle.interactable)
{
if (!toggle.interactable)
{
toggle.interactable = true; // 确保Toggle可交互
Debug.Log($"启用TextPanelToggle交互: {currentPage}");
}
return toggle;
toggle.interactable = true;
}
Debug.LogWarning($"未在页面 {currentPage} 找到TextPanelToggle");
return null;
return toggle;
}
Debug.LogWarning($"未找到页面 {currentPage}");
return null;
}
// 切换激活的UI页面
private void ShowPage(string pageName)
{
foreach (Transform child in background)
{
child.gameObject.SetActive(child.name == pageName); // 仅激活目标页面
child.gameObject.SetActive(child.name == pageName);
}
currentPage = pageName;
currentSingleItemModel = "";
// 清空进度队列以避免旧页面数据干扰
lock (queueLock)
{
progressQueue.Clear();
hasAnimationQueue.Clear();
}
// 初始化当前页面的Slider
Slider slider = GetCurrentPageSlider();
if (slider != null)
{
// 临时禁用OnValueChanged以防止初始化触发
var onValueChanged = slider.onValueChanged;
slider.onValueChanged = new Slider.SliderEvent();
slider.value = 0f; // 重置Slider到0
slider.interactable = true; // 确保可交互
// 恢复OnValueChanged并绑定
slider.value = 0f;
slider.interactable = true;
slider.onValueChanged = onValueChanged;
slider.onValueChanged.RemoveAllListeners();
slider.onValueChanged.AddListener((value) => OnSliderChanged(slider));
lastSentProgress = 0f; // 重置最后发送的进度
Debug.Log($"初始化Slider: {pageName}, 值: {slider.value}");
lastSentProgress = 0f;
}
// 初始化当前页面的TextPanelToggle
Toggle toggle = GetCurrentPageTextPanelToggle();
if (toggle != null)
{
// 临时禁用OnValueChanged以防止初始化触发
var onValueChanged = toggle.onValueChanged;
toggle.onValueChanged = new Toggle.ToggleEvent();
toggle.isOn = true; // 默认显示文字面板
toggle.interactable = true; // 确保可交互
// 更新Sprite和文本
toggle.isOn = true;
toggle.interactable = true;
Transform backgroundTransform = toggle.transform.Find("Background");
Image toggleImage = backgroundTransform != null ? backgroundTransform.GetComponent<Image>() : null;
TextMeshProUGUI toggleText = toggle.GetComponentInChildren<TextMeshProUGUI>();
if (toggleImage != null)
{
toggleImage.sprite = showSprite;
Debug.Log($"初始化Toggle sprite: {pageName}, sprite={(showSprite != null ? showSprite.name : "null")}");
}
else
{
Debug.LogWarning($"Toggle {toggle.name} 未找到Background的Image组件");
}
if (toggleText != null)
{
toggleText.text = "显示文字";
Debug.Log($"初始化Toggle 文本: {pageName}, text={toggleText.text}");
}
else
{
Debug.LogWarning($"Toggle {toggle.name} 未找到Text(TMP)组件");
}
// 验证Toggle的Graphic字段
if (toggle.graphic != null && toggle.graphic is Image graphicImage)
{
Debug.Log($"初始化Toggle Graphic验证: {pageName}, graphic sprite={graphicImage.sprite?.name ?? "null"}");
}
else
{
Debug.LogWarning($"Toggle {toggle.name} 的Graphic字段未正确配置或为空");
}
// 恢复OnValueChanged并绑定
toggle.onValueChanged = onValueChanged;
toggle.onValueChanged.RemoveAllListeners();
toggle.onValueChanged.AddListener((value) => OnTextPanelToggleChanged(toggle));
// 发送初始显隐状态
SendMessageToServer("TextPanel:Show");
Debug.Log($"初始化TextPanelToggle: {pageName}, isOn: {toggle.isOn}");
SendMessageToServer("Background:Text");
SendMessageToServer("ModelMove:Reset");
}
Debug.Log($"切换到页面: {pageName}, Slider {(slider != null ? "" : "")}, TextPanelToggle {(toggle != null ? "" : "")}");
if (singleItemButtonCache.TryGetValue(pageName, out List<Button> buttons))
{
foreach (var button in buttons)
{
if (button != null)
{
button.interactable = true;
}
}
}
SendMessageToServer("RequestHasAnimation");
}
private Transform FindDeep(Transform parent, string name)
{
Transform result = parent.Find(name);
if (result != null)
return result;
foreach (Transform child in parent)
{
result = FindDeep(child, name);
if (result != null)
return result;
}
return null;
}
// 在主线程中更新Slider进度
private void Update()
{
if (isDraggingSlider) return; // 拖动时忽略服务器进度
if (isDraggingSlider) return;
float progress = -1f;
bool? hasAnimation = null;
lock (queueLock)
{
if (progressQueue.Count > 0)
{
progress = progressQueue.Dequeue(); // 获取最新进度
progress = progressQueue.Dequeue();
}
if (hasAnimationQueue.Count > 0)
{
hasAnimation = hasAnimationQueue.Dequeue();
}
}
@ -482,37 +515,42 @@ public class TouchClient : MonoBehaviour
Slider slider = GetCurrentPageSlider();
if (slider != null)
{
// 仅当进度与当前Slider值差异较大或接近1.0时更新
float currentProgress = slider.value / 100f;
if (progress > 0f || Mathf.Abs(progress - 1f) < 0.005f)
{
// 临时禁用OnValueChanged以防止循环触发
var onValueChanged = slider.onValueChanged;
slider.onValueChanged = new Slider.SliderEvent();
slider.value = progress * 100f; // 更新Slider值0-100
slider.onValueChanged = onValueChanged; // 恢复事件
Debug.Log($"更新Slider进度: {progress:F2}, Slider值: {slider.value}");
slider.value = progress * 100f;
slider.onValueChanged = onValueChanged;
}
}
}
if (hasAnimation.HasValue)
{
UpdatePlayButtonVisibility(hasAnimation.Value);
}
}
// 应用程序退出时清理资源
private void OnApplicationQuit()
{
udpCts.Cancel(); // 通知UDP线程停止
receiveCts.Cancel(); // 通知接收线程停止
udpCts.Cancel();
receiveCts.Cancel();
if (udpThread != null && udpThread.IsAlive)
{
udpThread.Join(1000); // 等待UDP线程结束
udpThread.Join(1000);
}
if (receiveThread != null && receiveThread.IsAlive)
{
receiveThread.Join(1000); // 等待接收线程结束
receiveThread.Join(1000);
}
udpListener?.Close(); // 关闭UDP监听器
stream?.Close(); // 关闭TCP流
client?.Close(); // 关闭TCP客户端
Debug.Log("触摸端客户端已停止");
udpListener?.Close();
stream?.Close();
client?.Close();
}
private void OnDestroy()
{
OnApplicationQuit();
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,21 +0,0 @@
fileFormatVersion: 2
guid: 1756ec4a744794f49bc384cf92de4f97
TrueTypeFontImporter:
externalObjects: {}
serializedVersion: 4
fontSize: 16
forceTextureCase: -2
characterSpacing: 0
characterPadding: 1
includeFontData: 1
fontNames:
- Alibaba PuHuiTi 2.0
fallbackFontReferences: []
customCharacters:
fontRenderingMode: 0
ascentCalculationMode: 1
useLegacyBoundsCalculation: 0
shouldRoundAdvanceValue: 1
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,21 +0,0 @@
fileFormatVersion: 2
guid: 20729a5f21981634f83cec0f4575d37a
TrueTypeFontImporter:
externalObjects: {}
serializedVersion: 4
fontSize: 16
forceTextureCase: -2
characterSpacing: 0
characterPadding: 1
includeFontData: 1
fontNames:
- Alibaba PuHuiTi 2.0
fallbackFontReferences: []
customCharacters:
fontRenderingMode: 0
ascentCalculationMode: 1
useLegacyBoundsCalculation: 0
shouldRoundAdvanceValue: 1
userData:
assetBundleName:
assetBundleVariant:

View File

@ -12,11 +12,20 @@ EditorUserSettings:
value: 54035756510d5a0c095f0d7414760b4446154b782e7b7063752a1b62e7b5363b
flags: 0
RecentlyUsedSceneGuid-2:
value: 5303510050530a0a0e58087140210b44474f1a78742973637a2a4560b5b3656d
value: 0204525104005f5f5e5d5526117b0b44424e4073752d2536747c1b31e7b3673c
flags: 0
RecentlyUsedSceneGuid-3:
value: 02020157070050580c5b582340215c44464f4b297f7d7e64792d1c62b1e16269
flags: 0
RecentlyUsedSceneGuid-4:
value: 5550060701065c085e5c5924162609444f4f4b297e70226674284564b1b8326d
flags: 0
RecentlyUsedSceneGuid-5:
value: 5a5757560101590a5d0c0e24427b5d44434e4c7a7b7a23677f2b4565b7b5353a
flags: 0
RecentlyUsedSceneGuid-6:
value: 5303510050530a0a0e58087140210b44474f1a78742973637a2a4560b5b3656d
flags: 0
vcSharedLogLevel:
value: 0d5e400f0650
flags: 0

View File

@ -17,14 +17,65 @@ MonoBehaviour:
x: 0
y: 43.2
width: 1536
height: 820.8
height: 772.8
m_ShowMode: 4
m_Title: Game
m_RootView: {fileID: 2}
m_MinSize: {x: 875, y: 300}
m_Title: Scene
m_RootView: {fileID: 4}
m_MinSize: {x: 875, y: 321}
m_MaxSize: {x: 10000, y: 10000}
m_Maximized: 1
--- !u!114 &2
MonoBehaviour:
m_ObjectHideFlags: 52
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 12006, guid: 0000000000000000e000000000000000, type: 0}
m_Name: SceneHierarchyWindow
m_EditorClassIdentifier:
m_Children: []
m_Position:
serializedVersion: 2
x: 0
y: 0
width: 243.19995
height: 340.8
m_MinSize: {x: 202, y: 221}
m_MaxSize: {x: 4002, y: 4021}
m_ActualView: {fileID: 16}
m_Panes:
- {fileID: 16}
m_Selected: 0
m_LastSelected: 0
--- !u!114 &3
MonoBehaviour:
m_ObjectHideFlags: 52
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 12010, guid: 0000000000000000e000000000000000, type: 0}
m_Name:
m_EditorClassIdentifier:
m_Children:
- {fileID: 2}
- {fileID: 10}
m_Position:
serializedVersion: 2
x: 888
y: 0
width: 243.19995
height: 722.8
m_MinSize: {x: 100, y: 200}
m_MaxSize: {x: 8096, y: 16192}
vertical: 1
controlID: 44
--- !u!114 &4
MonoBehaviour:
m_ObjectHideFlags: 52
m_CorrespondingSourceObject: {fileID: 0}
@ -37,22 +88,22 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
m_Children:
- {fileID: 3}
- {fileID: 4}
- {fileID: 5}
- {fileID: 6}
- {fileID: 7}
m_Position:
serializedVersion: 2
x: 0
y: 0
width: 1536
height: 820.8
height: 772.8
m_MinSize: {x: 875, y: 300}
m_MaxSize: {x: 10000, y: 10000}
m_UseTopView: 1
m_TopViewHeight: 30
m_UseBottomView: 1
m_BottomViewHeight: 20
--- !u!114 &3
--- !u!114 &5
MonoBehaviour:
m_ObjectHideFlags: 52
m_CorrespondingSourceObject: {fileID: 0}
@ -74,7 +125,7 @@ MonoBehaviour:
m_MinSize: {x: 0, y: 0}
m_MaxSize: {x: 0, y: 0}
m_LastLoadedLayoutName:
--- !u!114 &4
--- !u!114 &6
MonoBehaviour:
m_ObjectHideFlags: 52
m_CorrespondingSourceObject: {fileID: 0}
@ -87,20 +138,20 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
m_Children:
- {fileID: 6}
- {fileID: 7}
- {fileID: 8}
- {fileID: 3}
- {fileID: 9}
m_Position:
serializedVersion: 2
x: 0
y: 30
width: 1536
height: 770.8
height: 722.8
m_MinSize: {x: 300, y: 200}
m_MaxSize: {x: 24288, y: 16192}
vertical: 0
controlID: 17
--- !u!114 &5
controlID: 97
--- !u!114 &7
MonoBehaviour:
m_ObjectHideFlags: 52
m_CorrespondingSourceObject: {fileID: 0}
@ -116,12 +167,12 @@ MonoBehaviour:
m_Position:
serializedVersion: 2
x: 0
y: 800.8
y: 752.8
width: 1536
height: 20
m_MinSize: {x: 0, y: 0}
m_MaxSize: {x: 0, y: 0}
--- !u!114 &6
--- !u!114 &8
MonoBehaviour:
m_ObjectHideFlags: 52
m_CorrespondingSourceObject: {fileID: 0}
@ -138,8 +189,8 @@ MonoBehaviour:
serializedVersion: 2
x: 0
y: 0
width: 854.4
height: 770.8
width: 888
height: 722.8
m_MinSize: {x: 201, y: 221}
m_MaxSize: {x: 4001, y: 4021}
m_ActualView: {fileID: 15}
@ -150,32 +201,7 @@ MonoBehaviour:
- {fileID: 11}
m_Selected: 0
m_LastSelected: 1
--- !u!114 &7
MonoBehaviour:
m_ObjectHideFlags: 52
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 1
m_Script: {fileID: 12010, guid: 0000000000000000e000000000000000, type: 0}
m_Name:
m_EditorClassIdentifier:
m_Children:
- {fileID: 9}
- {fileID: 10}
m_Position:
serializedVersion: 2
x: 854.4
y: 0
width: 278.40002
height: 770.8
m_MinSize: {x: 100, y: 200}
m_MaxSize: {x: 8096, y: 16192}
vertical: 1
controlID: 55
--- !u!114 &8
--- !u!114 &9
MonoBehaviour:
m_ObjectHideFlags: 52
m_CorrespondingSourceObject: {fileID: 0}
@ -190,43 +216,17 @@ MonoBehaviour:
m_Children: []
m_Position:
serializedVersion: 2
x: 1132.8
x: 1131.2
y: 0
width: 403.19995
height: 770.8
m_MinSize: {x: 275, y: 50}
m_MaxSize: {x: 4000, y: 4000}
width: 404.80005
height: 722.8
m_MinSize: {x: 276, y: 71}
m_MaxSize: {x: 4001, y: 4021}
m_ActualView: {fileID: 13}
m_Panes:
- {fileID: 13}
m_Selected: 0
m_LastSelected: 0
--- !u!114 &9
MonoBehaviour:
m_ObjectHideFlags: 52
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 1
m_Script: {fileID: 12006, guid: 0000000000000000e000000000000000, type: 0}
m_Name:
m_EditorClassIdentifier:
m_Children: []
m_Position:
serializedVersion: 2
x: 0
y: 0
width: 278.40002
height: 341.6
m_MinSize: {x: 200, y: 200}
m_MaxSize: {x: 4000, y: 4000}
m_ActualView: {fileID: 16}
m_Panes:
- {fileID: 16}
m_Selected: 0
m_LastSelected: 0
--- !u!114 &10
MonoBehaviour:
m_ObjectHideFlags: 52
@ -243,9 +243,9 @@ MonoBehaviour:
m_Position:
serializedVersion: 2
x: 0
y: 341.6
width: 278.40002
height: 429.19998
y: 340.8
width: 243.19995
height: 382
m_MinSize: {x: 232, y: 271}
m_MaxSize: {x: 10002, y: 10021}
m_ActualView: {fileID: 14}
@ -284,7 +284,7 @@ MonoBehaviour:
m_OverlaysVisible: 1
m_LockTracker:
m_IsLocked: 0
m_LastSelectedObjectID: 162098
m_LastSelectedObjectID: 3226668
--- !u!114 &12
MonoBehaviour:
m_ObjectHideFlags: 52
@ -307,8 +307,8 @@ MonoBehaviour:
serializedVersion: 2
x: 0
y: 73.6
width: 853.4
height: 749.8
width: 1183
height: 989.80005
m_ViewDataDictionary: {fileID: 0}
m_OverlayCanvas:
m_LastAppliedPresetName: Default
@ -321,6 +321,7 @@ MonoBehaviour:
- {fileID: -5493858010228640296, guid: da2d18bdd63eddf4db4344988663132b, type: 2}
- {fileID: -5073058742846949024, guid: 9a5ed5f9dc25f9b498cfc53347cb4567, type: 2}
- {fileID: -2230655706508628860, guid: c06c13b013fc9334096e1edcfb15e759, type: 2}
- {fileID: 0}
m_ValueSerializationHelper:
- e00: 1
e01: 0
@ -402,10 +403,26 @@ MonoBehaviour:
e31: 0
e32: 0
e33: 1
- e00: 1
e01: 0
e02: 0
e03: 0
e10: 0
e11: 1
e12: 0
e13: 0
e20: 0
e21: 0
e22: 1
e23: 0
e30: 0
e31: 0
e32: 0
e33: 1
m_PreviewAnimator: {fileID: 0}
m_AnimatorController: {fileID: 9100000, guid: c06c13b013fc9334096e1edcfb15e759, type: 2}
m_AnimatorController: {fileID: 0}
m_BreadCrumbs:
- m_Target: {fileID: -2230655706508628860, guid: c06c13b013fc9334096e1edcfb15e759, type: 2}
- m_Target: {fileID: 0}
m_ScrollPosition: {x: 0, y: 0}
stateMachineGraph: {fileID: 0}
stateMachineGraphGUI: {fileID: 0}
@ -438,10 +455,10 @@ MonoBehaviour:
m_Tooltip:
m_Pos:
serializedVersion: 2
x: 1132.8
x: 1131.2001
y: 73.6
width: 402.19995
height: 749.8
width: 403.80005
height: 701.8
m_ViewDataDictionary: {fileID: 0}
m_OverlayCanvas:
m_LastAppliedPresetName: Default
@ -480,10 +497,10 @@ MonoBehaviour:
m_Tooltip:
m_Pos:
serializedVersion: 2
x: 854.4
y: 415.2
width: 276.40002
height: 408.19998
x: 888
y: 414.4
width: 241.19995
height: 361
m_ViewDataDictionary: {fileID: 0}
m_OverlayCanvas:
m_LastAppliedPresetName: Default
@ -500,7 +517,7 @@ MonoBehaviour:
m_SkipHidden: 0
m_SearchArea: 1
m_Folders:
- Assets/Scenes
- Assets/Resources
m_Globs: []
m_OriginalText:
m_FilterByTypeIntersection: 0
@ -515,7 +532,7 @@ MonoBehaviour:
scrollPos: {x: 0, y: 0}
m_SelectedIDs: 7c780000
m_LastClickedID: 30844
m_ExpandedIDs: 00000000d6ac0100d8ac0100daac0100dcac0100deac0100e0ac0100e2ac0100e4ac0100e6ac0100e8ac0100eaac0100ecac0100eeac0100
m_ExpandedIDs: 0000000006b3010008b301000ab301000cb301000eb3010010b3010012b3010014b3010016b3010018b301001ab301001cb301001eb30100
m_RenameOverlay:
m_UserAcceptedRename: 0
m_Name:
@ -540,10 +557,10 @@ MonoBehaviour:
m_Icon: {fileID: 0}
m_ResourceFile:
m_AssetTreeState:
scrollPos: {x: 0, y: 0}
scrollPos: {x: 0, y: 369}
m_SelectedIDs:
m_LastClickedID: 0
m_ExpandedIDs: ffffffff00000000d6ac0100d8ac0100daac0100dcac0100deac0100e0ac0100e2ac0100e4ac0100eaac0100944d0900
m_ExpandedIDs: ffffffff0000000006b3010008b301000ab301000cb301000eb3010010b3010012b3010014b3010016b3010018b301001cb301001eb3010068b3010060b80100
m_RenameOverlay:
m_UserAcceptedRename: 0
m_Name:
@ -621,8 +638,8 @@ MonoBehaviour:
serializedVersion: 2
x: 0
y: 73.6
width: 853.4
height: 749.8
width: 887
height: 701.8
m_ViewDataDictionary: {fileID: 0}
m_OverlayCanvas:
m_LastAppliedPresetName: Default
@ -632,8 +649,8 @@ MonoBehaviour:
floating: 0
collapsed: 0
displayed: 1
snapOffset: {x: -100, y: -25.600006}
snapOffsetDelta: {x: 0, y: 0.000030517578}
snapOffset: {x: -101, y: -26}
snapOffsetDelta: {x: 0, y: 0}
snapCorner: 3
id: Tool Settings
index: 0
@ -869,9 +886,9 @@ MonoBehaviour:
m_PlayAudio: 0
m_AudioPlay: 0
m_Position:
m_Target: {x: 944.95264, y: 582.91113, z: 2.357466}
m_Target: {x: 682.3883, y: 647.0643, z: 4.6536684}
speed: 2
m_Value: {x: 944.95264, y: 582.91113, z: 2.357466}
m_Value: {x: 706.0194, y: 641.32666, z: 4.927581}
m_RenderMode: 0
m_CameraMode:
drawMode: 0
@ -922,9 +939,9 @@ MonoBehaviour:
speed: 2
m_Value: {x: 0, y: 0, z: 0, w: 1}
m_Size:
m_Target: 866.09686
m_Target: 636.08655
speed: 2
m_Value: 866.09686
m_Value: 608.69525
m_Ortho:
m_Target: 1
speed: 2
@ -969,10 +986,10 @@ MonoBehaviour:
m_Tooltip:
m_Pos:
serializedVersion: 2
x: 854.4
x: 888
y: 73.6
width: 276.40002
height: 320.6
width: 241.19995
height: 319.8
m_ViewDataDictionary: {fileID: 0}
m_OverlayCanvas:
m_LastAppliedPresetName: Default
@ -980,26 +997,26 @@ MonoBehaviour:
m_OverlaysVisible: 1
m_SceneHierarchy:
m_TreeViewState:
scrollPos: {x: 0, y: 0}
m_SelectedIDs: 38ad0100
m_LastClickedID: 0
m_ExpandedIDs: 24aef9ff6caef9ff54aff9ffa8aff9ffe0b0f9ff4cb2f9ff5671faffa630fbffa231fbffbcf1fbfff008fcff56cafcffdad6fcffc4e5fcff06e6fcff46e7fcff66ecfcffa8ecfcffecedfcff5cadfdffeaadfdfffc73feff9675fefffc36ffff7a37ffff08fbffff8ab20100c8fb0700ee210800f4340800e6530800a65508003e560800ea4d0900ee4d0900044e0900304e09003c4e0900404e0900064f09001c4f0900ae4f0900ba4f0900be4f0900f44f090032500900c2500900265109005c51090070510900a45109006c5709007057090086570900be570900c25709009e580900f65809004459090048590900865909009a590900c4590900f2590900285a0900c85a0900fe5a0900025b0900125b0900465b09000a6009005260090094600900c06009003a610900d06409001865090094650900dc6509001e6609002666090000680900c06909002a6a0900ec6a0900966b0900de6b0900
scrollPos: {x: 0, y: 53.200012}
m_SelectedIDs: ecb50100
m_LastClickedID: 112108
m_ExpandedIDs: 8438ffff08fbffffceb30100d2b3010054b40100eab4010084b50100ecb50100b0b70100bcb70100
m_RenameOverlay:
m_UserAcceptedRename: 0
m_Name: "SPECT\u7CFB\u7EDF"
m_OriginalName: "SPECT\u7CFB\u7EDF"
m_Name:
m_OriginalName:
m_EditFieldRect:
serializedVersion: 2
x: 0
y: 0
width: 0
height: 0
m_UserData: 614482
m_UserData: 0
m_IsWaitingForDelay: 0
m_IsRenaming: 0
m_OriginalEventType: 0
m_OriginalEventType: 11
m_IsRenamingFilename: 0
m_ClientGUIView: {fileID: 9}
m_ClientGUIView: {fileID: 2}
m_SearchString:
m_ExpandedScenes: []
m_CurrenRootInstanceID: 0
@ -1029,8 +1046,8 @@ MonoBehaviour:
serializedVersion: 2
x: 0
y: 73.6
width: 853.4
height: 749.8
width: 887
height: 701.8
m_ViewDataDictionary: {fileID: 0}
m_OverlayCanvas:
m_LastAppliedPresetName: Default
@ -1044,7 +1061,7 @@ MonoBehaviour:
m_ShowGizmos: 0
m_TargetDisplay: 0
m_ClearColor: {r: 0, g: 0, b: 0, a: 0}
m_TargetSize: {x: 3328, y: 1352}
m_TargetSize: {x: 1920, y: 1080}
m_TextureFilterMode: 0
m_TextureHideFlags: 61
m_RenderIMGUI: 1
@ -1053,16 +1070,16 @@ MonoBehaviour:
m_VSyncEnabled: 0
m_Gizmos: 0
m_Stats: 0
m_SelectedSizes: 08000000000000000000000012000000000000000000000000000000000000000000000000000000
m_SelectedSizes: 03000000000000000000000012000000000000000000000000000000000000000000000000000000
m_ZoomArea:
m_HRangeLocked: 0
m_VRangeLocked: 0
hZoomLockedByDefault: 0
vZoomLockedByDefault: 0
m_HBaseRangeMin: -1331.2001
m_HBaseRangeMax: 1331.2001
m_VBaseRangeMin: -540.8
m_VBaseRangeMax: 540.8
m_HBaseRangeMin: -768
m_HBaseRangeMax: 768
m_VBaseRangeMin: -432
m_VBaseRangeMax: 432
m_HAllowExceedBaseRangeMin: 1
m_HAllowExceedBaseRangeMax: 1
m_VAllowExceedBaseRangeMin: 1
@ -1071,7 +1088,7 @@ MonoBehaviour:
m_HSlider: 0
m_VSlider: 0
m_IgnoreScrollWheelUntilClicked: 0
m_EnableMouseInput: 0
m_EnableMouseInput: 1
m_EnableSliderZoomHorizontal: 0
m_EnableSliderZoomVertical: 0
m_UniformScale: 1
@ -1080,23 +1097,23 @@ MonoBehaviour:
serializedVersion: 2
x: 0
y: 21
width: 853.4
height: 728.8
m_Scale: {x: 0.32053787, y: 0.32053787}
m_Translation: {x: 426.70004, y: 364.4}
width: 887
height: 680.8
m_Scale: {x: 0.57747394, y: 0.57747394}
m_Translation: {x: 443.5, y: 340.4}
m_MarginLeft: 0
m_MarginRight: 0
m_MarginTop: 0
m_MarginBottom: 0
m_LastShownAreaInsideMargins:
serializedVersion: 2
x: -1331.2001
y: -1136.8391
width: 2662.4001
height: 2273.6782
x: -768
y: -589.4638
width: 1536
height: 1178.9276
m_MinimalGUI: 1
m_defaultScale: 0.32053787
m_LastWindowPixelSize: {x: 1066.75, y: 937.25}
m_defaultScale: 0.57747394
m_LastWindowPixelSize: {x: 1108.75, y: 877.25}
m_ClearInEditMode: 1
m_NoCameraWarning: 1
m_LowResolutionForAspectRatios: 00000000000000000000