diff --git a/src/Client/CMakeLists.txt b/src/Client/CMakeLists.txt index eb13bd4..a39536b 100644 --- a/src/Client/CMakeLists.txt +++ b/src/Client/CMakeLists.txt @@ -50,8 +50,8 @@ if (ANDROID) addDeployAPK(${CURRENT_PROJECT} "${CMAKE_CURRENT_LIST_DIR}/android" - "Crawl" - "${SIGPATH}/Crawl.keystore" + "Snake" + "${SIGPATH}/Snake.keystore" "${SIGPASS_SNAKE}" "${TARGET_DIR}" "${SNAKE_EXTRA_LIBS}") diff --git a/src/Core/Crawl/claster.cpp b/src/Core/Crawl/claster.cpp new file mode 100644 index 0000000..5f37fa2 --- /dev/null +++ b/src/Core/Crawl/claster.cpp @@ -0,0 +1,41 @@ +//# +//# Copyright (C) 2021-2021 QuasarApp. +//# Distributed under the GPLv3 software license, see the accompanying +//# Everyone is permitted to copy and distribute verbatim copies +//# of this license document, but changing it is not allowed. +//# + +#include "claster.h" +#include "singleclasterworlditem.h" + +Claster::Claster(const QString &name, + const QString &viewTempalte, + QObject *ptr): + IWorldItem(name, viewTempalte, ptr) { + +} + +Claster::~Claster() { + for (auto child : qAsConst(_objects)) { + child->removeClaster(this); + } +} + +void Claster::add(ClasterItem *object) { + _objects.insert(object->guiId(), object); + if (auto singlClasterObject = dynamic_cast(object)) { + singlClasterObject->setClaster(this); + } +} + +void Claster::remove(ClasterItem *object) { + _objects.remove(object->guiId()); +} + +void Claster::remove(int id) { + _objects.remove(id); +} + +const QHash &Claster::objects() const { + return _objects; +} diff --git a/src/Core/Crawl/claster.h b/src/Core/Crawl/claster.h new file mode 100644 index 0000000..d341d24 --- /dev/null +++ b/src/Core/Crawl/claster.h @@ -0,0 +1,57 @@ +//# +//# Copyright (C) 2021-2021 QuasarApp. +//# Distributed under the GPLv3 software license, see the accompanying +//# Everyone is permitted to copy and distribute verbatim copies +//# of this license document, but changing it is not allowed. +//# + +#ifndef CLASTER_H +#define CLASTER_H + +#include "Crawl/iworlditem.h" + +class ClasterItem; + +/** + * @brief The Claster class are object with support multiple objects render. + * For example snake with 20 points of the snake blocks. + */ +class CRAWL_EXPORT Claster: public IWorldItem +{ + Q_OBJECT +public: + Claster(const QString& name, + const QString& viewTempalte = DEFAULT_VIEW_TEMPLATE, + QObject *ptr = nullptr); + + ~Claster(); + + /** + * @brief add This method added new object to claster. + * @param object This is model of added object + */ + void add(ClasterItem* object); + + /** + * @brief remove This method remove object from claster + * @param object poiter of removed object + */ + void remove(ClasterItem* object); + + /** + * @brief remove some as a Claster::remove(IWorldItem* object) but by id. + * @param id of the remved object. + */ + void remove(int id); + + /** + * @brief objects This method return list of collected objects. + * @return return const reference to objects list . + */ + const QHash &objects() const; + +private: + QHash _objects; +}; + +#endif // CLASTER_H diff --git a/src/Core/Crawl/clasteritem.cpp b/src/Core/Crawl/clasteritem.cpp new file mode 100644 index 0000000..6294640 --- /dev/null +++ b/src/Core/Crawl/clasteritem.cpp @@ -0,0 +1,38 @@ +//# +//# Copyright (C) 2021-2021 QuasarApp. +//# Distributed under the GPLv3 software license, see the accompanying +//# Everyone is permitted to copy and distribute verbatim copies +//# of this license document, but changing it is not allowed. +//# + +#include "claster.h" +#include "clasteritem.h" + +ClasterItem::ClasterItem(const QString &name, + const QString &viewTempalte, + QObject *ptr): + IWorldItem(name, viewTempalte, ptr) { + +} + +ClasterItem::~ClasterItem() { + for (auto claster : qAsConst(_parentClasters)) { + claster->remove(this); + } +} + +int ClasterItem::parentClastersCount() const { + return _parentClasters.size(); +} + +void ClasterItem::setClaster(Claster *claster) { + _parentClasters += claster; +} + +void ClasterItem::removeClaster(Claster *claster) { + _parentClasters -= claster; +} + +const QSet &ClasterItem::parentClasters() const { + return _parentClasters; +} diff --git a/src/Core/Crawl/clasteritem.h b/src/Core/Crawl/clasteritem.h new file mode 100644 index 0000000..503b1c4 --- /dev/null +++ b/src/Core/Crawl/clasteritem.h @@ -0,0 +1,62 @@ +//# +//# Copyright (C) 2021-2021 QuasarApp. +//# Distributed under the GPLv3 software license, see the accompanying +//# Everyone is permitted to copy and distribute verbatim copies +//# of this license document, but changing it is not allowed. +//# + +#include "iworlditem.h" + +#include + + +#ifndef CLASTERITEM_H +#define CLASTERITEM_H + +class Claster; + +/** + * @brief The ClasterItem class This is item of the claster object. Thi class can be used as a one element of the claster class. + * @note This object invoke the Claster::remove method in destructor. + */ +class CRAWL_EXPORT ClasterItem: public IWorldItem +{ + Q_OBJECT +public: + ClasterItem(const QString& name, + const QString& viewTempalte = DEFAULT_VIEW_TEMPLATE, + QObject *ptr = nullptr); + ~ClasterItem(); + + /** + * @brief parentClastersCount This method return count of the parent clasters. + * @return parent clasters count + */ + int parentClastersCount() const; + +protected: + /** + * @brief setClaster invoked when object added to new claster. + * @param claster pointer to invoker claster object. + */ + virtual void setClaster(Claster *claster); + + /** + * @brief removeClaster + * @param claster + */ + virtual void removeClaster(Claster *claster); + + /** + * @brief parentClasters return current parent clasters list; + * @return + */ + const QSet &parentClasters() const; +private: + + QSet _parentClasters; + + friend class Claster; +}; + +#endif // CLASTERITEM_H diff --git a/src/Core/Crawl/clientapp.h b/src/Core/Crawl/clientapp.h index 8f89b5b..ac7e6c4 100644 --- a/src/Core/Crawl/clientapp.h +++ b/src/Core/Crawl/clientapp.h @@ -40,7 +40,7 @@ class CRAWL_EXPORT ClientApp : public QObject Q_OBJECT public: ClientApp(); - ~ClientApp(); + ~ClientApp() override; /** * @brief init This method initialize engine on application. diff --git a/src/Core/Crawl/guiobject.cpp b/src/Core/Crawl/guiobject.cpp index fdade29..88319e3 100644 --- a/src/Core/Crawl/guiobject.cpp +++ b/src/Core/Crawl/guiobject.cpp @@ -9,11 +9,11 @@ #include -GuiObject::GuiObject(const QString &viewTempalte, QObject *ptr): +GuiObject::GuiObject(const QString &name, const QString &viewTempalte, QObject *ptr): QObject (ptr) { _viewTemplate = viewTempalte; + _className = name; generateId(); - } QString GuiObject::color() const { @@ -33,6 +33,10 @@ void GuiObject::generateId() { _guiId = id++; } +const QString &GuiObject::className() const { + return _className; +} + void GuiObject::reset() { setX(0); setY(0); diff --git a/src/Core/Crawl/guiobject.h b/src/Core/Crawl/guiobject.h index e746dd0..2e4f8a7 100644 --- a/src/Core/Crawl/guiobject.h +++ b/src/Core/Crawl/guiobject.h @@ -15,6 +15,8 @@ #include #include "Crawl/irender.h" +#define DEFAULT_VIEW_TEMPLATE "qrc:/CrawlModule/GraphicItem.qml" + /** * @brief The GuiObject class This base model for gui objects. */ @@ -38,7 +40,9 @@ class CRAWL_EXPORT GuiObject: public QObject, public IRender { public: - GuiObject(const QString& viewTempalte = "qrc:/CrawlModule/GraphicItem.qml", QObject *ptr = nullptr); + GuiObject(const QString& name, + const QString& viewTempalte = DEFAULT_VIEW_TEMPLATE, + QObject *ptr = nullptr); QString color() const; void setColor(QString color); @@ -97,6 +101,14 @@ public: const QString &mash() const; void setMash(const QString &newMash); + /** + * @brief className This method return class name. + * The class name using as a group of objects on thw world. + * @return class name; + * @note the class name should be sets on the consturctor of child classes of this class. + */ + const QString &className() const; + signals: void guiIdChanged(int guiId); void colorChanged(QString color); @@ -131,6 +143,7 @@ private: QVector3D _size; QQuaternion _ratation; QString _mash; + QString _className; }; #endif // GUIOBJECT_H diff --git a/src/Core/Crawl/iground.cpp b/src/Core/Crawl/iground.cpp index f8c68b4..3a97c55 100644 --- a/src/Core/Crawl/iground.cpp +++ b/src/Core/Crawl/iground.cpp @@ -8,7 +8,10 @@ #include "iground.h" #include "iworld.h" -IGround::IGround() { +IGround::IGround(const QString &name, + const QString &viewTempalte, + QObject *ptr): + IWorldItem(name, viewTempalte, ptr) { } diff --git a/src/Core/Crawl/iground.h b/src/Core/Crawl/iground.h index c60c749..8dbd4b0 100644 --- a/src/Core/Crawl/iground.h +++ b/src/Core/Crawl/iground.h @@ -16,7 +16,9 @@ */ class CRAWL_EXPORT IGround: public IWorldItem { public: - IGround(); + IGround(const QString& name, + const QString& viewTempalte = DEFAULT_VIEW_TEMPLATE, + QObject *ptr = nullptr); // IRender interface public: diff --git a/src/Core/Crawl/iplayer.cpp b/src/Core/Crawl/iplayer.cpp index 736007c..d1d80ff 100644 --- a/src/Core/Crawl/iplayer.cpp +++ b/src/Core/Crawl/iplayer.cpp @@ -7,7 +7,10 @@ #include "iplayer.h" -IPlayer::IPlayer() { +IPlayer::IPlayer(const QString &name, + const QString &viewTempalte, + QObject *ptr): + IWorldItem(name, viewTempalte, ptr) { } diff --git a/src/Core/Crawl/iplayer.h b/src/Core/Crawl/iplayer.h index f46f386..0a3a3dc 100644 --- a/src/Core/Crawl/iplayer.h +++ b/src/Core/Crawl/iplayer.h @@ -20,7 +20,9 @@ class IControl; class CRAWL_EXPORT IPlayer: public IWorldItem { Q_OBJECT public: - IPlayer(); + IPlayer(const QString& name, + const QString& viewTempalte = DEFAULT_VIEW_TEMPLATE, + QObject *ptr = nullptr); /** * @brief getCurrentStatus This method return current game state of the player. @@ -90,6 +92,12 @@ protected: */ void fine(int value); + /** + * @brief onTap This method invoked when user tap on screen. + * @note method connected in the IPlayer::setControl function. So if you overrid the IPlayer::setControl method then please invoke method of a parent class. + */ + virtual void onTap() = 0; + private: bool _fDead = false; int _currentPoints = 0; diff --git a/src/Core/Crawl/irender.h b/src/Core/Crawl/irender.h index 2f66981..7c996f4 100644 --- a/src/Core/Crawl/irender.h +++ b/src/Core/Crawl/irender.h @@ -17,6 +17,7 @@ class CRAWL_EXPORT IRender { public: IRender(); + virtual ~IRender() = default; /** * @brief render This method should be recalc all properyes of the this object. diff --git a/src/Core/Crawl/iworld.cpp b/src/Core/Crawl/iworld.cpp index eb256d9..b5fa62e 100644 --- a/src/Core/Crawl/iworld.cpp +++ b/src/Core/Crawl/iworld.cpp @@ -5,6 +5,7 @@ //# of this license document, but changing it is not allowed. //# +#include "claster.h" #include "iai.h" #include "iworld.h" #include "iworlditem.h" @@ -14,6 +15,7 @@ #include "defaultcontrol.h" #include "worldstatus.h" #include "iai.h" +#include "clasteritem.h" IWorld::IWorld() { @@ -30,11 +32,11 @@ IControl *IWorld::initUserInterface() const { void IWorld::render(unsigned int tbfMsec) { for (auto i = _items.begin(); i != _items.end(); ++i) { - (*i).objectPtr->render(tbfMsec); + (*i)->render(tbfMsec); // intersects event. - if ((*i).objectPtr->intersects(*_player)) { - _player->onIntersects((*i).objectPtr); + if ((*i)->intersects(*_player)) { + _player->onIntersects((*i)); } } @@ -61,10 +63,38 @@ bool IWorld::start() { worldChanged(*_worldRules->begin()); - return true; } +QObject *IWorld::player() const { + return _player; +} + +void IWorld::setPlayer(QObject *newPlayer) { + if (_player == newPlayer) + return; + + auto newPlayerObject = dynamic_cast(newPlayer); + if (!newPlayerObject) { + QuasarAppUtils::Params::log("Failed to set player object. The input object is not player.", + QuasarAppUtils::Error); + return; + } + + if (_player) { + removeIAtomicItem(_player->guiId()); + } + + _player = newPlayerObject; + addAtomicItem(_player); + + emit playerChanged(); +} + +IWorldItem *IWorld::generate(const QString &objectType) const { + return _registeredTypes.value(objectType, [](){return nullptr;}).operator()(); +} + bool IWorld::stop() { start(); @@ -81,7 +111,7 @@ IAI *IWorld::initBackGroundAI() const { } IWorldItem *IWorld::getItem(int id) const { - return _items.value(id, {}).objectPtr; + return _items.value(id, nullptr); } bool IWorld::init() { @@ -90,8 +120,9 @@ bool IWorld::init() { return true; _worldRules = initWorldRules(); + _hdrMap = initHdrBackGround(); - _player = initPlayer(); + setPlayer(initPlayer()); _player->initOnWorld(this, _player); _userInterface = initUserInterface(); _backgroundAI = initBackGroundAI(); @@ -109,19 +140,67 @@ bool IWorld::init() { initPlayerControl(_userInterface); initPlayerControl(dynamic_cast(_backgroundAI)); - generateGround(); return true; } void IWorld::clearItems() { for (const auto& item : qAsConst(_items)) { - delete item.objectPtr; + delete item; } _items.clear(); } +void IWorld::addItem(IWorldItem *obj, QList *addedObjectsList) { + if (!obj) + return; + + // Work wih claster + if (auto claster = dynamic_cast(obj)) { + for (auto item : claster->objects()) { + addAtomicItem(item); + if (item && addedObjectsList) { + addedObjectsList->push_back(item->guiId()); + } + } + } + + addAtomicItem(obj); + if (addedObjectsList) + addedObjectsList->push_back(obj->guiId()); + +} + +void IWorld::removeItem(int id, QList *removedObjectsList) { + + auto obj = getItem(id); + + if (!obj) + return; + + // Work wih claster + if (auto claster = dynamic_cast(obj)) { + auto copyOfObjectsList = claster->objects(); + for (auto item : copyOfObjectsList) { + if (!item || !item->parentClastersCount()) + continue; + + int id = item->guiId(); + + removeIAtomicItem(item); + if (removedObjectsList) + removedObjectsList->push_back(id); + + } + } + + addAtomicItem(obj); + if (removedObjectsList) + removedObjectsList->push_back(obj->guiId()); + +} + void IWorld::deinit() { if (_player) { delete _player; @@ -148,49 +227,47 @@ void IWorld::deinit() { } -void IWorld::generateGround() { - int count = 10; - QVector3D position = {0,0,0}; - float increment = cameraReleativePosition().z() * 2; +void IWorld::addAtomicItem(IWorldItem* obj) { + if (!obj) + return; - while (count--) { - auto item = generateGroundTile(); - item->initOnWorld(this, _player); - - position.setX(position.x() + increment); - item->setposition(position); - addItem("groundTile", item); - } + _items.insert(obj->guiId(), obj); + _itemsGroup.insert(obj->className(), obj->guiId()); } -void IWorld::addItem(const QString& group, IWorldItem* obj) { - _items.insert(obj->guiId(), WorldObjectWraper{obj, group}); - _itemsGroup.insert(group, obj->guiId()); -} - -bool IWorld::removeItem(int id) { +bool IWorld::removeIAtomicItem(int id) { auto obj = _items.value(id); - if (!obj.objectPtr) { + if (!obj) { return false; } - _itemsGroup.remove(obj.groupName, id); + _itemsGroup.remove(obj->className(), id); _items.remove(id); - delete obj.objectPtr; + delete obj; return true; } -int IWorld::removeAnyItemFromGroup(const QString &group) { - int anyObjectId = _itemsGroup.value(group); - if (!removeItem(anyObjectId)) { +bool IWorld::removeIAtomicItem(IWorldItem *obj) { + if (!obj) { return false; } - return anyObjectId; + _itemsGroup.remove(obj->className(), obj->guiId()); + _items.remove(obj->guiId()); + + delete obj; + + return true; +} + +void IWorld::removeAnyItemFromGroup(const QString &group, + QList *removedObjectsList) { + int anyObjectId = _itemsGroup.value(group); + removeItem(anyObjectId, removedObjectsList); } const QQuaternion &IWorld::cameraRatation() const { @@ -245,29 +322,11 @@ void IWorld::worldChanged(const WorldObjects &objects) { if (count > 0) { for ( int i = 0; i < count; ++i ) { - IWorldItem *obj = generate(it.key()); - - obj->initOnWorld(this, _player); - - if (!obj) { - QuasarAppUtils::Params::log("object not created line:" + - QString::fromLatin1(Q_FUNC_INFO), - QuasarAppUtils::Warning); - break; - } - - addItem(it.key(), obj); - diff.addedIds.append(obj->guiId()); + addItem(generate(it.key()), &diff.addedIds); } } else { for (; count < 0; ++count ) { - int removedObjectId = removeAnyItemFromGroup(it.key()); - if (!removedObjectId) { - QuasarAppUtils::Params::log("World::changeCountObjects error delete object!", - QuasarAppUtils::Warning); - break; - } - diff.removeIds.append(removedObjectId); + removeAnyItemFromGroup(it.key(), &diff.removeIds); } } } @@ -288,3 +347,4 @@ void IWorld::setWorldStatus(int newWorldStatus) { _worldStatus = newWorldStatus; emit worldStatusChanged(); } + diff --git a/src/Core/Crawl/iworld.h b/src/Core/Crawl/iworld.h index 6925067..3eeee9a 100644 --- a/src/Core/Crawl/iworld.h +++ b/src/Core/Crawl/iworld.h @@ -36,14 +36,6 @@ typedef QMap WorldObjects; */ typedef QMap WorldRule; -/** - * @brief The WorldObjectWraper struct This is simple wraper structure for the internal functionality of the IWorld objects. - */ -struct WorldObjectWraper { - IWorldItem* objectPtr = nullptr; - QString groupName = ""; -}; - /** * @brief The IWorld class use this interface for implementation your own game levels */ @@ -52,6 +44,7 @@ class CRAWL_EXPORT IWorld : public QObject, public IRender Q_OBJECT Q_PROPERTY(QVector3D cameraReleativePosition READ cameraReleativePosition NOTIFY cameraReleativePositionChanged) Q_PROPERTY(QQuaternion cameraRatation READ cameraRatation NOTIFY cameraRatationChanged) + Q_PROPERTY(QObject * player READ player WRITE setPlayer NOTIFY playerChanged) Q_PROPERTY(int worldStatus READ wordlStatus WRITE setWorldStatus NOTIFY worldStatusChanged) @@ -59,14 +52,6 @@ public: IWorld(); virtual ~IWorld(); - /** - * @brief generateGroundTile This method should be generate a new tile of the world. - * @return raw pointer to tile of the world ground. - * @note The tile count sets automaticly. - * @note All generated objects will be distroed automaticaly. - */ - virtual IGround* generateGroundTile() = 0; - /** * @brief initPlayer The implementation of This interface must be return playerObject. * @return raw pointer to the player object. @@ -78,11 +63,27 @@ public: /** * @brief initWorldRules The implementation of this interface must be retun initialized list of the world rules. * For more information see the WorldRules map. + * + * Example of use : + * + * ```cpp + * WorldRule *World::initWorldRules() { + * return new WorldRule { + * { + * 0, {{registerObject(), 10}}, + * 100, {{registerObject(), 10}, {registerObject(), 1}}, + * } + * }; + * } + * ``` + * * @return a raw pointer to world a rules map. * @note The Palyer object will be deleted when wold distroed. * So do not delete your created player pbject yuorself. + * + * */ - virtual WorldRule* initWorldRules() const = 0; + virtual WorldRule* initWorldRules() = 0; /** * @brief initUserInterface This method should be return point to userInterface object. @@ -211,6 +212,12 @@ public: */ const QQuaternion &cameraRatation() const; + /** + * @brief player This method return player object + * @return player object + */ + QObject *player() const; + signals: /** * @brief sigGameFinished This signal emit when game are finished @@ -245,15 +252,39 @@ signals: */ void cameraRatationChanged(); + /** + * @brief playerChanged This signal eited when player are changed. + */ + void playerChanged(); + protected: + /** + * @brief setPlayer This method sets new player object + * @param newPlayer This is new player object. + * @note This method remove old player object if it exists + */ + void setPlayer(QObject *newPlayer); + /** * @brief generate This method shold be generate object from the @a objectType. * Override this method for add support yourown objects. + * @note If your objects not requre custom setting then use the default implementation of the generate method. * @param objectType This is string type name of the object, * @return pointer to the object. + * + * **Example** + * ```cpp + * IWorldItem* generate(const QString& objectType)) const { + * auto registeredObject = IWorld::generate(objectType); + * if (registeredObject) { + * // process creating of object. + * } + * return registeredObject; + * } + * ``` */ - virtual IWorldItem* generate(const QString& objectType) const = 0; + virtual IWorldItem* generate(const QString& objectType) const; /** * @brief setCameraReleativePosition This method update camera position @@ -267,7 +298,45 @@ protected: */ void setCameraRatation(const QQuaternion &newCameraRatation); + template + + /** + * @brief registerObject This method will register object type for generation on the world. + * + * Example of use: + * + * ```cpp + * ... + * QString className = registerObject(); + * ... + * ``` + * + * @return name of registered class. + */ + QString registerObject() { + + static_assert(std::is_base_of_v, + "You try register no IWorldItem class. Please inherit of IWorldItem class and try again"); + + QString type = Type().className(); + + if (!_registeredTypes.contains(type)) { + + auto wraper = []() { + return new Type(); + }; + + _registeredTypes.insert(type, wraper); + } + + return type; + } + private slots: + + /** + * @brief handleStop This slot invoked when user click return main menu button. + */ void handleStop(); private: @@ -279,27 +348,55 @@ private: bool init(); void deinit(); - void generateGround(); void worldChanged(const WorldObjects& objects); void clearItems(); - void addItem(const QString &group, IWorldItem *obj); /** - * @brief removeItem This method remove object with @a id. + * @brief addItem This method remove object from the scane. If object are calster then this method remove all child objects. + * @param obj pointer to any engine object. + * @param addedObjectsList This is list of added items into world. + */ + void addItem(IWorldItem *obj, + QList* addedObjectsList = nullptr); + + /** + * @brief removeItem This method remove item from the world. If the @a id are id of the claster object then its child object will be removed too. + * @param id This is id of removed object. + * @param removedObjectsList This is list of removed objects. Leave this argument nullptr for ignore this argument. + */ + void removeItem(int id, + QList* removedObjectsList = nullptr); + + /** + * @brief addAtomicItem This method execure atomic operation of add new item. This method support only atomic objects. (not clasters) + * @param obj This is pointer to the atomic object. If the object are claster then it will be added without childs objects. + */ + void addAtomicItem(IWorldItem *obj); + + /** + * @brief removeIAtomictem This method remove object with @a id. This method work with atomic objects only. If you rty remove claster objects then it will be ramoved witohout child objects. * @param id This is id of removed objects. * @return return true if object remove successul */ - bool removeItem(int id); + bool removeIAtomicItem(int id); /** - * @brief removeAnyItemFromGroup This method remove any object from group and return id of removed object. - * @param group This is name of the objects group - * @return id of removed object. - * @note if object not removed return 0 + * @brief removeIAtomicItem This method remove object @a obj. This method work with atomic objects only. If you rty remove claster objects then it will be ramoved witohout child objects. + * @param obj This is id of removed objects. + * @return return true if object remove successul */ - int removeAnyItemFromGroup(const QString &group); + bool removeIAtomicItem(IWorldItem *obj); - QHash _items; + /** + * @brief removeAnyItemFromGroup This method remove any object from group and return id of removed object. If The objec are claster then this method remove all child objects. + * @param group This is name of the objects group + * @param removedObjectsList This is list of removed objcts. + * @return id of removed object. + */ + void removeAnyItemFromGroup(const QString &group, + QList* removedObjectsList = nullptr); + + QHash _items; QMultiHash _itemsGroup; QVector3D _cameraReleativePosition; QQuaternion _cameraRatation; @@ -309,9 +406,15 @@ private: IPlayer *_player = nullptr; IControl *_userInterface = nullptr; IAI *_backgroundAI = nullptr; - - friend class Engine; int _worldStatus = 0; + QHash> _registeredTypes; + + // engine + friend class Engine; + + // testing + friend class ClastersTest; + }; #endif // IWORLD_H diff --git a/src/Core/Crawl/iworlditem.cpp b/src/Core/Crawl/iworlditem.cpp index 72b809e..9db8175 100644 --- a/src/Core/Crawl/iworlditem.cpp +++ b/src/Core/Crawl/iworlditem.cpp @@ -9,7 +9,10 @@ #include "iworld.h" #include "quasarapp.h" -IWorldItem::IWorldItem() { +IWorldItem::IWorldItem(const QString& name, + const QString& viewTempalte, + QObject *ptr): + GuiObject(name, viewTempalte, ptr) { } diff --git a/src/Core/Crawl/iworlditem.h b/src/Core/Crawl/iworlditem.h index 1ac6551..5f42158 100644 --- a/src/Core/Crawl/iworlditem.h +++ b/src/Core/Crawl/iworlditem.h @@ -17,11 +17,21 @@ class IWorld; */ class CRAWL_EXPORT IWorldItem: public GuiObject { Q_OBJECT + public: - IWorldItem(); + IWorldItem(const QString& name, + const QString& viewTempalte = DEFAULT_VIEW_TEMPLATE, + QObject *ptr = nullptr); const IWorld *world() const; + /** + * @brief render This implementation move objects from end of scane to begin. + * @param tbfMsec + * @note new position = playerPosition + scaneSize; + */ + void render(unsigned int tbfMsec) override; + protected: /** @@ -42,12 +52,7 @@ protected: */ const IWorldItem * getPlayer() const; - /** - * @brief render This implementation move objects from end of scane to begin. - * @param tbfMsec - * @note new position = playerPosition + scaneSize; - */ - void render(unsigned int tbfMsec) override; + private: void initOnWorld(const IWorld* world, const IWorldItem *player); diff --git a/src/Core/Crawl/singleclasterworlditem.cpp b/src/Core/Crawl/singleclasterworlditem.cpp new file mode 100644 index 0000000..6bada5e --- /dev/null +++ b/src/Core/Crawl/singleclasterworlditem.cpp @@ -0,0 +1,28 @@ +//# +//# Copyright (C) 2021-2021 QuasarApp. +//# Distributed under the GPLv3 software license, see the accompanying +//# Everyone is permitted to copy and distribute verbatim copies +//# of this license document, but changing it is not allowed. +//# + + +#include "claster.h" +#include "singleclasterworlditem.h" +#include "quasarapp.h" + +SingleClasterWorldItem::SingleClasterWorldItem(const QString &name, + const QString &viewTempalte, + QObject *ptr): + ClasterItem(name, viewTempalte, ptr) { + +} + +void SingleClasterWorldItem::setClaster(Claster *claster) { + if (parentClasters().size() > 0) { + Claster* parent = *parentClasters().begin(); + parent->remove(this); + removeClaster(parent); + } + + ClasterItem::setClaster(claster); +} diff --git a/src/Core/Crawl/singleclasterworlditem.h b/src/Core/Crawl/singleclasterworlditem.h new file mode 100644 index 0000000..875cef9 --- /dev/null +++ b/src/Core/Crawl/singleclasterworlditem.h @@ -0,0 +1,39 @@ +//# +//# Copyright (C) 2021-2021 QuasarApp. +//# Distributed under the GPLv3 software license, see the accompanying +//# Everyone is permitted to copy and distribute verbatim copies +//# of this license document, but changing it is not allowed. +//# + + +#ifndef SINGLECLASTERWORLDITEM_H +#define SINGLECLASTERWORLDITEM_H + +#include "clasteritem.h" + +class Claster; + +/** + * @brief The SingleClasterWorldItem class This is wraper of the OWorldOitem for the controll parent clasters. + * This object can belong to only one cluster in one time + */ +class CRAWL_EXPORT SingleClasterWorldItem: public ClasterItem +{ + Q_OBJECT +public: + SingleClasterWorldItem(const QString& name, + const QString& viewTempalte = DEFAULT_VIEW_TEMPLATE, + QObject *ptr = nullptr); +private: + + /** + * @brief setClaster invoked when object added to new claster. + * @param claster pointer to invoker claster object. + * @note This implementation can be sets only one object as a parent. + */ + void setClaster(Claster *claster) override; + + friend class Claster; +}; + +#endif // SINGLECLASTERWORLDITEM_H diff --git a/src/Core/CrawlModule/GraphicItem.qml b/src/Core/CrawlModule/GraphicItem.qml index 295cb4f..d4c7459 100644 --- a/src/Core/CrawlModule/GraphicItem.qml +++ b/src/Core/CrawlModule/GraphicItem.qml @@ -29,7 +29,7 @@ Model { } materials: [ - (fMapColor)? objectMaterial: defaultMaterial + (fMapColor)? objMaterial: defaultMaterial ] rotation: (model)? model.ratation: Qt.quaternion(0, 0, 0, 0) @@ -38,3 +38,15 @@ Model { position: (model) ? model.position: Qt.vector3d(0,0,0); } + +//Model { +// source: "#Cube"; +// property var model: null +// property int guiId: (model) ? model.guiId : -1; +// materials: [ +// DefaultMaterial { +// id: defaultMaterial +// diffuseColor: "#ff1111" +// } +// ] +//} diff --git a/src/Core/CrawlModule/Scene.qml b/src/Core/CrawlModule/Scene.qml index 16cdc0c..e86dede 100644 --- a/src/Core/CrawlModule/Scene.qml +++ b/src/Core/CrawlModule/Scene.qml @@ -12,47 +12,47 @@ View3D { property var model: null; property alias showMenu: privateRoot.showMenu + renderMode: View3D.Underlay PerspectiveCamera { id: camera - position: (privateRoot.player)? Qt.vector3d( - privateRoot.player.position.x + privateRoot.releativeCameraPosition.x, - privateRoot.player.position.y + privateRoot.releativeCameraPosition.y, - privateRoot.player.position.z + privateRoot.releativeCameraPosition.z - ) + position: (privateRoot.player && privateRoot.releativeCameraPosition)? + Qt.vector3d(privateRoot.player.position.x + privateRoot.releativeCameraPosition.x, + privateRoot.player.position.y + privateRoot.releativeCameraPosition.y, + privateRoot.player.position.z + privateRoot.releativeCameraPosition.z) : - Qt.vector3d(0,0,0) + Qt.vector3d(0,0,100) + + onPositionChanged: { + console.log(position) + } rotation: (privateRoot.world)? privateRoot.world.cameraRatation: Qt.quaternion(0,0,0,0) } - DirectionalLight { - position: Qt.vector3d(0,0,100) - eulerRotation.z: 90 - - } - - Node { - id: mainScane + PointLight { + position: camera.position + brightness: 1500 } environment: SceneEnvironment { id: background backgroundMode: SceneEnvironment.SkyBox - lightProbe: Texture { source: (model)? model.hdr: "" } } - Item { + Node { id: privateRoot property var arrayObjects: [] - property var player: (model)? model.player: null property var world: (model)? model.world: null + property int oldPlayerId: -1 + property var gameMenuModel: (model)? model.menu: null + property var player: (world)? world.player: null property var releativeCameraPosition: (world)? world.cameraReleativePosition: null property var progress: (model)? model.prepareLvlProgress: null @@ -75,7 +75,7 @@ View3D { var temp = Qt.createComponent(viewTemplate) if (temp.status === Component.Ready) { - var obj = temp.createObject(mainScane) // mainScane - это обьект на который будет помещен соззданный элемент + var obj = temp.createObject(privateRoot) obj.model = model.getGameObject(cppObjId); arrayObjects.push(obj) } else { @@ -122,6 +122,19 @@ View3D { Connections { target: privateRoot; + function onPlayerChanged() { + + if (!privateRoot.player) + return + + if (privateRoot.oldPlayerId >= 0) { + privateRoot.remove(privateRoot.oldPlayerId); + } + + privateRoot.add(privateRoot.player.guiId); + privateRoot.oldPlayerId = privateRoot.player.guiId + } + function onGameMenuModelChanged() { if (!privateRoot.gameMenuModel) { return; diff --git a/src/CrawlTestLvl b/src/CrawlTestLvl index 9fe1e01..3f8198a 160000 --- a/src/CrawlTestLvl +++ b/src/CrawlTestLvl @@ -1 +1 @@ -Subproject commit 9fe1e017da688c760fa2c9aaaa76622ad3c2f658 +Subproject commit 3f8198a0767f860fa17fed86f6772f09462077fa diff --git a/tests/tstMain.cpp b/tests/tstMain.cpp index 6655607..b38d014 100644 --- a/tests/tstMain.cpp +++ b/tests/tstMain.cpp @@ -7,6 +7,7 @@ #include #include "pluginloadertest.h" +#include "clasterstest.h" // Use This macros for initialize your own test classes. // Check exampletests @@ -33,6 +34,8 @@ private slots: // BEGIN TESTS CASES TestCase(exampleTest, PluginLoaderTest) + TestCase(clastersTest, ClastersTest) + // END TEST CASES private: diff --git a/tests/units/clasterstest.cpp b/tests/units/clasterstest.cpp new file mode 100644 index 0000000..78151f4 --- /dev/null +++ b/tests/units/clasterstest.cpp @@ -0,0 +1,143 @@ +//# +//# Copyright (C) 2020-2021 QuasarApp. +//# Distributed under the GPLv3 software license, see the accompanying +//# Everyone is permitted to copy and distribute verbatim copies +//# of this license document, but changing it is not allowed. +//# + +#include "clasterstest.h" +#include +#include +#include +#include +#include + +// Test claster object. +class TestClasterObject: public Claster { + +public: + TestClasterObject(): Claster("TestClaster"){}; +protected: + void onIntersects(const IWorldItem *) {}; +}; + +// Test single claster item +class TestClasterSingleItem: public SingleClasterWorldItem { +public: + TestClasterSingleItem(): SingleClasterWorldItem("TestClasterSingleItem"){}; +protected: + void onIntersects(const IWorldItem *) {}; +}; + +// Test claster item +class TestClasterItem: public ClasterItem { +public: + TestClasterItem(): ClasterItem("TestClasterItem"){}; +protected: + void onIntersects(const IWorldItem *) {}; +}; + +// Test world of clasters +class TestWorld: public IWorld { +public: + TestWorld(): IWorld(){}; + + // IWorld interface +public: + IPlayer *initPlayer() const {return nullptr;}; + WorldRule *initWorldRules() {return nullptr;}; + QString initHdrBackGround() const {return "";}; + QString description() const {return "";}; + QString imagePreview() const {return "";}; + QString name() const {return "TestWorld";}; + int costToUnlock() const {return 0;}; + + friend class ClastersTest; +}; + +ClastersTest::ClastersTest() { + +} + +void ClastersTest::test() { + // test clasters + testOneClaster(); + testClastersWithWorld(); +} + +void ClastersTest::testOneClaster() const { + TestClasterItem item; + TestClasterSingleItem singleItem; + + // life of the clasters + { + TestClasterObject claster, claster2; + + // Add items to first clasters + claster.add(&item); + claster.add(&singleItem); + + // in the first claster should be 2 objects + QVERIFY(claster.objects().size() == 2); + + // item sould be contains oly one parents claster object. + QVERIFY(item.parentClastersCount() == 1); + QVERIFY(singleItem.parentClastersCount() == 1); + + // Add items into second claster object + claster2.add(&item); + claster2.add(&singleItem); + + // in the second claster should be 2 objects + QVERIFY(claster2.objects().size() == 2); + // but first claster should be contains only one claster item because the singleclater item cannot are child of the two clasters. + QVERIFY(claster.objects().size() == 1); + + // item sould be contains two parents claster object. + + QVERIFY(item.parentClastersCount() == 2); + // item sould be contains oly one parents claster object. + QVERIFY(singleItem.parentClastersCount() == 1); + } + + // after distrou clasters objects the parents list size should be equals 0 + QVERIFY(item.parentClastersCount() == 0); + QVERIFY(singleItem.parentClastersCount() == 0); + +} + +void ClastersTest::testClastersWithWorld() const { + TestWorld world; + TestClasterObject *claster = new TestClasterObject(), + *claster2 = new TestClasterObject(); + + TestClasterItem *item = new TestClasterItem(), + *item2 = new TestClasterItem; + + // Add to first claster two items. + claster->add(item); + claster->add(item2); + + // The claster 2 contains item 2 only. + claster2->add(item2); + + // Add claster item to world + world.addItem(claster); + + // After adding claster object ito world child objects should be addeed automaticaly + QVERIFY(world._items.size() == 3); + + // add second claster ot world + world.addItem(claster2); + + QVERIFY(world._items.size() == 4); + + // remove claster with 2 items from world + world.removeItem(claster->guiId()); + + // after removing claster ovject child items should be removed too. but ony items that contains one parent claster. + QVERIFY(world._items.size() == 2); + + world.removeItem(claster2->guiId()); + +} diff --git a/tests/units/clasterstest.h b/tests/units/clasterstest.h new file mode 100644 index 0000000..436326f --- /dev/null +++ b/tests/units/clasterstest.h @@ -0,0 +1,35 @@ +//# +//# Copyright (C) 2020-2021 QuasarApp. +//# Distributed under the GPLv3 software license, see the accompanying +//# Everyone is permitted to copy and distribute verbatim copies +//# of this license document, but changing it is not allowed. +//#s + +#include "test.h" +#include "testutils.h" + +#ifndef CLASTERSTEST_H +#define CLASTERSTEST_H + +/** + * @brief The ClastersTest class This test of the claster objects system. + */ +class ClastersTest: public Test, protected TestUtils +{ +public: + ClastersTest(); + void test() override; +private: + + /** + * @brief testOneClaster This test check functionality of the claster class. + */ + void testOneClaster() const; + + /** + * @brief testClastersWithWorld This test check clasters integrarion on the world + */ + void testClastersWithWorld() const; +}; + +#endif // CLASTERSTEST_H