MC2D v0.0.6 Source Code

目录

MC2D v0.0.6 Source Code


Declaration

A Minecraft 2D Version Powered By Qt


main.cpp

#include "Tool.h"
#include "selectworld.h"
#include "maininterface.h"
#include "optionwidget.h"
#include "createmap.h"
#include "gamewidget.h"

int main(int argc, char *argv[]) {
    QApplication a(argc, argv);


    MainInterface *main_interface = new MainInterface(nullptr, 1280, 720, TITLE);
    SelectWorld *select_world = new SelectWorld(nullptr, 1280, 720, TITLE);
    OptionWidget *option_widget = new OptionWidget(nullptr, 1280, 720, TITLE);
    CreateMap *create_map = new CreateMap(nullptr, 1280, 720, TITLE);
    GameWidget *game_widget = new GameWidget(30, nullptr, 1280, 720, TITLE);

    /* Main Interface -> Select Map */
    QObject::connect(main_interface, &MainInterface::select_world, [=]() {select_world->updateMapList();select_world->Show(main_interface);});

    /* Select Map ->  Main Interface*/
    QObject::connect(select_world, &SelectWorld::main_interface, [=]() {main_interface->Show(select_world);});

    /* Select Map ->  Create Map */
    QObject::connect(select_world, &SelectWorld::create_map, [=]() {create_map->Show(select_world);});

    /* Main Interface -> Option Widget */
    QObject::connect(main_interface, &MainInterface::option, [=]() {option_widget->Show(main_interface);});

    /* Option Widget ->  Main Interface*/
    QObject::connect(option_widget, &OptionWidget::main_interface, [=]() {main_interface->Show(option_widget);});

    /* Create Map ->  Select World*/
    QObject::connect(create_map, &CreateMap::select_world, [=]() {select_world->updateMapList();select_world->Show(create_map);});
    QObject::connect(select_world, &SelectWorld::game_widget, [=]() {
        game_widget->startGame();
        game_widget->Show(select_world);
    });

    QObject::connect(option_widget, &OptionWidget::update_setting, [=]() {
        /* Update Font */
        if(option_widget->langMode == 1)
            option_widget->setLang->langs->setCurrentIndex(0);
        else if(option_widget->langMode == 2)
            option_widget->setLang->langs->setCurrentIndex(1);
        else if(option_widget->langMode == 3)
            option_widget->setLang->langs->setCurrentIndex(2);
        else if(option_widget->langMode == 4)
            option_widget->setLang->langs->setCurrentIndex(3);

        main_interface->updateFont(option_widget->font());
        select_world->updateFont(option_widget->font());
        option_widget->updateFont(option_widget->font());
        create_map->updateFont(option_widget->font());

        main_interface->updateLang(option_widget->langMode);
        option_widget->updateLang(option_widget->langMode);
        select_world->updateLang(option_widget->langMode);
        create_map->updateLang(option_widget->langMode);
    });


    QObject::connect(main_interface, &BaseWidget::GameOver, [=]() {
        sendInfo("Game has been over");
        option_widget->saveSetting();
        exit(0);
    });
    QObject::connect(select_world, &BaseWidget::GameOver, [=]() {
        sendInfo("Game has been over");
        option_widget->saveSetting();
        exit(0);
    });
    QObject::connect(option_widget, &BaseWidget::GameOver, [=]() {
        sendInfo("Game has been over");
        option_widget->saveSetting();
        exit(0);
    });
    QObject::connect(create_map, &BaseWidget::GameOver, [=]() {
        sendInfo("Game has been over");
        option_widget->saveSetting();
        exit(0);
    });

    option_widget->loadSetting();
    /* Start Game (Centered) */
    main_interface->Show((QApplication::desktop()->width() - 1280) / 2, (QApplication::desktop()->height() - 720) / 2, 0);
    return a.exec();
}

basewidget.h

#ifndef BASEWIDGET_H
#define BASEWIDGET_H

#include "Tool.h"

/* A Basic Widget in Game */
class BaseWidget : public QWidget {
    Q_OBJECT
public:
    explicit BaseWidget(QWidget *parent = nullptr,
        int width = 1280,
        int height = 720,
        QString title = TITLE);

    void Show(int x = 0, int y = 0, int mode = 0);
    void Show(BaseWidget *widget);
    void Hide();
    virtual void updateFont(QFont font);
    void closeEvent(QCloseEvent *event) override;
    virtual void updateLang(int langMode);

    int langMode;
    /* Button Clicked Sound */
    QSound *buttonSound = new QSound(":/sound/musics/ButtonClicked.wav");

signals:
    void GameOver();
    void widgetShow();
};

#endif // BASEWIDGET_H

basewidget.cpp

#include "basewidget.h"

BaseWidget::BaseWidget(QWidget *parent,
        int width,
        int height,
        QString title) {
    /* Init Widget */
    this->setWindowIcon(QIcon(":/gui/images/gui/icon.png"));
    this->setParent(parent);
    this->resize(width, height);
    this->setWindowTitle(title);
}

void BaseWidget::Show(int x, int y, int mode) {
    /* Mode == 0 : Normal */
    /* Mode == 1 : Maximized */
    /* Mode == 2 : FullScreen */
    if(!mode) this->move(x, y);
    switch(mode) {
        case 0: this->showNormal(); break;
        case 1: this->showMaximized(); break;
        case 2: this->showFullScreen(); break;
    }
    sendInfo("Widget Has Been Shown");
    widgetShow();
}

void BaseWidget::Show(BaseWidget *widget)
{
    widget->Hide();
    if(widget->isMaximized()) this->Show(0, 0, 1);
    else if(widget->isFullScreen()) this->Show(0, 0, 2);
    else {
        this->resize(widget->width(), widget->height());
        this->Show(widget->x(), widget->y());
    }
    widgetShow();
}

void BaseWidget::Hide() {
    this->hide();
    sendInfo("Widget Has Been Hidden");
}

void BaseWidget::updateFont(QFont font)
{
    setFont(font);
}

void BaseWidget::closeEvent(QCloseEvent *event)
{
    GameOver();
}

void BaseWidget::updateLang(int langMode)
{
    if(langMode == 1) {
        setWindowTitle(CN_TITLE);
    } else if(langMode == 2) {
        setWindowTitle(TITLE);
    }
    sendInfo("Lang has been updated");
}

maininterface.h

#ifndef MAININTERFACE_H
#define MAININTERFACE_H

#include "basewidget.h"

class MainInterface : public BaseWidget
{
    Q_OBJECT
public:
    explicit MainInterface(QWidget *parent = nullptr,
                           int width = 1280,
                           int height = 720,
                           QString title = nullptr);
    void paintEvent(QPaintEvent *event) override;
    void resizeEvent(QResizeEvent *event) override;
    void keyPressEvent(QKeyEvent *event) override;
    void updateFont(QFont font) override;
    void updateLang(int langMode) override;

