QT5寫Tetris之使用Sqlite3實現(xiàn)游戲回放

背景

使用Qt5.12.9的QGraphicsItem來實現(xiàn)俄羅斯方塊,使用Sqlit3存儲數(shù)據(jù)來進行游戲的回放,既然已經(jīng)使用QT,就盡量用其組件,重寫了原來的JSON封裝及數(shù)據(jù)庫操作接口實現(xiàn)。

思路

盡量復用已經(jīng)實現(xiàn)的代碼,所以只記錄了每個方塊的形狀與姿態(tài)(旋轉次數(shù))及最終位置。與真實游戲的區(qū)別只是在于方塊的來源一個是隨機生成,一個是數(shù)據(jù)庫。記錄的ID我引用了原來使用的snowflake模型,但卻使用了QString類型,無它,只是長整型在編程的過程中總是不好控制,莫名的被改成科學計數(shù)法或溢出。數(shù)據(jù)庫操作使用C++對sqlit3庫進行封裝并結合Qjson實現(xiàn)ORM自動操作。Sqlit3的動態(tài)鏈接庫,在windows、linux、mac各平臺下需要重新編譯。

效果圖

tetris.png

關鍵代碼分析

cmake之操作系統(tǒng)選擇

if(MSVC)                            #windows
        set(EnclibName Sqlit3.dll)
elseif(APPLE)                       #mac
        set(EnclibName sqlite3.o)
elseif(UNIX)                            #linux
        set(EnclibName libsqlite3.so)
endif()

Qjson.h - json操作封裝

我的數(shù)據(jù)操作實現(xiàn)中的信息傳遞,都是以json對象形式進行的,封裝QJsonObject、QJsonArray等,提供方便的json操作接口,實現(xiàn)參數(shù)傳遞與SQL自動生成。我的實現(xiàn)Object是一等公民,Array是二等公民只作為Qjson的一個子項。這樣既能滿足應用又把設計大大的簡化了,規(guī)范使用,避免誤用。

class Qjson {
private:
    QJsonObject* json;                      //真實的json對象,我只是對其封裝,簡化操作或轉化成簡單的操作
    bool _IsObject_;                            //是否是正確的json對象,構造函數(shù)中對其進行判斷,表示json對象的有效性
public:
    Qjson();
    Qjson(const Qjson& origin);             //復制構造函數(shù)
    QString operator[](QString key);            //下標操作,取特定key對應的值,使用QString返回,可以方便進行類型轉換
    Qjson& operator = (const Qjson& origin);    //賦值構造函數(shù)
    bool HasMember(QString key) ;
        Qjson ExtendObject(Qjson obj);          //合并兩個Object,第一個中同名key會被覆蓋
    template<typename T> void AddValueBase(QString k, T v); //key - value 插入模板函數(shù),基礎類型插入它就能搞定
    void AddValueObjectsArray(string k, QVector<Qjson>& arr) ;  //Array類型值插入
    QString GetJsonString();                    //取得json的字符串
    void GetValueAndTypeByKey(QString key, QString* v, int* vType);     //取值的真正操作函數(shù)
    QStringList GetAllKeys();                   //取得json對象的所有key,用于對象遍歷 
    bool IsObject();
private:
    QJsonObject* GetOriginRapidJson();      //取得真實的json對象,類內部使用
};

數(shù)據(jù)庫通用接口 - Idb.h

經(jīng)實踐總結,數(shù)據(jù)庫操作有以下接口,百分之九十以上的需求就都能滿足。

class Idb
{
public:
    virtual Qjson select(QString tablename, Qjson& params, QStringList fields = QStringList(), int queryType = 1) = 0;
    virtual Qjson create(QString tablename, Qjson& params) = 0;
    virtual Qjson update(QString tablename, Qjson& params) = 0;
    virtual Qjson remove(QString tablename, Qjson& params) = 0;
        virtual Qjson querySql(QString sql, Qjson params = Qjson(), QStringList filelds = QStringList()) = 0;
    virtual Qjson execSql(QString sql) = 0;
    virtual Qjson insertBatch(QString tablename, QVector<Qjson> elements, QString constraint = "id") = 0;
    virtual Qjson transGo(QStringList sqls, bool isAsync = false) = 0;
};

數(shù)據(jù)庫操作標準實現(xiàn) - DbBase.h

我們的上層應用都是操作這個實現(xiàn),這個類組合了一個Idb的具體實現(xiàn),從而達到與具體的數(shù)據(jù)庫解耦的目的,可以輕松的切換不同的數(shù)據(jù)庫實例。

