Merge pull request #60 from QuasarApp/render

Add support render function
This commit is contained in:
Andrei Yankovich 2021-06-24 09:15:12 +03:00 committed by GitHub
commit dbab1e081a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 290 additions and 9 deletions

View File

@ -31,7 +31,6 @@ QByteArray ClientApp::initTheme() {
case 1: return "Dark";
default: return "Light";
}
}
ClientApp::ClientApp() {
@ -85,7 +84,6 @@ void ClientApp::initLvls() {
}
_menu->setAvailableLvls(_availableWorlds);
}
IWorld *ClientApp::getLastWorld() {

View File

@ -30,7 +30,7 @@ void GuiObject::setColor(QString color) {
void GuiObject::generateId() {
static int id = 0;
_guiId = id++;
setGuiId(id++);
}
const QString &GuiObject::className() const {

View File

@ -5,12 +5,13 @@
//# of this license document, but changing it is not allowed.
//#
#include "defaultcontrol.h"
#include "iplayer.h"
IPlayer::IPlayer(const QString &name,
const QString &viewTempalte,
QObject *ptr):
IWorldItem(name, viewTempalte, ptr) {
MovableObject(name, viewTempalte, ptr) {
}
@ -52,6 +53,21 @@ void IPlayer::setSpeed(float newSpead) {
}
}
void IPlayer::setControl(const IControl *control) {
if (auto oldControl = dynamic_cast<const DefaultControl*>(_currentControl)) {
disconnect(oldControl, &DefaultControl::userTap, this, &IPlayer::onTap);
}
auto defaultControl = dynamic_cast<const DefaultControl*>(control);
_currentControl = defaultControl;
if (_currentControl) {
connect(defaultControl, &DefaultControl::userTap, this, &IPlayer::onTap);
}
}
void IPlayer::kill() {
_fDead = true;
}

View File

@ -9,15 +9,15 @@
#define IPLAYER_H
#include "gameresult.h"
#include "iworlditem.h"
#include "global.h"
#include "movableobject.h"
class IControl;
/**
* @brief The IPlayer class This is base class of the player functions.
*/
class CRAWL_EXPORT IPlayer: public IWorldItem {
class CRAWL_EXPORT IPlayer: public MovableObject {
Q_OBJECT
public:
IPlayer(const QString& name,
@ -53,7 +53,7 @@ public:
* @param control This is control object.
* @note This method can invoked two or more times, for example connect with AI control object and player control object. So your implementation should be contains disconnect methods.
*/
virtual void setControl(const IControl* control) = 0;
virtual void setControl(const IControl* control);
protected:
@ -92,6 +92,7 @@ protected:
*/
void fine(int value);
protected slots:
/**
* @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.
@ -102,6 +103,7 @@ private:
bool _fDead = false;
int _currentPoints = 0;
float _speed = 0;
const IControl * _currentControl = nullptr;
};
#endif // IPLAYER_H

View File

@ -16,6 +16,8 @@
#include "worldstatus.h"
#include "iai.h"
#include "clasteritem.h"
#include "thread"
#include "chrono"
IWorld::IWorld() {
@ -31,6 +33,8 @@ IControl *IWorld::initUserInterface() const {
void IWorld::render(unsigned int tbfMsec) {
_ItemsMutex.lock();
for (auto i = _items.begin(); i != _items.end(); ++i) {
(*i)->render(tbfMsec);
@ -43,6 +47,12 @@ void IWorld::render(unsigned int tbfMsec) {
if (_player->isDead()) {
emit sigGameFinished(_player->getCurrentStatus());
}
_ItemsMutex.unlock();
int waitTime = 1000 / _targetFps - tbfMsec;
if (waitTime > 0)
std::this_thread::sleep_for(std::chrono::milliseconds(waitTime));
}
void IWorld::initPlayerControl(IControl *control) {
@ -63,6 +73,7 @@ bool IWorld::start() {
worldChanged(*_worldRules->begin());
setTargetFps(60);
return true;
}
@ -103,6 +114,8 @@ bool IWorld::stop() {
_backgroundAI->startAI();
setTargetFps(30);
return true;
}
@ -111,6 +124,8 @@ IAI *IWorld::initBackGroundAI() const {
}
IWorldItem *IWorld::getItem(int id) const {
QMutexLocker lock(&_ItemsMutex);
return _items.value(id, nullptr);
}
@ -145,6 +160,8 @@ bool IWorld::init() {
}
void IWorld::clearItems() {
QMutexLocker lock(&_ItemsMutex);
for (const auto& item : qAsConst(_items)) {
delete item;
}
@ -232,11 +249,17 @@ void IWorld::addAtomicItem(IWorldItem* obj) {
if (!obj)
return;
QMutexLocker lock(&_ItemsMutex);
_items.insert(obj->guiId(), obj);
_itemsGroup.insert(obj->className(), obj->guiId());
obj->initOnWorld(this, _player);
}
bool IWorld::removeIAtomicItem(int id) {
QMutexLocker lock(&_ItemsMutex);
auto obj = _items.value(id);
if (!obj) {
@ -256,6 +279,8 @@ bool IWorld::removeIAtomicItem(IWorldItem *obj) {
return false;
}
QMutexLocker lock(&_ItemsMutex);
_itemsGroup.remove(obj->className(), obj->guiId());
_items.remove(obj->guiId());
@ -270,6 +295,14 @@ void IWorld::removeAnyItemFromGroup(const QString &group,
removeItem(anyObjectId, removedObjectsList);
}
int IWorld::targetFps() const {
return _targetFps;
}
void IWorld::setTargetFps(int newTargetFps) {
_targetFps = newTargetFps;
}
const QQuaternion &IWorld::cameraRatation() const {
return _cameraRatation;
}

View File

@ -19,6 +19,7 @@
#include "irender.h"
#include "diff.h"
#include "global.h"
#include <QMutex>
class IWorldItem;
class IPlayer;
@ -298,6 +299,18 @@ protected:
*/
void setCameraRatation(const QQuaternion &newCameraRatation);
/**
* @brief targetFps This method return current targetFps;
* @return current target FPS.
*/
int targetFps() const;
/**
* @brief setTargetFps This method sets new targetFps.
* @param newTargetFps This is new value of target Fps;
*/
void setTargetFps(int newTargetFps);
template<class Type>
/**
@ -398,6 +411,9 @@ private:
QHash<int, IWorldItem*> _items;
QMultiHash<QString, int> _itemsGroup;
mutable QMutex _ItemsMutex;
QVector3D _cameraReleativePosition;
QQuaternion _cameraRatation;
@ -409,6 +425,8 @@ private:
int _worldStatus = 0;
QHash<QString, std::function<IWorldItem*()>> _registeredTypes;
int _targetFps = 60;
// engine
friend class Engine;

View File

@ -0,0 +1,61 @@
#include "movableobject.h"
#include <QDebug>
MovableObject::MovableObject(const QString &name,
const QString &viewTempalte,
QObject *ptr):
IWorldItem(name, viewTempalte, ptr) {
}
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;
}
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

@ -0,0 +1,78 @@
#ifndef MOVABLEOBJECT_H
#define MOVABLEOBJECT_H
#include "iworlditem.h"
/**
* @brief The MovableObject class contains functions for moving object on the world.
* All moving separate to next properties:
*
* * **Movable vector** This property sets direction of move
* * **Movable vector force** This is force of the movable vector.
* * **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
{
Q_OBJECT
public:
MovableObject(const QString& name,
const QString& viewTempalte = DEFAULT_VIEW_TEMPLATE,
QObject *ptr = nullptr);
/**
* @brief render This impplementation of the render method add simulation of the physics in the vacuum space.
* @param tbfMsec This is time betwin frames argument.
*/
void render(unsigned int tbfMsec) override;
/**
* @brief movableVector This method return current mvable vector.
* The movable vector it is second point of line betwin object center and movableVector point.
* The movableVector base on own releative asix system wher the object center is vector {0 0 0}
* @note So movableVector are 3d angle of the moving of this object.
* @return movable vector of object
*/
const QVector3D &movableVector() const;
/**
* @brief setMovableVector This method sets new value of the mvable vector.
* @param newMovableVector - this is a new value ofthe movable vector
*/
void setMovableVector(const QVector3D &newMovableVector);
/**
* @brief angularVelocity This method return current angular veloscity.
* @return angular velosity
* @note This property contains speed on angle per second (a/s)
*/
float angularVelocity() const;
/**
* @brief setAngularVelocity This method sets new value of the angular velacity in angele per second
* @param newAngularVelocity This is new value of the angular velacity
*/
void setAngularVelocity(float newAngularVelocity);
/**
* @brief breakingForce This method return current value of the breaking force.
* @return urrent value of the breaking force
*/
float breakingForce() const;
/**
* @brief setBreakingForce This method sets new value of the breaking force.
* @param newBreakingForce This is new value of the breaking force
*/
void setBreakingForce(float newBreakingForce);
private:
QVector3D _movableVector;
QVector3D _currentMovableVector;
float _angularVelocity = 0;
float _breakingForce = 0;
};
#endif // MOVABLEOBJECT_H

View File

@ -103,6 +103,8 @@ Item {
return;
item1.model.newGame(view.selectedLvl)
selectLvl.close();
}
}

View File

@ -33,7 +33,9 @@ View3D {
PointLight {
position: camera.position
brightness: 1500
rotation: camera.rotation
brightness: 250
}
environment: SceneEnvironment {
@ -64,6 +66,7 @@ View3D {
console.log("create object fail")
return;
}
const objModel = model.getGameObject(cppObjId);
if (!objModel) {

View File

@ -10,13 +10,20 @@
#include <QQmlComponent>
#include <Crawl/guiobject.h>
#include "Crawl/iworld.h"
#include <QThread>
#include <quasarapp.h>
#include "Crawl/icontrol.h"
#include "QDateTime"
#include "QtConcurrent"
Engine::Engine(QObject *parent): QObject(parent) {
}
Engine::~Engine() {
stopRenderLoop();
}
QObject *Engine::scane() {
return _scane;
}
@ -54,6 +61,7 @@ void Engine::setWorld(IWorld *world) {
emit worldChanged();
startRenderLoop();
}
QString Engine::hdr() const {
@ -116,6 +124,23 @@ QObject *Engine::getGameObject(int id) const {
return _currentWorld->getItem(id);
}
void Engine::startRenderLoop() {
if (isRendering())
return;
_renderLoop = true;
_renderLoopFuture = QtConcurrent::run(this, &Engine::renderLoop);
}
void Engine::stopRenderLoop() {
_renderLoop = false;
_renderLoopFuture.waitForFinished();
}
bool Engine::isRendering() const {
return _renderLoopFuture.isRunning();
}
void Engine::setPrepareLvlProgress(int newPrepareLvlProgress) {
if (_prepareLvlProgress == newPrepareLvlProgress) {
return;
@ -123,3 +148,24 @@ void Engine::setPrepareLvlProgress(int newPrepareLvlProgress) {
_prepareLvlProgress = newPrepareLvlProgress;
emit prepareLvlProgressChanged();
}
void Engine::renderLoop() {
if (!_currentWorld)
return;
while (_renderLoop) {
quint64 currentTime = QDateTime::currentMSecsSinceEpoch();
if (!_oldTimeRender) {
_oldTimeRender = currentTime;
continue;
}
_currentWorld->render(currentTime - _oldTimeRender);
_oldTimeRender = currentTime;
}
}

View File

@ -8,6 +8,7 @@
#ifndef ENGINE_H
#define ENGINE_H
#include <QFuture>
#include <QObject>
#include <QQmlEngine>
#include <Crawl/diff.h>
@ -30,6 +31,7 @@ class Engine : public QObject {
public:
Engine(QObject * parent = nullptr);
~Engine();
/**
* @brief scane This method return main scane of the game.
@ -111,6 +113,21 @@ public:
*/
Q_INVOKABLE QObject *getGameObject(int id) const;
/**
* @brief startRenderLoop This method start render loop in engine.
*/
void startRenderLoop();
/**
* @brief stopRenderLoop This method stop render loop in engine.
*/
void stopRenderLoop();
/**
* @brief isRendering This method erturn true if the render loop is working else false.
* @return true if the render loop is working else false.
*/
bool isRendering() const;
signals:
void scaneChanged();
@ -123,12 +140,19 @@ signals:
private:
void setPrepareLvlProgress(int newPrepareLvlProgress);
void renderLoop();
QObject *_scane = nullptr;
QQmlEngine *_engine = nullptr;
IWorld* _currentWorld = nullptr;
QObject *_menu = nullptr;
int _prepareLvlProgress;
quint64 _oldTimeRender = 0;
QFuture<void> _renderLoopFuture;
bool _renderLoop = false;
};
#endif // ENGINE_H

@ -1 +1 @@
Subproject commit 3f8198a0767f860fa17fed86f6772f09462077fa
Subproject commit 46878c18cae14eed67a2b105dc993ff2d670a3bc