    /* Image */
    QImage titleImg = QImage(":/gui/images/gui/title.png");
    QImage bg = QImage(":/gui/images/gui/bg.png");
    int titleWidth = titleImg.width(), titleHeight = titleImg.height();

    /* Button */
    GameButton *SinglePlayer = new GameButton( ("SinglePlayer"), this);
    GameButton *MultiPlayer = new GameButton( ("MultiPlayer"), this);
    GameButton *Exit = new GameButton( ("Exit"), this);
    GameButton *Option = new GameButton( ("Options..."), this);

    /* Text */
    QStaticText GameInfoText = QStaticText( ("Minecraft  2D    Author: Bili_TianX"));

signals:
    void select_world();
    void option();
};

#endif // MAININTERFACE_H

maininterface.cpp

#include "maininterface.h"

MainInterface::MainInterface(QWidget *parent, int width, int height, QString title) : BaseWidget(parent, width, height, title)
{
    /* Init Buttons */
    MultiPlayer->setEnabled(false);

    connect(SinglePlayer, &QPushButton::clicked, [=]() {
        sendInfo("Player Clicked SinglePlayer Button");
        buttonSound->play();
        select_world();
    });
    connect(MultiPlayer, &QPushButton::clicked, [=]() {
        sendInfo("Player Clicked MultiPlayer Button");
        sendError("MultiPlayer Button is Invalid");
        buttonSound->play();
    });
    connect(Option, &QPushButton::clicked, [=]() {
        sendInfo("Player Clicked Option Button");
        buttonSound->play();
        option();
    });
    connect(Exit, &QPushButton::clicked, [=]() {
        sendInfo("Player Clicked Exit Button");
        buttonSound->play();
        GameOver();
    });
}

void MainInterface::paintEvent(QPaintEvent *event)
{
    QPainter p(this);

    /* Draw Background */
    p.drawImage(QRect(0, 0, width(), height()), bg);

    /* Draw Title */
    p.drawImage(19 * width() / 160,
                35 * height() / 288,
                titleImg.scaled(titleWidth * width() / 1280,
                                titleHeight * height() / 720));

    /* Draw Text */
    p.setFont(this->font());
    p.setPen(QColor(255, 255, 255));
    p.drawStaticText(QPoint(10, height() - GameInfoText.size().height() - 5), GameInfoText);
}

void MainInterface::resizeEvent(QResizeEvent *event)
{
    /* Update The Buttons Size */
    SinglePlayer->resize(400 * width() / 1280, 40 * height() / 720);
    MultiPlayer->resize(400 * width() / 1280, 40 * height() / 720);
    Option->resize(400 * width() / 1280, 40 * height() / 720);
    Exit->resize(400 * width() / 1280, 40 * height() / 720);

    /* Update The Buttons Position */
    SinglePlayer->move(440 * width() / 1280, 360 * height() / 720); // 360 + 40 * 1
    MultiPlayer->move(440 * width() / 1280, 440 * height() / 720); // 360 + 40 * 3
    Option->move(440 * width() / 1280, 520 * height() / 720); // 360 + 40 * 5
    Exit->move(440 * width() / 1280, 600 * height() / 720); // 360 + 40 * 7
}

void MainInterface::keyPressEvent(QKeyEvent *event)
{
    switch(event->key()) {
    /* F11 -> Full Screen */
    case Qt::Key_F11:
        if(!isFullScreen()) this->showFullScreen();
        else this->showNormal();
        break;
    /* ESC -> Exit Game */
    case Qt::Key_Escape:
        GameOver();
    }
}

void MainInterface::updateFont(QFont font)
{
    setFont(font);
    SinglePlayer->setFont(font);
    MultiPlayer->setFont(font);
    Option->setFont(font);
    Exit->setFont(font);
    GameInfoText.prepare(QTransform(), font);
}

void MainInterface::updateLang(int langMode)
{
        this->langMode = langMode;
    if(langMode == 1) {
        SinglePlayer->setText("单人游戏");
        MultiPlayer->setText("多人游戏");
        Option->setText("选项...");
        Exit->setText("退出");
        setWindowTitle(CN_TITLE);
        GameInfoText.setText("我的世界  2D    作者:B站天下wu双");
    } else if(langMode == 2) {
        SinglePlayer->setText("SinglePlayer");
        MultiPlayer->setText("MultiPlayer");
        Option->setText("Option...");
        Exit->setText("Exit");
        setWindowTitle(TITLE);
        GameInfoText.setText("Minecraft  2D    Author: Bili_TianX");
    } else if(langMode == 3) {
        SinglePlayer->setText("單人游戲");
        MultiPlayer->setText("多人游戲");
        Option->setText("選項...");
        Exit->setText("退出");
        setWindowTitle(TW_TITLE);
        GameInfoText.setText("我的世界  2D    作者: B站天下wu雙");
    } else if(langMode == 4) {
        SinglePlayer->setText("シングルプレイヤー");
        MultiPlayer->setText("マルチプレイヤー");
        Option->setText("オプション...");
        Exit->setText("出口");
        setWindowTitle(JP_TITLE);
        GameInfoText.setText("マインクラフト  2D    作者: Bili_TianX");
    }
    sendInfo("Lang has been updated");
}

selectworld.h

#ifndef SELECTWORLD_H
#define SELECTWORLD_H

#include "basewidget.h"

struct MapList : public QListWidget {
    QListWidgetItem item;
    MapList(QWidget *parent) : QListWidget(parent) {
        setStyleSheet("QListWidget{background-color:rgba(0, 0, 0, 0);border:0px;color:white;outline:0px;}"
                      "QListWidget::item:selected:!active{color:white;border:2px solid grey;background-color:black;}"
                      "QListWidget::item:selected:active{color:white;border:2px solid grey;background-color:black;}"
                      "QListWidget::item:hover{color:none;border:none;background:none;}");

        QScrollBar *qsb = new QScrollBar(this);
        qsb->setStyleSheet("QScrollBar:vertical {border: none;background: black;}"
                           "QScrollBar::handle:vertical {background: rgb(192, 192, 192);border:2px solid grey;}"
                           "QScrollBar::add-line:vertical {border: 0px;background: black;height: 20px;subcontrol-position: bottom;subcontrol-origin: margin;}"
                           "QScrollBar::sub-line:vertical {border: 0px;background: black;height: 20px;subcontrol-position: top;subcontrol-origin: margin;}"
                           "QScrollBar::up-arrow:vertical, QScrollBar::down-arrow:vertical {border: none;background: none;}"
                           "QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical {background: none;}");
        setVerticalScrollBar(qsb);

    }
};

