我正在构建用户界面服务器/客户端。为了复制问题,我准备了一个MVCE来复制我遇到的问题。
GUI的描述如下:服务器计算机具有一个QGraphicsView,其中{。{1}}和障碍物的边界内有N.1个绿色方块在移动。 一旦正方形碰到边界或障碍物,服务器计算机应将带有碰撞坐标的消息发送给客户端。
为了运行示例,步骤如下:
1)设置客户端和服务器上的端口号(端口号必须相同)
2)准备要从服务器发送到客户端的消息
3)连接客户端
4)将消息从服务器发送到客户端
5)等到正方形碰到边界或障碍物
6)服务器应尽快将冲突的坐标发送给客户端。 (我被困在最后一点)
请参见下图描述
到目前为止我尝试过的事情:
从this post看来,从/向服务器计算机发送的消息应该具有优先级。但是,我可以成功地将消息从服务器发送到客户端。
还根据this source,为了不丢失应该设置多个数据报的信息。
此外,始终使用the same post的UDP和TCP可能是造成数据丢失的主要原因。
请参见下面的复制问题的代码:
UDP客户端
widget.h
QGraphicsScene
widget.cpp
namespace Ui {
class Widget;
}
class QUdpSocket;
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = nullptr);
~Widget();
private slots:
void on_connectBtn_clicked();
private:
Ui::Widget *ui;
QUdpSocket *mSocket;
};
#endif // WIDGET_H
UDP服务器
widget.h
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
mSocket = new QUdpSocket(this);
setWindowTitle("Client Machine");
connect(mSocket, &QUdpSocket::readyRead, [&]() {
if(mSocket->hasPendingDatagrams()) {
QByteArray datagram;
datagram.resize(mSocket->pendingDatagramSize());
mSocket->readDatagram(datagram.data(), datagram.size());
ui->listWidget->addItem(QString(datagram));
}
});
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_connectBtn_clicked()
{
mSocket->bind(ui->portSpinBoxClient->value(), QUdpSocket::ShareAddress);
}
widget.cpp
#include <QWidget>
#include <QGraphicsItem>
namespace Ui {
class Widget;
}
class QUdpSocket;
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = nullptr);
~Widget();
private slots:
void on_sendBtn_clicked();
void on_pushButton_clicked();
private:
Ui::Widget *ui;
QUdpSocket *mSocket;
QGraphicsScene *scene;
QTimer *timer;
QGraphicsRectItem *itemRect;
#endif // WIDGET_H
最后是检测到碰撞对象的类:
myitem.h
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
mSocket = new QUdpSocket(this);
setWindowTitle("Server Machine");
scene = new QGraphicsScene(this);
itemRect = new QGraphicsRectItem();
ui->graphicsView->setScene(scene);
ui->graphicsView->setRenderHint(QPainter::Antialiasing);
scene->setSceneRect(-200, -200, 300, 300);
QBrush darkBrush(Qt::darkRed);
QPen darkRedPen(Qt::darkRed);
itemRect = scene->addRect(-100, -100, 30, 100, darkRedPen, darkBrush);
itemRect->setFlag(QGraphicsItem::ItemIsMovable);
QPen myPen = QPen(Qt::red);
QLineF TopLine(scene->sceneRect().topLeft(), scene->sceneRect().topRight());
QLineF LeftLine(scene->sceneRect().topLeft(), scene->sceneRect().bottomLeft());
QLineF RightLine(scene->sceneRect().topRight(), scene->sceneRect().bottomRight());
QLineF Bottom(scene->sceneRect().bottomLeft(), scene->sceneRect().bottomRight());
scene->addLine(TopLine, myPen);
scene->addLine(LeftLine, myPen);
scene->addLine(RightLine, myPen);
scene->addLine(Bottom, myPen);
int itemCount = 1;
for(int i = 0; i < itemCount; i++) {
MyItem *item = new MyItem();
scene->addItem(item);
}
timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), scene, SLOT(advance()));
timer->start(100);
ui->pushButton->setStyleSheet("QPushButton{ background-color: grey }");
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_sendBtn_clicked()
{
auto datagram = ui->msgLineEdit->text().toLatin1();
mSocket->writeDatagram(datagram, QHostAddress::Broadcast,ui->spinBox->value());
}
void Widget::on_pushButton_clicked()
{
ui->pushButton->setStyleSheet("QPushButton{ background-color: green }");
ui->pushButton->setText("Stop");
}
myitem.cpp
class MyItem : public QGraphicsItem
{
public:
MyItem();
QRectF boundingRect() const;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
protected:
void advance(int phase);
private:
qreal angle;
qreal speed;
void doCollision();
};
#endif // MYITEM_H
预期结果:绿色方块碰到#include "myitem.h"
MyItem::MyItem()
{
angle = (qrand() % 360);
setRotation(angle);
speed = 5;
int startX = 0;
int startY = 0;
if((qrand() % 1)){
startX = (qrand() % 200);
startY = (qrand() % 200);
}else{
startX = (qrand() % -100);
startY = (qrand() % -100);
}
setPos(mapToParent(startX, startY));
}
QRectF MyItem::boundingRect() const
{
return QRect(0, 0, 30, 30);
}
void MyItem::paint(QPainter *painter,
const QStyleOptionGraphicsItem *option,
QWidget *widget)
{
QRectF rec = boundingRect();
QBrush brush(Qt::gray);
if(scene()->collidingItems(this).isEmpty()){
brush.setColor(Qt::green); // no collision
}else{
brush.setColor(Qt::red); // yes collision
doCollision();
}
painter->fillRect(rec, brush);
painter->drawRect(rec);
}
void MyItem::advance(int phase)
{
if(!phase) return;
QPointF location = this->pos();
setPos(mapToParent(0, -(speed)));
}
void MyItem::doCollision()
{
if((qrand() %1)) {
setRotation(rotation() + (180+(qrand() % 10)));
}else{
setRotation(rotation() + (180+(qrand() % -10)));
}
// see if the new position is in bounds
QPointF newPoint = mapToParent(-(boundingRect().width()), -(boundingRect().width() + 2));
if(!scene()->sceneRect().contains((newPoint))){
newPoint = mapToParent(0, 0); // move it back in bounds
}else{
setPos(newPoint); // set new position
}
}
或对象的边界后,应将碰撞坐标发送给客户端。
实际结果:如何将冲突坐标发送给客户?
任何有关如何解决此问题的见解都将非常有用。