Merge pull request #59 from QuasarApp/engine

Clasters Objects
This commit is contained in:
Andrei Yankovich 2021-06-21 15:04:46 +03:00 committed by GitHub
commit bd2c53d3be
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 797 additions and 121 deletions

View File

@ -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}")

View File

@ -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<ClasterItem*>(object)) {
singlClasterObject->setClaster(this);
}
}
void Claster::remove(ClasterItem *object) {
_objects.remove(object->guiId());
}
void Claster::remove(int id) {
_objects.remove(id);
}
const QHash<int, ClasterItem *> &Claster::objects() const {
return _objects;
}

57
src/Core/Crawl/claster.h Normal file
View File

@ -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<int, ClasterItem*> &objects() const;
private:
QHash<int, ClasterItem*> _objects;
};
#endif // CLASTER_H

View File

@ -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<Claster *> &ClasterItem::parentClasters() const {
return _parentClasters;
}

View File

@ -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 <QSet>
#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<Claster *> &parentClasters() const;
private:
QSet<Claster*> _parentClasters;
friend class Claster;
};
#endif // CLASTERITEM_H

View File

@ -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.

View File

@ -9,11 +9,11 @@
#include <QVector3D>
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);

View File

@ -15,6 +15,8 @@
#include <QVector3D>
#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

View File

@ -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) {
}

View File

@ -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:

View File

@ -7,7 +7,10 @@
#include "iplayer.h"
IPlayer::IPlayer() {
IPlayer::IPlayer(const QString &name,
const QString &viewTempalte,
QObject *ptr):
IWorldItem(name, viewTempalte, ptr) {
}

View File

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

View File

@ -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.

View File

@ -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<IPlayer*>(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<IControl*>(_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<int> *addedObjectsList) {
if (!obj)
return;
// Work wih claster
if (auto claster = dynamic_cast<Claster*>(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<int> *removedObjectsList) {
auto obj = getItem(id);
if (!obj)
return;
// Work wih claster
if (auto claster = dynamic_cast<Claster*>(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<int> *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();
}

View File

@ -36,14 +36,6 @@ typedef QMap<QString, int> WorldObjects;
*/
typedef QMap<int, WorldObjects> 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<Box>(), 10}},
* 100, {{registerObject<Box>(), 10}, {registerObject<Round>(), 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<class Type>
/**
* @brief registerObject This method will register object type for generation on the world.
*
* Example of use:
*
* ```cpp
* ...
* QString className = registerObject<MyType>();
* ...
* ```
*
* @return name of registered class.
*/
QString registerObject() {
static_assert(std::is_base_of_v<IWorldItem, Type>,
"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<int>* 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<int>* 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<int, WorldObjectWraper> _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<int>* removedObjectsList = nullptr);
QHash<int, IWorldItem*> _items;
QMultiHash<QString, int> _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<QString, std::function<IWorldItem*()>> _registeredTypes;
// engine
friend class Engine;
// testing
friend class ClastersTest;
};
#endif // IWORLD_H

View File

@ -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) {
}

View File

@ -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);

View File

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

View File

@ -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

View File

@ -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"
// }
// ]
//}

View File

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

@ -1 +1 @@
Subproject commit 9fe1e017da688c760fa2c9aaaa76622ad3c2f658
Subproject commit 3f8198a0767f860fa17fed86f6772f09462077fa

View File

@ -7,6 +7,7 @@
#include <QtTest>
#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:

View File

@ -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 <QtTest>
#include <Crawl/claster.h>
#include <Crawl/clasteritem.h>
#include <Crawl/singleclasterworlditem.h>
#include <Crawl/iworld.h>
// 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());
}

View File

@ -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