/* A Widget to Select World */
class SelectWorld : public BaseWidget
{
    Q_OBJECT
public:
    explicit SelectWorld(QWidget *parent = nullptr,
                           int width = 1280,
                           int height = 720,
                           QString title = nullptr);
    void paintEvent(QPaintEvent *event) override;
    void resizeEvent(QResizeEvent *event) override;
    void keyPressEvent(QKeyEvent *event) override;
    void updateFont(QFont font) override;
    void updateLang(int langMode) override;
    void updateMapList();


    /* Images */
    QImage bg = QImage(":/gui/images/gui/SelectWorld.png");

    /* Buttons */
    GameButton *PlaySelectedWorld = new GameButton( ("Play Selected World"), this);
    GameButton *CreateNewWorld = new GameButton( ("Create New World"), this);
    GameButton *Rename = new GameButton( ("Rename"), this);
    GameButton *Delete = new GameButton( ("Delete"), this);
    GameButton *ReCreate = new GameButton( ("Re-Create"), this);
    GameButton *Cancel = new GameButton( ("Cancle"), this);

    /* Text */
    QStaticText SelectWorldText = QStaticText( ("Select World"));

    MapList *list = new MapList(this);

private:
    QString getTitle() {
        switch(langMode) {
        case 1:return "删除地图";break;
        case 2:return "Delete Map";break;
        case 3:return "刪除地圖";break;
        case 4:return "削除マップ";break;
        default:return "";
        };
    };
    QString getText(){
        switch(langMode) {
        case 1:return QString("确定删除地图 : \"" + list->currentItem()->text() +"\"?");break;
        case 2:return "Be Sure To Delete The Map : \"" + list->currentItem()->text() +"\"?";break;
        case 3:return "確定刪除地圖 : \"" + list->currentItem()->text() +"\"?";break;
        case 4:return "地図を削除するには : \"" + list->currentItem()->text() +"\"?";break;
        default:return "";
        };
    };
signals:
    void main_interface();
    void create_map();
    void game_widget();
};

#endif // SELECTWORLD_H

selectworld.cpp

#include "selectworld.h"



SelectWorld::SelectWorld(QWidget *parent, int width, int height, QString title) : BaseWidget(parent, width, height, title)
{
    updateMapList();
    connect(list, &QListWidget::itemSelectionChanged, [=](){
        sendInfo(list->currentItem()->text());
        Delete->setEnabled(true);
        PlaySelectedWorld->setEnabled(true);
    });
    /* Init Buttons */
    PlaySelectedWorld->setEnabled(false);
    Rename->setEnabled(false);
    Delete->setEnabled(false);
    ReCreate->setEnabled(false);

    connect(PlaySelectedWorld, &QPushButton::clicked, [=]() {
        sendInfo("Player Clicked PlaySelectedWorld Button");
        buttonSound->play();
        game_widget();
    });
    connect(CreateNewWorld, &QPushButton::clicked, [=]() {
        sendInfo("Player Clicked CreateNewWorld Button");
        create_map();
        buttonSound->play();
    });
    connect(Delete, &QPushButton::clicked, [=]() {
        sendInfo("Player Clicked Delete Button");
        buttonSound->play();
        if (QMessageBox::Yes == QMessageBox::question(this,getTitle(),getText(),
                                                      QMessageBox::Yes | QMessageBox::No,
                                                      QMessageBox::Yes)) {
            sendInfo("Will be deleted map:" + list->currentItem()->text());
            QDir dir("saves/"+list->currentItem()->text());
            dir.removeRecursively();
            updateMapList();
        }
    });
    connect(Rename, &QPushButton::clicked, [=]() {
        sendInfo("Player Clicked Rename Button");
        buttonSound->play();
    });

    connect(ReCreate, &QPushButton::clicked, [=]() {
        sendInfo("Player Clicked ReCreate Button");
        buttonSound->play();
    });
    connect(Cancel, &QPushButton::clicked, [=]() {
        sendInfo("Player Clicked Cancel Button");
        buttonSound->play();
        main_interface();
    });
}

void SelectWorld::paintEvent(QPaintEvent *event)
{
    QPainter p(this);

    /* Draw Background */
    p.drawImage(QRect(0, 0, width(), height()), bg);

    /* Draw Text */
    p.setFont(font());
    p.setPen(QColor(255, 255, 255));
    p.drawStaticText((width() - SelectWorldText.size().width()) / 2,
                     (140 * height() / 720 - SelectWorldText.size().height() - 5),
                     SelectWorldText);
}

void SelectWorld::resizeEvent(QResizeEvent *event)
{
    /* Update The Buttons Size */
    int tmpWidth = 190 * width() / 1280, tmpHeight = 40 * height() / 720;
    PlaySelectedWorld->resize(400 * width() / 1280, 40 * height() / 720);
    CreateNewWorld->resize(400 * width() / 1280, 40 * height() / 720);
    Rename->resize(tmpWidth, tmpHeight);
    Delete->resize(tmpWidth, tmpHeight);
    ReCreate->resize(tmpWidth, tmpHeight);
    Cancel->resize(tmpWidth, tmpHeight);
    /* h - 28 * 2 * h / 144 */
    list->resize(4 * width() / 7, height() - 56 * height() / 144);

    /* Update The Buttons Position */
    PlaySelectedWorld->move(230 * width() / 1280, 600 * height() / 720);
    CreateNewWorld->move(650 * width() / 1280, 600 * height() / 720);
    Rename->move(230 * width() / 1280, 660 * height() / 720);
    Delete->move(440 * width() / 1280, 660 * height() / 720);
    ReCreate->move(650 * width() / 1280, 660 * height() / 720);
    Cancel->move(860 * width() / 1280, 660 * height() / 720);
    list->move((width() - list->width()) / 2, 28 * height() / 144);
}

void SelectWorld::keyPressEvent(QKeyEvent *event)
{
    switch (event->key()) {
    /* F11 -> Full Screen */
    case Qt::Key_F11:
        if(!isFullScreen()) this->showFullScreen();
        else this->showNormal();
        break;
    /* ESC -> Go To Main Interface */
    case Qt::Key_Escape:
        main_interface();
        break;
    }
}

void SelectWorld::updateFont(QFont font)
{
    setFont(font);
    PlaySelectedWorld->setFont(font);
    CreateNewWorld->setFont(font);
    Rename->setFont(font);
    Delete->setFont(font);
    ReCreate->setFont(font);
    Cancel->setFont(font);
    list->setFont(font);
    SelectWorldText.prepare(QTransform(), font);
}

