QT 電子寵物專案

2020-08-13 00:06:38

QT 電子寵物專案

專案原始碼+QT 5.8.0+Sqlite : https://github.com/yangzhenyu322/QT-DigitalPet.git

1.目的

使用Qt開發一個電子寵物專案,並將伺服器架設到伺服器端中,通過這個專案進一步掌握Qt開發的能力。

2.總體設計

2.1 功能特點

①.在登陸介面能夠與伺服器端自動連線,(本地)伺服器端能夠對用戶端的登陸、註冊、儲存數據等做相應正確處理並且與數據庫自動連線;
②.在開始介面能夠載入上次儲存的遊戲、開始新的遊戲、返回登陸介面以及退出遊戲;
③.在主介面中有白天、黑夜兩種不同的效果
④.在主介面能夠顯示寵物的詳細資訊、治療等
⑤.擁有戶外玩耍(即在桌面顯示)、在廚房吃飯、在臥室睡覺、在體育館鍛鍊等多樣化活動;
⑥.寵物能夠通過鍵盤自由移動,並且移動時寵物會做出相應的動作;
⑦.寵物在正常狀態、飢餓或生病狀態、死亡狀態等不同場面。
⑧.設定了比較全面的bgm以及觸發功能時的音效;
⑨.擁有比較全面的數值增減機制 機製;
⑩.及時儲存數據,並保證不同賬號各自數據的唯一性

2.2 模組結構

1.結構概況
電子寵物用戶端:
在这里插入图片描述

電子寵物伺服器端:
在这里插入图片描述

2.各類結構圖
在这里插入图片描述

2.3 開發環境
1.平臺: Qt 5.8.0
2.程式語言:C++
3模組說明

  1. 伺服器端模組:①能夠連線用戶端,當用戶端發出註冊、登陸請求時,伺服器端會連線數據庫,對這些請求做出判斷,然後將處理結果告知用戶端使其顯示註冊成功、註冊失敗、登陸成功、登陸失敗等資訊並做出相應操作;②能夠在使用者從主介面返回開始介面時自動儲存數據,防止數據丟失,而且由於數據庫設有賬號、密碼等欄位,能夠保證每個賬號數據的唯一性。
  2. 用戶端模組:
    a) 登陸介面:自動連線用戶端,向伺服器端發送註冊、登陸、儲存數據等請求;
    b) 開始介面:規定登陸後下一步的操作,使用者能夠繼續使用上次儲存的數據、開始新的遊戲(載入初始預設值)、返回登陸介面、退出遊戲等操作;
    c) 主介面:擁有白天、黑夜、死亡、復活等不同場景,並且配備時鐘畫面;使用者能夠通過鍵盤(W、A、S、D)來分別控制寵物的上下左右等移動,並且能夠檢視寵物的當前詳細資訊和治療寵物恢復健康值;可以返回開始介面的同時儲存當前數據;能夠跳轉到臥室、廚房、體育館、戶外玩耍等功能模組;在返回開始介面時能夠自動儲存數據,防止數據的丟失;
    d) 在臥室能夠休息,定時恢復活力;
    e) 在戶外能夠在桌面顯示,並且實現了在所有視窗置頂的功能;
    f) 在廚房能夠吃飯恢復能量值並且與狗(NPC)進行互動;
    g) 在體育館能夠鍛鍊定時恢復活力,有進度條顯示鍛鍊情況;
    h) 注:在臥室、廚房、戶外、體育館時寵物同樣能夠自動移動。

4 介面設計
登陸介面(四種不同情況):
在这里插入图片描述

開始介面:

在这里插入图片描述

主介面:

白天黑夜不同效果:
在这里插入图片描述
顯示詳細資訊:
在这里插入图片描述

治療:
在这里插入图片描述

寵物的不同狀態:
在这里插入图片描述

臥室:

在这里插入图片描述

戶外:

在这里插入图片描述
廚房:
在这里插入图片描述
體育館:
在这里插入图片描述

寵物在桌面顯示、移動的演算法:
//永久置頂

    m_timer = new QTimer();
    //   m_timer->start(1000); //程式每隔1秒置頂一次,該計時器由entertainment視窗」開始遊戲「按鈕觸發,並在退出時停止
    connect(m_timer, &QTimer::timeout, [=]{
    #ifdef Q_OS_WIN32
    SetWindowPos((HWND)this->winId(),HWND_TOPMOST,this->pos().x(),this->pos().y(),this->width(),this->height(),SWP_SHOWWINDOW);
    #endif //要在windows上不獲取焦點切置頂,必須用Windows API
});

//滑鼠拖動寵物移動

void Mydialog::mousePressEvent(QMouseEvent *e){
    if(e->button()==Qt::RightButton){
        //如果是右鍵,關閉視窗
        m_timer->stop();
        emit backToPlay();
    }else if(e->button()==Qt::LeftButton){
        //如果是左鍵,移動
        //求座標差值
        point=e->globalPos()-this->frameGeometry().topLeft();    
    }
}

//滑鼠左鍵長按拖動寵物位置

void Mydialog::mouseMoveEvent(QMouseEvent* e){
     if(e->buttons() & Qt::LeftButton){
         move(e->globalPos()-point);
     }
}
伺服器端控制檯:

在这里插入图片描述

數據庫:

在这里插入图片描述

伺服器端處理用戶端請求演算法:

