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 public:
50  enum Modes{
51  DYNAMIC,
52  STATIC
53  };
54 
55  enum BodyTypes{
56  RIGID,
57  AREA,
58  SOFT
59  };
64  MASS_SPRING,
65  RIGID_BODY
66  };
67 
68  struct BodyPairHash {
69  size_t operator()(const std::pair<QBody*, QBody*>& p) const {
70  std::size_t h1 = std::hash<QBody*>{}(p.first);
71  std::size_t h2 = std::hash<QBody*>{}(p.second);
72  return h1 ^ (h2 + 0x9e3779b9 + (h1 << 6) + (h1 >> 2));
73  }
74  };
75 
76  struct BodyPairEqual {
77  bool operator()(const std::pair<QBody*, QBody*>& p1, const std::pair<QBody*, QBody*>& p2) const {
78  return (p1.first == p2.first && p1.second == p2.second) ||
79  (p1.first == p2.second && p1.second == p2.first);
80  }
81  };
82 
83 protected:
84 
85  //General Properties
86 
87  QWorld *world;
88  QVector position=QVector(0,0);
89  QVector prevPosition=QVector::Zero();
90  float rotation=0.0f;
91  float prevRotation=0.0f;
92  QAABB aabb;
93  Modes mode=QBody::Modes::DYNAMIC;
94  bool inertiaNeedsUpdate=true;
95  bool circumferenceNeedsUpdate=true;
96  bool enableBodySpecificTimeScale=false;
97  float bodySpecificTimeScale=1.0f;
98  BodyTypes bodyType=BodyTypes::RIGID;
99  bool enabled=true;
100  float velocityLimit=0.0f;
101  bool enableIntegratedVelocities=true;
102 
103  //Material Properties;
104 
105  float friction=0.2f;
106  float staticFriction=0.5f;
107  float airFriction=0.01f;
108  float mass=1.0f;
109  float restitution=0.0f;
110 
111  //Collision Features
112  int layersBit=1;
113  int collidableLayersBit=1;
114  bool isKinematic=false;
115  bool allowKinematicCollisions=false;
116 
117  //Sleeping Features
118  bool isSleeping=false;
119 
120  int sleepTick=120;
121  int fixedVelocityTick=0;
122  int fixedAngularTick=0;
123  bool canSleep=true;
124 
125 
126  void UpdateAABB();
127  void UpdateMeshTransforms();
129  virtual void Update(){};
131  virtual void PostUpdate(){};
132  virtual bool CanGiveCollisionResponseTo(QBody *otherBody);
133 
134  public:
135  QBody();
136  virtual ~QBody();
137 
138  //Collision Info
149  float penetration;
151  };
152 
153  //Default Events
155  virtual void OnPreStep(){};
157  virtual void OnStep(){};
162  virtual bool OnCollision(CollisionInfo){ return true;}
163 
164  //Custom Event Listeners
168  std::function<void(QBody *body)> PreStepEventListener;
172  std::function<void(QBody *body)> StepEventListener;
177  std::function<bool(QBody *body,CollisionInfo)> CollisionEventListener;
178 
179 
180 
181 
182  //General Get Methods
183 
185  BodyTypes GetBodyType(){
186  return bodyType;
187  }
190  return world;
191  }
194  return position;
195  }
198  return prevPosition;
199  }
201  float GetRotation(){
202  return rotation;
203  }
206  return GetRotation()/(M_PI/180);
207  }
210  return prevRotation;
211  }
213  QAABB GetAABB()const{
214  return aabb;
215  }
216 
219  float res=0.0f;
220  for(auto mesh:_meshes){
221  res+=mesh->GetInitialArea();
222  }
223  return res;
224  }
227  float res=0.0f;
228  for(auto mesh:_meshes){
229  res+=mesh->GetInitialPolygonsArea();
230  }
231  return res;
232  }
234  float GetTotalArea(){
235  float res=0.0f;
236  for(auto mesh:_meshes){
237  res+=mesh->GetArea();
238  }
239  return res;
240  }
243  float res=0.0f;
244  for(auto mesh:_meshes){
245  res+=mesh->GetPolygonsArea();
246  }
247  return res;
248  }
251  return mode;
252  }
254  float GetInertia(){
255  if(inertiaNeedsUpdate==true){
256  inertia=GetTotalInitialArea()*2.0f*mass;
257  inertia=inertia<500.0f ? 500.0f:inertia;
258  inertiaNeedsUpdate=false;
259  }
260  return inertia;
261  }
264  return layersBit;
265  }
268  return collidableLayersBit;
269  }
274  if( (layersBit & this->collidableLayersBit)==0 )
275  return false;
276  return true;
277  }
281  bool GetOverlapWithLayersBit(int layersBit){
282  if( (layersBit & this->layersBit)==0 ){
283  return false;
284  }
285  return true;
286  }
289  return isSleeping;
290  }
292  bool GetCanSleep(){
293  return canSleep;
294  }
297  return simulationModel;
298  }
299 
301  float GetFriction(){
302  return friction;
303  }
306  return staticFriction;
307  }
308 
310  float GetAirFriction(){
311  return airFriction;
312  }
313 
315  virtual float GetMass(){
316  return mass;
317  }
319  float GetRestitution(){
320  return restitution;
321  }
322 
325  if(circumferenceNeedsUpdate==true){
326  circumference=0.0f;
327  for(auto mesh:_meshes){
328  circumference+=mesh->GetCircumference();
329  }
330  circumferenceNeedsUpdate=false;
331  }
332 
333  return circumference;
334  }
335 
338  return enableBodySpecificTimeScale;
339  }
343  return bodySpecificTimeScale;
344  }
345 
347  bool GetEnabled(){
348  return enabled;
349  }
353  float GetVelocityLimit();
354 
359 
360 
361 
362  //General Set Methods
368  QBody * SetPosition(QVector value, bool withPreviousPosition=true){
369  position=value;
370  if (withPreviousPosition) {
371  prevPosition=position;
372  }
373  WakeUp();
374 
375  UpdateMeshTransforms();
376  UpdateAABB();
377  return this;
378  }
379 
385  QBody *AddPosition(QVector value, bool withPreviousPosition=true){
386  return SetPosition(GetPosition()+value,withPreviousPosition);
387  }
393  prevPosition=value;
394  return this;
395  }
402  }
408  QBody * SetRotation(float angleRadian, bool withPreviousRotation=true){
409  rotation=angleRadian;
410  if(withPreviousRotation)
411  prevRotation=angleRadian;
412  WakeUp();
413  UpdateMeshTransforms();
414  return this;
415  }
421  QBody * SetRotationDegree(float degree, bool withPreviousRotation=true){
422  return SetRotation( degree*(M_PI/180.0f),withPreviousRotation );
423  }
424 
430  QBody *AddRotation(float angleRadian, bool withPreviousRotation=true){
431  return SetRotation(GetRotation()+angleRadian,withPreviousRotation);
432  }
437  QBody *SetPreviousRotation(float angleRadian){
438  prevRotation=angleRadian;
439  return this;
440  }
445  QBody *AddPreviousRotation(float angleRadian){
446  return SetPreviousRotation(GetPreviousRotation()+angleRadian);
447  }
448 
449 
450 
451 
452 
457  QBody *SetLayersBit(int value){
458  layersBit=value;
459  return this;
460  }
466  collidableLayersBit=value;
467  return this;
468  }
473  QBody *SetCanSleep(bool value){
474  canSleep=value;
475  return this;
476  }
482  mode=bodyMode;
483  return this;
484  }
490  {
491  simulationModel=model;
492  for(auto mesh:_meshes){
493  mesh->UpdateCollisionBehavior();
494  }
495  UpdateMeshTransforms();
496 
497  return this;
498  }
503  QBody *SetFriction(float value){
504  friction=value;
505  return this;
506  }
511  QBody *SetStaticFriction(float value){
512  staticFriction=value;
513  return this;
514  }
515 
520  QBody *SetAirFriction(float value){
521  airFriction=value;
522  return this;
523  }
524 
529  QBody *SetMass(float value){
530  mass=value;
531  inertiaNeedsUpdate=true;
532  return this;
533  }
538  QBody *SetRestitution(float value){
539  restitution=value;
540  return this;
541  }
542 
548  enableBodySpecificTimeScale=value;
549  return this;
550  }
551 
557  bodySpecificTimeScale=value;
558  return this;
559  }
564  QBody *SetEnabled(bool value){
565  enabled=true;
566  return this;
567  }
568 
573 
574 
575  //Mesh Methods
580  QBody * AddMesh(QMesh *mesh);
585  QBody * RemoveMeshAt(int index);
589  QMesh * GetMeshAt(int index);
591  int GetMeshCount();
593  vector<QMesh*> *GetMeshes();
594 
599  QBody * AddMeshesFromFile(string filePath);
600 
601 
602  //Methods About the Sleeping Feature
608  isSleeping = false;
609  return this;
610  }
611 
616  QBody *SetVelocityLimit(float value);
617 
618 
619  friend class QMesh;
620  friend class QWorld;
621  friend class QManifold;
622  friend class QParticle;
623  friend class QJoint;
624  friend class QBroadPhase;
625 
626  protected:
627  vector<QMesh*> _meshes=vector<QMesh*>();
628  SimulationModels simulationModel=SimulationModels::RIGID_BODY;
629  static QVector ComputeFriction(QBody *bodyA, QBody *bodyB, QVector &normal, float penetration, QVector &relativeVelocity);
630  static bool CanCollide(QBody *bodyA,QBody *bodyB,bool checkBodiesAreEnabled=true);
631 
632 
633 };
634 
635 #endif // QBODY_H
Definition: qaabb.h:34
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:197
virtual void OnPreStep()
Definition: qbody.h:155
QBody * SetBodySpecificTimeScaleEnabled(bool value)
Definition: qbody.h:547
QBody * AddPreviousRotation(float angleRadian)
Definition: qbody.h:445
float GetTotalPolygonsInitialArea()
Definition: qbody.h:226
QBody * SetVelocityLimit(float value)
Definition: qbody.cpp:61
QBody * SetStaticFriction(float value)
Definition: qbody.h:511
QBody * SetIntegratedVelocitiesEnabled(bool value)
Definition: qbody.cpp:123
float GetFriction()
Definition: qbody.h:301
QBody * RemoveMeshAt(int index)
Definition: qbody.cpp:147
virtual void OnStep()
Definition: qbody.h:157
QBody * AddMesh(QMesh *mesh)
Definition: qbody.cpp:128
float GetAirFriction()
Definition: qbody.h:310
QBody * SetCollidableLayersBit(int value)
Definition: qbody.h:465
QBody * WakeUp()
Definition: qbody.h:607
virtual bool OnCollision(CollisionInfo)
Definition: qbody.h:162
QBody * AddRotation(float angleRadian, bool withPreviousRotation=true)
Definition: qbody.h:430
SimulationModels GetSimulationModel()
Definition: qbody.h:296
QBody * SetMass(float value)
Definition: qbody.h:529
QBody * SetLayersBit(int value)
Definition: qbody.h:457
int GetCollidableLayersBit()
Definition: qbody.h:267
QBody * SetRestitution(float value)
Definition: qbody.h:538
QAABB GetAABB() const
Definition: qbody.h:213
QBody * AddPosition(QVector value, bool withPreviousPosition=true)
Definition: qbody.h:385
float GetStaticFriction()
Definition: qbody.h:305
float GetTotalArea()
Definition: qbody.h:234
QWorld * GetWorld()
Definition: qbody.h:189
QBody * SetMode(QBody::Modes bodyMode)
Definition: qbody.h:481
float GetPreviousRotation()
Definition: qbody.h:209
float GetCircumference()
Definition: qbody.h:324
int GetMeshCount()
Definition: qbody.cpp:165
QBody * SetFriction(float value)
Definition: qbody.h:503
float GetRotation()
Definition: qbody.h:201
bool GetBodySpecificTimeScaleEnabled()
Definition: qbody.h:337
QBody * SetBodySpecificTimeScale(float value)
Definition: qbody.h:556
virtual float GetMass()
Definition: qbody.h:315
bool GetIsSleeping()
Definition: qbody.h:288
bool GetEnabled()
Definition: qbody.h:347
SimulationModels
Definition: qbody.h:63
QBody * SetRotationDegree(float degree, bool withPreviousRotation=true)
Definition: qbody.h:421
float GetVelocityLimit()
Definition: qbody.cpp:53
float GetInertia()
Definition: qbody.h:254
std::function< void(QBody *body)> PreStepEventListener
Definition: qbody.h:168
QVector GetPosition()
Definition: qbody.h:193
virtual void PostUpdate()
Definition: qbody.h:131
float GetTotalInitialArea()
Definition: qbody.h:218
QBody * AddMeshesFromFile(string filePath)
Definition: qbody.cpp:138
bool GetOverlapWithCollidableLayersBit(int layersBit)
Definition: qbody.h:273
BodyTypes GetBodyType()
Definition: qbody.h:185
bool GetIntegratedVelocitiesEnabled()
Definition: qbody.cpp:57
QBody * SetPreviousRotation(float angleRadian)
Definition: qbody.h:437
float GetRestitution()
Definition: qbody.h:319
QBody * AddPreviousPosition(QVector value)
Definition: qbody.h:400
std::function< bool(QBody *body, CollisionInfo)> CollisionEventListener
Definition: qbody.h:177
float GetRotationDegree()
Definition: qbody.h:205
QMesh * GetMeshAt(int index)
Definition: qbody.cpp:158
QBody * SetAirFriction(float value)
Definition: qbody.h:520
QBody * SetSimulationModel(SimulationModels model)
Definition: qbody.h:489
Modes GetMode()
Definition: qbody.h:250
float GetBodySpesificTimeScale()
Definition: qbody.h:342
QBody * SetEnabled(bool value)
Definition: qbody.h:564
std::function< void(QBody *body)> StepEventListener
Definition: qbody.h:172
virtual void Update()
Definition: qbody.h:129
float GetTotalPolygonsArea()
Definition: qbody.h:242
Modes
Definition: qbody.h:50
vector< QMesh * > * GetMeshes()
Definition: qbody.cpp:161
QBody * SetPosition(QVector value, bool withPreviousPosition=true)
Definition: qbody.h:368
QBody * SetPreviousPosition(QVector value)
Definition: qbody.h:392
QBody * SetRotation(float angleRadian, bool withPreviousRotation=true)
Definition: qbody.h:408
int GetLayersBit()
Definition: qbody.h:263
bool GetOverlapWithLayersBit(int layersBit)
Definition: qbody.h:281
QBody * SetCanSleep(bool value)
Definition: qbody.h:473
bool GetCanSleep()
Definition: qbody.h:292
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:37
A QWorld object is required to create a physics simulation. The QWorld class manages the entire physi...
Definition: qworld.h:51
Definition: qbody.h:76
Definition: qbody.h:68
CollisionInfo structure contains collision information of a body object. This information is sent to ...
Definition: qbody.h:141
QVector position
Definition: qbody.h:143
QBody * body
Definition: qbody.h:145
QVector normal
Definition: qbody.h:147
float penetration
Definition: qbody.h:149
Every QBody object requires meshes. In other traditional physics engines, the term 'shape' is used in...
Definition: qmesh.h:48
Definition: qvector.h:44