void SelectWorld::updateLang(int langMode)
{
    this->langMode = langMode;
    if(langMode == 1) {
        PlaySelectedWorld->setText("进入选中的世界");
        CreateNewWorld->setText("创建新的世界");
        Rename->setText("重命名");
        Delete->setText("删除");
        ReCreate->setText("重建");
        Cancel->setText("取消");
        SelectWorldText.setText("选择世界");

        setWindowTitle(CN_TITLE);
    } else if(langMode == 2) {
        PlaySelectedWorld->setText("Play Selected World");
        CreateNewWorld->setText("Create New World");
        Rename->setText("Rename");
        Delete->setText("Delete");
        ReCreate->setText("Re-Create");
        Cancel->setText("Cancel");
        SelectWorldText.setText("Select World");

        setWindowTitle(TITLE);
    } else if(langMode == 3) {
        PlaySelectedWorld->setText("進入選中的世界");
        CreateNewWorld->setText("創建新的世界");
        Rename->setText("重命名");
        Delete->setText("刪除");
        ReCreate->setText("重建");
        Cancel->setText("取消");
        SelectWorldText.setText("選擇世界");

        setWindowTitle(TW_TITLE);
    } else if(langMode == 4) {
        PlaySelectedWorld->setText("選択された世界を再生する");
        CreateNewWorld->setText("新しい世界を創造する");
        Rename->setText("名前の変更");
        Delete->setText("削除");
        ReCreate->setText("再作成");
        Cancel->setText("キャンセル");
        SelectWorldText.setText("世界を選択");

        setWindowTitle(JP_TITLE);
    }
}


/* Make Sure the floder is a map */
bool checkMap(QString path) {
    QFileInfo f1(path + "/map.mc2d"), f2(path + "/setting.mc2d");
    return f1.isFile() && f2.isFile();
}

void SelectWorld::updateMapList()
{
    list->clear();
    QDir dir("saves");
    dir.setFilter(QDir::Dirs);
    auto fileList = dir.entryInfoList();
    for(QFileInfo i: fileList) {
        if(checkMap(i.filePath())) {
            list->addItem(i.fileName());
            sendInfo("has been added:" + i.filePath());
        }
    }
}

optionwidget.h

#ifndef OPTIONWIDGET_H
#define OPTIONWIDGET_H

#include "basewidget.h"

struct ChooseLang : public QDialog{
    QComboBox *langs = new QComboBox;
    QHBoxLayout *h = new QHBoxLayout();
    ChooseLang(QWidget *parent = nullptr) : QDialog(parent) {
        langs->addItem("中文");
        langs->addItem("English");
        langs->addItem("繁體中文");
        langs->addItem("日本語");
        h->addWidget(langs);
        this->setLayout(h);
        this->setFixedSize(250, 50);
        this->setWindowTitle( ("Choose Language"));
    }
};


class OptionWidget : public BaseWidget
{
    Q_OBJECT
public:
    explicit OptionWidget(QWidget *parent = nullptr,
                          int width = 1280,
                          int height = 720,
                          QString title = nullptr);
    void saveSetting(); // Save Setting From File
    void loadSetting(); // Load Setting From File

    void paintEvent(QPaintEvent *event) override;
    void resizeEvent(QResizeEvent *event) override;
    void keyPressEvent(QKeyEvent *event) override;
    void updateFont(QFont font) override;
    void updateLang(int langMode) override;

    int langMode = 1; // 1 中文 2 英文
    /* Widget Background */
    QImage bg = QImage(":/gui/images/gui/OptionBG.png");

    /* Widget Text */
    QStaticText OptionText = QStaticText( ("Options"));

    /* Widget Button */
    GameButton *Done = new GameButton( ("Done"), this);
    GameButton *Font = new GameButton( ("Font..."), this);
    GameButton *Lang = new GameButton( ("Language"), this);

    /* Font Select */
    QFontDialog *SettingFont = new QFontDialog(this);
    ChooseLang *setLang = new ChooseLang(this);
signals:
    void main_interface();
    void update_setting();
};

#endif // OPTIONWIDGET_H

optionwidget.cpp

#include "optionwidget.h"


OptionWidget::OptionWidget(QWidget *parent, int width, int height, QString title) : BaseWidget(parent, width, height, title)
{
    /* Init Buttons */
    connect(Done, &QPushButton::clicked, [=](){
        sendInfo("Player Clicked Done Button");
        buttonSound->play();
        setFont(SettingFont->currentFont());
        if(setLang->langs->currentIndex() == 0) langMode = 1;
        else if(setLang->langs->currentIndex() == 1) langMode = 2;
        else if(setLang->langs->currentIndex() == 2) langMode = 3;
        else if(setLang->langs->currentIndex() == 3) langMode = 4;
        update_setting();
        main_interface();
    });

    connect(Font, &QPushButton::clicked, [=]() {
        sendInfo("Player Clicked Font... Button");
        buttonSound->play();
        SettingFont->resize(1024, 768);
        SettingFont->show();
    });

    connect(Lang, &QPushButton::clicked, [=]() {
        sendInfo("Player Clicked Language Button");
        setLang->show();
    });
}

void OptionWidget::saveSetting()
{
    QFile *file = new QFile("settings.json");
    file->open(QIODevice::WriteOnly);

    QJsonObject obj;
    obj.insert("FontFamily", QJsonValue(font().family()));
    obj.insert("FontSize", QJsonValue(font().pointSize()));
    obj.insert("Language", QJsonValue(langMode));

    QJsonDocument doc = QJsonDocument(obj);
    file->write(doc.toJson());
    file->close();
    sendInfo("Setting has been saved");
}

void OptionWidget::loadSetting()
{
    QFile *file = new QFile("settings.json");
    file->open(QIODevice::ReadOnly);
    QByteArray b = file->readAll();
    QJsonParseError *error = new QJsonParseError;
    QJsonDocument settings = QJsonDocument::fromJson(b, error);
    if(error->error == QJsonParseError::NoError) {
        if(settings.isObject()) {
            QJsonObject obj = settings.object();
            setFont(QFont(obj["FontFamily"].toString(), obj["FontSize"].toInt()));
            langMode = obj["Language"].toInt();
        }
    } else {
        sendError("Unable To Load Setting");
        return;
    }
    file->close();
    update_setting();
    sendInfo("Setting has been loaded");
}

void OptionWidget::paintEvent(QPaintEvent *event)
{
    QPainter p(this);

    /* Draw Background */
    p.drawImage(QRect(0, 0, width(), height()), bg);

    /* Draw Text */
    p.setFont(font());
    p.setPen(QColor(255, 255, 255));
    p.drawStaticText((width() - OptionText.size().width()) / 2,
                     (OptionText.size().height() * 1.5) * height() / 720,
                     OptionText);
}