connect(tcpSocket,&QTcpSocket::readyRead,[=](){
                QString str=tcpSocket->readAll();
                qDebug()<<str;
                if(str.mid(0,2)=="註冊"){
                     QString account="";
                     QString password="";
                     int count=0;
                     for(int i=2;i<str.size();i++){
                         if(str.mid(i,1)=="#"){
                             count++;
                             continue;
                         }
                         if(count==0){
                             account+=str.mid(i,1);
                             continue;
                         }
                         if(count==1){
                             password=str.mid(i,str.size()-i+1);
                             break;
                         }
                     }
                     qDebug()<<"賬號"<<account;
                     qDebug()<<"密碼"<<password;
                     if(db.isAccountExist(account)){  //賬號存在
                            tcpSocket->write(QString("註冊失敗").toUtf8().data());
                     }else{  //賬號不存在,註冊成功
                         //註冊賬號
                         Pet pet;
                         pet.setAccount(account);
                         pet.setPassword(password);
                         db.insertIntable(pet);
                         //提示用戶端註冊成功
                         tcpSocket->write(QString("註冊成功").toUtf8().data());
                     }
                }else if(str.mid(0,2)=="登陸"){
                    QString account="";
                    QString password="";
                    int count=0;
                    for(int i=2;i<str.size();i++){
                        if(str.mid(i,1)=="#"){
                            count++;
                            continue;
                        }
                        if(count==0){
                            account+=str.mid(i,1);
                            continue;
                        }
                        if(count==1){
                            password=str.mid(i,str.size()-i+1);
                            break;
                        }
                    }
                    qDebug()<<"賬號"<<account;
                    qDebug()<<"密碼"<<password;
                    if(db.isPasswordExist(account,password)){  //登陸成功
                        //暫時儲存當前使用者的賬號密碼
                        pet=db.selectTable(account);
                        //提示用戶端登陸成功並將該賬號數據並返回給用戶端
                        tcpSocket->write(QString("登陸成功"+pet.getName()+"#"+pet.getState()+"#"
                                                 +QString::number(pet.getWeight())+"#"+QString::number(pet.getAge())
                                                 +"#"+QString::number(pet.getMood())+"#"+QString::number(pet.getHealth())
                                                 +"#"+QString::number(pet.getHunger())+"#"+QString::number(pet.getActive())
                                                 +"#"+QString::number(pet.getWidth())+"#"+QString::number(pet.getHeight())).toUtf8().data());
                    }else{  //登陸失敗
                        //提示用戶端登陸失敗
                        tcpSocket->write(QString("登陸失敗").toUtf8().data());
                    }

                }else if(str.mid(0,2)=="儲存"){
                      int count=0;
                      int index[10]={0};
                      for(int i=2;i<str.size();i++){
                          if(str.mid(i,1)=="#"){
                              count++;
                              continue;
                          }
                          index[count]++;
                          switch (count) {
                          case 0:
                              break;
                          case 1://name
                              pet.setName(str.mid(2,index[0]));
                              break;
                          case 2://state
                              pet.setState(str.mid(3+index[0],index[1]));
                              break;
                          case 3://weight
                              pet.setWeight(str.mid(4+index[0]+index[1],index[2]).toDouble());
                              break;
                          case 4://age
                              pet.setAge(str.mid(5+index[0]+index[1]+index[2],index[3]).toInt());
                              break;
                          case 5://mood
                              pet.setMood(str.mid(6+index[0]+index[1]+index[2]+index[3],index[4]).toInt());
                              break;
                          case 6://health
                              pet.setHealth(str.mid(7+index[0]+index[1]+index[2]+index[3]+index[4],index[5]).toInt());
                              break;
                          case 7://hunger
                              pet.setHunger(str.mid(8+index[0]+index[1]+index[2]+index[3]+index[4]+index[5],index[6]).toInt());
                              break;
                          case 8://active
                              pet.setActive(str.mid(9+index[0]+index[1]+index[2]+index[3]+index[4]+index[5]+index[6],index[7]).toInt());
                              break;
                          case 9://width
                              pet.setWidth(str.mid(10+index[0]+index[1]+index[2]+index[3]+index[4]+index[5]+index[6]+index[7],index[8]).toInt());
                              //height
                              int temp=11+index[0]+index[1]+index[2]+index[3]+index[4]+index[5]+index[6]+index[7]+index[8];
                              pet.setHeight(str.mid(temp,str.size()-temp+1).toInt());
                              count++;
                              break;
                          }
                      }
                      //儲存到數據庫中
                      qDebug()<<"儲存";
                      qDebug()<<pet.getAccount()<<" "<<pet.getPassword()<<" "<<pet.getName()<<" "<<pet.getState()<<" "<<pet.getWeight()
                             <<" "<<pet.getAge()<<" "<<pet.getMood()<<" "<<pet.getHealth()<<" "<<pet.getHunger()<<" "<<pet.getActive()<<" "
                            <<pet.getWidth()<<" "<<pet.getHeight();
                      //更新當前賬號數據
                      db.updateTable(pet);
                }
        });
    });

ps: 卑微大一小白三週的實訓成果,大佬勿噴(看在我難得寫一次部落格的份上),喜歡的在GitHub上點上一個star可以讓我開心很久哦~~(當然CSDN這邊順手點一下就更好了dog.jpg)