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 // 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 . 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 . append("result " );
        QByteArray . 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 . append("result " );
        QByteArray . 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 - > 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 ,  & 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 else 
        discoveryAgent- > setUuidFilter(QBluetoothUuid #else 
    discoveryAgent- > setUuidFilter(QBluetoothUuid #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 . setNum(m_boardWidth);
    size. append(' ' );
    QByteArray . 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 :: message() const 
{
    return  m_message;
}
void  PingPong:: serverConnected()
{
    setMessage("Server Connected" );
    QByteArray . setNum(m_boardWidth);
    size. append(' ' );
    QByteArray . 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 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 =  result. at(1 );
                QByteArray =  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 =  boardSize. at(0 );
            QByteArray =  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 =  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 =  boardSize. at(0 );
            QByteArray =  boardSize. at(1 );
            QByteArray =  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;
}