Vue3对接UE,通过MQTT完成通讯

Vue3对接UE,通过MQTT完成通讯

概述

一个基于Vue3的实时视频流显示系统,主要用于连接和显示Unreal Engine (UE) 服务器的实时渲染内容。该页面集成了PixelStreaming技术和MQTT通信协议,提供了完整的视频流控制和交互功能。

主要功能

  • 实时视频流显示:连接UE服务器,显示实时渲染的3D场景
  • 协议支持:支持PixelStreaming连接
  • MQTT通信:通过MQTT协议进行消息通信和控制
  • 连接状态监控:实时显示UE和MQTT连接状态
  • 错误处理与重连:自动处理连接错误并尝试重连

快速开始

安装依赖

bash 复制代码
npm install @epicgames-ps/lib-pixelstreamingfrontend-ue5.3
npm install @epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.3
npm install mqtt

基本使用

  1. 确保UE服务器运行
  2. 确保MQTT服务器运行

技术架构

核心技术栈

  • 前端框架: Vue 3 (Composition API)
  • 视频流技术: Epic Games PixelStreaming
  • 消息协议: MQTT

连接方式

  1. PixelStreaming链接
  2. MQTT连接(消息通信)

代码详情

1. 页面结构

vue 复制代码
<template>链接链接
  <div class="scene-display-container">
    <!-- 连接状态 -->
    <div class="connection-status">
      <span>UE: {{ ueStatus }}</span>
      <span>MQTT: {{ mqttStatus }}</span>
    </div>

    <!-- 视频流容器 -->
    <div class="video-container">
      <div id="streamingVideo" class="streaming-video"></div>

      <!-- 错误状态 -->
      <div v-if="errorMessage" class="error-overlay">
        <p>{{ errorMessage }}</p>
        <button @click="reconnect">重新连接</button>
      </div>
    </div>
  </div>
</template>

说明

  • connection-status:显示UE和MQTT的连接状态
  • video-container:视频流显示容器
  • error-overlay:错误状态覆盖层,提供重新连接功能

2. 响应式数据

javascript 复制代码
// 响应式数据
const errorMessage = ref('') // 存储错误信息
const ueStatus = ref('未连接') // UE连接状态
const mqttStatus = ref('未连接') // MQTT连接状态

// 实例
let pixelStreaming = null // PixelStreaming实例
let mqttClient = null // MQTT客户端实例

3. UE连接初始化

javascript 复制代码
// 初始化UE连接
const initPixelStreaming = () => {
  try {
    const style = new PixelStreamingApplicationStyle();
    style.applyStyleSheet();
    Logger.SetLoggerVerbosity(1);

    const config = new Config({ useUrlParams: false });
    config.setFlagEnabled(Flags.AutoPlayVideo, true);
    config.setFlagEnabled(Flags.AutoConnect, true);
    config.setTextSetting(TextParameters.SignallingServerUrl, "此处输入UE服务器地址");
    config.setFlagEnabled(Flags.HoveringMouseMode, ControlSchemeType.HoveringMouse);
    config.setFlagEnabled(Flags.MouseInput, true);
    config.setFlagEnabled(Flags.KeyboardInput, true);
    config.setFlagEnabled(Flags.TouchInput, true);
    config.setFlagEnabled(Flags.GamepadInput, false);
    config.setFlagEnabled(Flags.XRControllerInput, false);

    pixelStreaming = new PixelStreaming(config);

    const application = new Application({
      stream: pixelStreaming,
      settingsPanelConfig: { isEnabled: false, visibilityButtonConfig: { creationMode: UIElementCreationMode.Disable } },
      statsPanelConfig: { isEnabled: false, visibilityButtonConfig: { creationMode: UIElementCreationMode.Disable } },
      fullScreenControlsConfig: { creationMode: UIElementCreationMode.Disable },
      xrControlsConfig: { creationMode: UIElementCreationMode.Disable },
      videoQpIndicatorConfig: { disableIndicator: true },
    });

    const container = document.getElementById("streamingVideo");
    if (container) {
      container.innerHTML = '';
      container.appendChild(application.rootElement);
    }

    setupPixelStreamingEvents();
  } catch (error) {
    errorMessage.value = `UE连接失败: ${error}`;
  }
}

配置说明

  • AutoPlayVideo: true:自动播放视频
  • AutoConnect: true:自动连接
  • SignallingServerUrl:信令服务器地址
  • HoveringMouseMode:鼠标悬停模式
  • 各种输入控制:鼠标、键盘、触屏等

4. 事件监听器设置

javascript 复制代码
// 设置PixelStreaming事件监听器
const setupPixelStreamingEvents = () => {
  if (!pixelStreaming) return

  pixelStreaming.addEventListener('streamReady', () => {
    ueStatus.value = '已连接'
    errorMessage.value = ''
  })

  pixelStreaming.addEventListener('connectionEstablished', () => {
    ueStatus.value = '已连接'
    errorMessage.value = ''
  })

  pixelStreaming.addEventListener('connectionClose', () => {
    ueStatus.value = '连接断开'
  })

  pixelStreaming.addEventListener('connectionError', (error) => {
    ueStatus.value = '连接失败'
    errorMessage.value = `UE连接错误: ${error}`
  })

  pixelStreaming.addEventListener('webRTCConnected', () => {
    ueStatus.value = '已连接'
  })

  pixelStreaming.addEventListener('webRTCDisconnected', () => {
    ueStatus.value = '连接断开'
  })
}

事件说明

  • streamReady:视频流准备就绪
  • connectionEstablished:连接建立成功
  • connectionClose:连接关闭
  • connectionError:连接错误
  • webRTCConnected:WebRTC连接成功
  • webRTCDisconnected:WebRTC连接断开

5. MQTT连接初始化

