using System; using System.Collections.Generic; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using UnityEngine; using UnityEngine.UI; public class TouchClient : MonoBehaviour { private TcpClient client; // 用于与显示端通信的TCP客户端 private NetworkStream stream; // 用于发送/接收数据的流 private volatile bool isConnected = false; // 线程安全的连接状态标志 private UdpClient udpListener; // 用于接收广播IP的UDP客户端 private Thread udpThread; // 监听广播的线程 private CancellationTokenSource udpCts = new CancellationTokenSource(); // 控制UDP线程取消 private Thread receiveThread; // 接收服务器消息的线程 private CancellationTokenSource receiveCts = new CancellationTokenSource(); // 控制接收线程取消 public Transform background; // UI页面的父级变换 private string currentPage = "首页"; // 跟踪当前显示的页面 private readonly Queue progressQueue = new Queue(); // 线程安全的进度队列 private readonly object queueLock = new object(); // 进度队列访问锁 private bool isDraggingSlider = false; // 标记是否正在拖动Slider // 脚本启动时调用 void Start() { // 设置触摸控制端分辨率为 1920x1080 Screen.SetResolution(1920, 1080, false); // 在端口9999上初始化UDP监听 udpListener = new UdpClient(9999); udpThread = new Thread(() => ListenForBroadcast(udpCts.Token)); udpThread.Start(); Debug.Log("触摸端等待显示端广播..."); // 显示初始页面 ShowPage("首页"); } // 监听UDP广播以发现显示端IP private void ListenForBroadcast(CancellationToken token) { IPEndPoint endPoint = new IPEndPoint(IPAddress.Any, 9999); // 在未连接或未取消的情况下持续监听 while (!isConnected && !token.IsCancellationRequested) { try { // 接收广播数据 byte[] data = udpListener.Receive(ref endPoint); string serverIp = Encoding.UTF8.GetString(data); Debug.Log("发现显示端IP: " + serverIp); ConnectToServer(serverIp, 8888); // 尝试连接到服务器 } catch (Exception ex) { Debug.LogError($"UDP接收错误: {ex.Message}"); Thread.Sleep(1000); // 避免快速重试 } } } // 通过TCP连接到显示端服务器 private void ConnectToServer(string ip, int port) { try { client = new TcpClient(); client.Connect(ip, port); // 连接到服务器 stream = client.GetStream(); isConnected = true; udpCts.Cancel(); // 连接成功后停止UDP监听线程 udpListener?.Close(); // 关闭UDP监听器 Debug.Log("触摸端已连接到显示端: " + ip); // 启动接收线程以处理服务器消息 receiveThread = new Thread(() => ReceiveMessages(receiveCts.Token)); receiveThread.Start(); } catch (Exception ex) { Debug.LogError($"连接显示端失败: {ex.Message}"); } } // 接收服务器发送的消息 private void ReceiveMessages(CancellationToken token) { byte[] message = new byte[4096]; int bytesRead; while (!token.IsCancellationRequested && isConnected) { try { bytesRead = stream.Read(message, 0, 4096); 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) { progressQueue.Clear(); // 清空队列以确保最新进度 progressQueue.Enqueue(progress); // 将进度加入队列 Debug.Log($"收到进度: {progress:F2}"); } } } catch (Exception ex) { Debug.LogError($"接收服务器消息错误: {ex.Message}"); isConnected = false; break; } } } // 向显示端服务器发送消息 private void SendMessageToServer(string msg) { if (isConnected && stream != null) { try { byte[] data = Encoding.UTF8.GetBytes(msg); stream.Write(data, 0, data.Length); Debug.Log("发送指令: " + msg); } catch (Exception ex) { Debug.LogError($"发送消息失败: {ex.Message}"); isConnected = false; // 标记连接失效 } } } // 页面按钮点击时调用 public void OnButtonClick_Page(string pageName) { ShowPage(pageName); // 切换到指定页面 SendMessageToServer("Page:" + pageName); // 通知服务器 } // 模型播放按钮点击时调用 public void OnButtonClick_PlayModel(string modelName) { SendMessageToServer("Model:" + modelName); // 通知服务器播放模型 } // 滑块值改变时调用 public void OnSliderChanged(Slider slider) { isDraggingSlider = true; // 标记正在拖动 float progress = slider.value / 100f; // 转换为0-1 SendMessageToServer("Progress:" + progress.ToString("F2")); // 发送进度 Debug.Log($"Slider拖动到: {progress:F2}"); } // 滑块拖动结束时调用(需在Inspector中绑定) public void OnSliderEndDrag() { isDraggingSlider = false; // 结束拖动 Debug.Log("Slider拖动结束"); } // 获取当前页面的Slider组件 private Slider GetCurrentPageSlider() { if (background == null || currentPage == "首页") return null; Transform pageTransform = background.Find(currentPage); if (pageTransform != null) { Slider slider = pageTransform.GetComponentInChildren(); if (slider != null) { if (!slider.interactable) { slider.interactable = true; // 确保Slider可交互 Debug.Log($"启用Slider交互: {currentPage}"); } return slider; } Debug.LogWarning($"未在页面 {currentPage} 找到Slider"); return null; } Debug.LogWarning($"未找到页面 {currentPage}"); return null; } // 切换激活的UI页面 private void ShowPage(string pageName) { foreach (Transform child in background) { child.gameObject.SetActive(child.name == pageName); // 仅激活目标页面 } currentPage = pageName; // 清空进度队列以避免旧页面数据干扰 lock (queueLock) { progressQueue.Clear(); } // 初始化当前页面的Slider Slider slider = GetCurrentPageSlider(); if (slider != null) { slider.value = 0f; // 重置Slider到0 slider.interactable = true; // 确保可交互 // 绑定OnValueChanged事件 slider.onValueChanged.RemoveAllListeners(); slider.onValueChanged.AddListener((value) => OnSliderChanged(slider)); Debug.Log($"初始化Slider: {pageName}, 值: {slider.value}"); } Debug.Log($"切换到页面: {pageName}, Slider {(slider != null ? "找到" : "未找到")}"); } // 在主线程中更新Slider进度 private void Update() { if (isDraggingSlider) return; // 拖动时忽略服务器进度 float progress = 0f; lock (queueLock) { if (progressQueue.Count > 0) { progress = progressQueue.Dequeue(); // 获取最新进度 } } if (progress >= 0f) { Slider slider = GetCurrentPageSlider(); if (slider != null) { slider.value = progress * 100f; // 更新Slider值(0-100) Debug.Log($"更新Slider进度: {progress:F2}, Slider值: {slider.value}"); } } } // 应用程序退出时清理资源 private void OnApplicationQuit() { udpCts.Cancel(); // 通知UDP线程停止 receiveCts.Cancel(); // 通知接收线程停止 if (udpThread != null && udpThread.IsAlive) { udpThread.Join(1000); // 等待UDP线程结束 } if (receiveThread != null && receiveThread.IsAlive) { receiveThread.Join(1000); // 等待接收线程结束 } udpListener?.Close(); // 关闭UDP监听器 stream?.Close(); // 关闭TCP流 client?.Close(); // 关闭TCP客户端 } }