Unity+QT, 如何把Unity打包出的exe嵌入QT程序中,并且使用Socket进行交互

1 篇文章 0 订阅

概要

在 VR 开发中,常常需要桌面窗口和 VR 头盔使用者进行交互。通过将 Unity制作的 VR 程序嵌入到 QT 应用程序窗口中,并使用 Socket进行通信,可以实现这种交互。本文将介绍如何实现这一功能。

前期准备

  1. Unity 项目打包 首先,在 Unity 中开发并打包您的项目为可执行文件(EXE)。确保您已经测试过独立运行的 EXE 并且一切正常。

  2. QT 环境设置 安装并配置好 QT 开发环境。如果您还没有 QT 安装,可以访问 QT 官方网站 下载和安装。

QT 与 Unity 的 Socket 通信

  1. QT 服务器设置 在 QT 中,使用 QUdpSocket 创建一个 UDP 服务器来接收来自 Unity 的数据,在QT程序初始化时用QProcess启动Unity程序,并且等待Unity程序连接,Unity程序连接后获取Unity程序的窗口句柄,并把这个窗口嵌入到QT中:
#include <QPushButton>
#include <QVBoxLayout>
#include <QtNetwork>
#include "QProcess"
class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr) : QMainWindow(parent)
    {
        QUdpSocket* socket = new QUdpSocket(this);
		socket->bind(QHostAddress("127.0.0.1"), 6060);
		connect(socket, SIGNAL(readyRead()), this, SLOT(readData()));

		QProcess* process = new QProcess(this);
		QString cmd = "path/to/your/VRUnityApp.exe";
		process->start(cmd, QStringList() << "");
 
        QVBoxLayout *layout = new QVBoxLayout;
        QWidget *centralWidget = new QWidget(this);
        centralWidget->setLayout(layout);
        setCentralWidget(centralWidget);

        QPushButton *switchSceneButton = new QPushButton("Switch Scene", this);
        QPushButton *createObjectButton = new QPushButton("Create Object", this);

        layout->addWidget(switchSceneButton);
        layout->addWidget(createObjectButton);

        connect(switchSceneButton, &QPushButton::clicked, [server]() {
            sendData("switch_scene");
        });

        connect(createObjectButton, &QPushButton::clicked, [server]() {
            sendData("create_object");
        });
    }
    void sendData(const QString& data)
    {
    	for (int i = 0; i < m_client.count(); i++) {
			QString str = m_client.at(i);
			QStringList list = str.split(":");
			QByteArray buffer;
			buffer = data.toUtf8();
			socket->writeDatagram(buffer, QHostAddress(list.at(0)), list.at(1).toInt());
		}
    }
    void OnDataRecived(const QString& msg)
    {
    	if (msg == "Connect")
		{
			WId wid = (WId)FindWindow(L"XXXXX", NULL);//获取窗口句柄
			m_window = QWindow::fromWinId(wid);
			m_window->setFlags(m_window->flags() | Qt::CustomizeWindowHint | Qt::WindowTitleHint);
	
			QWidget* m_widget;
			m_widget = QWidget::createWindowContainer(m_window, this);
			ui->containerWidget->layout()->addWidget(m_widget);
		}
    }
 private slots:
    void readData()
    {
    	QHostAddress host;
		quint16 port;
		QByteArray data;
		QString buffer;
		
		while (socket->hasPendingDatagrams()) {
			data.resize(socket->pendingDatagramSize());
			socket->readDatagram(data.data(), data.size(), &host, &port);
		
			buffer = QString(data);
			OnDataRecived(buffer);
			QString ip = host.toString();
			ip = ip.replace("::ffff:", "");
			if (ip.isEmpty()) {
				continue;
			}
		
			QString str = QString("[%1:%2] %3").arg(ip).arg(port);
		
			//先过滤重复的
			str = QString("%1:%2").arg(ip).arg(port);
			for (int i = 0; i < m_client.count(); i++) {
				if (str == m_client.at(i)) {
					return;
				}
			}
			//添加到列表
			m_client.push_back(str);
		}
    }
};
  1. Unity 客户端设置 在 Unity 中,使用 System.Net.Sockets.UdpClient 创建一个 UDP 客户端,并向 QT 服务器发送数据:
public class UnityClient : MonoBehaviour
{
    private UdpClient client;

    void Start()
    {
        client = new UdpClient();
        SendMessageToServer("Connect");
        client.BeginReceive(OnReceive, null);
    }

    void SendMessageToServer(string message)
    {
        byte[] data = Encoding.UTF8.GetBytes(message);
        client.Send(data, data.Length, "127.0.0.1", 12345);
    }

	private void OnReceive(IAsyncResult ar)
    {
        IPEndPoint endpoint = new IPEndPoint(System.Net.IPAddress.Any, 54321);
        byte[] data = client.EndReceive(ar, ref endpoint);
        string command = Encoding.UTF8.GetString(data);

        Debug.Log("Received command: " + command);

        // 根据命令执行相应的操作
        if (command == "switch_scene")
        {
            SwitchScene();
        }
        else if (command == "create_object")
        {
            CreateObject();
        }

        // 继续接收下一个命令
        client.BeginReceive(OnReceive, null);
    }

    void SwitchScene()
    {
        // 切换到另一个场景
        SceneManager.LoadScene("AnotherScene");
    }

    void CreateObject()
    {
        // 创建一个简单的游戏物体
        GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
        cube.transform.position = new Vector3(0, 1, 0);
    }

    void OnDestroy()
    {
        client.Close();
    }
}

此脚本在 Unity 中启动时会向 QT 服务器发送一条消息。QT收到消息后会获取Unity程序的窗口句柄,并把这个窗口嵌入到QT中

实际应用场景

通过上述设置,QT 程序可以在桌面上实时控制 VR 场景中的行为,例如切换场景或创建游戏物体。这种交互方式适用于各种需要实时控制 VR 场景的应用场景,比如 VR 培训、虚拟展览等。

总结

本文详细介绍了如何通过 QT 服务器向 Unity VR 程序发送命令,以实现场景切换和游戏物体创建等交互功能。通过 UDP 进行通讯,您可以实现桌面和 VR 头盔之间的无缝互动,提升用户体验。如果您在实施过程中遇到问题或有其他需求,欢迎交流讨论。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱写代码的辰洋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值