void OptionWidget::resizeEvent(QResizeEvent *event)
{
    Done->resize(400 * width() / 1280, 40 * height() / 720);
    Font->resize(400 * width() / 1280, 40 * height() / 720);
    Lang->resize(400 * width() / 1280, 40 * height() / 720);

    Done->move((width() - Done->width()) / 2, height() - Done->height() * 1.5);
    Font->move((width() / 2 - Font->width()) / 2, 150 * height() / 720);
    Lang->move(width() / 2 + (width() / 2 - Font->width()) / 2, 150 * height() / 720);
}

void OptionWidget::keyPressEvent(QKeyEvent *event)
{
    switch (event->key()) {
    /* F11 -> Full Screen */
    case Qt::Key_F11:
        if(!isFullScreen()) this->showFullScreen();
        else this->showNormal();
        break;
    /* ESC -> Go To Main Interface */
    case Qt::Key_Escape:
        main_interface();
        break;
    }
}

void OptionWidget::updateFont(QFont font)
{

    setFont(font);
    Done->setFont(font);
    Font->setFont(font);
    Lang->setFont(font);
    setLang->setFont(font);
    setLang->langs->setFont(font);
    SettingFont->setFont(font);

    OptionText.prepare(QTransform(), font);
    SettingFont->setCurrentFont(this->font());
}

void OptionWidget::updateLang(int langMode)
{
        this->langMode = langMode;
    if(langMode == 1) {
        Done->setText("完成");
        Lang->setText("语言...");
        Font->setText("字体...");
        setLang->setWindowTitle("选择语言");
        OptionText.setText("选项");
        SettingFont->setWindowTitle("选择字体");

        setWindowTitle(CN_TITLE);
    } else if(langMode == 2) {
        Done->setText("Done");
        Lang->setText("Language...");
        Font->setText("Font...");
        setLang->setWindowTitle("Choose Language");
        OptionText.setText("Options");
        SettingFont->setWindowTitle("Select Font");

        setWindowTitle(TITLE);
    } else if(langMode == 3) {
        Done->setText("完成");
        Lang->setText("語言...");
        Font->setText("字體...");
        setLang->setWindowTitle("選擇語言");
        OptionText.setText("選項");
        SettingFont->setWindowTitle("選擇字體");
        setWindowTitle(TW_TITLE);
    } else if(langMode == 4) {
        Done->setText("了");
        Lang->setText("言語...");
        Font->setText("フォント...");
        setLang->setWindowTitle("言語を選択");
        OptionText.setText("オプション");
        SettingFont->setWindowTitle("フォントを選択");
        setWindowTitle(JP_TITLE);
    }
}

createmap.h

#ifndef CREATEMAP_H
#define CREATEMAP_H

#include "basewidget.h"

struct CreatingWorld : QDialog{
    QProgressBar *pb = new QProgressBar();
    QVBoxLayout *v = new QVBoxLayout();
    CreatingWorld(QWidget *parent = nullptr) : QDialog(parent) {
        v->addWidget(pb);
        pb->setRange(0, 100);
        pb->setFormat("Current Progress: %p%");
        pb->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
        setFixedSize(500, 50);
        setLayout(v);
    };
};

/* A Widget to Create a Map */
class CreateMap : public BaseWidget
{
    Q_OBJECT
public:
    explicit CreateMap(QWidget *parent = nullptr,
              int width = 1280,
              int height = 720,
              QString title = nullptr);
    void paintEvent(QPaintEvent *event) override;
    void resizeEvent(QResizeEvent *event) override;
    void keyPressEvent(QKeyEvent *event) override;
    void updateFont(QFont font) override;
    void updateLang(int langMode) override;
    /* Images */
    QImage bg = QImage(":/gui/images/gui/OptionBG.png");

    /* Widget Text */
    QStaticText createText = QStaticText("Create New World");

    GameLabel *WorldNameLabel = new GameLabel("Will be saved in:", this);
    GameLabel *Label1 = new GameLabel("World Name", this);
    GameLineEdit *inputWorldName = new GameLineEdit(this);
    GameButton *Cancel = new GameButton("Cancel", this);
    GameButton *CreateNewWorld = new GameButton("Create New World", this);
    CreatingWorld *cw = new CreatingWorld(this);

    QString curMapName;
signals:
    void select_world();
};

#endif // CREATEMAP_H

createmap.cpp

#include "createmap.h"