javascript 复制代码
// 初始化MQTT连接
const initMqtt = () => {
  try {
    const options = {
      username: 'admin',
      password: 'public',
      clientId: `vue_client_${Math.random().toString(16).substr(2, 8)}`,
      clean: true,
      reconnectPeriod: 5000,
      connectTimeout: 30 * 1000,
      keepalive: 60,
      protocolVersion: 4
    }

    mqttClient = mqtt.connect('此处输入MQTT地址', options) // 地址末尾需要加:/mqtt

    mqttClient.on('connect', () => {
      mqttStatus.value = '已连接'
      mqttClient.subscribe('此处输入订阅主题的路径')
    })

    mqttClient.on('error', (error) => {
      mqttStatus.value = '连接失败'
    })

    mqttClient.on('close', () => {
      mqttStatus.value = '连接断开'
    })

    mqttClient.on('message', (topic, message) => {
      // 处理MQTT消息
      console.log(`收到MQTT消息 [${topic}]: ${message.toString()}`)
    })
  } catch (error) {
    mqttStatus.value = '初始化失败'
  }
}

MQTT配置说明

  • username/password:MQTT认证信息
  • clientId:客户端唯一标识
  • reconnectPeriod:重连间隔(5秒)
  • connectTimeout:连接超时(30秒)
  • keepalive:心跳间隔(60秒)

6. 重新连接功能

javascript 复制代码
const reconnect = () => {
  errorMessage.value = ''
  
  if (pixelStreaming) {
    try {
      pixelStreaming.close()
    } catch (error) {
      console.warn('PixelStreaming断开连接时出错:', error)
    }
    pixelStreaming = null
  }

  if (mqttClient) {
    mqttClient.end()
    mqttClient = null
  }

  ueStatus.value = '未连接'
  mqttStatus.value = '未连接'

  setTimeout(() => {
    initPixelStreaming()
    initMqtt()
  }, 1000)
}

重连流程

  1. 清空错误信息
  2. 关闭现有连接
  3. 重置状态
  4. 延迟1秒后重新初始化

7. 生命周期管理

javascript 复制代码
// 生命周期
onMounted(() => {
  initPixelStreaming()
  initMqtt()
})

onUnmounted(() => {
  if (pixelStreaming) {
    try {
      pixelStreaming.close()
    } catch (error) {
      console.warn('PixelStreaming清理时出错:', error)
    }
  }
  
  if (mqttClient) {
    mqttClient.end()
  }
})

说明

  • onMounted:组件挂载时初始化连接
  • onUnmounted:组件卸载时清理连接

常见问题及解决方案

1. 连接超时问题
javascript 复制代码
// 检查网络连接
const checkNetworkConnection = () => {
  const testUrl = 'wss://192.168.110.176'
  const testSocket = new WebSocket(testUrl)
  
  testSocket.onopen = () => {
    console.log('网络连接正常')
    testSocket.close()
  }
  
  testSocket.onerror = (error) => {
    console.log(`网络连接失败: ${error}`)
    console.log('请检查服务器地址和网络连接')
  }
}
2. MQTT连接失败
javascript 复制代码
// MQTT连接测试
const testMqttConnection = () => {
  const testClient = mqtt.connect('ws://192.168.110.176:8083/mqtt', {
    username: 'admin',
    password: 'public',
    clientId: `test_client_${Date.now()}`,
    clean: true,
    connectTimeout: 5000
  })
  
  testClient.on('connect', () => {
    console.log('MQTT连接成功')
    testClient.end()
  })
  
  testClient.on('error', (error) => {
    console.log(`MQTT连接失败: ${error.message}`)
    console.log('请检查MQTT服务器状态和认证信息')
    testClient.end()
  })
}

自动重连机制

WebSocket自动重连

javascript 复制代码
nativeWebSocket.onclose = (event) => {
  console.log(`UE WebSocket连接已关闭 (代码: ${event.code})`)
  isConnected.value = false
  connectionStatus.type = 'danger'
  connectionStatus.text = '连接断开'
  
  // 自动重连
  if (event.code !== 1000) { // 不是正常关闭
    console.log('5秒后尝试重新连接...')
    setTimeout(() => {
      if (!isConnected.value) {
        initNativeWebSocket()
      }
    }, 5000)
  }
}

MQTT自动重连

javascript 复制代码
const mqttOptions = {
  reconnectPeriod: 5000, // 5秒重连间隔
  connectTimeout: 30 * 1000, // 30秒连接超时
  keepalive: 60 // 60秒心跳
}

Over!

相关推荐
华仔啊3 小时前
基于 RuoYi-Vue 轻松实现单用户登录功能,亲测有效
java·vue.js·后端
程序员鱼皮3 小时前
刚刚 Java 25 炸裂发布!让 Java 再次伟大
java·javascript·计算机·程序员·编程·开发·代码
Asort3 小时前
JavaScript 从零开始(五):运算符和表达式——从零开始掌握算术、比较与逻辑运算
前端·javascript
一枚前端小能手3 小时前
🚀 缓存用错了网站更慢?前端缓存策略的5个致命误区
前端·javascript
艾小码3 小时前
为什么你的页面会闪烁?useLayoutEffect和useEffect的区别藏在这里!
前端·javascript·react.js
艾小码3 小时前
告别Vue混入的坑!Composition API让我效率翻倍的3个秘密
前端·javascript·vue.js
小高0073 小时前
🔍说说对React的理解?有哪些特性?
前端·javascript·react.js
烛阴3 小时前
【TS 设计模式完全指南】懒加载、缓存与权限控制:代理模式在 TypeScript 中的三大妙用
javascript·设计模式·typescript
Samsong3 小时前
JavaScript逆向之反制无限debugger陷阱
前端·javascript