You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Unity转速表GUI未同步更新Python脚本发送的RPM数据问题求助

Unity转速表GUI未同步更新Python脚本发送的RPM数据问题求助

看起来你已经成功打通了Python和Unity的Socket连接,数据也能被Unity接收到,但转速表指针就是不更新,我帮你梳理几个最可能的问题点和对应的解决方案:


1. 核心问题:UnityMainThreadDispatcher未正确生效

你用UnityMainThreadDispatcher.Instance().Enqueue(() => targetSpeed = parsedValue)来尝试在主线程更新targetSpeed,但如果你的场景里没有挂载UnityMainThreadDispatcher脚本的GameObject实例,这个回调根本不会执行,导致targetSpeed一直停在初始值0,Update方法自然不会触发指针更新逻辑。

替代方案:用原生线程安全队列摆脱第三方依赖

不需要依赖第三方工具,用ConcurrentQueue缓存子线程收到的数据,在主线程的Update里统一处理,更可靠:

using System.Collections.Concurrent; // 别忘了添加这个命名空间

public class Speedometer : MonoBehaviour
{
    // 新增线程安全队列,用来缓存子线程收到的转速数据
    private ConcurrentQueue<float> speedUpdateQueue = new ConcurrentQueue<float>();
    
    // ... 其他原有变量保持不变 ...

    void GetData()
    {
        server = new TcpListener(IPAddress.Any, connectionPort);
        server.Start();
        running = true;
        
        while (running)
        {
            client = server.AcceptTcpClient();
            NetworkStream nwStream = client.GetStream();
            byte[] buffer = new byte[client.ReceiveBufferSize];

            while (client.Connected)
            {
                int bytesRead = nwStream.Read(buffer, 0, client.ReceiveBufferSize);
                if (bytesRead == 0) // 检测到Python客户端断开连接
                {
                    Debug.Log("Python客户端已断开");
                    break;
                }
                if (bytesRead > 0)
                {
                    string dataReceived = Encoding.UTF8.GetString(buffer, 0, bytesRead);
                    float parsedValue = ParseData(dataReceived);
                    
                    // 将数据加入队列,不用依赖Dispatcher
                    speedUpdateQueue.Enqueue(parsedValue);

                    // 如果你不需要Unity给Python回传数据,可以删掉下面这行echo逻辑
                    // nwStream.Write(buffer, 0, bytesRead);
                }
            }

            client.Close();
        }
        server.Stop();
    }

    void Update()
    {
        // 先处理队列里所有待更新的转速数据
        while (speedUpdateQueue.TryDequeue(out float newTargetSpeed))
        {
            targetSpeed = newTargetSpeed;
            Debug.Log($"已更新目标转速: {targetSpeed}");
        }

        // 加个小阈值,避免极小的数值变化频繁触发更新
        if (Mathf.Abs(targetSpeed - currentSpeed) > 0.01f)
        {
            UpdateSpeed();
        }
    }

    // ... 其他原有方法保持不变 ...
}

2. 数据解析存在潜在异常

你的ParseData函数里有判断字符串是否以(开头、)结尾的逻辑,但Python发送的是纯数字字符串(比如"12.3"),这个判断不会触发;另外如果数据里有多余的空白字符或者格式错误,float.Parse会直接抛出异常,导致targetSpeed无法被正确赋值。

优化方案:增强解析的鲁棒性

private static float ParseData(string dataString)
{
    Debug.Log($"收到原始数据: {dataString}");
    // 先去除首尾空白字符,避免换行、空格等导致解析失败
    dataString = dataString.Trim();
    
    // 去掉不需要的括号判断(Python并没有发送括号)
    // if (dataString.StartsWith("(") && dataString.EndsWith(")"))
    // {
    //     dataString = dataString.Substring(1, dataString.Length - 2);
    // }

    // 使用TryParse避免解析失败抛出异常,同时输出错误日志
    if (float.TryParse(dataString, out float result))
    {
        return result;
    }
    else
    {
        Debug.LogError($"解析数据失败: {dataString}");
        return 0f;
    }
}

3. 额外检查点

  • 确认指针的RectTransform设置:检查SpeedoMeter_Needle的旋转轴是否为Z轴,锚点是否设置在指针的旋转中心,否则旋转后指针会偏移,看起来像是没更新。
  • 验证数值是否真的更新:在Update方法里添加Debug.Log($"目标转速: {targetSpeed}, 当前转速: {currentSpeed}"),确认数值是否在正常变化。
  • TCP连接逻辑优化:当前代码在Python断开后会重新等待新连接,但通过bytesRead == 0的判断可以更及时地检测连接断开,避免不必要的阻塞。

备注:内容来源于stack exchange,提问作者Lord_Kordec

火山引擎 最新活动