Unity/C#中GameObject与OnMessage的两难困境求解
解决Unity中WebSocket子线程更新物体朝向的问题
你的代码存在两个核心问题:
1. 静态变量未正确赋值
你在WS_Client类里声明了静态的_cube,但在Start()方法里又定义了一个同名局部变量GameObject _cube = GameObject.Find("MyCube");,这导致静态变量始终为null,OnMessage自然无法访问到正确的物体引用。
2. 子线程操作Unity API
WebSocketSharp的OnMessage回调是在子线程中执行的,而Unity的所有组件操作(比如修改Transform)必须在主线程进行,直接在OnMessage里修改_cube.transform会触发线程安全错误。
修复后的完整代码
using UnityEngine; using WebSocketSharp; using WebSocketSharp.Server; using System; using System.Threading; public class WS_Client : MonoBehaviour { private static GameObject _cube; // 线程安全的共享变量,存储收到的旋转数据 private static Vector3? _targetRotation; private static readonly object _lockObj = new object(); public class MyWebSocketServer : WebSocketBehavior { protected override void OnMessage(MessageEventArgs e) { try { string data = e.Data; string[] components = data.Split(' '); // 先校验数据格式是否合法 if (components.Length != 3) { Debug.LogError("Invalid rotation data format. Expected 3 float values separated by space."); return; } if (!float.TryParse(components[0], out float x) || !float.TryParse(components[1], out float y) || !float.TryParse(components[2], out float z)) { Debug.LogError("Failed to parse rotation values to float."); return; } Vector3 newRotation = new Vector3(x, y, z); // 用lock保护共享变量,避免多线程冲突 lock (_lockObj) { _targetRotation = newRotation; } Debug.Log($"Received rotation: {newRotation}"); } catch (Exception ex) { Debug.LogError($"OnMessage error: {ex.Message}"); } } protected override void OnOpen() { Debug.Log("Client connected"); } protected override void OnClose(CloseEventArgs e) { Debug.Log("Client disconnected"); } } private WebSocketServer _wssv; void Start() { // 正确赋值静态变量,去掉局部变量的声明 _cube = GameObject.Find("MyCube"); if (_cube == null) { Debug.LogError("Cube with name 'MyCube' not found in scene!"); return; } // 初始化并启动WebSocket服务器 _wssv = new WebSocketServer(8080); _wssv.AddWebSocketService<MyWebSocketServer>("/MyWebSocket"); _wssv.Start(); Debug.Log("WebSocket server started on port 8080"); } void Update() { // 在主线程中处理旋转更新 Vector3? rotationToApply = null; lock (_lockObj) { if (_targetRotation.HasValue) { rotationToApply = _targetRotation.Value; _targetRotation = null; // 重置,避免重复应用 } } if (rotationToApply.HasValue && _cube != null) { _cube.transform.eulerAngles = rotationToApply.Value; Debug.Log($"Updated cube rotation to: {rotationToApply.Value}"); } } void OnDestroy() { // 停止WebSocket服务器,避免资源泄漏 if (_wssv != null && _wssv.IsListening) { _wssv.Stop(); Debug.Log("WebSocket server stopped"); } } }
关键修复点说明
- 静态变量赋值:去掉
Start()里的局部_cube声明,直接给类级别的静态_cube赋值,确保MyWebSocketServer能访问到正确的物体引用。 - 线程安全的数据传递:使用
Vector3?(可空类型)存储目标旋转,并用lock关键字保护共享变量的读写,避免多线程并发访问导致的数据异常。 - 主线程更新:所有对
Transform的修改都移到Update()方法中执行,这是Unity的主线程回调,符合Unity的线程安全要求。 - 增强的错误处理:增加了数据格式校验和
TryParse,避免非法数据导致的崩溃;在OnDestroy中停止WebSocket服务器,防止资源泄漏。
内容的提问来源于stack exchange,提问作者Ivan Viti
相关产品推荐
相关产品推荐

