Merge pull request #66 from QuasarApp/task_63

Snake template
This commit is contained in:
Andrei Yankovich 2021-06-30 22:53:15 +03:00 committed by GitHub
commit 8606beb60e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 827 additions and 241 deletions

View File

@ -12,6 +12,7 @@ add_definitions(-DCRAWL_LIBRARY)
file(GLOB SOURCE_CPP
"*Crawl/*.cpp"
"*Extensions/*.cpp"
"private/*.cpp"
"*.qrc"
"Crawl/*.qrc"

View File

@ -5,7 +5,7 @@
//# of this license document, but changing it is not allowed.
//#
#include "claster.h"
#include "Extensions/claster.h"
#include "clasteritem.h"
ClasterItem::ClasterItem(const QString &name,

View File

@ -14,6 +14,7 @@ GuiObject::GuiObject(const QString &name, const QString &viewTempalte, QObject *
_viewTemplate = viewTempalte;
_className = name;
generateId();
setRatation({1,1,0,0});
}
QString GuiObject::color() const {

View File

@ -52,7 +52,7 @@
* }
* ```
*/
class CRAWL_EXPORT GuiObject: public QObject, public IRender {
class CRAWL_EXPORT GuiObject: public QObject, virtual public IRender {
Q_OBJECT
Q_PROPERTY(QString color READ color WRITE setColor NOTIFY colorChanged)
Q_PROPERTY(int guiId READ guiId NOTIFY guiIdChanged)

View File

@ -11,7 +11,7 @@
IPlayer::IPlayer(const QString &name,
const QString &viewTempalte,
QObject *ptr):
MovableObject(name, viewTempalte, ptr) {
IWorldItem(name, viewTempalte, ptr) {
}
@ -27,30 +27,12 @@ void IPlayer::reward(int value) {
_currentPoints += value;
}
float IPlayer::speedUp(float increment) {
setSpeed(_speed + increment);
return _speed;
}
float IPlayer::setSpeedDown(float decrement) {
setSpeed(_speed - decrement);
return _speed;
}
void IPlayer::fine(int value) {
_currentPoints -= value;
}
float IPlayer::speed() const {
return _speed;
}
void IPlayer::setSpeed(float newSpead) {
_speed = newSpead;
if (_speed < 0) {
_speed = 0;
}
void IPlayer::render(unsigned int tbfMsec) {
MovableObject::render(tbfMsec);
}
void IPlayer::setControl(const IControl *control) {

View File

@ -10,14 +10,15 @@
#include "gameresult.h"
#include "global.h"
#include "movableobject.h"
#include "iworlditem.h"
#include "Extensions/movableobject.h"
class IControl;
/**
* @brief The IPlayer class This is base class of the player functions.
*/
class CRAWL_EXPORT IPlayer: public MovableObject {
class CRAWL_EXPORT IPlayer: public IWorldItem, public MovableObject {
Q_OBJECT
public:
IPlayer(const QString& name,
@ -36,18 +37,6 @@ public:
*/
bool isDead() const;
/**
* @brief speed This method return current speed of the snake.
* @return current speed
*/
float speed() const;
/**
* @brief setSpeed This method sets new value for player spead.
* @param newSpead This is a new value of a snake speed.
*/
void setSpeed(float newSpead);
/**
* @brief setControl This method should be connect player object with control object.
* @param control This is control object.
@ -70,21 +59,6 @@ protected:
*/
void reward(int value);
/**
* @brief speedUp This method increment snake speed.
* @param increment This is value that will added to a snake speed.
* @return new snake speed.
*/
float speedUp(float increment);
/**
* @brief setSpeedDown This method decrement snake speed.
* @param decrement This is value that will take away from a snake speed.
* @return new snake speed.
* @note return 0 if a snake speed less than a decrement value.
*/
float setSpeedDown(float decrement);
/**
* @brief fine This method remove reward for player.
* @param value This is fine amount;
@ -92,6 +66,8 @@ protected:
*/
void fine(int value);
void render(unsigned int tbfMsec) override;
protected slots:
/**
* @brief onTap This method invoked when user tap on screen.
@ -99,11 +75,12 @@ protected slots:
*/
virtual void onTap() = 0;
private:
bool _fDead = false;
int _currentPoints = 0;
float _speed = 0;
const IControl * _currentControl = nullptr;
};
#endif // IPLAYER_H

View File

@ -9,10 +9,16 @@
#define IRENDER_H
#include "global.h"
#include "quasarapp.h"
/**
* @brief The IRender class This interface provide render functionality for all objects.
* @note Override the render method.
* @note The IRender Interface suppor extension concept
*
* ### Extension concept
* You can create child class of the IRender class and override the render method. But the render method will works with another class object using dynamic_cast of this pointer.
*
*/
class CRAWL_EXPORT IRender {
public:
@ -24,6 +30,31 @@ public:
* @param tbf This is time betwin frame in milesecunds.
*/
virtual void render(unsigned int tbfMsec) = 0;
/**
* @brief init This method should be invoked after create object.
*/
virtual void init() = 0;
/**
* @brief checkminimumRequariedType This method check
* @return This object casted to Requared type this objct.
*
* **Example of use**:
*
* ```cpp
* auto _this = checkminimumRequariedType<RequaredType>();
* ```
*/
template<class Requared>
Requared* checkminimumRequariedType() {
Requared* result = dynamic_cast<Requared*>(this);
debug_assert(result, "This render function not support this class");
return result;
};
};
#endif // IRENDER_H

View File

@ -5,7 +5,7 @@
//# of this license document, but changing it is not allowed.
//#
#include "claster.h"
#include "Extensions/claster.h"
#include "iai.h"
#include "iworld.h"
#include "iworlditem.h"
@ -24,15 +24,22 @@ IWorld::IWorld() {
}
IWorld::~IWorld() {
deinit();
reset();
}
void IWorld::init() {prepare();}
IControl *IWorld::initUserInterface() const {
return new DefaultControl;
}
void IWorld::render(unsigned int tbfMsec) {
if (!_running) {
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
return;
}
_ItemsMutex.lock();
for (auto i = _items.begin(); i != _items.end(); ++i) {
@ -44,11 +51,13 @@ void IWorld::render(unsigned int tbfMsec) {
}
}
_ItemsMutex.unlock();
if (_player->isDead()) {
emit sigGameFinished(_player->getCurrentStatus());
}
_ItemsMutex.unlock();
int waitTime = 1000 / _targetFps - tbfMsec;
if (waitTime > 0)
@ -65,7 +74,6 @@ void IWorld::initPlayerControl(IControl *control) {
bool IWorld::start() {
_player->setposition({0,0,0});
_player->setSpeed(0);
setWorldStatus(WorldStatus::Game);
_backgroundAI->stopAI();
@ -74,6 +82,8 @@ bool IWorld::start() {
worldChanged(*_worldRules->begin());
setTargetFps(60);
setRunning(true);
return true;
}
@ -92,12 +102,11 @@ void IWorld::setPlayer(QObject *newPlayer) {
return;
}
if (_player) {
removeIAtomicItem(_player->guiId());
}
if (_player)
removeItem(_player->guiId());
_player = newPlayerObject;
addAtomicItem(_player);
addItem(_player);
emit playerChanged();
}
@ -107,15 +116,7 @@ IWorldItem *IWorld::generate(const QString &objectType) const {
}
bool IWorld::stop() {
start();
setWorldStatus(WorldStatus::Background);
_player->setControl(dynamic_cast<IControl*>(_backgroundAI));
_backgroundAI->startAI();
setTargetFps(30);
setRunning(false);
return true;
}
@ -129,14 +130,14 @@ IWorldItem *IWorld::getItem(int id) const {
return _items.value(id, nullptr);
}
bool IWorld::init() {
bool IWorld::prepare() {
if (isInit())
return true;
_worldRules = initWorldRules();
_hdrMap = initHdrBackGround();
setHdr(initHdrBackGround());
setPlayer(initPlayer());
_player->initOnWorld(this, _player);
_userInterface = initUserInterface();
@ -144,12 +145,12 @@ bool IWorld::init() {
if (!isInit()) {
QuasarAppUtils::Params::log("Failed to init world implementation.");
deinit();
reset();
return false;
}
if (!_worldRules->size()) {
deinit();
reset();
return false;
}
@ -173,19 +174,26 @@ void IWorld::addItem(IWorldItem *obj, QList<int> *addedObjectsList) {
if (!obj)
return;
obj->init();
Diff diff;
// 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());
if (item) {
diff.addedIds.push_back(item->guiId());
}
}
}
addAtomicItem(obj);
diff.addedIds.push_back(obj->guiId());
if (addedObjectsList)
addedObjectsList->push_back(obj->guiId());
*addedObjectsList = diff.addedIds;
emit sigOBjctsListChanged(diff);
}
@ -196,29 +204,35 @@ void IWorld::removeItem(int id, QList<int> *removedObjectsList) {
if (!obj)
return;
Diff diff;
// Work wih claster
if (auto claster = dynamic_cast<Claster*>(obj)) {
auto copyOfObjectsList = claster->objects();
const auto copyOfObjectsList = claster->objects();
for (auto item : copyOfObjectsList) {
if (!item || !item->parentClastersCount())
if (!item || item->parentClastersCount() > 1)
continue;
int id = item->guiId();
removeIAtomicItem(item);
removeAtomicItem(item);
if (removedObjectsList)
removedObjectsList->push_back(id);
diff.removeIds.push_back(id);
}
}
addAtomicItem(obj);
if (removedObjectsList)
removedObjectsList->push_back(obj->guiId());
removeAtomicItem(obj);
diff.removeIds.push_back(id);
if (removedObjectsList)
*removedObjectsList = diff.removeIds;
emit sigOBjctsListChanged(diff);
}
void IWorld::deinit() {
void IWorld::reset() {
if (_player) {
delete _player;
_player = nullptr;
@ -240,7 +254,7 @@ void IWorld::deinit() {
}
clearItems();
_hdrMap = "";
setHdr("");
}
@ -257,7 +271,7 @@ void IWorld::addAtomicItem(IWorldItem* obj) {
obj->initOnWorld(this, _player);
}
bool IWorld::removeIAtomicItem(int id) {
bool IWorld::removeAtomicItem(int id) {
QMutexLocker lock(&_ItemsMutex);
auto obj = _items.value(id);
@ -274,7 +288,7 @@ bool IWorld::removeIAtomicItem(int id) {
return true;
}
bool IWorld::removeIAtomicItem(IWorldItem *obj) {
bool IWorld::removeAtomicItem(IWorldItem *obj) {
if (!obj) {
return false;
}
@ -295,6 +309,14 @@ void IWorld::removeAnyItemFromGroup(const QString &group,
removeItem(anyObjectId, removedObjectsList);
}
bool IWorld::running() const {
return _running;
}
void IWorld::setRunning(bool newRunning) {
_running = newRunning;
}
int IWorld::targetFps() const {
return _targetFps;
}
@ -303,6 +325,14 @@ void IWorld::setTargetFps(int newTargetFps) {
_targetFps = newTargetFps;
}
void IWorld::setHdr(const QString &hdr) {
if (hdr == _hdrMap)
return;
_hdrMap = hdr;
emit hdrChanged();
}
const QQuaternion &IWorld::cameraRatation() const {
return _cameraRatation;
}
@ -335,40 +365,33 @@ void IWorld::setCameraReleativePosition(const QVector3D &newCameraReleativePosit
}
void IWorld::handleStop() {
stop();
runAsBackGround();
}
const QVector3D &IWorld::cameraReleativePosition() const {
return _cameraReleativePosition;
}
const QString &IWorld::hdrMap() const {
return _hdrMap;
}
void IWorld::worldChanged(WorldObjects objects) {
void IWorld::worldChanged(const WorldObjects &objects) {
objects[_player->className()] = 1;
Diff diff;
for (auto it = objects.begin(); it != objects.end(); ++it) {
int count = it.value() - _itemsGroup.count(it.key());
if (count > 0) {
for ( int i = 0; i < count; ++i ) {
addItem(generate(it.key()), &diff.addedIds);
addItem(generate(it.key()));
}
} else {
for (; count < 0; ++count ) {
removeAnyItemFromGroup(it.key(), &diff.removeIds);
removeAnyItemFromGroup(it.key());
}
}
}
if (diff.addedIds.size() || diff.removeIds.size())
emit sigOBjctsListChanged(diff);
}
int IWorld::wordlStatus() const {
return _worldStatus;
}
@ -381,3 +404,18 @@ void IWorld::setWorldStatus(int newWorldStatus) {
emit worldStatusChanged();
}
const QString &IWorld::hdr() const {
return _hdrMap;
}
void IWorld::runAsBackGround() {
start();
setWorldStatus(WorldStatus::Background);
_player->setControl(dynamic_cast<IControl*>(_backgroundAI));
_backgroundAI->startAI();
setTargetFps(30);
}

View File

@ -46,12 +46,15 @@ class CRAWL_EXPORT IWorld : public QObject, public IRender
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(QString hdr READ hdr NOTIFY hdrChanged)
Q_PROPERTY(int worldStatus READ wordlStatus WRITE setWorldStatus NOTIFY worldStatusChanged)
public:
IWorld();
virtual ~IWorld();
~IWorld() override;
void init() override;
/**
* @brief initPlayer The implementation of This interface must be return playerObject.
@ -165,12 +168,6 @@ public:
*/
IWorldItem *getItem(int id) const;
/**
* @brief hdrMap This method return path to hdr map of world.
* @return
*/
const QString &hdrMap() const;
/**
* @brief cameraReleativePosition return a releative of player camera position.
* @return
@ -219,6 +216,18 @@ public:
*/
QObject *player() const;
/**
* @brief hdr This method return path to hdr map of the lvl.
* @return path to hdr map of this lvl.
*/
const QString &hdr() const;
/**
* @brief runAsBackGround This method run this world as a backgroud.
* The player start new game and sets new control from the backgroundAI method.
*/
void runAsBackGround();
signals:
/**
* @brief sigGameFinished This signal emit when game are finished
@ -258,6 +267,11 @@ signals:
*/
void playerChanged();
/**
* @brief hdrChanged This signal emited when the hdr map are changed.
*/
void hdrChanged();
protected:
/**
@ -311,6 +325,12 @@ protected:
*/
void setTargetFps(int newTargetFps);
/**
* @brief setHdr This method sets new path to hdr map of this lvl.
* @param hdr path to hdr map.
*/
void setHdr(const QString& hdr);
template<class Type>
/**
@ -354,14 +374,33 @@ private slots:
private:
/**
* @brief init This method initialize world object.
* @brief prepare This method initialize world object.
* @note If object alredy initalize then this method do nothing.
* @return true if world initialized successful
*/
bool prepare();
void reset();
/**
* @brief running This varibale check in render function if the running is true then render loop are working correctly
* @return
*/
bool init();
void deinit();
bool running() const;
/**
* @brief setRunning
* @param newRunning
*/
void setRunning(bool newRunning);
/**
* @brief worldChanged This method generate diff for the qml
* @param objects This is list of object on lvl
* @note This method addd player object to this list.
*/
void worldChanged(WorldObjects objects);
void worldChanged(const WorldObjects& objects);
void clearItems();
/**
@ -387,18 +426,18 @@ private:
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.
* @brief removeAtomicItem 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 removeIAtomicItem(int id);
bool removeAtomicItem(int id);
/**
* @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.
* @brief removeAtomicItem 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
*/
bool removeIAtomicItem(IWorldItem *obj);
bool removeAtomicItem(IWorldItem *obj);
/**
* @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.
@ -411,6 +450,7 @@ private:
QHash<int, IWorldItem*> _items;
QMultiHash<QString, int> _itemsGroup;
QMultiHash<QString, int> _lastItemsGroup;
mutable QMutex _ItemsMutex;
@ -426,13 +466,13 @@ private:
QHash<QString, std::function<IWorldItem*()>> _registeredTypes;
int _targetFps = 60;
bool _running = false;
// engine
friend class Engine;
// testing
friend class ClastersTest;
};
#endif // IWORLD_H

View File

@ -31,17 +31,23 @@ const IWorldItem *IWorldItem::getPlayer() const {
}
void IWorldItem::render(unsigned int) {
if (_playerObject->position().x() - position().x() >
_world->cameraReleativePosition().z() * 2) {
setX(_playerObject->position().x() + _world->cameraReleativePosition().z() * 4);
if (_playerObject->position().x() - _world->cameraReleativePosition().z() >
position().x()) {
float dY = rand() % static_cast<int>(_world->cameraReleativePosition().z() * 2
- _world->cameraReleativePosition().z());
float dX = _world->cameraReleativePosition().z() * 2 +
(rand() % static_cast<int>(_world->cameraReleativePosition().z()));
setX(_playerObject->position().x() + dX);
float dY = (rand() % static_cast<int>(_world->cameraReleativePosition().z() * 4)
- _world->cameraReleativePosition().z() * 2);
setY(_playerObject->position().y() + dY);
}
}
void IWorldItem::init() {}
void IWorldItem::initOnWorld(const IWorld *world, const IWorldItem * player) {
_world = world;
_playerObject = player;

View File

@ -31,6 +31,7 @@ public:
* @note new position = playerPosition + scaneSize;
*/
void render(unsigned int tbfMsec) override;
void init() override;
protected:
@ -60,7 +61,6 @@ private:
const IWorld* _world = nullptr;
const IWorldItem *_playerObject = nullptr;
friend class IWorld;
};
#endif // IWORLDITEM_H

View File

@ -6,7 +6,7 @@
//#
#include "claster.h"
#include "Extensions/claster.h"
#include "singleclasterworlditem.h"
#include "quasarapp.h"
@ -26,3 +26,11 @@ void SingleClasterWorldItem::setClaster(Claster *claster) {
ClasterItem::setClaster(claster);
}
Claster *SingleClasterWorldItem::parentClaster() const {
if (parentClastersCount() <= 0 ) {
return nullptr;
}
return *ClasterItem::parentClasters().begin();
}

View File

@ -24,7 +24,7 @@ public:
SingleClasterWorldItem(const QString& name,
const QString& viewTempalte = DEFAULT_VIEW_TEMPLATE,
QObject *ptr = nullptr);
private:
protected:
/**
* @brief setClaster invoked when object added to new claster.
@ -33,6 +33,12 @@ private:
*/
void setClaster(Claster *claster) override;
/**
* @brief parentClaster This method is wraper of the ClasterItem::parentClasters method.
* @return pointer to the parent claster object.
*/
Claster* parentClaster() const;
friend class Claster;
};

161
src/Core/Crawl/snake.cpp Normal file
View File

@ -0,0 +1,161 @@
//#
//# 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 "clasteritem.h"
#include "snake.h"
#include "snakeitem.h"
#include <QQuaternion>
#include <quasarapp.h>
#include <cmath>
Snake::Snake(const QString &name, const QString &viewTempalte, QObject *ptr):
IPlayer (name, viewTempalte, ptr) {
_vectors = new QVector3D[2];
setAngularVelocity(100);
setSpeed(100);
setLengthBetwinItems(1);
setBodyCount(50);
setSpeed(100);
_clickIndex = 0;
setScales({{0, 0.8},
{0.4, 1.2},
{1, 0.5}});
}
Snake::~Snake( ){
delete [] _vectors;
}
void Snake::render(unsigned int tbfMsec) {
IPlayer::render(tbfMsec);
}
void Snake::add(ClasterItem *object) {
if (auto snakeItem = dynamic_cast<SnakeItem*>(object)) {
if (_lastSnakeItem) {
snakeItem->setPrev(_lastSnakeItem);
} else {
snakeItem->setPrev(this);
}
snakeItem->setBreakingForce(breakingForce());
_lastSnakeItem = static_cast<IWorldItem*>(snakeItem);
Claster::add(object);
return ;
}
QuasarAppUtils::Params::log("Failed to add item to Snake."
" You need to use the SnakeItem child class as a argument",
QuasarAppUtils::Error);
}
void Snake::remove(ClasterItem *object) {
if (_lastSnakeItem == object) {
_lastSnakeItem = static_cast<const SnakeItem*>(_lastSnakeItem)->prev();
}
return Claster::remove(object);
}
void Snake::remove(int id) {
if (_lastSnakeItem->guiId() == id) {
_lastSnakeItem = static_cast<const SnakeItem*>(_lastSnakeItem)->prev();
}
return Claster::remove(id);
}
void Snake::init() {
generateBody();
}
void Snake::onTap() {
setMovableVector(_vectors[_clickIndex++ % 2]);
}
void Snake::generateBody() {
auto scaleIt = _scales.begin();
float from = 0, fromKey = 0;
float to = scaleIt.value(), toKey = scaleIt.key();
for(int i = 0; i < _bodyCount; ++i) {
if (!_factory) {
QuasarAppUtils::Params::log("Please use the registerBodyitem method"
" before invoke parent constructor.",
QuasarAppUtils::Error);
return;
}
auto item = _factory();
float scale = 1;
if (scaleIt != _scales.end()) {
float position = static_cast<float>(i) / _bodyCount;
while (position >= scaleIt.key() && scaleIt != _scales.end()) {
scaleIt++;
if (scaleIt != _scales.end()) {
from = to;
to = scaleIt.value();
fromKey = toKey;
toKey = scaleIt.key();
}
}
scale = ((position - fromKey) * toKey / (to - from)) + from;
}
item->setSize(item->size() * scale);
add(item);
}
}
float Snake::speed() const {
return _speed;
}
void Snake::setSpeed(float newSpeed) {
_speed = newSpeed;
float asixPos = std::sqrt(std::pow(_speed, 2.0) / 2);
_vectors[0] = QVector3D(asixPos, asixPos,0); // left tap
_vectors[1] = QVector3D(asixPos,-asixPos,0); // right tap
}
int Snake::bodyCount() const {
return _bodyCount;
}
void Snake::setBodyCount(int newBodyCount) {
_bodyCount = newBodyCount;
}
const QMap<float, float> &Snake::scales() const {
return _scales;
}
void Snake::setScales(const QMap<float, float> &newScales) {
_scales = newScales;
}
float Snake::lengthBetwinItems() const{
return _lengthBetwinItems;
}
void Snake::setLengthBetwinItems(float newLengthBetwinItems) {
_lengthBetwinItems = newLengthBetwinItems;
}

121
src/Core/Crawl/snake.h Normal file
View File

@ -0,0 +1,121 @@
//#
//# 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 SNAKE_H
#define SNAKE_H
#include "iplayer.h"
#include "Extensions/claster.h"
class SnakeItem;
/**
* @brief The Snake class This class implement render mehod for snake object.
*/
class CRAWL_EXPORT Snake : public IPlayer, public Claster
{
Q_OBJECT
public:
Snake(const QString& name,
const QString& viewTempalte = DEFAULT_VIEW_TEMPLATE,
QObject *ptr = nullptr);
~Snake() override;
void render(unsigned int tbfMsec) override;
void add(ClasterItem *object) override;
void remove(ClasterItem *object) override;
void remove(int id) override;
void init() override;
// IPlayer interface
/**
* @brief lengthBetwinItems This method return length betwin snake items;
* @return length betwin snake items
*/
float lengthBetwinItems() const;
/**
* @brief setLengthBetwinItems This method sets length betwin snake items.
* @param newLengthBetwinItems This is new value of the length betwin snake items.
*/
void setLengthBetwinItems(float newLengthBetwinItems);
template<class Type>
/**
* @brief registerBodyitem This method register snake body item type. The body items will be generated in the generateBody method. The size of body companents calc from the Snake::scales property.
*/
void registerBodyitem() {
_factory = [](){
return new Type;
};
}
/**
* @brief scales This method return the map of the snake body scales.
* The key of map are position of snake Body and the value are scale factor of current body item.
* The default scales map of snake are:
* ```
* 0.0 - 0.8
* 0.6 - 1.2
* 1 - 0.5
* ```
* @return scales map of snake body.
*/
const QMap<float, float> &scales() const;
/**
* @brief setScales This method sets new scales map for snake body.
* @param newScales This is new value of the scales map.
*/
void setScales(const QMap<float, float> &newScales);
/**
* @brief bodyCount This method return count of the body items of this snake.
* @return count of body items of the snake.
*/
int bodyCount() const;
/**
* @brief setBodyCount This method sets new size of snake.
* @param newBodyCount this is new value of the body count.
* @note Use This method in the constructor of your child snake class.
*/
void setBodyCount(int newBodyCount);
/**
* @brief speed This method return current speed snake speed.
* @return snake speed
*/
float speed() const;
/**
* @brief setSpeed This method sets new current speed of the snake.
* @param newSpeed new value of the snake speed.
*/
void setSpeed(float newSpeed);
protected slots:
void onTap() override;
private:
void generateBody();
QMap<float, float> _scales;
std::function<ClasterItem*()> _factory = nullptr;
float _lengthBetwinItems;
int _bodyCount;
const IWorldItem* _lastSnakeItem = nullptr;
unsigned int _clickIndex;
QVector3D* _vectors;
float _speed;
};
#endif // SNAKE_H

View File

@ -0,0 +1,43 @@
//#
//# 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 "snake.h"
#include "snakeitem.h"
SnakeItem::SnakeItem(const QString itemName): SingleClasterWorldItem(itemName) {
setAngularVelocity(-1);
}
void SnakeItem::setPrev(const IWorldItem * newPrev) {
_prevObject = newPrev;
}
void SnakeItem::render(unsigned int tbfMsec) {
if (!_prevObject) {
return;
}
auto ratationVector = (_prevObject->position() - position());
if (auto claster = static_cast<Snake*>(parentClaster())) {
float ratationLength = ratationVector.length();
if (ratationLength > claster->lengthBetwinItems() * 10) {
setposition(_prevObject->position());
} else if (ratationLength > claster->lengthBetwinItems()) {
setMovableVector(ratationVector.normalized() * claster->currentMovableVector().length());
}
}
MovableObject::render(tbfMsec);
}
const IWorldItem * SnakeItem::prev() const {
return _prevObject;
}

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.
//#
#ifndef SNAKEITEM_H
#define SNAKEITEM_H
#include "singleclasterworlditem.h"
#include "Extensions/movableobject.h"
class CRAWL_EXPORT SnakeItem: public SingleClasterWorldItem, public MovableObject
{
Q_OBJECT
public:
SnakeItem(const QString itemName = "SnakeItem");
/**
* @brief setPrev This method sets id of the previous snake item.
* @param newPrev this is new value of the previous snake item.
*/
void setPrev(const IWorldItem * newPrev);
void render(unsigned int tbfMsec) override;
/**
* @brief prev This method return prev object of snake
* @return the prev objects of the snake
*/
const IWorldItem * prev() const;
private:
const IWorldItem *_prevObject = nullptr;
};
#endif // SNAKEITEM_H

View File

@ -13,7 +13,10 @@ Model {
property var model: null
property int guiId: (model) ? model.guiId : -1;
property bool fMapColor: model && (model.baseColorMap.length || model.emissiveMap.length || model.roughnessMap.length || model.normalMap.length)
property bool fMapColor: model && (model.baseColorMap.length ||
model.emissiveMap.length ||
model.roughnessMap.length ||
model.normalMap.length)
DefaultMaterial {
id: defaultMaterial
@ -38,15 +41,3 @@ 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

@ -23,10 +23,6 @@ View3D {
:
Qt.vector3d(0,0,100)
onPositionChanged: {
console.log(position)
}
rotation: (privateRoot.world)? privateRoot.world.cameraRatation: Qt.quaternion(0,0,0,0)
}
@ -42,7 +38,7 @@ View3D {
id: background
backgroundMode: SceneEnvironment.SkyBox
lightProbe: Texture {
source: (model)? model.hdr: ""
source: (privateRoot.world)? privateRoot.world.hdr: ""
}
}
@ -51,7 +47,6 @@ View3D {
property var arrayObjects: []
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
@ -82,7 +77,7 @@ View3D {
obj.model = model.getGameObject(cppObjId);
arrayObjects.push(obj)
} else {
console.log("wrong viewTemplate in model");
console.log("wrong viewTemplate in model " + temp.errorString());
}
}
@ -125,19 +120,6 @@ 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;

View File

@ -0,0 +1,110 @@
# Extension concept
The extension it is separate module class with custom function.
## How to use
1. Create own child class from IRender interface.
2. Override the IRender::render method of base interface
3. Check compatibility betwin this type and requred type using the IRender::checkminimumRequariedType method.
4. In the render method using dynamic_cast operator get neede interface of class object.
5. Implement needed functions for object.
## Example:
Movable object header:
```cpp
class CRAWL_EXPORT MovableObject: public virtual IRender
{
public:
MovableObject();
void render(unsigned int tbfMsec) override;
const QVector3D &movableVector() const;
void setMovableVector(const QVector3D &newMovableVector);
float angularVelocity() const;
void setAngularVelocity(float newAngularVelocity);
float breakingForce() const;
void setBreakingForce(float newBreakingForce);
private:
QVector3D _movableVector;
QVector3D _currentMovableVector;
float _angularVelocity = 0;
float _breakingForce = 0;
};
```
Movable object source:
```cpp
MovableObject::MovableObject()
{
}
void MovableObject::render(unsigned int tbfMsec) {
auto _this = checkminimumRequariedType<IWorldItem>();
// get object center position
QVector3D currentPosition = _this->position();
// move object to vector
currentPosition += (_currentMovableVector * (tbfMsec / 1000.0));
_this->setposition(currentPosition);
// calc temp vector betvin user moveble vector and real moveble vector
QVector3D tempVector = _movableVector - _currentMovableVector ;
// calc change on this iteration for new moveble vector
float delta = std::min(_angularVelocity * (tbfMsec / 1000.0), static_cast<double>(tempVector.length()));
// resize temp vector for calc changes of the movableVector
tempVector = tempVector.normalized() * delta;
// recalc new currentMovable vector (applay changes)
_currentMovableVector += tempVector;
float newMovableVectorLength = std::max(_movableVector.length() - (_breakingForce * (tbfMsec / 1000.0)), 0.0);
// update movable vector
_movableVector = _movableVector.normalized() * newMovableVectorLength;
}
const QVector3D &MovableObject::movableVector() const {
return _movableVector;
}
void MovableObject::setMovableVector(const QVector3D &newMovableVector) {
_movableVector = newMovableVector;
}
float MovableObject::angularVelocity() const {
return _angularVelocity;
}
void MovableObject::setAngularVelocity(float newAngularVelocity) {
_angularVelocity = newAngularVelocity;
}
float MovableObject::breakingForce() const {
return _breakingForce;
}
void MovableObject::setBreakingForce(float newBreakingForce) {
_breakingForce = newBreakingForce;
}
```

View File

@ -6,14 +6,9 @@
//#
#include "claster.h"
#include "singleclasterworlditem.h"
#include "Crawl/singleclasterworlditem.h"
Claster::Claster(const QString &name,
const QString &viewTempalte,
QObject *ptr):
IWorldItem(name, viewTempalte, ptr) {
}
Claster::Claster() {}
Claster::~Claster() {
for (auto child : qAsConst(_objects)) {

View File

@ -15,34 +15,33 @@ class ClasterItem;
/**
* @brief The Claster class are object with support multiple objects render.
* For example snake with 20 points of the snake blocks.
* @note The claster object is extansion for the IWorldItems objects.
*/
class CRAWL_EXPORT Claster: public IWorldItem
class CRAWL_EXPORT Claster
{
Q_OBJECT
public:
Claster(const QString& name,
const QString& viewTempalte = DEFAULT_VIEW_TEMPLATE,
QObject *ptr = nullptr);
Claster();
~Claster();
virtual ~Claster();
/**
* @brief add This method added new object to claster.
* @param object This is model of added object
* @note if you want you can override this methods for extend functionality of this class.
*/
void add(ClasterItem* object);
virtual void add(ClasterItem* object);
/**
* @brief remove This method remove object from claster
* @param object poiter of removed object
*/
void remove(ClasterItem* object);
virtual 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);
virtual void remove(int id);
/**
* @brief objects This method return list of collected objects.
@ -52,6 +51,7 @@ public:
private:
QHash<int, ClasterItem*> _objects;
};
#endif // CLASTER_H

View File

@ -1,39 +1,25 @@
#include "movableobject.h"
#include <QDebug>
//#
//# 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.
//#
MovableObject::MovableObject(const QString &name,
const QString &viewTempalte,
QObject *ptr):
IWorldItem(name, viewTempalte, ptr) {
#include "movableobject.h"
#include <math.h>
#include <Crawl/guiobject.h>
MovableObject::MovableObject() {
}
void MovableObject::render(unsigned int tbfMsec) {
// get object center position
QVector3D currentPosition = position();
// move object to vector
currentPosition += (_currentMovableVector * (tbfMsec / 1000.0));
setposition(currentPosition);
// calc temp vector betvin user moveble vector and real moveble vector
QVector3D tempVector = _movableVector - _currentMovableVector ;
// calc change on this iteration for new moveble vector
float delta = std::min(_angularVelocity * (tbfMsec / 1000.0), static_cast<double>(tempVector.length()));
// resize temp vector for calc changes of the movableVector
tempVector = tempVector.normalized() * delta;
// recalc new currentMovable vector (applay changes)
_currentMovableVector += tempVector;
float newMovableVectorLength = std::max(_movableVector.length() - (_breakingForce * (tbfMsec / 1000.0)), 0.0);
// update movable vector
_movableVector = _movableVector.normalized() * newMovableVectorLength;
if (auto _this = checkminimumRequariedType<GuiObject>()) {
renderPosition(_this, tbfMsec);
renderRatation(_this, tbfMsec);
}
}
const QVector3D &MovableObject::movableVector() const {
@ -59,3 +45,45 @@ float MovableObject::breakingForce() const {
void MovableObject::setBreakingForce(float newBreakingForce) {
_breakingForce = newBreakingForce;
}
void MovableObject::renderRatation(GuiObject *object, unsigned int) {
if (_currentMovableVector.length() > 0) {
object->setRatation(QQuaternion::rotationTo({1.0f, 0.0, 0.0}, _currentMovableVector));
}
}
void MovableObject::renderPosition(GuiObject *object, unsigned int tbfMsec) {
// get object center position
QVector3D currentPosition = object->position();
// move object to vector
currentPosition += (_currentMovableVector * (tbfMsec / 1000.0));
object->setposition(currentPosition);
// calc temp vector betvin user moveble vector and real moveble vector
QVector3D tempVector = _movableVector - _currentMovableVector ;
// calc change on this iteration for new moveble vector
float delta = 0.0;
if (_angularVelocity <= 0) {
delta = tempVector.length();
} else {
delta = std::min(_angularVelocity * (tbfMsec / 1000.0), static_cast<double>(tempVector.length()));
}
// resize temp vector for calc changes of the movableVector
tempVector = tempVector.normalized() * delta;
// recalc new currentMovable vector (applay changes)
_currentMovableVector += tempVector;
float newMovableVectorLength = std::max(_movableVector.length() - (_breakingForce * (tbfMsec / 1000.0)), 0.0);
// update movable vector
_movableVector = _movableVector.normalized() * newMovableVectorLength;
}
const QVector3D &MovableObject::currentMovableVector() const {
return _currentMovableVector;
}

View File

@ -1,7 +1,18 @@
//#
//# 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 MOVABLEOBJECT_H
#define MOVABLEOBJECT_H
#include "iworlditem.h"
#include "Crawl/irender.h"
#include <QVector3D>
class GuiObject;
/**
* @brief The MovableObject class contains functions for moving object on the world.
@ -12,13 +23,11 @@
* * **Angular velocity** This property sets spead of the angle moving.
* * **Braking force** This property are delta decriment the Power of the movable vector on time.
*/
class CRAWL_EXPORT MovableObject: public IWorldItem
class CRAWL_EXPORT MovableObject: public virtual IRender
{
Q_OBJECT
public:
MovableObject(const QString& name,
const QString& viewTempalte = DEFAULT_VIEW_TEMPLATE,
QObject *ptr = nullptr);
MovableObject();
/**
* @brief render This impplementation of the render method add simulation of the physics in the vacuum space.
@ -37,7 +46,8 @@ public:
/**
* @brief setMovableVector This method sets new value of the mvable vector.
* @param newMovableVector - this is a new value ofthe movable vector
* @param newMovableVector this is a new value ofthe movable vector
* @note The movable vector will be changed in time if you set the MovableObject::breakingForce propertye to non 0 value.
*/
void setMovableVector(const QVector3D &newMovableVector);
@ -66,13 +76,34 @@ public:
*/
void setBreakingForce(float newBreakingForce);
/**
* @brief currentMovableVector This method return current movable vector.
* @return current movable vector.
*/
const QVector3D &currentMovableVector() const;
protected:
/**
* @brief renderRatation This method recalc raration for an @a object. The Default implementation converts movableVector to ratation of an @a object.
* @param object This is provessing object. Usually @a an object is casted pointer of this to GuiObject type.
* @param tbfMsec This is time betwin frames argument. soame as in the IRender::render function.
*/
virtual void renderRatation(GuiObject* object, unsigned int tbfMsec);
/**
* @brief renderRatation This method recalc position for an @a object. The Default implementation move the current movable vector to setts movable vector. For example if you invoke the MovableObject::setMovableVector method then object change current movable vector with spead MovableObject::angularVelocity. If you sets
* @param object This is provessing object. Usually @a an object is casted pointer of this to GuiObject type.
* @param tbfMsec This is time betwin frames argument. soame as in the IRender::render function.
*/
virtual void renderPosition(GuiObject* object, unsigned int tbfMsec);
private:
QVector3D _movableVector;
QVector3D _currentMovableVector;
float _angularVelocity = 0;
float _breakingForce = 0;
};
#endif // MOVABLEOBJECT_H

View File

@ -11,6 +11,8 @@
DefaultBackgroundAI::DefaultBackgroundAI() {
_timer = new QTimer();
_timer->setInterval(1000);
connect(_timer, &QTimer::timeout, this, &DefaultBackgroundAI::handleTimerTriger);
}
DefaultBackgroundAI::~DefaultBackgroundAI() {
@ -27,7 +29,7 @@ void DefaultBackgroundAI::stopAI() {
}
void DefaultBackgroundAI::handleTimerTriger() {
_timer->setInterval(rand() % 1000 + 10);
_timer->setInterval(rand() % 2000 + 200);
emit userTap();
}

View File

@ -40,12 +40,13 @@ void Engine::setWorld(IWorld *world) {
return ;
if (_currentWorld) {
_currentWorld->deinit();
_currentWorld->reset();
}
_currentWorld = world;
emit worldChanged();
if (!_currentWorld->init()) {
if (!prepareNewWorld()) {
QuasarAppUtils::Params::log("Failed to init world. World name: " + _currentWorld->name(),
QuasarAppUtils::Error);
@ -53,22 +54,8 @@ void Engine::setWorld(IWorld *world) {
return;
}
if (!_currentWorld->userInterface()->init()) {
return;
}
setMenu(_currentWorld->userInterface());
emit worldChanged();
startRenderLoop();
}
QString Engine::hdr() const {
if (!_currentWorld)
return "";
return _currentWorld->hdrMap();
_currentWorld->runAsBackGround();
}
void Engine::setScane(QObject *newScane) {
@ -149,6 +136,20 @@ void Engine::setPrepareLvlProgress(int newPrepareLvlProgress) {
emit prepareLvlProgressChanged();
}
bool Engine::prepareNewWorld() {
if (!_currentWorld->prepare()) {
return false;
}
if (!_currentWorld->userInterface()->init()) {
return false;
}
setMenu(_currentWorld->userInterface());
return true;
}
void Engine::renderLoop() {
if (!_currentWorld)

View File

@ -21,7 +21,6 @@ class IWorld;
class Engine : public QObject {
Q_OBJECT
Q_PROPERTY(QString hdr READ hdr NOTIFY worldChanged)
Q_PROPERTY(QObject* player READ player NOTIFY playerChanged)
Q_PROPERTY(QObject* world READ world NOTIFY worldChanged)
@ -51,12 +50,6 @@ public:
*/
void setWorld(IWorld *world);
/**
* @brief hdr This method should return hdr map of the lvl
* @return path to hdr map.
*/
QString hdr() const;
/**
* @brief setScane This method sets new scane object. The scane object are
* @param newScane are Qt Quick 3d node object form qml.
@ -139,7 +132,7 @@ signals:
private:
void setPrepareLvlProgress(int newPrepareLvlProgress);
bool prepareNewWorld();
void renderLoop();

@ -1 +1 @@
Subproject commit 46878c18cae14eed67a2b105dc993ff2d670a3bc
Subproject commit b08e8238fba0c28aed2c65e3a1fb317e61422d23

View File

@ -7,16 +7,16 @@
#include "clasterstest.h"
#include <QtTest>
#include <Crawl/claster.h>
#include <Extensions/claster.h>
#include <Crawl/clasteritem.h>
#include <Crawl/singleclasterworlditem.h>
#include <Crawl/iworld.h>
// Test claster object.
class TestClasterObject: public Claster {
class TestClasterObject: public IWorldItem, public Claster {
public:
TestClasterObject(): Claster("TestClaster"){};
TestClasterObject(): IWorldItem("TestClaster"){};
protected:
void onIntersects(const IWorldItem *) {};
};