Quark Physics  1.0
2D Rigid and Soft Body Physics Engine
qbody.h
1 
2 /************************************************************************************
3  * MIT License
4  *
5  * Copyright (c) 2023 Eray Zesen
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy
8  * of this software and associated documentation files (the "Software"), to deal
9  * in the Software without restriction, including without limitation the rights
10  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11  * copies of the Software, and to permit persons to whom the Software is
12  * furnished to do so, subject to the following conditions:
13  * The above copyright notice and this permission notice shall be included in all
14  * copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  *
24  * https://github.com/erayzesen/QuarkPhysics
25  *
26 **************************************************************************************/
27 
28 #ifndef QBODY_H
29 #define QBODY_H
30 
31 #include "qvector.h"
32 #include "qaabb.h"
33 #include <cmath>
34 #include <vector>
35 #include "qmesh.h"
36 #include <functional>
37 #include "qmath_utils.h"
38 
39 
40 class QWorld;
43 class QBody{
44  float inertia=0.0f;
45  float circumference=0.0f;
46 
47 public:
51  enum Modes{
52  DYNAMIC,
53  STATIC
54  };
55 
56  enum BodyTypes{
57  RIGID,
58  AREA,
59  SOFT
60  };
65  MASS_SPRING,
66  RIGID_BODY
67  };
68 
69  struct BodyPairHash {
70  size_t operator()(const std::pair<QBody*, QBody*>& p) const {
71  std::size_t h1 = std::hash<QBody*>{}(p.first);
72  std::size_t h2 = std::hash<QBody*>{}(p.second);
73  return h1 ^ (h2 + 0x9e3779b9 + (h1 << 6) + (h1 >> 2));
74  }
75  };
76 
77  struct BodyPairEqual {
78  bool operator()(const std::pair<QBody*, QBody*>& p1, const std::pair<QBody*, QBody*>& p2) const {
79  return (p1.first == p2.first && p1.second == p2.second) ||
80  (p1.first == p2.second && p1.second == p2.first);
81  }
82  };
83 
84 protected:
85 
86  //General Properties
87 
88  QWorld *world;
89  QVector position=QVector(0,0);
90  QVector prevPosition=QVector::Zero();
91  float rotation=0.0f;
92  float prevRotation=0.0f;
93  QAABB aabb;
94  Modes mode=QBody::Modes::DYNAMIC;
95  bool inertiaNeedsUpdate=true;
96  bool circumferenceNeedsUpdate=true;
97  bool enableBodySpecificTimeScale=false;
98  float bodySpecificTimeScale=1.0f;
99  BodyTypes bodyType=BodyTypes::RIGID;
100  bool enabled=true;
101  float velocityLimit=0.0f;
102  bool enableIntegratedVelocities=true;
103  bool enableCustomGravity=false;
104  QVector customGravity=QVector::Zero();
105 
106  //Material Properties;
107 
108  float friction=0.2f;
109  float staticFriction=0.5f;
110  float airFriction=0.01f;
111  float mass=1.0f;
112  float restitution=0.0f;
113 
114  //Collision Features
115  int layersBit=1;
116  int collidableLayersBit=1;
117  bool isKinematic=false;
118  bool allowKinematicCollisions=false;
119 
120  //Sleeping Features
121  bool isSleeping=false;
122 
123  int sleepTick=120;
124  int fixedVelocityTick=0;
125  int fixedAngularTick=0;
126  bool canSleep=true;
127 
128 
129 
130 
131  void UpdateAABB();
132  void UpdateMeshTransforms();
134  virtual void Update();
136  virtual void PostUpdate(){};
137  virtual bool CanGiveCollisionResponseTo(QBody *otherBody);
138 
139  public:
140  QBody();
141  virtual ~QBody();
142 
143  //Collision Info
154  float penetration;
156  };
157 
158  //Default Events
160  virtual void OnPreStep(){};
162  virtual void OnStep(){};
167  virtual bool OnCollision(CollisionInfo){ return true;}
168 
169  //Custom Event Listeners
173  std::function<void(QBody *body)> PreStepEventListener;
177  std::function<void(QBody *body)> StepEventListener;
182  std::function<bool(QBody *body,CollisionInfo)> CollisionEventListener;
183 
184 
185 
186 
187  //General Get Methods
188 
190  BodyTypes GetBodyType(){
191  return bodyType;
192  }
195  return world;
196  }
199  return position;
200  }
203  return prevPosition;
204  }
206  float GetRotation(){
207  return rotation;
208  }
211  return GetRotation()/(M_PI/180);
212  }
215  return prevRotation;
216  }
218  QAABB GetAABB()const{
219  return aabb;
220  }
221 
222 
223 
226  float res=0.0f;
227  for(auto mesh:_meshes){
228  res+=mesh->GetInitialArea();
229  }
230  return res;
231  }
234  float res=0.0f;
235  for(auto mesh:_meshes){
236  res+=mesh->GetInitialPolygonsArea();
237  }
238  return res;
239  }
241  float GetTotalArea(){
242  float res=0.0f;
243  for(auto mesh:_meshes){
244  res+=mesh->GetArea();
245  }
246  return res;
247  }
250  float res=0.0f;
251  for(auto mesh:_meshes){
252  res+=mesh->GetPolygonsArea();
253  }
254  return res;
255  }
258  return mode;
259  }
261  float GetInertia(){
262  if(inertiaNeedsUpdate==true){
263  inertia=GetTotalInitialArea()*2.0f*mass;
264  inertia=inertia<500.0f ? 500.0f:inertia;
265  inertiaNeedsUpdate=false;
266  }
267  return inertia;
268  }
271  return layersBit;
272  }
275  return collidableLayersBit;
276  }
281  if( (layersBit & this->collidableLayersBit)==0 )
282  return false;
283  return true;
284  }
288  bool GetOverlapWithLayersBit(int layersBit){
289  if( (layersBit & this->layersBit)==0 ){
290  return false;
291  }
292  return true;
293  }
296  return isSleeping;
297  }
299  bool GetCanSleep(){
300  return canSleep;
301  }
304  return simulationModel;
305  }
306 
308  float GetFriction(){
309  return friction;
310  }
313  return staticFriction;
314  }
315 
317  float GetAirFriction(){
318  return airFriction;
319  }
320 
322  virtual float GetMass(){
323  return mass;
324  }
326  float GetRestitution(){
327  return restitution;
328  }
329 
332  if(circumferenceNeedsUpdate==true){
333  circumference=0.0f;
334  for(auto mesh:_meshes){
335  circumference+=mesh->GetCircumference();
336  }
337  circumferenceNeedsUpdate=false;
338  }
339 
340  return circumference;
341  }
342 
345  return enableBodySpecificTimeScale;
346  }
350  return bodySpecificTimeScale;
351  }
352 
354  bool GetEnabled(){
355  return enabled;
356  }
360  float GetVelocityLimit();
361 
366 
371 
372  /*
373  Returns the gravity vector specifically defined for the body.
374  */
375  QVector GetCustomGravity();
376 
377 
378 
379 
380 
381  //General Set Methods
387  QBody * SetPosition(QVector value, bool withPreviousPosition=true){
388  position=value;
389  if (withPreviousPosition) {
390  prevPosition=position;
391  }
392  WakeUp();
393 
394  UpdateMeshTransforms();
395  UpdateAABB();
396  return this;
397  }
398 
404  QBody *AddPosition(QVector value, bool withPreviousPosition=true){
405  return SetPosition(GetPosition()+value,withPreviousPosition);
406  }
411  virtual QBody* ApplyForce(QVector value){return this;};
417  prevPosition=value;
418  return this;
419  }
426  }
432  QBody * SetRotation(float angleRadian, bool withPreviousRotation=true){
433  rotation=angleRadian;
434  if(withPreviousRotation)
435  prevRotation=angleRadian;
436  WakeUp();
437  UpdateMeshTransforms();
438  return this;
439  }
445  QBody * SetRotationDegree(float degree, bool withPreviousRotation=true){
446  return SetRotation( degree*(M_PI/180.0f),withPreviousRotation );
447  }
448 
454  QBody *AddRotation(float angleRadian, bool withPreviousRotation=true){
455  return SetRotation(GetRotation()+angleRadian,withPreviousRotation);
456  }
461  QBody *SetPreviousRotation(float angleRadian){
462  prevRotation=angleRadian;
463  return this;
464  }
469  QBody *AddPreviousRotation(float angleRadian){
470  return SetPreviousRotation(GetPreviousRotation()+angleRadian);
471  }
472 
473 
474 
475 
480  QBody *SetLayersBit(int value){
481  layersBit=value;
482  return this;
483  }
489  collidableLayersBit=value;
490  return this;
491  }
496  QBody *SetCanSleep(bool value){
497  canSleep=value;
498  return this;
499  }
505  mode=bodyMode;
506  return this;
507  }
513  {
514  simulationModel=model;
515  for(auto mesh:_meshes){
516  mesh->UpdateCollisionBehavior();
517  }
518  UpdateMeshTransforms();
519 
520  return this;
521  }
526  QBody *SetFriction(float value){
527  friction=value;
528  return this;
529  }
534  QBody *SetStaticFriction(float value){
535  staticFriction=value;
536  return this;
537  }
538 
543  QBody *SetAirFriction(float value){
544  airFriction=value;
545  return this;
546  }
547 
552  QBody *SetMass(float value){
553  mass=value;
554  inertiaNeedsUpdate=true;
555  return this;
556  }
561  QBody *SetRestitution(float value){
562  restitution=value;
563  return this;
564  }
565 
571  enableBodySpecificTimeScale=value;
572  return this;
573  }
574 
580  bodySpecificTimeScale=value;
581  return this;
582  }
587  QBody *SetEnabled(bool value){
588  enabled=value;
589  return this;
590  }
591 
598 
604  QBody *SetCustomGravityEnabled(bool value);
605 
612 
613 
614  //Mesh Methods
619  QBody * AddMesh(QMesh *mesh);
624  QBody * RemoveMeshAt(int index);
628  QMesh * GetMeshAt(int index);
630  int GetMeshCount();
632  vector<QMesh*> *GetMeshes();
633 
638  QBody * AddMeshesFromFile(string filePath);
639 
640 
641  //Methods About the Sleeping Feature
647  isSleeping = false;
648  return this;
649  }
650 
655  QBody *SetVelocityLimit(float value);
656 
660  bool manualDeletion=false;
661 
662 
663  friend class QMesh;
664  friend class QWorld;
665  friend class QManifold;
666  friend class QParticle;
667  friend class QJoint;
668  friend class QBroadPhase;
669  friend class QAreaBody;
670 
671  protected:
672  vector<QMesh*> _meshes=vector<QMesh*>();
673  SimulationModels simulationModel=SimulationModels::RIGID_BODY;
674  static QVector ComputeFriction(QBody *bodyA, QBody *bodyB, QVector &normal, float penetration, QVector &relativeVelocity);
675  static bool CanCollide(QBody *bodyA,QBody *bodyB,bool checkBodiesAreEnabled=true);
676  //For Gravity-Free Feature of QArea Bodies
677  bool ignoreGravity=false;
678 
679 
680 
681 };
682 
683 #endif // QBODY_H
Definition: qaabb.h:38
QAreaBody objects are objects that don't respond to collisions or receive any response from them,...
Definition: qareabody.h:38
QBody objects are the base class for all types of bodies. Any class derived from QBody shares these m...
Definition: qbody.h:43
QVector GetPreviousPosition()
Definition: qbody.h:202
virtual void OnPreStep()
Definition: qbody.h:160
QBody * SetBodySpecificTimeScaleEnabled(bool value)
Definition: qbody.h:570
QBody * AddPreviousRotation(float angleRadian)
Definition: qbody.h:469
float GetTotalPolygonsInitialArea()
Definition: qbody.h:233
QBody * SetVelocityLimit(float value)
Definition: qbody.cpp:75
QBody * SetStaticFriction(float value)
Definition: qbody.h:534
QBody * SetIntegratedVelocitiesEnabled(bool value)
Definition: qbody.cpp:137
float GetFriction()
Definition: qbody.h:308
QBody * RemoveMeshAt(int index)
Definition: qbody.cpp:173
virtual void OnStep()
Definition: qbody.h:162
QBody * AddMesh(QMesh *mesh)
Definition: qbody.cpp:154
bool manualDeletion
Definition: qbody.h:660
float GetAirFriction()
Definition: qbody.h:317
QBody * SetCollidableLayersBit(int value)
Definition: qbody.h:488
QBody * WakeUp()
Definition: qbody.h:646
virtual bool OnCollision(CollisionInfo)
Definition: qbody.h:167
QBody * AddRotation(float angleRadian, bool withPreviousRotation=true)
Definition: qbody.h:454
SimulationModels GetSimulationModel()
Definition: qbody.h:303
QBody * SetMass(float value)
Definition: qbody.h:552
QBody * SetLayersBit(int value)
Definition: qbody.h:480
int GetCollidableLayersBit()
Definition: qbody.h:274
QBody * SetCustomGravityEnabled(bool value)
Definition: qbody.cpp:142
QBody * SetRestitution(float value)
Definition: qbody.h:561
QAABB GetAABB() const
Definition: qbody.h:218
QBody * AddPosition(QVector value, bool withPreviousPosition=true)
Definition: qbody.h:404
float GetStaticFriction()
Definition: qbody.h:312
bool GetCustomGravityEnabled()
Definition: qbody.cpp:63
float GetTotalArea()
Definition: qbody.h:241
QWorld * GetWorld()
Definition: qbody.h:194
QBody * SetMode(QBody::Modes bodyMode)
Definition: qbody.h:504
virtual void Update()
Definition: qbody.cpp:253
float GetPreviousRotation()
Definition: qbody.h:214
float GetCircumference()
Definition: qbody.h:331
int GetMeshCount()
Definition: qbody.cpp:191
QBody * SetFriction(float value)
Definition: qbody.h:526
float GetRotation()
Definition: qbody.h:206
bool GetBodySpecificTimeScaleEnabled()
Definition: qbody.h:344
QBody * SetBodySpecificTimeScale(float value)
Definition: qbody.h:579
virtual QBody * ApplyForce(QVector value)
Definition: qbody.h:411
virtual float GetMass()
Definition: qbody.h:322
QBody * SetCustomGravity(QVector value)
Definition: qbody.cpp:148
bool GetIsSleeping()
Definition: qbody.h:295
bool GetEnabled()
Definition: qbody.h:354
SimulationModels
Definition: qbody.h:64
QBody * SetRotationDegree(float degree, bool withPreviousRotation=true)
Definition: qbody.h:445
float GetVelocityLimit()
Definition: qbody.cpp:55
float GetInertia()
Definition: qbody.h:261
std::function< void(QBody *body)> PreStepEventListener
Definition: qbody.h:173
QVector GetPosition()
Definition: qbody.h:198
virtual void PostUpdate()
Definition: qbody.h:136
float GetTotalInitialArea()
Definition: qbody.h:225
QBody * AddMeshesFromFile(string filePath)
Definition: qbody.cpp:164
bool GetOverlapWithCollidableLayersBit(int layersBit)
Definition: qbody.h:280
BodyTypes GetBodyType()
Definition: qbody.h:190
bool GetIntegratedVelocitiesEnabled()
Definition: qbody.cpp:59
QBody * SetPreviousRotation(float angleRadian)
Definition: qbody.h:461
float GetRestitution()
Definition: qbody.h:326
QBody * AddPreviousPosition(QVector value)
Definition: qbody.h:424
std::function< bool(QBody *body, CollisionInfo)> CollisionEventListener
Definition: qbody.h:182
float GetRotationDegree()
Definition: qbody.h:210
QMesh * GetMeshAt(int index)
Definition: qbody.cpp:184
QBody * SetAirFriction(float value)
Definition: qbody.h:543
QBody * SetSimulationModel(SimulationModels model)
Definition: qbody.h:512
Modes GetMode()
Definition: qbody.h:257
float GetBodySpesificTimeScale()
Definition: qbody.h:349
QBody * SetEnabled(bool value)
Definition: qbody.h:587
std::function< void(QBody *body)> StepEventListener
Definition: qbody.h:177
float GetTotalPolygonsArea()
Definition: qbody.h:249
Modes
Definition: qbody.h:51
vector< QMesh * > * GetMeshes()
Definition: qbody.cpp:187
QBody * SetPosition(QVector value, bool withPreviousPosition=true)
Definition: qbody.h:387
QBody * SetPreviousPosition(QVector value)
Definition: qbody.h:416
QBody * SetRotation(float angleRadian, bool withPreviousRotation=true)
Definition: qbody.h:432
int GetLayersBit()
Definition: qbody.h:270
bool GetOverlapWithLayersBit(int layersBit)
Definition: qbody.h:288
QBody * SetCanSleep(bool value)
Definition: qbody.h:496
bool GetCanSleep()
Definition: qbody.h:299
Definition: qbroadphase.h:44
QJoint objects serves to apply various distance constraints between rigid bodies. Additionally,...
Definition: qjoint.h:37
QManifold retrieves collision data from collision tests between two QBody objects using QCollision me...
Definition: qmanifold.h:36
QParticle objects form the network structures of QMesh objects defined for all body object types....
Definition: qparticle.h:40
A QWorld object is required to create a physics simulation. The QWorld class manages the entire physi...
Definition: qworld.h:51
Definition: qbody.h:77
Definition: qbody.h:69
CollisionInfo structure contains collision information of a body object. This information is sent to ...
Definition: qbody.h:146
QVector position
Definition: qbody.h:148
QBody * body
Definition: qbody.h:150
QVector normal
Definition: qbody.h:152
float penetration
Definition: qbody.h:154
Every QBody object requires meshes. In other traditional physics engines, the term 'shape' is used in...
Definition: qmesh.h:49
Definition: qvector.h:44