class DbBase
{
public:
    DbBase(QString connStr, QString dbType = "sqlit3") : connStr(connStr) {
        dbType.toLower();
        if (dbType.compare("sqlit3") == 0)
            db = new Sqlit3::Sqlit3Db(connStr);
        else {
            throw "Db Type error or not be supported. ";
        }
    };
    ...
};

Sqlit3的C++封裝類 - Sqlit3Db.h

實現(xiàn)了Sqlit3的Idb接口,下面抽了幾個關鍵點進行一些說明:

std::unique_ptr

數(shù)據(jù)連接使用了std::unique_ptr,在gcc下一定要引入 memory 頭文件,這個問題折騰了我好久,在windows下沒出問題,但在linux下一直報錯。

sql語句中中文的支持

要保證送入底層的sql語句的編碼為Utf-8,為了保證對所有操作系統(tǒng)的支持,選擇使用QString::fromUtf8(szU8)來進行轉換。

Qjson ExecNoneQuerySql(QString aQuery) {
            Qjson rs = Utils::MakeJsonObjectForFuncReturn(STSUCCESS);
            sqlite3_stmt* stmt = NULL;
            sqlite3* handle = getHandle();
            char * u8Query = Utils::UnicodeToU8(aQuery);        //編碼轉換,函數(shù)中的主要功能由QString::fromUtf8完成
            const int ret = sqlite3_prepare_v2(handle, u8Query, strlen(u8Query), &stmt, NULL);
            if (SQLITE_OK != ret)
            {
                QString errmsg = sqlite3_errmsg(getHandle());
                rs.ExtendObject(Utils::MakeJsonObjectForFuncReturn(STDBOPERATEERR, errmsg));
            }
            else {
                sqlite3_step(stmt);
            }
            sqlite3_finalize(stmt);
            qDebug() << "SQL: " << aQuery << endl;      //日志輸入使用未轉換的
            return rs;
        }

批量插入操作

游戲記錄必須使用批量插入操作,不能一條一條插入。sqlit3的批量操作與mysql有些不同,用的是select ... union all,其實也只是按規(guī)定作好SQL語句拼接就可以了。

Qjson insertBatch(QString tablename, QVector<Qjson> elements, QString constraint) {
            QString sql = "insert into ";
            if (elements.empty()) {
                return Utils::MakeJsonObjectForFuncReturn(STPARAMERR);
            }
            else {
                QString keyStr = " (";
                keyStr.append(elements[0].GetAllKeys().join(',')).append(" ) ");        //取出參數(shù)第一個元素的所有key,組裝數(shù)據(jù)庫字段
                for (size_t i = 0; i < elements.size(); i++) {
                    QStringList keys = elements[i].GetAllKeys();                //取出參數(shù)的所有key,實現(xiàn)對json對象的遍歷
                    QString valueStr = " select ";
                    for (size_t j = 0; j < keys.size(); j++) {
                        valueStr.append("'").append(elements[i][keys[j]]).append("'");
                        if (j < keys.size() - 1) {
                            valueStr.append(",");
                        }
                    }
                    if (i < elements.size() - 1) {                  //拼接下一條記錄
                        valueStr.append(" union all ");
                    }
                    keyStr.append(valueStr);
                }
                sql.append(tablename).append(keyStr);
            }
            return ExecNoneQuerySql(sql);
        }

JOSN-ORM的使用方法

數(shù)據(jù)查詢使用的智能的ORM實現(xiàn),具體方法請參照前文《c++關系數(shù)據(jù)庫訪問通用接口設計》

Playback 功能實現(xiàn)

回放設置了幾個參數(shù)

  • last : 最后一次游戲的回放
  • one :積分排行第一的游戲
  • two :積分排行第二的游戲
  • three :積分排行第三的游戲

源代碼及運行方法

項目采用cmake組織,請安裝cmake3.10以上版本。下面腳本是windows下基于MSVC的,其它操作系統(tǒng)上基本類似,或者使用qtcreator打開進行操作。

cmake -A win32 -Bbuild .
cd build
cmake --build . --config Release

注:本項目采用方案能跨平臺運行,已經(jīng)適配過windows,linux,mac。

源代碼:

https://gitee.com/zhoutk/qtetris.git

https://gitee.com/zhoutk/qtdemo/tree/master/tetrisGraphicsItem

https://github.com/zhoutk/qtDemo/tree/master/tetrisGraphicsItem
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容