CreateMap::CreateMap(QWidget *parent, int width, int height, QString title) : BaseWidget(parent, width, height, title)
{
    QObject::connect(Cancel, &GameButton::clicked, [=]() {
        sendInfo("Player Clicked Cancel Button");
        buttonSound->play();
        select_world();
    });

    QObject::connect(CreateNewWorld, &GameButton::clicked, [=](){
        sendInfo("Player Clicked CreateNewWorld Button");
        buttonSound->play();
        cw->show();

        Map gameMap = Map(curMapName);

        /* Step 1: Gen Bedrock */
        for(int i = 0; i < MapWidth; ++i) {
            gameMap.MAPP[MapHeight - 1][i] = BLOCK::BEDROCK;
            cw->pb->setValue(5.0 * i / MapWidth);
            switch(langMode) {
            case 1:
                cw->pb->setFormat(QString("生成基岩中......: %1%").arg(QString::number(5.0 * i / MapWidth, 'f', 2)));
                break;
            case 2:
                cw->pb->setFormat(QString("Generating Bedrock......: %1%").arg(QString::number(5.0 * i / MapWidth, 'f', 2)));
                break;
            case 3:
                cw->pb->setFormat(QString("生成基岩中......: %1%").arg(QString::number(5.0 * i / MapWidth, 'f', 2)));
                break;
            case 4:
                cw->pb->setFormat(QString("岩盤の生成......: %1%").arg(QString::number(5.0 * i / MapWidth, 'f', 2)));
                break;
            }
            QCoreApplication::processEvents();
        }

        sendInfo("Bedrock has been generated");

        /* Step 2: Gen Grass */
        qsrand(gameMap.seed);
        int cur = myRand(70, 100);
        bool isUp = (cur > 85 ? false : true);
        gameMap.MAPP[cur][0] = BLOCK::GRASSBLOCK;

        for(int i = 1; i < MapWidth; ++i) {

            int delta = myRand(0, 1000) & 1;
            cur = (isUp ? cur + delta : cur - delta);

            isUp = isUp ^ (myRand(0, 1000) & 1);
            if(cur > 100) isUp = false;
            if(cur < 70) isUp = true;

            gameMap.MAPP[cur][i] = BLOCK::GRASSBLOCK;

            cw->pb->setValue(5 + 10.0 * i / MapWidth);
            switch(langMode) {
            case 1:
                cw->pb->setFormat(QString("生成草方块中......: %1%").arg(QString::number(5 + 10.0 * i / MapWidth, 'f', 2)));
                break;
            case 2:
                cw->pb->setFormat(QString("Generating GrassBlock......: %1%").arg(QString::number(5 + 10.0 * i / MapWidth, 'f', 2)));
                break;
            case 3:
                cw->pb->setFormat(QString("生成草方塊中......: %1%").arg(QString::number(5 + 10.0 * i / MapWidth, 'f', 2)));
                break;
            case 4:
                cw->pb->setFormat(QString("草の生成......: %1%").arg(QString::number(5 + 10.0 * i / MapWidth, 'f', 2)));
                break;
            }
            QCoreApplication::processEvents();

        }

        sendInfo("GrassBlock has been generated");


        cw->pb->setRange(0, 0);
        switch(langMode) {
        case 1:
            cw->setWindowTitle(QString("保存地图中......"));
            break;
        case 2:
            cw->setWindowTitle(QString("Saving Map......"));
            break;
        case 3:
            cw->setWindowTitle(QString("保存地圖中......"));
            break;
        case 4:
            cw->setWindowTitle(QString("保存マップ......"));
            break;
        }
        QCoreApplication::processEvents();
        if(!gameMap.createMap()) {
            sendError("Unable To Create Map");
            switch(langMode) {
            case 1:
                QMessageBox::critical(this, "错误", "无法创建地图!");
                break;
            case 2:
                QMessageBox::critical(this, "Wrong", "Unable To Create Map!");
                break;
            case 3:
                QMessageBox::critical(this, "錯誤", "無法創建地圖!");
                break;
            case 4:
                QMessageBox::critical(this, "エラー", "地図が作成できません!");
                break;
            }
        }
        QCoreApplication::processEvents();
        cw->pb->setRange(0, 100);

        inputWorldName->textChanged("");
        cw->hide();
        select_world();
    });

    inputWorldName->setMaxLength(20);
    QObject::connect(inputWorldName, &QLineEdit::textChanged, [=]() {
        sendInfo("Input World Name Changed");
        if(inputWorldName->text().length() == 0) CreateNewWorld->setEnabled(false);
        else CreateNewWorld->setEnabled(true);
        curMapName = replaceStr(inputWorldName->text(),
                                       "\\/:*?\"<>|",
                                       '_');

        sendInfo("world name changed as:" + curMapName);
        while(!checkName(curMapName)) curMapName += '_';

        switch(langMode) {
        case 1:
            WorldNameLabel->setText("将会被保存为: " + curMapName);
            break;
        case 2:
            WorldNameLabel->setText("Will be saved in: " + curMapName);
            break;
        case 3:
            WorldNameLabel->setText("將會被保存為: " + curMapName);
            break;
        case 4:
            WorldNameLabel->setText("に保存されます: " + curMapName);
            break;
        }
    });
}

void CreateMap::paintEvent(QPaintEvent *event)
{
    QPainter p(this);

    /* Draw Background */
    p.drawImage(QRect(0, 0, width(), height()), bg);

    /* Draw Text */
    p.setFont(font());
    p.setPen(QColor(255, 255, 255));
    p.drawStaticText((width() - createText.size().width()) / 2,
                     (createText.size().height() * 1.5) * height() / 720,
                     createText);
}

void CreateMap::resizeEvent(QResizeEvent *event)
{
    this->inputWorldName->resize(500 * width() / 1280, 55 * height() / 720);
    this->Cancel->resize(400 * width() / 1280, 40 * height() / 720);
    this->CreateNewWorld->resize(400 * width() / 1280, 40 * height() / 720);

    this->inputWorldName->move((width() - inputWorldName->width()) / 2, 150 * height() / 720);
    this->WorldNameLabel->move((width() - inputWorldName->width()) / 2, 150 * height() / 720 + inputWorldName->height());
    this->Label1->move((width() - inputWorldName->width()) / 2, 150 * height() / 720 - Label1->height());
    this->CreateNewWorld->move((width() / 2 - CreateNewWorld->width()) / 2,
                       height() - CreateNewWorld->height() * 1.5);
    this->Cancel->move(width() / 2 + (width() / 2 - Cancel->width()) / 2,
                               height() - Cancel->height() * 1.5);
}

void CreateMap::keyPressEvent(QKeyEvent *event)
{
    switch (event->key()) {
    /* F11 -> Full Screen */
    case Qt::Key_F11:
        if(!isFullScreen()) this->showFullScreen();
        else this->showNormal();
        break;
    /* ESC -> Go To Main Interface */
    case Qt::Key_Escape:
        select_world();
        break;
    }
}

void CreateMap::updateFont(QFont font)
{
    setFont(font);
    createText.prepare(QTransform(), font);
    inputWorldName->setFont(font);
    WorldNameLabel->setFont(font);
    Cancel->setFont(font);
    CreateNewWorld->setFont(font);
}

void CreateMap::updateLang(int langMode)
{
        this->langMode = langMode;
    this->langMode = langMode;
    if(langMode == 1) {
        createText.setText("创建新的世界");
        inputWorldName->setText("新的世界");
        inputWorldName->setPlaceholderText("世界名称");
        Cancel->setText("取消");
        CreateNewWorld->setText("创建新的世界");
        Label1->setText("世界名称");
        cw->setWindowTitle("创建世界中……");
        setWindowTitle(CN_TITLE);
    } else if(langMode == 2) {
        createText.setText("Create New World");
        inputWorldName->setPlaceholderText("World Name");
        inputWorldName->setText("New World");
        Cancel->setText("Cancel");
        CreateNewWorld->setText("Create New World");
        Label1->setText("World Name");
        cw->setWindowTitle("Creating World……");
        setWindowTitle(TITLE);
    } else if(langMode == 3) {
        createText.setText("創建新的世界");
        inputWorldName->setPlaceholderText("世界名稱");
        inputWorldName->setText("新的世界");
        Cancel->setText("取消");
        CreateNewWorld->setText("創建新的世界");
        Label1->setText("世界名稱");
        cw->setWindowTitle("創建世界中……");
        setWindowTitle(TW_TITLE);
    } else if(langMode == 4) {
        createText.setText("新しい世界を創造する");
        inputWorldName->setPlaceholderText("世界名");
        inputWorldName->setText("新世界");
        Cancel->setText("キャンセル");
        CreateNewWorld->setText("新しい世界を創造する");
        cw->setWindowTitle("世界を創る……");
        Label1->setText("世界名");
        setWindowTitle(JP_TITLE);
    }
}

gamewidget.h

#ifndef GAMEWIDGET_H
#define GAMEWIDGET_H

#include "basewidget.h"
#include "Tool.h"

enum DIR {
    LEFT, RIGHT, UP, DOWN
};

class Entity {
public:
    int x, y;
    int curHealth, maxHealth;
    QString name;

