QT+Unity3D连接
在QT中连接unity3D,首先要有一个unity.exe执行文件。在这里不提供unity执行文件的编写,只提供QT这边与unity3D连接和信息传递。
创建项目
创建一个新的项目,我创建的项目名称如下。
下图是我建立新项目的文件。APP文件就是我的unity.exe执行文件。
打开APP文件,里面就是关于unity3D的东西了。
直接上代码(看注释更通透)
在unityConnect.pro 文件中添加QT += network模块。
javascript
QT += core gui
QT += network
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++17
# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
UnityConfigure.cpp \
main.cpp \
UnityShow.cpp
HEADERS += \
UnityConfigure.h \
UnityShow.h
FORMS += \
UnityShow.ui
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
在UnityConfigure.h中。
javascript
#ifndef UNITYCONFIGURE_H
#define UNITYCONFIGURE_H
#include <QObject>
#include <QProcess>
#include <windows.h>
#include <winuser.h>
#include <qDebug>
class UnityConfigure : public QObject
{
Q_OBJECT
public:
explicit UnityConfigure(QObject *parent = nullptr);
~UnityConfigure();
void startUnityProgram(const QString& unityExePath);
void setWindowParent(HWND parentWidgetHandle, const QString& sonWindowTitleName);
QProcess* process;
signals:
void unityProgramStarted();
};
#endif // UNITYCONFIGURE_H
在UnityConfigure.cpp中。
javascript
#include "UnityConfigure.h"
UnityConfigure::UnityConfigure(QObject *parent)
: QObject{parent}
{
process = new QProcess(this);//创建一个新的进程
connect(process, &QProcess::started, this, &UnityConfigure::unityProgramStarted);//将进程与unity连接起来
}
UnityConfigure::~UnityConfigure()//用于关闭
{
process->kill();//关闭进程
}
void UnityConfigure::startUnityProgram(const QString& unityExePath)
{
process->setProgram(unityExePath);//设置unity路径
process->start(QIODevice::Truncate);//启动进程
}
void UnityConfigure::setWindowParent(HWND parentWidgetHandle, const QString& sonWindowTitleName)//设置unity窗口属性
{
std::wstring titleName = sonWindowTitleName.toStdWString();//设置unity标题
HWND hfigure = nullptr;
while (true)
{
hfigure = FindWindowW(nullptr, titleName.c_str());
if (hfigure != nullptr)
{
break;
}
}
RECT rect;
GetWindowRect(parentWidgetHandle, &rect);//得到你要嵌入QT控件窗口的大小
SetParent(hfigure, parentWidgetHandle);//将unity嵌入到QT控件中
LONG_PTR dwStyle = GetWindowLongPtr(hfigure, GWL_STYLE);//子窗口样式
dwStyle = dwStyle & ~(WS_THICKFRAME | WS_CAPTION | WS_SIZEBOX | WS_MAXIMIZEBOX | WS_MINIMIZEBOX);//移除子窗口的移动和调整大小的样式
//如果想要使用unity缩放功能,就需要把"dwStyle |= WS_CHILD | WS_CLIPCHILDREN;"这行注释掉就可以了
dwStyle |= WS_CHILD | WS_CLIPCHILDREN;//添加固定位置的样式。WS_CHILD 表示这是一个子窗口,WS_CLIPCHILDREN 表示绘制子窗口时,只绘制子窗口区域内的内容。
SetWindowLongPtr(hfigure, GWL_STYLE, dwStyle);//更新子窗口的样式
//这段代码用于改变unity窗口在QT控件中的位置以及大小。
// MoveWindow(hfigure, 0, 0, 1400, 870, false);
// SetWindowPos(hfigure, HWND_TOP, 0, 0, 1400, 870, SWP_SHOWWINDOW |SWP_HIDEWINDOW);
// ShowWindow(hfigure, SW_SHOW);
// SetFocus(hfigure);
}
在UnityShow.h中。
javascript
#ifndef UNITYSHOW_H
#define UNITYSHOW_H
#include <QMainWindow>
#include "UnityConfigure.h"
#include <QTcpSocket>
QT_BEGIN_NAMESPACE
namespace Ui { class UnityShow; }
QT_END_NAMESPACE
class UnityShow : public QMainWindow
{
Q_OBJECT
UnityConfigure* unity;
QTcpSocket* tcpSocket;
public:
UnityShow(QWidget *parent = nullptr);
~UnityShow();
void onReceive();//接收数据
void onSend();//发送数据
private slots:
void onConnected();//连接建立时的处理
void onDisconnected();//连接断开时的处理
private:
Ui::UnityShow *ui;
};
#endif // UNITYSHOW_H
在UnityShow.cpp中。
javascript
#include "UnityShow.h"
#include "ui_UnityShow.h"
UnityShow::UnityShow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::UnityShow)
{
ui->setupUi(this);
unity = new UnityConfigure(this);
QString titleName("1025using");//创建标题,切记要与unity执行文件名字相同,要不然无法嵌入到QT中
QString unityExePath("./APP/1025using.exe");//读取unity路径
//将QT与unity进行连接
connect(unity, &UnityConfigure::unityProgramStarted, this, [&]()
{
unity->setWindowParent((HWND)ui->unityWidget->winId(),titleName);
});
unity->startUnityProgram(unityExePath);//启动unity
tcpSocket = new QTcpSocket(this);//创建TCP通信
tcpSocket->connectToHost("127.0.0.1", 9999);//进行和unity接口连接,这个接口是在unity里面进行设置的,QT直接用就行。
connect(tcpSocket, &QTcpSocket::connected, this, &UnityShow::onConnected);
connect(tcpSocket, &QTcpSocket::disconnected, this, &UnityShow::onDisconnected);
onSend();//进行发送消息
}
UnityShow::~UnityShow()
{
delete ui;
}
void UnityShow::onConnected()
{
// 连接建立时的处理
qDebug()<<"Connected successfully!";
}
void UnityShow::onDisconnected()
{
// 连接断开时的处理
qDebug()<<"disConnected successfully!";
}
void UnityShow::onReceive()
{
// 接收unity发送的命令,收到命令之后去执行QT这边的操作。
QByteArray data = tcpSocket->readAll();
}
void UnityShow::onSend()
{
/*
* 发送信息,BulletEyeRendezvous这条信息是在unity中进行设置的,
* 然后在QT中进行发送这条消息即可。发完之后unity会执行这条信息,
* 去执行unity接下来的程序。
*/
QString msg="BulletEyeRendezvous";//unity设置的命令
tcpSocket->write(msg.toUtf8());//进行发送命令
}
在UnityShow.ui 中,定义一个Widget 控件即可。
运行结果
如果不想出现下面的unity边框,就在UnityConfigure.cpp 中加上这行代码dwStyle |= WS_CHILD | WS_CLIPCHILDREN; 加完之后就不能使用unity缩放功能。
如果想要使用unity缩放功能,就需要把dwStyle |= WS_CHILD | WS_CLIPCHILDREN; 这行注释掉就可以了,但会出现unity边框。
目前我还没找到两全其美的办法,如果哪位大佬有更好的解决方法,欢迎您在评论区留言。