pingpong.cpp Example File
pingpong/pingpong.cpp
/***************************************************************************
**
** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the QtBluetooth module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** BSD License Usage
** Alternatively, you may use this file under the terms of the BSD license
** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of The Qt Company Ltd nor the names of its
** contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "pingpong.h"
#include <QDebug>
#ifdef Q_OS_ANDROID
#include <QtAndroid>
#endif
PingPong:: PingPong():
m_serverInfo(0 ), socket(0 ), discoveryAgent(0 ), interval(5 ), m_resultLeft(0 ), m_resultRight(0 ),
m_showDialog(false ), m_role(0 ), m_proportionX(0 ), m_proportionY(0 ), m_serviceFound(false )
{
m_timer = new QTimer (this );
connect(m_timer, & QTimer :: timeout, this , & PingPong:: update);
}
PingPong:: ~ PingPong()
{
delete m_timer;
delete m_serverInfo;
delete socket;
delete discoveryAgent;
}
void PingPong:: startGame()
{
m_showDialog = false ;
emit showDialogChanged();
if (m_role = = 1 )
updateDirection();
m_timer- > start(50 );
}
void PingPong:: update()
{
QByteArray size;
// Server is only updating the coordinates
if (m_role = = 1 ) {
checkBoundaries();
m_ballPreviousX = m_ballX;
m_ballPreviousY = m_ballY;
m_ballY = m_direction* (m_ballX+ interval) - m_direction* m_ballX + m_ballY;
m_ballX = m_ballX + interval;
size. setNum(m_ballX);
size. append(' ' );
QByteArray size1;
size1. setNum(m_ballY);
size. append(size1);
size. append(' ' );
size1. setNum(m_leftBlockY);
size. append(size1);
size. append(" \n" );
socket- > write(size. constData());
emit ballChanged();
}
else if (m_role = = 2 ) {
size. setNum(m_rightBlockY);
size. append(" \n" );
socket- > write(size. constData());
}
}
void PingPong:: setSize(const float & x, const float & y)
{
m_boardWidth = x;
m_boardHeight = y;
m_targetX = m_boardWidth;
m_targetY = m_boardHeight/ 2 ;
m_ballPreviousX = m_ballX = m_boardWidth/ 2 ;
m_ballPreviousY = m_ballY = m_boardHeight - m_boardWidth/ 54 ;
emit ballChanged();
}
void PingPong:: updateBall(const float & bX, const float & bY)
{
m_ballX = bX;
m_ballY = bY;
}
void PingPong:: updateLeftBlock(const float & lY)
{
m_leftBlockY = lY;
}
void PingPong:: updateRightBlock(const float & rY)
{
m_rightBlockY = rY;
}
void PingPong:: checkBoundaries()
{
float ballWidth = m_boardWidth/ 54 ;
float blockSize = m_boardWidth/ 27 ;
float blockHeight = m_boardHeight/ 5 ;
if (((m_ballX + ballWidth) > (m_boardWidth - blockSize)) & & ((m_ballY + ballWidth) < (m_rightBlockY + blockHeight))
& & (m_ballY > m_rightBlockY)) {
m_targetY = 2 * m_ballY - m_ballPreviousY;
m_targetX = m_ballPreviousX;
interval = - 5 ;
updateDirection();
}
else if ((m_ballX < blockSize) & & ((m_ballY + ballWidth) < (m_leftBlockY + blockHeight))
& & (m_ballY > m_leftBlockY)) {
m_targetY = 2 * m_ballY - m_ballPreviousY;
m_targetX = m_ballPreviousX;
interval = 5 ;
updateDirection();
}
else if (m_ballY < 0 | | (m_ballY + ballWidth > m_boardHeight)) {
m_targetY = m_ballPreviousY;
m_targetX = m_ballX + interval;
updateDirection();
}
else if ((m_ballX + ballWidth) > m_boardWidth) {
m_resultLeft+ + ;
m_targetX = m_boardWidth;
m_targetY = m_boardHeight/ 2 ;
m_ballPreviousX = m_ballX = m_boardWidth/ 2 ;
m_ballPreviousY = m_ballY = m_boardHeight - m_boardWidth/ 54 ;
updateDirection();
checkResult();
QByteArray result;
result. append("result " );
QByteArray res;
res. setNum(m_resultLeft);
result. append(res);
result. append(' ' );
res. setNum(m_resultRight);
result. append(res);
result. append(" \n" );
socket- > write(result);
qDebug () < < result;
emit resultChanged();
}
else if (m_ballX < 0 ) {
m_resultRight+ + ;
m_targetX = 0 ;
m_targetY = m_boardHeight/ 2 ;
m_ballPreviousX = m_ballX = m_boardWidth/ 2 ;
m_ballPreviousY = m_ballY = m_boardHeight - m_boardWidth/ 54 ;
updateDirection();
checkResult();
QByteArray result;
result. append("result " );
QByteArray res;
res. setNum(m_resultLeft);
result. append(res);
result. append(' ' );
res. setNum(m_resultRight);
result. append(res);
result. append(" \n" );
socket- > write(result);
emit resultChanged();
}
}
void PingPong:: checkResult()
{
if (m_resultRight = = 10 & & m_role = = 2 ) {
setMessage("Game over. You win!" );
m_timer- > stop();
}
else if (m_resultRight = = 10 & & m_role = = 1 ) {
setMessage("Game over. You lose!" );
m_timer- > stop();
}
else if (m_resultLeft = = 10 & & m_role = = 1 ) {
setMessage("Game over. You win!" );
m_timer- > stop();
}
else if (m_resultLeft = = 10 & & m_role = = 2 ) {
setMessage("Game over. You lose!" );
m_timer- > stop();
}
}
void PingPong:: updateDirection()
{
m_direction = (m_targetY - m_ballY)/ (m_targetX - m_ballX);
}
void PingPong:: startServer()
{
setMessage(QStringLiteral ("Starting the server" ));
m_serverInfo = new QBluetoothServer (QBluetoothServiceInfo :: RfcommProtocol, this );
connect(m_serverInfo, & QBluetoothServer :: newConnection,
this , & PingPong:: clientConnected);
connect(m_serverInfo, QOverload < QBluetoothServer :: Error> :: of(& QBluetoothServer :: error),
this , & PingPong:: serverError);
const QBluetoothUuid uuid(serviceUuid);
m_serverInfo- > listen(uuid, QStringLiteral ("PingPong server" ));
setMessage(QStringLiteral ("Server started, waiting for the client. You are the left player." ));
// m_role is set to 1 if it is a server
m_role = 1 ;
emit roleChanged();
}
void PingPong:: startClient()
{
discoveryAgent = new QBluetoothServiceDiscoveryAgent (QBluetoothAddress ());
connect(discoveryAgent, & QBluetoothServiceDiscoveryAgent :: serviceDiscovered,
this , & PingPong:: addService);
connect(discoveryAgent, & QBluetoothServiceDiscoveryAgent :: finished,
this , & PingPong:: done);
connect(discoveryAgent, QOverload < QBluetoothServiceDiscoveryAgent :: Error> :: of(& QBluetoothServiceDiscoveryAgent :: error),
this , & PingPong:: serviceScanError);
#ifdef Q_OS_ANDROID //see QTBUG-61392
if (QtAndroid :: androidSdkVersion() > = 23 )
discoveryAgent- > setUuidFilter(QBluetoothUuid (androidUuid));
else
discoveryAgent- > setUuidFilter(QBluetoothUuid (serviceUuid));
#else
discoveryAgent- > setUuidFilter(QBluetoothUuid (serviceUuid));
#endif
discoveryAgent- > start(QBluetoothServiceDiscoveryAgent :: FullDiscovery);
setMessage(QStringLiteral ("Starting server discovery. You are the right player" ));
// m_role is set to 2 if it is a client
m_role = 2 ;
emit roleChanged();
}
void PingPong:: clientConnected()
{
if (! m_serverInfo- > hasPendingConnections()) {
setMessage("FAIL: expected pending server connection" );
return ;
}
socket = m_serverInfo- > nextPendingConnection();
if (! socket)
return ;
socket- > setParent(this );
connect(socket, & QBluetoothSocket :: readyRead,
this , & PingPong:: readSocket);
connect(socket, & QBluetoothSocket :: disconnected,
this , & PingPong:: clientDisconnected);
connect(socket, QOverload < QBluetoothSocket :: SocketError> :: of(& QBluetoothSocket :: error),
this , & PingPong:: socketError);
setMessage(QStringLiteral ("Client connected." ));
QByteArray size;
size. setNum(m_boardWidth);
size. append(' ' );
QByteArray size1;
size1. setNum(m_boardHeight);
size. append(size1);
size. append(" \n" );
socket- > write(size. constData());
}
void PingPong:: clientDisconnected()
{
setMessage(QStringLiteral ("Client disconnected" ));
m_timer- > stop();
}
void PingPong:: socketError(QBluetoothSocket :: SocketError error)
{
Q_UNUSED(error);
m_timer- > stop();
}
void PingPong:: serverError(QBluetoothServer :: Error error)
{
Q_UNUSED(error);
m_timer- > stop();
}
void PingPong:: done()
{
qDebug () < < "Service scan done" ;
if (! m_serviceFound)
setMessage("PingPong service not found" );
}
void PingPong:: addService(const QBluetoothServiceInfo & service)
{
setMessage("Service found. Setting parameters..." );
socket = new QBluetoothSocket (QBluetoothServiceInfo :: RfcommProtocol);
socket- > connectToService(service);
connect(socket, & QBluetoothSocket :: readyRead, this , & PingPong:: readSocket);
connect(socket, & QBluetoothSocket :: connected, this , & PingPong:: serverConnected);
connect(socket, & QBluetoothSocket :: disconnected, this , & PingPong:: serverDisconnected);
m_serviceFound = true ;
}
void PingPong:: serviceScanError(QBluetoothServiceDiscoveryAgent :: Error error)
{
setMessage(QStringLiteral ("Scanning error" ) + error);
}
bool PingPong:: showDialog() const
{
return m_showDialog;
}
QString PingPong:: message() const
{
return m_message;
}
void PingPong:: serverConnected()
{
setMessage("Server Connected" );
QByteArray size;
size. setNum(m_boardWidth);
size. append(' ' );
QByteArray size1;
size1. setNum(m_boardHeight);
size. append(size1);
size. append(" \n" );
socket- > write(size. constData());
}
void PingPong:: serverDisconnected()
{
setMessage("Server Disconnected" );
m_timer- > stop();
}
void PingPong:: readSocket()
{
if (! socket)
return ;
const char sep = ' ' ;
QByteArray line;
while (socket- > canReadLine()) {
line = socket- > readLine();
//qDebug() << QString::fromUtf8(line.constData(), line.length());
if (line. contains("result" )) {
QList < QByteArray > result = line. split(sep);
if (result. size() > 2 ) {
QByteArray leftSide = result. at(1 );
QByteArray rightSide = result. at(2 );
m_resultLeft = leftSide. toInt();
m_resultRight = rightSide. toInt();
emit resultChanged();
checkResult();
}
}
}
if ((m_proportionX = = 0 | | m_proportionY = = 0 )) {
QList < QByteArray > boardSize = line. split(sep);
if (boardSize. size() > 1 ) {
QByteArray boardWidth = boardSize. at(0 );
QByteArray boardHeight = boardSize. at(1 );
m_proportionX = m_boardWidth/ boardWidth. toFloat();
m_proportionY = m_boardHeight/ boardHeight. toFloat();
setMessage("Screen adjusted. Get ready!" );
QTimer :: singleShot(3000 , this , SLOT(startGame()));
}
}
else if (m_role = = 1 ) {
QList < QByteArray > boardSize = line. split(sep);
if (boardSize. size() > 1 ) {
QByteArray rightBlockY = boardSize. at(0 );
m_rightBlockY = m_proportionY * rightBlockY. toFloat();
emit rightBlockChanged();
}
}
else if (m_role = = 2 ) {
QList < QByteArray > boardSize = line. split(sep);
if (boardSize. size() > 2 ) {
QByteArray ballX = boardSize. at(0 );
QByteArray ballY = boardSize. at(1 );
QByteArray leftBlockY = boardSize. at(2 );
m_ballX = m_proportionX * ballX. toFloat();
m_ballY = m_proportionY * ballY. toFloat();
m_leftBlockY = m_proportionY * leftBlockY. toFloat();
emit leftBlockChanged();
emit ballChanged();
}
}
}
void PingPong:: setMessage(const QString & message)
{
m_showDialog = true ;
m_message = message;
emit showDialogChanged();
}
int PingPong:: role() const
{
return m_role;
}
int PingPong:: leftResult() const
{
return m_resultLeft;
}
int PingPong:: rightResult() const
{
return m_resultRight;
}
float PingPong:: ballX() const
{
return m_ballX;
}
float PingPong:: ballY() const
{
return m_ballY;
}
float PingPong:: leftBlockY() const
{
return m_leftBlockY;
}
float PingPong:: rightBlockY() const
{
return m_rightBlockY;
}