    Entity(QString name, int curHealth, int maxHealth) : name(name), curHealth(curHealth), maxHealth(maxHealth) {};
};

class ItemDrop : public Entity {
};
class Monster : public Entity {
};
class Animal : public Entity {
};

class Player : public Entity {

public:
    int speed = 10;
    QImage player_image = PLAYER_FRONT;
    Player() : Entity("Steve", 20, 20) {};
    void setPos(int x, int y) {
        this->x = max(0, x);
        this->y = max(0, y);
    };
    void move(int dir) {
        switch(dir) {
        case LEFT:setPos(x, y - speed);player_image = PLAYER_LEFT;break;
        case RIGHT:setPos(x, y + speed);player_image = PLAYER_RIGHT;break;
        case DOWN:setPos(x + speed, y);player_image = PLAYER_DOWN;break;
        case UP:setPos(x - speed, y);player_image = PLAYER_UP;break;
        }

    }
};

class GameWidget : public BaseWidget
{
    Q_OBJECT
public:
    int fps;
    bool isRunning = false;
    GameWidget(int fps, QWidget *parent, int width, int height, QString title);
    Map CurrentMap();
    void startGame();
    void quitGame();
    void run();
    void paintEvent(QPaintEvent *event) override;
    void updatePlayerPos();
    void updateWorld();
    void resizeEvent(QResizeEvent *event) override;
    void wait();

    void keyPressEvent(QKeyEvent *event) override;
    void keyReleaseEvent(QKeyEvent *event) override;
    void mousePressEvent(QMouseEvent *event) override;

    Player player;
    QSet<int> pressedKeys;
};
#endif // GAMEWIDGET_H


gamewidget.cpp

#include "gamewidget.h"

GameWidget::GameWidget(int fps, QWidget *parent, int width, int height, QString title) : fps(fps), BaseWidget(parent, width, height, title)
{
    player.setPos(0, 0);
}

void GameWidget::startGame()
{
    if(isRunning) return;
    isRunning = true;
    run();
}

void GameWidget::run() {
    while(isRunning) {
        repaint();
        updatePlayerPos();
        MySleep(1000 / fps);
    }
}

void GameWidget::paintEvent(QPaintEvent *event)
{
    QPainter p(this);
    int y = -(player.x % BLOCK::BLOCK_WIDTH), x = -(player.y % BLOCK::BLOCK_HEIGHT);
    for(int i = 0; i <= width() / BLOCK::BLOCK_WIDTH + 1; ++i) {
        for(int j = 0; j <= height() / BLOCK::BLOCK_HEIGHT + 1; ++j) {
            switch(myRand(BLOCK::AIR, BLOCK::STONE)) {
            case BLOCK::STONE:p.drawImage(QRect(x + BLOCK::BLOCK_WIDTH * i, y + BLOCK::BLOCK_HEIGHT * j, BLOCK::BLOCK_WIDTH, BLOCK::BLOCK_HEIGHT), BLOCK::STONE_IMAGE);break;
            case BLOCK::DIRT:p.drawImage(QRect(x + BLOCK::BLOCK_WIDTH * i, y + BLOCK::BLOCK_HEIGHT * j, BLOCK::BLOCK_WIDTH, BLOCK::BLOCK_HEIGHT), BLOCK::DIRT_IMAGE);break;
            case BLOCK::GRASSBLOCK:p.drawImage(QRect(x + BLOCK::BLOCK_WIDTH * i, y + BLOCK::BLOCK_HEIGHT * j, BLOCK::BLOCK_WIDTH, BLOCK::BLOCK_HEIGHT), BLOCK::GRASSBLOCK_IMAGE);break;
            case BLOCK::BEDROCK:p.drawImage(QRect(x + BLOCK::BLOCK_WIDTH * i, y + BLOCK::BLOCK_HEIGHT * j, BLOCK::BLOCK_WIDTH, BLOCK::BLOCK_HEIGHT), BLOCK::BEDROCK_IMAGE);break;
            }


        }
    }
    p.drawImage(QRect((width() - BLOCK::BLOCK_WIDTH) / 2, (height() - BLOCK::BLOCK_HEIGHT * 2) / 2, BLOCK::BLOCK_WIDTH, BLOCK::BLOCK_HEIGHT * 2), player.player_image);
}

void GameWidget::updatePlayerPos()
{
    for(auto i : pressedKeys) {
        switch(i) {
        case Qt::Key_W : player.move(UP); break;
        case Qt::Key_A : player.move(LEFT); break;
        case Qt::Key_S : player.move(DOWN); break;
        case Qt::Key_D : player.move(RIGHT); break;
        }
    }
}

void GameWidget::updateWorld()
{

}

void GameWidget::resizeEvent(QResizeEvent *event)
{
    BLOCK::BLOCK_WIDTH = 48 * width() / 1280;
    BLOCK::BLOCK_HEIGHT = 48 * height() / 720;
    repaint();
}

void GameWidget::keyPressEvent(QKeyEvent *event)
{
    if(!event->isAutoRepeat()) pressedKeys.insert(event->key());
}

void GameWidget::keyReleaseEvent(QKeyEvent *event)
{
    if(!event->isAutoRepeat()) pressedKeys.remove(event->key());
}

void GameWidget::mousePressEvent(QMouseEvent *event)
{
    sendInfo(QString::number(event->x()) + "-" + QString::number(event->y()));
}

void GameWidget::quitGame()
{
    if(!isRunning) return;
    isRunning = false;
}

Tool.cpp

#ifndef TOOL_H
#define TOOL_H

#include <QDebug>
#include <QTime>
#include <QFont>
#include <QSound>
#include <QStaticText>
#include <QPushButton>
#include <QMouseEvent>
#include <QScrollBar>
#include <QThread>
#include <QTimer>
#include <QLineEdit>
#include <QWidget>
#include <QLabel>
#include <QIcon>
#include <QPainter>
#include <QKeyEvent>
#include <QWidget>
#include <QImage>
#include <QPushButton>
#include <QStaticText>
#include <QPainter>
#include <QKeyEvent>
#include <QIcon>
#include <QPainter>
#include <QWidget>
#include <QImage>
#include <QKeyEvent>
#include <QStaticText>
#include <QFontDialog>
#include <QFile>
#include <QDialog>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonValue>
#include <QByteArray>
#include <QJsonParseError>
#include <QComboBox>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QLabel>
#include <QApplication>
#include <QWidget>
#include <QPushButton>
#include <QTranslator>
#include <QIcon>
#include <Qt>
#include <QObject>
#include <QDesktopWidget>
#include <QPalette>
#include <QProgressBar>
#include <QDir>
#include <QProgressDialog>
#include <QtGlobal>
#include <QTableView>
#include <QSet>
#include <QTableWidget>
#include <QTableWidgetItem>
#include <QTableWidgetSelectionRange>
#include <QListWidget>
#include <QElapsedTimer>
#include <QListWidgetItem>
#include <QMessageBox>

