Bluetooth QML Ping Pong example¶
A QML example showing Bluetooth communication.
The Bluetooth QML Ping Pong example presents the socket communication between two Bluetooth devices. The basic concept is the ping pong game where two players communicate via sockets.
Running the Example¶
To run the example from Qt Creator , open the Welcome mode and select the example from Examples. For more information, visit Building and Running an Example.
At the beginning, the user selects the role. One device acts as a server and the second one as a client. The server side starts a service named “PingPong server”.
m_serverInfo = QBluetoothServer(QBluetoothServiceInfo.RfcommProtocol, self) connect(m_serverInfo, QBluetoothServer.newConnection, self, PingPong::clientConnected) connect(m_serverInfo, QBluetoothServer.errorOccurred, self, PingPong.serverError) uuid = QBluetoothUuid(serviceUuid) m_serverInfo.listen(uuid, QStringLiteral("PingPong server"))
On the client side, the full service discovery on the nearby Bluetooth devices is done.
discoveryAgent = QBluetoothServiceDiscoveryAgent(QBluetoothAddress()) connect(discoveryAgent, QBluetoothServiceDiscoveryAgent.serviceDiscovered, self, PingPong::addService) connect(discoveryAgent, QBluetoothServiceDiscoveryAgent.finished, self, PingPong::done) connect(discoveryAgent, QBluetoothServiceDiscoveryAgent.errorOccurred, self, PingPong::serviceScanError) #ifdef Q_OS_ANDROID //see QTBUG-61392 if (QNativeInterface.QAndroidApplication.sdkVersion() >= 23) discoveryAgent.setUuidFilter(QBluetoothUuid(androidUuid)) else: discoveryAgent.setUuidFilter(QBluetoothUuid(serviceUuid)) #else discoveryAgent.setUuidFilter(QBluetoothUuid(serviceUuid)) #endif discoveryAgent.start(QBluetoothServiceDiscoveryAgent.FullDiscovery)
When the ping pong service is discovered, the client connects to the server using the socket.
socket = QBluetoothSocket(QBluetoothServiceInfo.RfcommProtocol) socket.connectToService(service) connect(socket, QBluetoothSocket.readyRead, self, PingPong.readSocket) connect(socket, QBluetoothSocket.connected, self, PingPong.serverConnected) connect(socket, QBluetoothSocket.disconnected, self, PingPong.serverDisconnected)
On the server side, the connected signal is emitted initiating that the client is connected. The necessary signals and slots on the server side are connected.
if (not m_serverInfo.hasPendingConnections()) { setMessage("FAIL: expected pending server connection") return socket = m_serverInfo.nextPendingConnection() if (not socket) return socket.setParent(self) connect(socket, QBluetoothSocket.readyRead, self, PingPong::readSocket) connect(socket, QBluetoothSocket.disconnected, self, PingPong::clientDisconnected) connect(socket, QBluetoothSocket.errorOccurred, self, PingPong.socketError)
The game starts after the devices are connected and the screen is adjusted.
m_timer.start(10)
The server updates the ball direction and coordinates. The coordinates of pedals are sent to each other every 10ms.
if (m_role == 1) { checkBoundaries() m_ballY += m_speedy m_ballX += m_speedx size.setNum(m_ballX) size.append(' ') size1 = QByteArray() size1.setNum(m_ballY) size.append(size1) size.append(' ') size1.setNum(m_leftBlockY) size.append(size1) size.append(" \n") socket.write(size.constData()) ballChanged.emit() elif m_role == 2: size.setNum(m_rightBlockY) size.append(" \n") socket.write(size.constData())
The coordinates are updated and exchanged via sockets. As presented, the server sends its pedal’s y coordinate and the ball coordinates whereas, the client sends only its pedal y coordinate.
if (((m_ballX + ballWidth) > (1. - blockSize)) and (ballCenterY < (m_rightBlockY + blockHeight)) and (ballCenterY > m_rightBlockY)) { # right paddle collision # simulating paddle surface to be a quarter of a circle paddlecenter = m_rightBlockY + blockHeight / 2. relpos = (ballCenterY - paddlecenter) / (blockHeight / 2.) # [-1 : 1] surfaceangle = M_PI_4 * relpos() # calculation of surface normal normalx = -cos(surfaceangle) normaly = sin(surfaceangle) # calculation of surface tangent tangentx = sin(surfaceangle) tangenty = cos(surfaceangle) # calculation of tangentialspeed tangentialspeed = tangentx * m_speedx + tangenty * m_speedy # calculation of normal speed normalspeed = normalx * m_speedx + normaly * m_speedy # speed increase of 10% = 1.1f if (normalspeed < 0) { // if we are coming from the left. To avoid float reflections m_speedx = tangentialspeed * tangentx - normalspeed * normalx m_speedy = tangentialspeed * tangenty - normalspeed * normaly } else if ((m_ballX < blockSize) and (ballCenterY < (m_leftBlockY + blockHeight)) and (ballCenterY > m_leftBlockY)) { # left paddle collision # simulating paddle surface to be a quarter of a circle paddlecenter = m_leftBlockY + blockHeight / 2. relpos = (ballCenterY - paddlecenter) / (blockHeight / 2.) # [-1 : 1] surfaceangle = M_PI_4 * relpos() # calculation of surface normal normalx = cos(surfaceangle) normaly = sin(surfaceangle) # calculation of surface tangent tangentx = -sin(surfaceangle) tangenty = cos(surfaceangle) # calculation of tangentialspeed tangentialspeed = tangentx * m_speedx + tangenty * m_speedy # calculation of normal speed normalspeed = normalx * m_speedx + normaly * m_speedy # speed increase of 10% = 1.1f if (normalspeed < 0) { // if we are coming from the left. To avoid float reflections m_speedx = tangentialspeed * tangentx - normalspeed * normalx m_speedy = tangentialspeed * tangenty - normalspeed * normaly } else if (m_ballY < 0) { m_speedy = std::abs(m_speedy) } else if (m_ballY + ballWidth > 1.f) { m_speedy = -std::abs(m_speedy)
In the code above, it was shown how the server checks whether the ball has reached the boundaries of the board. In case of a collision with a pedal, a convex surface is simulated. The part of the velocity normal to the simulated surface is inverted and increased by 10% to speed up the game. In the case of the goal, the server updates the results via its socket.
© 2022 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.