You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 05:25:26