/* Game Title */
static QString TITLE =  "Minecraft 2D v0.0.6";
static QString CN_TITLE = "我的世界 2D v0.0.6";
static QString TW_TITLE = "我的世界 2D v0.0.6";
static QString JP_TITLE = "マインクラフト v0.0.6";

const static QImage PLAYER_FRONT(":/entity/images/entity/player_front.png");
const static QImage PLAYER_LEFT(":/entity/images/entity/player_left.png");
const static QImage PLAYER_RIGHT(":/entity/images/entity/player_right.png");
const static QImage PLAYER_BACK(":/entity/images/entity/player_back.png");
const static QImage PLAYER_UP(":/entity/images/entity/player_up.png");
const static QImage PLAYER_DOWN(":/entity/images/entity/player_down.png");

class GameButton : public QPushButton
{
    Q_OBJECT
public:
    explicit GameButton(QString text = nullptr, QWidget *parent = nullptr) : QPushButton(text, parent){
        this->resize(400, 40);
        /* Enabled : White */
        /* Hoverd : Golden */
        /* Disabled : Grey */
        this->setStyleSheet("QPushButton{border-image: url(:/gui/images/gui/button_normal.png);color:rgb(255, 255, 255);}"
                            "QPushButton::hover{border-image: url(:/gui/images/gui/button_select.png);color:rgb(255, 215, 0);}"
                            "QPushButton::disabled{border-image: url(:/gui/images/gui/button_disabled.png);color:rgb(128, 128, 128)};");
    };
};

class GameLineEdit : public QLineEdit
{
    Q_OBJECT
public:
    GameLineEdit(QWidget *parent = nullptr) : QLineEdit(parent)
    {
        setStyleSheet("QLineEdit{border:3px solid grey;"
                      "background:black;"
                      "color:white}");
        resize(500, 55);
    };
};

class GameLabel : public QLabel {
    Q_OBJECT
public:
    GameLabel(QString text = "", QWidget *parent = nullptr) : QLabel(text, parent) {
        resize(1000, 50);
        QPalette pa;
        pa.setColor(QPalette::WindowText, Qt::gray);
        setPalette(pa);
    }
};

/* Loggers */
static void sendInfo(QString msg) {
    QDateTime current_time = QDateTime::currentDateTime();
    qDebug() << "[" + current_time.toString("yyyy-MM-dd hh:mm:ss") +  ("][Info]") + msg;
}

static void sendError(QString msg) {
    QDateTime current_time = QDateTime::currentDateTime();
    qDebug() << "[" + current_time.toString("yyyy-MM-dd hh:mm:ss") +  ("][Error]") + msg;
}

static void sendWarning(QString msg) {
    QDateTime current_time = QDateTime::currentDateTime();
    qDebug() << "[" + current_time.toString("yyyy-MM-dd hh:mm:ss") +  ("][Warning]") + msg;
}

static void sendInfo(int num) {
    sendInfo(QString::number(num));
}

/* Easy Function */
static QString replaceStr(QString before, QString after, QChar c) {
    if(before.length() == 0) {
        return "(NULL)";
    }
    int len = after.length();
    for(int i = 0; i < len; ++i) {
        before.replace(after[i], c);
    }
    return before;
}

static int myRand(int minn, int maxn) {
    return qrand() % (maxn - minn + 1) + minn;
}

static bool checkName(QString mapName) {
    QDir saves;
    return !saves.exists("saves/" + mapName);
}

static void MySleep(int msec) {
    QElapsedTimer t;
    t.start();
    while(t.elapsed() < msec) QCoreApplication::processEvents();
}

static int max(int x, int y) {
    return x > y ?  x : y;
}

namespace BLOCK {

enum BlockID {
    AIR, BEDROCK, GRASSBLOCK, DIRT, STONE
};

static int BLOCK_WIDTH = 48;
static int BLOCK_HEIGHT = 48;
const static QImage DIRT_IMAGE(":/block/images/blocks/dirt.png");
const static QImage BEDROCK_IMAGE(":/block/images/blocks/bedrock.png");
const static QImage GRASSBLOCK_IMAGE(":/block/images/blocks/grass_block_side.png");
const static QImage STONE_IMAGE(":/block/images/blocks/stone.png");

class Block {
public:
    short id; QString name;
    Block() : id(0), name("") {};
    Block(short id, QString name) : id(id), name(name) {};

    virtual void onRightClick(){
        sendInfo("Block be clicked");
    };
};
}

const int MapWidth = 50000;
const int MapHeight = 150;
const int MapSize = MapWidth * MapHeight;



class Map {
public:
    short **MAPP = nullptr;
    int seed;
    QString mapName;


    Map(QString name, int seed = -1) {
        MAPP = (short **)malloc(sizeof(short *) * MapHeight);
        for(int i = 0; i < MapHeight; ++i)
            MAPP[i] = (short *)malloc(sizeof(short) * MapWidth);


        qsrand(QTime(0, 0, 0).secsTo(QTime::currentTime()));
        if(seed == -1) this->seed = qrand();

        mapName = name;
        for(int i = 0; i < MapHeight; ++i) {
            for(int j = 0; j < MapWidth; ++j) {
                this->MAPP[i][j] = BLOCK::AIR;
            }
        }
    }
    bool isSameName() {
        QDir saves;
        return saves.exists("saves/" + mapName);
    }
    bool createMap() {
        QDir saves;
        if(!saves.exists("saves")) saves.mkdir("saves");
        if(isSameName()) return false;
        saves.mkdir("saves/" + mapName);

        QFile MapFile("saves/" +  mapName + "/map.mc2d");
        QFile setting("saves/" + mapName + "/setting.mc2d");
        if(!MapFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
            return false;
        }
        if(!setting.open(QIODevice::WriteOnly | QIODevice::Text)) {
            return false;
        }
        QTextStream out(&MapFile);
        for(int i = 0; i < MapHeight; ++i) {
            for(int j = 0; j < MapWidth; ++j) {
                out << this->MAPP[i][j] << " ";
            }
            QCoreApplication::processEvents();
            out << "\n";
        }
        MapFile.close();

        QJsonObject obj;
        obj.insert("seed", QJsonValue(seed));
        obj.insert("MapName", mapName);
        QJsonDocument doc(obj);
        setting.write(doc.toJson());

        setting.close();

        return true;
    }
};

#endif // LOGGER_H
上一篇:[React] Write a Custom State Hook in React


下一篇:LeetCode 第三题--无重复字符的最长子串