通过 TCP/IP 实现 Unity 和 JSBSim 的时间同步加速

在开发模拟类游戏或仿真系统时,当我们需要加速仿真(例如通过 Unity 的 Time.timeScale 实现 4 倍速运行)时,Unity 和 JSBSim 的时间步长可能会不同步,导致仿真数据不一致。同样的方法也能扩展到其他的仿真系统上

背景

我们开发了一个基于 Unity 的城市交通场景,其中车辆通过 TrafficSystem 和 TrafficCar 脚本动态生成和移动。为了加速仿真,我们编写了一个 TimeSpeeder.cs 脚本,通过调整 Time.timeScale 实现游戏速度的倍增(例如 4 倍速)。同时,场景中的飞行器数据由 JSBSim 提供,Unity 通过 TCP/IP 协议与 JSBSim 通信。为了让 JSBSim 的仿真速度与 Unity 保持一致,我们需要将 Unity 的时间倍率传递给 JSBSim,并调整 JSBSim 的仿真时间步长。

实现方案

1. Unity 端:通过timescale进行编写加速脚本

    private void ApplyTimeScale(float scale)
    {
        Time.timeScale = scale;
        // 优化物理时间调整
        Time.fixedDeltaTime = 0.02f * Mathf.Max(1f, scale); // 避免过小的 fixedDeltaTime
    }

 

功能说明
  • 加速控制:通过 UI 或快捷键(1-5 键)设置时间倍率(0.5x 到 4x)。
  • TCP 客户端:连接到 JSBSim 服务器(默认 127.0.0.1:1138),每次调整 Time.timeScale 时发送 timescale:<value> 消息。
  • 物理同步:调整 Time.fixedDeltaTime,确保 Unity 的物理模拟与时间倍率同步。

2. JSBSim 端:修改仿真速度

为了让 JSBSim 根据 Unity 发送的时间倍率调整仿真速度,我们需要修改 JSBSim 的源代码。

2.1 配置 JSBSim 的输入/输出

在 JSBSim 的脚本文件(例如 scripts/C1723.xml)中,添加以下配置:

<output name="localhost" type="SOCKET" port="1138" rate="20"> <property>position/lat-gc-deg</property> <property>position/long-gc-deg</property> <property>position/h-agl-ft</property> </output> <input type="SOCKET" port="1139"/>

  • <output>:JSBSim 将飞行数据发送到 localhost:1138(Unity 连接的端口)。
  • <input>:JSBSim 从 localhost:1139 接收时间倍率数据。
2.2 修改 JSBSim 源代码

我们需要修改 JSBSim 的 FGInput 和 FGFDMExec 类,以解析时间倍率并调整仿真速度。

  1. 修改 FGInput::Read 方法(src/input_output/FGInput.cpp):

    void FGInput::Read(int socket) { char buffer[256]; int bytes_received = recv(socket, buffer, sizeof(buffer) - 1, 0); if (bytes_received > 0) { buffer[bytes_received] = '\0'; std::string message(buffer); if (message.find("timescale:") == 0) { std::string value = message.substr(10); float timeScale = std::stof(value); if (FDMExec) { FDMExec->SetSimulationRate(timeScale); } } } }

  2. 添加 SetSimulationRate 方法(src/FDM/JSBSim/FGFDMExec.h 和 FGFDMExec.cpp):

    // FGFDMExec.h class FGFDMExec { public: void SetSimulationRate(float rate); private: float simulationRate = 1.0f; double delta_t = 1.0 / 120.0; // 默认时间步长 double base_delta_t = 1.0 / 120.0; }; // FGFDMExec.cpp void FGFDMExec::SetSimulationRate(float rate) { simulationRate = std::max(0.1f, std::min(rate, 10.0f)); if (simulationRate != 0.0f) { delta_t = base_delta_t / simulationRate; } }

  3. 编译 JSBSim

    • 使用 CMake 和 C++ 编译器(例如 Visual Studio 或 GCC)重新编译 JSBSim。
    • 替换旧的 JSBSim 可执行文件。
功能说明
  • 解析时间倍率:JSBSim 解析 Unity 发送的 timescale:<value> 消息。
  • 调整仿真速度:通过 SetSimulationRate 修改仿真时间步长 delta_t,与 Unity 的 Time.timeScale 同步。

3. 使用步骤

3.1 在 Unity 中设置
  1. 添加 TimeSpeeder.cs
    • 创建一个空的 GameObject(例如命名为 "TimeSpeeder")。
    • 将 TimeSpeeder.cs 脚本附加到该 GameObject。
  2. 配置 TCP 参数
    • 在 Unity 编辑器的 Inspector 中,设置 Server IP(默认 127.0.0.1)和 Server Port(默认 1138),确保与 JSBSim 的输出端口匹配。
  3. 运行 Unity 场景
    • 运行场景,调整时间倍率(通过 UI 或快捷键 1-5)。
3.2 启动 JSBSim
  1. 修改 JSBSim 脚本
    • 确保 C1723.xml(或你的 JSBSim 脚本)包含上述 <input> 和 <output> 配置。
  2. 运行 JSBSim
    • 打开终端,运行以下命令:

      jsbsim --script=scripts/C1723.xml

    • JSBSim 将监听 1139 端口,等待 Unity 发送时间倍率。
3.3 测试同步
  • 在 Unity 中将时间倍率设置为 4 倍速(Time.timeScale = 4)。
  • 观察 JSBSim 的仿真速度是否同步加速(例如飞机的位置更新频率应为原来的 4 倍)。

4. 运行时行为

4.1 预期结果
  • 数据传输
    • Unity 每次调整 Time.timeScale 时,通过 TCP 发送 timescale:<value> 消息。
    • JSBSim 接收消息并调整仿真速度。
  • 同步加速
    • Unity 和 JSBSim 以相同的倍率运行(例如 4 倍速)。
    • 两者的时间步长保持一致,仿真数据同步更新。
  • 日志输出
    • Unity 控制台:

      Connected to JSBSim server at 127.0.0.1:1138 Sent timescale 4 to JSBSim

    • (需添加日志):

      Received timescale: 4, adjusting simulation rate

4.2 可能的问题及解决方法
  1. 连接失败
    • 问题:Unity 无法连接到 JSBSim。
    • 解决:检查 JSBSim 是否启动并监听 1139 端口,使用 netcat 测试:

      确保 serverIP 和 serverPort 正确。
  2. 数据不同步
    • 问题:Unity 和 JSBSim 的仿真速度不同步。
    • 解决:检查网络延迟,考虑使用 UDP 协议(修改 JSBSim 的 <input> 为 protocol="udp",并在 Unity 中使用 UdpClient)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值