1

background

Use QGraphicsItem of Qt5.12.9 to implement Tetris, and use Sqlit3 to store data for game playback. Since QT has been used, try to use its components as much as possible to rewrite the original JSON package and database operation interface implementation.

Ideas

Try to reuse the code that has been implemented, so only the shape and posture (number of rotations) and final position of each square are recorded. The difference from the real game is that one of the sources of the blocks is randomly generated and the other is a database. The ID of the record I quoted the original snowflake model, but used the QString type. Without it, the long integer type is always difficult to control during the programming process, and it is inexplicably changed to scientific notation or overflow. The database operation uses C++ to encapsulate the sqlit3 library and combines with Qjson to realize ORM automatic operation. The dynamic link library of Sqlit3 needs to be recompiled under windows, linux and mac platforms.

Effect picture

Key code analysis

Operating system choice of cmake

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 operation package

The information transmission in my data operation implementation is carried out in the form of json objects, encapsulating QJsonObject, QJsonArray, etc., providing a convenient json operation interface, realizing parameter transmission and automatic SQL generation. My realization Object is a first-class citizen, Array is a second-class citizen only as a sub-item of Qjson. This not only satisfies the application, but also greatly simplifies the design, standardizes the use, and avoids misuse.

class Qjson {
private:
    QJsonObject* json;                        //真实的json对象,我只是对其封装,简化操作或转化成简单的操作
    bool _IsObject_;                            //是否是正确的json对象,构造函数中对其进行判断,表示json对象的有效性
public:
    Qjson();
    Qjson(const Qjson& origin);                //复制构造函数
    QString operator[](QString key);            //下标操作,取特定key对应的值,使用QString返回,可以方便进行类型转换
    Qjson& operator = (const Qjson& origin);    //赋值构造函数
    bool HasMember(QString key) ;
        Qjson ExtendObject(Qjson obj);            //合并两个Object,第一个中同名key会被覆盖
    template<typename T> void AddValueBase(QString k, T v);    //key - value 插入模板函数,基础类型插入它就能搞定
    void AddValueObjectsArray(string k, QVector<Qjson>& arr) ;    //Array类型值插入
    QString GetJsonString();                    //取得json的字符串
    void GetValueAndTypeByKey(QString key, QString* v, int* vType);        //取值的真正操作函数
    QStringList GetAllKeys();                    //取得json对象的所有key,用于对象遍历    
    bool IsObject();
private:
    QJsonObject* GetOriginRapidJson();        //取得真实的json对象,类内部使用
};

Database general interface-Idb.h

After practice, the database operation has the following interfaces, and more than 90% of the requirements can be met.

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;
};

Database operation standard implementation-DbBase.h

Our upper-level applications are all operating this implementation. This class combines a specific implementation of Idb, so as to achieve the purpose of decoupling from the specific database, and you can easily switch between different database instances.

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's C++ wrapper class-Sqlit3Db.h

The Idb interface of Sqlit3 has been implemented. Here are some key points for some explanation:

std::unique_ptr

The data connection uses std::unique_ptr, and the memory header file must be introduced under gcc. This problem has troubled me for a long time. There is no problem under Windows, but it keeps reporting errors under Linux.

Chinese support in sql statement

To ensure that the encoding of the sql statement sent to the bottom layer is Utf-8, in order to ensure the support of all operating systems, choose to use QString::fromUtf8(szU8) for conversion.

Qjson ExecNoneQuerySql(QString aQuery) {
            Qjson rs = Utils::MakeJsonObjectForFuncReturn(STSUCCESS);
            sqlite3_stmt* stmt = NULL;
            sqlite3* handle = getHandle();
            char * u8Query = Utils::UnicodeToU8(aQuery);        //编码转换,函数中的主要功能由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;
        }

Bulk insert operation

Game records must be inserted in batches, not one by one. The batch operation of sqlit3 is somewhat different from that of mysql. It uses select ... union all. In fact, it is only necessary to splice the SQL statements according to the regulations.

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(" ) ");        //取出参数第一个元素的所有key,组装数据库字段
                for (size_t i = 0; i < elements.size(); i++) {
                    QStringList keys = elements[i].GetAllKeys();                //取出参数的所有key,实现对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);
        }

How to use JOSN-ORM

Intelligent ORM implementation for data query, please refer to the previous article "C++ Relational Database Access Common Interface Design"

Playback function implementation

Several parameters are set for playback

  • last: the replay of the last game
  • one: the game with the highest points
  • two: the second-ranked game
  • three: the third-ranked game

Source code and operation method

The project is organized by cmake, please install cmake 3.10 or above. The following script is based on MSVC under Windows, and is basically similar on other operating systems, or use qtcreator to open and operate.

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

Note: This project can run cross-platform and has been adapted to windows, linux, mac.

Source code:

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

or

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

or

https://github.com/zhoutk/qtDemo/tree/master/tetrisGraphicsItem

zhoutk
2.6k 声望1.2k 粉丝

自由程序员,技术路线c,delphi,c++,c#,java,php,node.js,python,golang,typescript;超喜欢react.js的设计思路,全栈开发成为我的终极目标。开发机器macbook pro,或装ubuntu、fedora的机器,编程用vim...