diff --git a/src/Core/Crawl/groupobject.cpp b/src/Core/Crawl/groupobject.cpp index f4fa5c3..96e2cc9 100644 --- a/src/Core/Crawl/groupobject.cpp +++ b/src/Core/Crawl/groupobject.cpp @@ -22,10 +22,14 @@ void GroupObject::render(unsigned int tbfMsec) { for (ClasterItem* object: objects()) { if (Localpropertys *props = getLocalpropertys(object->guiId())) { + if (!props->_rotation.isNull()) object->setRotation(_this->rotation() * props->_rotation); - object->setposition(_this->position() + props->_position); + QVector3D reCalcVectorPs = reCalcPos(props->_position, + _this->rotation().toEulerAngles()); + + object->setposition(_this->position() + reCalcVectorPs); } } @@ -48,6 +52,31 @@ void GroupObject::updateRotation(int id, const QQuaternion &roatation) { _extrapropertys[id]._rotation = roatation; } +const QVector3D GroupObject::reCalcPos(const QVector3D& pos, const QVector3D &eulerAngles) const +{ + float alha = eulerAngles.z(); + float beta = eulerAngles.y(); + float gamma = eulerAngles.x(); + + float x = pos.x(); + float y = pos.y(); + float z = pos.z(); + + float newX = x*(qCos(alha)*qCos(beta)) + + y*(qCos(alha)*qSin(beta)*qSin(gamma) - qSin(alha)*qCos(gamma)) + + z*(qCos(alha)*qSin(beta)*qCos(gamma) + qSin(alha)*qSin(gamma)); + + float newY = x*(qSin(alha)*qCos(beta)) + + y*(qSin(alha)*qSin(beta)*qSin(gamma) + qCos(alha)*qCos(gamma)) + + z*(qSin(alha)*qSin(beta)*qCos(gamma) - qCos(alha)*qSin(gamma)); + + float newZ = x*(-qSin(beta)) + + y*(qCos(beta)*qSin(gamma)) + + z*(qCos(beta)*qCos(gamma)); + + return QVector3D({newX, newY, newZ}); +} + QQuaternion *GroupObject::getLocalrotation(int id) { if (_extrapropertys.contains(id)) { return &_extrapropertys[id]._rotation; diff --git a/src/Core/Crawl/groupobject.h b/src/Core/Crawl/groupobject.h index 63b4a85..f8208d9 100644 --- a/src/Core/Crawl/groupobject.h +++ b/src/Core/Crawl/groupobject.h @@ -123,6 +123,8 @@ protected: private: QHash _extrapropertys; + const QVector3D reCalcPos(const QVector3D& pos, const QVector3D& eulerAngles) const; + }; } #endif // GROUPOBJECT_H diff --git a/src/Core/Crawl/layout.cpp b/src/Core/Crawl/layout.cpp new file mode 100644 index 0000000..a08db99 --- /dev/null +++ b/src/Core/Crawl/layout.cpp @@ -0,0 +1,125 @@ +//# +//# 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 "layout.h" +#include "clasteritem.h" +#include + +namespace CRAWL { + +Layout::Layout() { + +} + +void Layout::add(ClasterItem *object) { + + Claster::add(object); + updatePosition(); + +} + +void Layout::remove(ClasterItem *object) { + + Claster::remove(object); + updatePosition(); + +} + +void Layout::changeLayout(const LayoutType &fig) { + _shape = fig; + updatePosition(); +} + +void Layout::setDistance(int dist) { + _distance = dist; + updatePosition(); +} + +void Layout::updatePosition() { + + switch (_shape) { + case CIRCLE: + drawCircle(); + break; + + case SQUARE: + drawSquare(); + break; + + case LINE: + drawLine(); + break; + + default: + break; + } + +} + +void Layout::drawCircle() { + + if (objects().size() == 0) { + QuasarAppUtils::Params::log(QString("The number of objects is zero. Add object."), QuasarAppUtils::Error); + return; + } + + float step = 360 / objects().size(); + int temp = 0; + + for (ClasterItem* object: objects()) { + + float x = _distance * qCos(step*temp); + float y = _distance * qSin(step*temp); + GroupObject::updatePosition(object->guiId(), {x, y, 0}); + + temp++; + } + +} + +void Layout::drawSquare() { + + if (objects().size() == 0) { + QuasarAppUtils::Params::log(QString("The number of objects is zero. Add object."), QuasarAppUtils::Error); + return; + } + + int height = qFloor(qSqrt(objects().size())); + int width = qFloor(objects().size() / height); + + int indObject = 0; + for (auto idObj = objects().keyBegin(); idObj != objects().keyEnd(); idObj++) { + + float x = indObject % height; + float y = qCeil(indObject / height); + + GroupObject::updatePosition(*idObj, {(x * _distance) - (height * _distance / 2), + (y * _distance) - (width * _distance / 2), 0}); + indObject++; + + } + +} + +void Layout::drawLine() { + + if (objects().size() == 0) { + QuasarAppUtils::Params::log(QString("The number of objects is zero. Add object."), QuasarAppUtils::Error); + return; + } + + float xObject = 0; + float height = objects().size() * _distance; + for (auto idObj = objects().keyBegin(); idObj != objects().keyEnd(); idObj++) { + + GroupObject::updatePosition(*idObj, {(xObject * _distance) - (height/2 * _distance), 0, 0}); + + xObject++; + } +} + +} diff --git a/src/Core/Crawl/layout.h b/src/Core/Crawl/layout.h new file mode 100644 index 0000000..502bbfa --- /dev/null +++ b/src/Core/Crawl/layout.h @@ -0,0 +1,127 @@ +//# +//# 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 LAYOUT_H +#define LAYOUT_H + +#include + + +namespace CRAWL { + +/** + * @brief The LayoutType enum Lists the shapes to convert the group object to. + */ +enum LayoutType { + /// The circle property calls the drawCircle method, which recalculates and updates + /// the coordinates of the passed object's positions. + CIRCLE, + + /// The square property calls the drawSquare method, which updates the coordinates of + /// the objects' positions, giving them the shape of a square. + SQUARE, + + /// The LINE property calls the drawLine method, which updates the coordinates of the + /// objects' positions, giving it a line shape. + LINE +}; + +/** + * @brief The Layout class The class that control position of group objects. + * ### Requried child classes: IWorldItem + * + * This class overloads the add() and remove() methods, which add objects to the cluster while updating positions according to the selected LayoutType. + * Has two public methods for setting the distance to the object and selecting the grouping of objects. + * + * ## Example of use + * + * ### For what this object uses + * This object is convenient to use if you want to create a cluster object directly, within which subobjects are grouped into a circle or square, depending on the selected property. + * For example : snake obstacle. + * + * ### Example of use + * + * 1. Create the GroupObjObstacle class. + * + * ```cpp + * + * class GroupObjObstacle: public CRAWL::Layout, public CRAWL::IWorldItem { + * + * // sets the distance to the object from the center. + * setDistance(20); + * + * // Set the property of grouping objects + * changeLayout(CRAWL::LayoutType::CIRCLE); + * + * for(int i(0); i < 20; i++) { + * add(new BoxItem); + * } + * + * }; + * ``` + * + * @note The added object must inherit from ClasterItem and have a child class required for overloading software renderers. + * + * All done. Now the added objects will be grouped into a circle shape. + * + * You can change the center-to-object distance and the shape of a group of objects using the setDistance and changeLayout methods. + * + * @note This class requried the GuiObject functions as a parent class. + * @note This class requires an overload of the render method; The implementation must call the render methods of the parent classes. + * + */ +class Layout: public GroupObject { +public: + Layout(); + +// Claster interface +public: + void add(ClasterItem *object); + void remove(ClasterItem *object); + + /** + * @brief changeLayout This method defines the shape of the group object. + * @param fig This is the name of the figure to change the group object. + */ + void changeLayout(const LayoutType &fig); + + /** + * @brief setDistance This method sets, depending on the shape selected, the radius for the circle or the indentation for the square. + * @param dist This is the radius or margin. + */ + void setDistance(int dist); + +private: + + + /** + * @brief updatePosition This method updates the coordinates of the positions of all objects. + */ + void updatePosition(); + + /** + * @brief drawCircle This method updates the coordinates to a circle shape. + */ + void drawCircle(); + + /** + * @brief drawSquare This method updates the coordinates to a square shape. + */ + void drawSquare(); + + /** + * @brief drawLine This method updates the coordinates to a line shape. + */ + void drawLine(); + + int _distance; + LayoutType _shape; + +}; + +} +#endif // LAYOUT_H diff --git a/src/CrawlAbstractLvl/private/abslvlworld.cpp b/src/CrawlAbstractLvl/private/abslvlworld.cpp index 5d36d6c..ffb1d8b 100644 --- a/src/CrawlAbstractLvl/private/abslvlworld.cpp +++ b/src/CrawlAbstractLvl/private/abslvlworld.cpp @@ -12,6 +12,7 @@ #include "abslvlworld.h" #include #include "Crawl/iworlditem.h" +#include "groupobstaclered.h" #include "Crawl/defaultlight.h" @@ -31,23 +32,23 @@ CRAWL::WorldRule *AbsLvlWorld::initWorldRules() { return new CRAWL::WorldRule { - {0, - { - {registerObject(), 10}, {registerObject(), 1} - } - }, - - {20, + {200, { {registerObject(), 10}, {registerObject(), 1} } }, - {30, + {250, { - {registerObject(), 40}, {registerObject(), 1} + {registerObject(), 1}, {registerObject(), 1} } - } + }, + +// {30, +// { +// {registerObject(), 40}, {registerObject(), 1} +// } +// } }; } diff --git a/src/CrawlAbstractLvl/private/groupobstaclered.cpp b/src/CrawlAbstractLvl/private/groupobstaclered.cpp new file mode 100644 index 0000000..b2b1db6 --- /dev/null +++ b/src/CrawlAbstractLvl/private/groupobstaclered.cpp @@ -0,0 +1,37 @@ +//# +//# 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 "obstaclerebitem.h" +#include "groupobstaclered.h" + +namespace AbstractLvl { + +GroupObstacleRed::GroupObstacleRed(): CRAWL::IWorldItem(AUTO_CLASS_NAME) { + + QQuaternion rotation = + QQuaternion::fromEulerAngles(QVector3D(0,0,90)); + + setDistance(7); + setRotation(rotation); + changeLayout(CRAWL::LayoutType::LINE); + + for(int i(0); i < 10; i++) { + add(new ObstacleRebItem); + } + +} + +void GroupObstacleRed::render(unsigned int tbfMsec) { + Layout::render(tbfMsec); + IWorldItem::render(tbfMsec); +} + +void GroupObstacleRed::init() { + +} + +} diff --git a/src/CrawlAbstractLvl/private/groupobstaclered.h b/src/CrawlAbstractLvl/private/groupobstaclered.h new file mode 100644 index 0000000..93d25c0 --- /dev/null +++ b/src/CrawlAbstractLvl/private/groupobstaclered.h @@ -0,0 +1,27 @@ +//# +//# 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 GROUPOBSTACLERED_H +#define GROUPOBSTACLERED_H + +#include "Crawl/layout.h" +#include "Crawl/clasteritem.h" + +namespace AbstractLvl { + +class GroupObstacleRed: public CRAWL::Layout, public CRAWL::IWorldItem { +public: + GroupObstacleRed(); + + // IRender interface +public: + void render(unsigned int tbfMsec); + void init(); +}; +} + +#endif // GROUPOBSTACLERED_H diff --git a/src/CrawlAbstractLvl/private/obstaclerebitem.cpp b/src/CrawlAbstractLvl/private/obstaclerebitem.cpp new file mode 100644 index 0000000..ff15027 --- /dev/null +++ b/src/CrawlAbstractLvl/private/obstaclerebitem.cpp @@ -0,0 +1,20 @@ +//# +//# 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 "obstaclerebitem.h" + +namespace AbstractLvl { + +ObstacleRebItem::ObstacleRebItem() { + +} + +void ObstacleRebItem::render(unsigned int tbfMsec) { + +} + +} diff --git a/src/CrawlAbstractLvl/private/obstaclerebitem.h b/src/CrawlAbstractLvl/private/obstaclerebitem.h new file mode 100644 index 0000000..829dabf --- /dev/null +++ b/src/CrawlAbstractLvl/private/obstaclerebitem.h @@ -0,0 +1,26 @@ +//# +//# 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 OBSTACLEREBITEM_H +#define OBSTACLEREBITEM_H + +#include "obstaclered.h" + +namespace AbstractLvl { + +class ObstacleRebItem: public ObstacleRed { +public: + ObstacleRebItem(); + + // IRender interface +public: + void render(unsigned int tbfMsec); +}; + +} + +#endif // OBSTACLEREBITEM_H diff --git a/src/CrawlAbstractLvl/private/obstaclered.cpp b/src/CrawlAbstractLvl/private/obstaclered.cpp index e0d03ac..f52ac5a 100644 --- a/src/CrawlAbstractLvl/private/obstaclered.cpp +++ b/src/CrawlAbstractLvl/private/obstaclered.cpp @@ -9,7 +9,7 @@ namespace AbstractLvl { -ObstacleRed::ObstacleRed() : IWorldItem(AUTO_CLASS_NAME) { +ObstacleRed::ObstacleRed() : CRAWL::ClasterItem(AUTO_CLASS_NAME) { setMash("qrc:/mesh/meshes/ObstacleRed.mesh"); setSize({1,1,1}); setColor("#ff1927"); diff --git a/src/CrawlAbstractLvl/private/obstaclered.h b/src/CrawlAbstractLvl/private/obstaclered.h index 24bd915..68130a6 100644 --- a/src/CrawlAbstractLvl/private/obstaclered.h +++ b/src/CrawlAbstractLvl/private/obstaclered.h @@ -7,11 +7,11 @@ #ifndef OBJOBSTACLERED_H #define OBJOBSTACLERED_H -#include "Crawl/iworlditem.h" +#include "Crawl/clasteritem.h" namespace AbstractLvl { -class ObstacleRed: public CRAWL::IWorldItem { +class ObstacleRed: public CRAWL::ClasterItem { public: ObstacleRed(); diff --git a/src/CrawlTestLvl/private/box.cpp b/src/CrawlTestLvl/private/box.cpp index f1df44c..1803795 100644 --- a/src/CrawlTestLvl/private/box.cpp +++ b/src/CrawlTestLvl/private/box.cpp @@ -11,7 +11,7 @@ namespace TestLvl { -Box::Box(): IWorldItem("Box") { +Box::Box(): ClasterItem("Box") { setMash("qrc:/mesh/meshes/cube.mesh"); setSize({2,2,2}); setColor(QColor::fromRgb(rand()).name()); diff --git a/src/CrawlTestLvl/private/box.h b/src/CrawlTestLvl/private/box.h index 16adf4b..0b2f757 100644 --- a/src/CrawlTestLvl/private/box.h +++ b/src/CrawlTestLvl/private/box.h @@ -7,12 +7,12 @@ #ifndef BOX_H #define BOX_H -#include "Crawl/iworlditem.h" +#include "Crawl/clasteritem.h" namespace TestLvl { -class Box: public CRAWL::IWorldItem { +class Box: public CRAWL::ClasterItem { public: Box(); diff --git a/src/CrawlTestLvl/private/boxitem.cpp b/src/CrawlTestLvl/private/boxitem.cpp new file mode 100644 index 0000000..02a9963 --- /dev/null +++ b/src/CrawlTestLvl/private/boxitem.cpp @@ -0,0 +1,22 @@ +//# +//# 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 "boxitem.h" + +namespace TestLvl { + +BoxItem::BoxItem() +{ + +} + +void BoxItem::render(unsigned int tbfMsec) +{ + +} + +} diff --git a/src/CrawlTestLvl/private/boxitem.h b/src/CrawlTestLvl/private/boxitem.h new file mode 100644 index 0000000..2ebb2db --- /dev/null +++ b/src/CrawlTestLvl/private/boxitem.h @@ -0,0 +1,25 @@ +//# +//# 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 BOXITEM_H +#define BOXITEM_H + +#include "box.h" + +namespace TestLvl { + +class BoxItem: public Box { +public: + BoxItem(); + + // IRender interface +public: + void render(unsigned int tbfMsec); +}; + +} +#endif // BOXITEM_H diff --git a/src/CrawlTestLvl/private/groupobjbox.cpp b/src/CrawlTestLvl/private/groupobjbox.cpp new file mode 100644 index 0000000..ac53b5e --- /dev/null +++ b/src/CrawlTestLvl/private/groupobjbox.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 "boxitem.h" +#include "groupobjbox.h" + +namespace TestLvl { + +GroupObjBox::GroupObjBox(): CRAWL::IWorldItem("GroupObjBox") { + + setDistance(20); + changeLayout(CRAWL::LayoutType::CIRCLE); + + for(int i(0); i < 20; i++) { + add(new BoxItem); + } + +} + +void GroupObjBox::render(unsigned int tbfMsec) +{ + Layout::render(tbfMsec); + IWorldItem::render(tbfMsec); +} + +void GroupObjBox::init() +{ + +} + + + + +} diff --git a/src/CrawlTestLvl/private/groupobjbox.h b/src/CrawlTestLvl/private/groupobjbox.h new file mode 100644 index 0000000..190ece7 --- /dev/null +++ b/src/CrawlTestLvl/private/groupobjbox.h @@ -0,0 +1,29 @@ +//# +//# 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 GROUPOBJBOX_H +#define GROUPOBJBOX_H + +#include "Crawl/layout.h" +#include "Crawl/clasteritem.h" + +namespace TestLvl { + +class GroupObjBox: public CRAWL::Layout, public CRAWL::IWorldItem { +public: + GroupObjBox(); + + + // IRender interface +public: + void render(unsigned int tbfMsec); + void init(); + +}; + +} +#endif // GROUPOBJBOX_H diff --git a/src/CrawlTestLvl/private/world.cpp b/src/CrawlTestLvl/private/world.cpp index 7bf6964..f6e38f8 100644 --- a/src/CrawlTestLvl/private/world.cpp +++ b/src/CrawlTestLvl/private/world.cpp @@ -18,6 +18,7 @@ #include #include #include +#include namespace TestLvl { @@ -31,12 +32,18 @@ CRAWL::WorldRule *World::initWorldRules() { using Day = CRAWL::Day; return new CRAWL::WorldRule { - {0, {{registerObject(), 1000}, + {0, {{registerObject(), 100}, {registerObject(), 10}, {registerObject(), 1}, {registerObject(), 1}, - {registerObject(), 1}}} + {registerObject(), 1}}}, + {300, + { + {registerObject(),5} + } + }, + }; } diff --git a/src/JungleLvl/private/ground.cpp b/src/JungleLvl/private/ground.cpp index baf9bbb..82d819e 100644 --- a/src/JungleLvl/private/ground.cpp +++ b/src/JungleLvl/private/ground.cpp @@ -16,4 +16,8 @@ Ground::Ground() : CRAWL::GroundClaster("JungelGroud") { unsigned int Ground::itemsCount() const { return 3; } + +int Ground::newObjectDistance() const { + return 150; +} } diff --git a/src/JungleLvl/private/ground.h b/src/JungleLvl/private/ground.h index 6d49d65..6ab7983 100644 --- a/src/JungleLvl/private/ground.h +++ b/src/JungleLvl/private/ground.h @@ -21,6 +21,10 @@ class Ground : public CRAWL::GroundClaster public: Ground(); unsigned int itemsCount() const override; + + // GroundClaster interface +protected: + int newObjectDistance() const; }; } diff --git a/src/JungleLvl/private/world.h b/src/JungleLvl/private/world.h index 063a7e6..cebe5e7 100644 --- a/src/JungleLvl/private/world.h +++ b/src/JungleLvl/private/world.h @@ -14,6 +14,7 @@ namespace JungleLvl { class World : public CRAWL::IWorld { + Q_OBJECT // IWorld interface public: diff --git a/tests/units/groupobjecttest.cpp b/tests/units/groupobjecttest.cpp index cf60629..806eb12 100644 --- a/tests/units/groupobjecttest.cpp +++ b/tests/units/groupobjecttest.cpp @@ -73,14 +73,16 @@ void GroupObjectTest::testBehavior() const { QVector3D localPosition = {10,0,0}; QQuaternion localRotation = QQuaternion::fromEulerAngles(0,5,0); - object.updatePosition(item.guiId(), localPosition); object.updateRotation(item.guiId(), localRotation); + object.render(0); + // after invoke the render function all positions and rotations should be changed + QVERIFY(item.rotation() == (object.rotation() * localRotation)); + + object.updatePosition(item.guiId(), localPosition); + object.setRotation(QQuaternion::fromEulerAngles(0,0,0)); object.render(0); - - // after invoke the render function all positions and rotations should be changed QVERIFY(item.position() == (object.position() + localPosition)); - QVERIFY(item.rotation() == (object.rotation() * localRotation)); object.remove(&item);