From 16f564edea2e51f5522f42278eae4f34d4f482e1 Mon Sep 17 00:00:00 2001
From: Daniel Chappuis <chappuis.daniel@gmail.com>
Date: Mon, 8 Jul 2019 17:41:10 +0200
Subject: [PATCH] Move Body attributes to BodyComponents

---
 src/body/Body.cpp                 |  84 ++++++++++++++++----
 src/body/Body.h                   | 115 +++------------------------
 src/body/CollisionBody.cpp        |  16 ++--
 src/body/CollisionBody.h          |   3 -
 src/body/RigidBody.cpp            |   9 ++-
 src/body/RigidBody.h              |   6 +-
 src/components/BodyComponents.cpp |  39 +++++++++-
 src/components/BodyComponents.h   | 125 ++++++++++++++++++++++++++++++
 src/components/Components.cpp     |   2 +-
 src/components/Components.h       |   4 +-
 src/engine/CollisionWorld.cpp     |   2 +-
 src/engine/CollisionWorld.h       |   1 +
 src/engine/DynamicsWorld.cpp      |  10 ++-
 13 files changed, 266 insertions(+), 150 deletions(-)

diff --git a/src/body/Body.cpp b/src/body/Body.cpp
index f1f80b0a..f0d362a9 100644
--- a/src/body/Body.cpp
+++ b/src/body/Body.cpp
@@ -25,6 +25,7 @@
 
 // Libraries
 #include "Body.h"
+#include "engine/CollisionWorld.h"
 #include "collision/shapes/CollisionShape.h"
 #include "utils/Logger.h"
 
@@ -35,9 +36,8 @@ using namespace reactphysics3d;
 /**
  * @param id ID of the new body
  */
-Body::Body(Entity entity)
-     : mEntity(entity), mIsAllowedToSleep(true), mIsActive(true),
-       mIsSleeping(false), mSleepTime(0), mUserData(nullptr) {
+Body::Body(Entity entity, CollisionWorld& world)
+     : mEntity(entity), mWorld(world) {
 
 #ifdef IS_LOGGING_ACTIVE
         mLogger = nullptr;
@@ -46,44 +46,54 @@ Body::Body(Entity entity)
 }
 
 // Set whether or not the body is active
+/// An inactive body does not participate in collision detection,
+/// is not simulated and will not be hit in a ray casting query.
+/// A body is active by default. If you set this
+/// value to "false", all the proxy shapes of this body will be
+/// removed from the broad-phase. If you set this value to "true",
+/// all the proxy shapes will be added to the broad-phase. A joint
+/// connected to an inactive body will also be inactive.
 /**
  * @param isActive True if you want to activate the body
  */
 void Body::setIsActive(bool isActive) {
-    mIsActive = isActive;
 
-    setIsSleeping(isActive);
+    setIsSleeping(!isActive);
+
+    mWorld.mBodyComponents.setIsActive(mEntity, isActive);
 
     RP3D_LOG(mLogger, Logger::Level::Information, Logger::Category::Body,
              "Body " + std::to_string(mEntity.id) + ": Set isActive=" +
-             (mIsActive ? "true" : "false"));
+             (isActive ? "true" : "false"));
 }
 
 // Set the variable to know whether or not the body is sleeping
 void Body::setIsSleeping(bool isSleeping) {
 
+    bool isBodySleeping = mWorld.mBodyComponents.getIsSleeping(mEntity);
+
     // If the body is not active, do nothing (it is sleeping)
-    if (!mIsActive) {
-        assert(mIsSleeping);
+    if (!mWorld.mBodyComponents.getIsActive(mEntity)) {
+        assert(isBodySleeping);
         return;
     }
 
     if (isSleeping) {
-        mSleepTime = decimal(0.0);
+        mWorld.mBodyComponents.setSleepTime(mEntity, decimal(0.0));
     }
     else {
-        if (mIsSleeping) {
-            mSleepTime = decimal(0.0);
+        if (isBodySleeping) {
+            mWorld.mBodyComponents.setSleepTime(mEntity, decimal(0.0));
         }
     }
 
-    if (mIsSleeping != isSleeping) {
+    if (isBodySleeping != isSleeping) {
 
-        mIsSleeping = isSleeping;
+        mWorld.mBodyComponents.setIsSleeping(mEntity, isSleeping);
 
         RP3D_LOG(mLogger, Logger::Level::Information, Logger::Category::Body,
              "Body " + std::to_string(mEntity.id) + ": Set isSleeping=" +
-             (mIsSleeping ? "true" : "false"));
+             (isSleeping ? "true" : "false"));
     }
 }
 
@@ -92,12 +102,52 @@ void Body::setIsSleeping(bool isSleeping) {
  * @param isAllowedToSleep True if the body is allowed to sleep
  */
 void Body::setIsAllowedToSleep(bool isAllowedToSleep) {
-    mIsAllowedToSleep = isAllowedToSleep;
 
-    if (!mIsAllowedToSleep) setIsSleeping(false);
+    mWorld.mBodyComponents.setIsAllowedToSleep(mEntity, isAllowedToSleep);
+
+    if (!isAllowedToSleep) setIsSleeping(false);
 
     RP3D_LOG(mLogger, Logger::Level::Information, Logger::Category::Body,
              "Body " + std::to_string(mEntity.id) + ": Set isAllowedToSleep=" +
-             (mIsAllowedToSleep ? "true" : "false"));
+             (isAllowedToSleep ? "true" : "false"));
 }
 
+// Return whether or not the body is allowed to sleep
+/**
+ * @return True if the body is allowed to sleep and false otherwise
+ */
+bool Body::isAllowedToSleep() const {
+    return mWorld.mBodyComponents.getIsAllowedToSleep(mEntity);
+}
+
+// Return whether or not the body is sleeping
+/**
+ * @return True if the body is currently sleeping and false otherwise
+ */
+bool Body::isSleeping() const {
+    return mWorld.mBodyComponents.getIsSleeping(mEntity);
+}
+
+// Return true if the body is active
+/**
+ * @return True if the body currently active and false otherwise
+ */
+bool Body::isActive() const {
+    return mWorld.mBodyComponents.getIsActive(mEntity);
+}
+
+// Return a pointer to the user data attached to this body
+/**
+ * @return A pointer to the user data you have attached to the body
+ */
+void* Body::getUserData() const {
+    return mWorld.mBodyComponents.getUserData(mEntity);
+}
+
+// Attach user data to this body
+/**
+ * @param userData A pointer to the user data you want to attach to the body
+ */
+void Body::setUserData(void* userData) {
+    mWorld.mBodyComponents.setUserData(mEntity, userData);
+}
diff --git a/src/body/Body.h b/src/body/Body.h
index 39093dd6..6edbf3c5 100644
--- a/src/body/Body.h
+++ b/src/body/Body.h
@@ -36,6 +36,7 @@ namespace reactphysics3d {
 
 // Declarations
 class Logger;
+class CollisionWorld;
 
 // TODO : Make this class abstract
 // Class Body
@@ -53,30 +54,8 @@ class Body {
         /// Identifier of the entity in the ECS
         Entity mEntity;
 
-        /// True if the body is allowed to go to sleep for better efficiency
-        bool mIsAllowedToSleep;
-
-        /// True if the body is active.
-        /// An inactive body does not participate in collision detection,
-        /// is not simulated and will not be hit in a ray casting query.
-        /// A body is active by default. If you set this
-        /// value to "false", all the proxy shapes of this body will be
-        /// removed from the broad-phase. If you set this value to "true",
-        /// all the proxy shapes will be added to the broad-phase. A joint
-        /// connected to an inactive body will also be inactive.
-        // TODO : Make sure we correctly use this field with ECS
-        bool mIsActive;
-
-        /// True if the body is sleeping (for sleeping technique)
-        // TODO : DELETE THIS
-        bool mIsSleeping;
-
-        // TODO : Move this into the body components
-        /// Elapsed time since the body velocity was bellow the sleep velocity
-        decimal mSleepTime;
-
-        /// Pointer that can be used to attach user data to the body
-        void* mUserData;
+        /// Reference to the world the body belongs to
+        CollisionWorld& mWorld;
 
 #ifdef IS_LOGGING_ACTIVE
 
@@ -84,12 +63,17 @@ class Body {
         Logger* mLogger;
 #endif
 
+        // -------------------- Methods -------------------- //
+
+        /// Set the variable to know whether or not the body is sleeping
+        virtual void setIsSleeping(bool isSleeping);
+
     public :
 
         // -------------------- Methods -------------------- //
 
         /// Constructor
-        Body(Entity entity);
+        Body(Entity entity, CollisionWorld& world);
 
         /// Deleted copy-constructor
         Body(const Body& body) = delete;
@@ -109,9 +93,6 @@ class Body {
         /// Set whether or not the body is allowed to go to sleep
         void setIsAllowedToSleep(bool isAllowedToSleep);
 
-        /// Set the variable to know whether or not the body is sleeping
-        virtual void setIsSleeping(bool isSleeping);
-
         /// Return whether or not the body is sleeping
         bool isSleeping() const;
 
@@ -133,22 +114,6 @@ class Body {
         void setLogger(Logger* logger);
 #endif
 
-        // TODO : Check if those operators are still used
-
-        /*
-        /// Smaller than operator
-        bool operator<(const Body& body2) const;
-
-        /// Larger than operator
-        bool operator>(const Body& body2) const;
-
-        /// Equal operator
-        bool operator==(const Body& body2) const;
-
-        /// Not equal operator
-        bool operator!=(const Body& body2) const;
-        */
-
         // -------------------- Friendship -------------------- //
 
         friend class DynamicsWorld;
@@ -162,46 +127,6 @@ inline Entity Body::getEntity() const {
     return mEntity;
 }
 
-// Return whether or not the body is allowed to sleep
-/**
- * @return True if the body is allowed to sleep and false otherwise
- */
-inline bool Body::isAllowedToSleep() const {
-    return mIsAllowedToSleep;
-}
-
-// Return whether or not the body is sleeping
-/**
- * @return True if the body is currently sleeping and false otherwise
- */
-inline bool Body::isSleeping() const {
-    return mIsSleeping;
-}
-
-// Return true if the body is active
-/**
- * @return True if the body currently active and false otherwise
- */
-inline bool Body::isActive() const {
-    return mIsActive;
-}
-
-// Return a pointer to the user data attached to this body
-/**
- * @return A pointer to the user data you have attached to the body
- */
-inline void* Body::getUserData() const {
-    return mUserData;
-}
-
-// Attach user data to this body
-/**
- * @param userData A pointer to the user data you want to attach to the body
- */
-inline void Body::setUserData(void* userData) {
-    mUserData = userData;
-}
-
 #ifdef IS_LOGGING_ACTIVE
 
 // Set the logger
@@ -211,28 +136,6 @@ inline void Body::setLogger(Logger* logger) {
 
 #endif
 
-/*
-// Smaller than operator
-inline bool Body::operator<(const Body& body2) const {
-    return (mID < body2.mID);
-} 
-
-// Larger than operator
-inline bool Body::operator>(const Body& body2) const {
-    return (mID > body2.mID);
-} 
-
-// Equal operator
-inline bool Body::operator==(const Body& body2) const {
-    return (mID == body2.mID);
-}
-        
-// Not equal operator
-inline bool Body::operator!=(const Body& body2) const {
-    return (mID != body2.mID);
-}               
-*/
-
 }
 
 #endif
diff --git a/src/body/CollisionBody.cpp b/src/body/CollisionBody.cpp
index 64d4323e..9b99cde1 100644
--- a/src/body/CollisionBody.cpp
+++ b/src/body/CollisionBody.cpp
@@ -40,7 +40,7 @@ using namespace reactphysics3d;
  * @param id ID of the body
  */
 CollisionBody::CollisionBody(CollisionWorld& world, Entity entity)
-              : Body(entity), mType(BodyType::DYNAMIC), mWorld(world) {
+              : Body(entity, world), mType(BodyType::DYNAMIC) {
 
 #ifdef IS_PROFILING_ACTIVE
         mProfiler = nullptr;
@@ -68,8 +68,7 @@ CollisionBody::~CollisionBody() {
  * @return A pointer to the proxy shape that has been created to link the body to
  *         the new collision shape you have added.
  */
-ProxyShape* CollisionBody::addCollisionShape(CollisionShape* collisionShape,
-                                             const Transform& transform) {
+ProxyShape* CollisionBody::addCollisionShape(CollisionShape* collisionShape, const Transform& transform) {
 
     // Create a new entity for the proxy-shape
     Entity proxyShapeEntity = mWorld.mEntityManager.createEntity();
@@ -86,7 +85,8 @@ ProxyShape* CollisionBody::addCollisionShape(CollisionShape* collisionShape,
     ProxyShapeComponents::ProxyShapeComponent proxyShapeComponent(mEntity, proxyShape, -1,
                                                                    AABB(localBoundsMin, localBoundsMax),
                                                                    transform, collisionShape, decimal(1), 0x0001, 0xFFFF);
-    mWorld.mProxyShapesComponents.addComponent(proxyShapeEntity, mIsSleeping, proxyShapeComponent);
+    bool isSleeping = mWorld.mBodyComponents.getIsSleeping(mEntity);
+    mWorld.mProxyShapesComponents.addComponent(proxyShapeEntity, isSleeping, proxyShapeComponent);
 
     mWorld.mBodyComponents.addProxyShapeToBody(mEntity, proxyShapeEntity);
 
@@ -228,7 +228,7 @@ void CollisionBody::updateBroadPhaseState() const {
 void CollisionBody::setIsActive(bool isActive) {
 
     // If the state does not change
-    if (mIsActive == isActive) return;
+    if (mWorld.mBodyComponents.getIsActive(mEntity) == isActive) return;
 
     Body::setIsActive(isActive);
 
@@ -269,7 +269,7 @@ void CollisionBody::setIsActive(bool isActive) {
 
     RP3D_LOG(mLogger, Logger::Level::Information, Logger::Category::Body,
              "Body " + std::to_string(mEntity.id) + ": Set isActive=" +
-             (mIsActive ? "true" : "false"));
+             (isActive ? "true" : "false"));
 }
 
 // Ask the broad-phase to test again the collision shapes of the body for collision
@@ -318,7 +318,7 @@ bool CollisionBody::testPointInside(const Vector3& worldPoint) const {
 bool CollisionBody::raycast(const Ray& ray, RaycastInfo& raycastInfo) {
 
     // If the body is not active, it cannot be hit by rays
-    if (!mIsActive) return false;
+    if (!mWorld.mBodyComponents.getIsActive(mEntity)) return false;
 
     bool isHit = false;
     Ray rayTemp(ray);
@@ -398,7 +398,7 @@ void CollisionBody::setTransform(const Transform& transform) {
 // Set the variable to know whether or not the body is sleeping
 void CollisionBody::setIsSleeping(bool isSleeping) {
 
-    if (mIsSleeping == isSleeping) return;
+    if (mWorld.mBodyComponents.getIsSleeping(mEntity) == isSleeping) return;
 
     Body::setIsSleeping(isSleeping);
 
diff --git a/src/body/CollisionBody.h b/src/body/CollisionBody.h
index 846e593c..a2b802dd 100644
--- a/src/body/CollisionBody.h
+++ b/src/body/CollisionBody.h
@@ -71,9 +71,6 @@ class CollisionBody : public Body {
         /// Type of body (static, kinematic or dynamic)
         BodyType mType;
 
-        /// Reference to the world the body belongs to
-        CollisionWorld& mWorld;
-
 #ifdef IS_PROFILING_ACTIVE
 
 		/// Pointer to the profiler
diff --git a/src/body/RigidBody.cpp b/src/body/RigidBody.cpp
index 39876931..158da8d4 100644
--- a/src/body/RigidBody.cpp
+++ b/src/body/RigidBody.cpp
@@ -162,7 +162,7 @@ void RigidBody::applyForce(const Vector3& force, const Vector3& point) {
     if (mType != BodyType::DYNAMIC) return;
 
     // Awake the body if it was sleeping
-    if (mIsSleeping) {
+    if (mWorld.mBodyComponents.getIsSleeping(mEntity)) {
         setIsSleeping(false);
     }
 
@@ -214,7 +214,7 @@ void RigidBody::applyForceToCenterOfMass(const Vector3& force) {
     if (mType != BodyType::DYNAMIC) return;
 
     // Awake the body if it was sleeping
-    if (mIsSleeping) {
+    if (mWorld.mBodyComponents.getIsSleeping(mEntity)) {
         setIsSleeping(false);
     }
 
@@ -399,7 +399,8 @@ ProxyShape* RigidBody::addCollisionShape(CollisionShape* collisionShape,
     ProxyShapeComponents::ProxyShapeComponent proxyShapeComponent(mEntity, proxyShape, -1,
                                                                    AABB(localBoundsMin, localBoundsMax),
                                                                    transform, collisionShape, mass, 0x0001, 0xFFFF);
-    mWorld.mProxyShapesComponents.addComponent(proxyShapeEntity, mIsSleeping, proxyShapeComponent);
+    bool isSleeping = mWorld.mBodyComponents.getIsSleeping(mEntity);
+    mWorld.mProxyShapesComponents.addComponent(proxyShapeEntity, isSleeping, proxyShapeComponent);
 
     mWorld.mBodyComponents.addProxyShapeToBody(mEntity, proxyShapeEntity);
 
@@ -725,7 +726,7 @@ void RigidBody::applyTorque(const Vector3& torque) {
     if (mType != BodyType::DYNAMIC) return;
 
     // Awake the body if it was sleeping
-    if (mIsSleeping) {
+    if (mWorld.mBodyComponents.getIsSleeping(mEntity)) {
         setIsSleeping(false);
     }
 
diff --git a/src/body/RigidBody.h b/src/body/RigidBody.h
index 2c9222bf..022bea9c 100644
--- a/src/body/RigidBody.h
+++ b/src/body/RigidBody.h
@@ -81,6 +81,9 @@ class RigidBody : public CollisionBody {
         /// Update the world inverse inertia tensor of the body
         void updateInertiaTensorInverseWorld();
 
+        /// Set the variable to know whether or not the body is sleeping
+        virtual void setIsSleeping(bool isSleeping) override;
+
     public :
 
         // -------------------- Methods -------------------- //
@@ -118,9 +121,6 @@ class RigidBody : public CollisionBody {
         /// Set the angular velocity.
         void setAngularVelocity(const Vector3& angularVelocity);
 
-        /// Set the variable to know whether or not the body is sleeping
-        virtual void setIsSleeping(bool isSleeping) override;
-
         /// Set the local inertia tensor of the body (in body coordinates)
         void setInertiaTensorLocal(const Matrix3x3& inertiaTensorLocal);
 
diff --git a/src/components/BodyComponents.cpp b/src/components/BodyComponents.cpp
index 8187492c..bf49cc62 100644
--- a/src/components/BodyComponents.cpp
+++ b/src/components/BodyComponents.cpp
@@ -34,7 +34,9 @@ using namespace reactphysics3d;
 
 // Constructor
 BodyComponents::BodyComponents(MemoryAllocator& allocator)
-                    :Components(allocator, sizeof(Entity) + sizeof(Body*) + sizeof(List<Entity>)) {
+                    :Components(allocator, sizeof(Entity) + sizeof(Body*) + sizeof(List<Entity>) +
+                                sizeof(bool) + sizeof(bool) + sizeof(bool) + sizeof(decimal) +
+                                sizeof(void*)) {
 
     // Allocate memory for the components data
     allocate(INIT_NB_ALLOCATED_COMPONENTS);
@@ -56,6 +58,11 @@ void BodyComponents::allocate(uint32 nbComponentsToAllocate) {
     Entity* newBodiesEntities = static_cast<Entity*>(newBuffer);
     Body** newBodies = reinterpret_cast<Body**>(newBodiesEntities + nbComponentsToAllocate);
     List<Entity>* newProxyShapes = reinterpret_cast<List<Entity>*>(newBodies + nbComponentsToAllocate);
+    bool* newIsAllowedToSleep = reinterpret_cast<bool*>(newProxyShapes + nbComponentsToAllocate);
+    bool* newIsActive = reinterpret_cast<bool*>(newIsAllowedToSleep + nbComponentsToAllocate);
+    bool* newIsSleeping = reinterpret_cast<bool*>(newIsActive + nbComponentsToAllocate);
+    decimal* newSleepTimes = reinterpret_cast<decimal*>(newIsSleeping + nbComponentsToAllocate);
+    void** newUserData = reinterpret_cast<void**>(newIsSleeping + nbComponentsToAllocate);
 
     // If there was already components before
     if (mNbComponents > 0) {
@@ -64,6 +71,11 @@ void BodyComponents::allocate(uint32 nbComponentsToAllocate) {
         memcpy(newBodiesEntities, mBodiesEntities, mNbComponents * sizeof(Entity));
         memcpy(newBodies, mBodies, mNbComponents * sizeof(Body*));
         memcpy(newProxyShapes, mProxyShapes, mNbComponents * sizeof(List<Entity>));
+        memcpy(newIsAllowedToSleep, mIsAllowedToSleep, mNbComponents * sizeof(bool));
+        memcpy(newIsActive, mIsActive, mNbComponents * sizeof(bool));
+        memcpy(newIsSleeping, mIsSleeping, mNbComponents * sizeof(bool));
+        memcpy(newSleepTimes, mSleepTimes, mNbComponents * sizeof(bool));
+        memcpy(newUserData, mUserData, mNbComponents * sizeof(void*));
 
         // Deallocate previous memory
         mMemoryAllocator.release(mBuffer, mNbAllocatedComponents * mComponentDataSize);
@@ -73,6 +85,11 @@ void BodyComponents::allocate(uint32 nbComponentsToAllocate) {
     mBodiesEntities = newBodiesEntities;
     mBodies = newBodies;
     mProxyShapes = newProxyShapes;
+    mIsAllowedToSleep = newIsAllowedToSleep;
+    mIsActive = newIsActive;
+    mIsSleeping = newIsSleeping;
+    mSleepTimes = newSleepTimes;
+    mUserData = newUserData;
     mNbAllocatedComponents = nbComponentsToAllocate;
 }
 
@@ -86,6 +103,11 @@ void BodyComponents::addComponent(Entity bodyEntity, bool isSleeping, const Body
     new (mBodiesEntities + index) Entity(bodyEntity);
     mBodies[index] = component.body;
     new (mProxyShapes + index) List<Entity>(mMemoryAllocator);
+    mIsAllowedToSleep[index] = true;
+    mIsActive[index] = true;
+    mIsSleeping[index] = false;
+    mSleepTimes[index] = decimal(0);
+    mUserData[index] = nullptr;
 
     // Map the entity with the new component lookup index
     mMapEntityToComponentIndex.add(Pair<Entity, uint32>(bodyEntity, index));
@@ -106,6 +128,11 @@ void BodyComponents::moveComponentToIndex(uint32 srcIndex, uint32 destIndex) {
     new (mBodiesEntities + destIndex) Entity(mBodiesEntities[srcIndex]);
     mBodies[destIndex] = mBodies[srcIndex];
     new (mProxyShapes + destIndex) List<Entity>(mProxyShapes[srcIndex]);
+    mIsAllowedToSleep[destIndex] = mIsAllowedToSleep[srcIndex];
+    mIsActive[destIndex] = mIsActive[srcIndex];
+    mIsSleeping[destIndex] = mIsSleeping[srcIndex];
+    mSleepTimes[destIndex] = mSleepTimes[srcIndex];
+    mUserData[destIndex] = mUserData[srcIndex];
 
     // Destroy the source component
     destroyComponent(srcIndex);
@@ -125,6 +152,11 @@ void BodyComponents::swapComponents(uint32 index1, uint32 index2) {
     Entity entity1(mBodiesEntities[index1]);
     Body* body1 = mBodies[index1];
     List<Entity> proxyShapes1(mProxyShapes[index1]);
+    bool isAllowedToSleep1 = mIsAllowedToSleep[index1];
+    bool isActive1 = mIsActive[index1];
+    bool isSleeping1 = mIsSleeping[index1];
+    decimal sleepTime1 = mSleepTimes[index1];
+    void* userData1 = mUserData[index1];
 
     // Destroy component 1
     destroyComponent(index1);
@@ -135,6 +167,10 @@ void BodyComponents::swapComponents(uint32 index1, uint32 index2) {
     new (mBodiesEntities + index2) Entity(entity1);
     new (mProxyShapes + index2) List<Entity>(proxyShapes1);
     mBodies[index2] = body1;
+    mIsAllowedToSleep[index2] = isAllowedToSleep1;
+    mIsActive[index2] = isActive1;
+    mIsSleeping[index2] = isSleeping1;
+    mUserData[index2] = userData1;
 
     // Update the entity to component index mapping
     mMapEntityToComponentIndex.add(Pair<Entity, uint32>(entity1, index2));
@@ -156,4 +192,5 @@ void BodyComponents::destroyComponent(uint32 index) {
     mBodiesEntities[index].~Entity();
     mBodies[index] = nullptr;
     mProxyShapes[index].~List<Entity>();
+    mUserData[index] = nullptr;
 }
diff --git a/src/components/BodyComponents.h b/src/components/BodyComponents.h
index 88edaa57..e84e4f88 100644
--- a/src/components/BodyComponents.h
+++ b/src/components/BodyComponents.h
@@ -60,6 +60,21 @@ class BodyComponents : public Components {
         /// Array with the list of proxy-shapes of each body
         List<Entity>* mProxyShapes;
 
+        /// Array of boolean values to know if the body is allowed to go to sleep
+        bool* mIsAllowedToSleep;
+
+        /// Array of boolean values to know if the body is active.
+        bool* mIsActive;
+
+        /// Array of boolean values to know if the body is sleeping
+        bool* mIsSleeping;
+
+        /// Array with values for elapsed time since the body velocity was bellow the sleep velocity
+        decimal* mSleepTimes;
+
+        /// Array of pointers that can be used to attach user data to the body
+        void** mUserData;
+
         // -------------------- Methods -------------------- //
 
         /// Allocate memory for a given number of components
@@ -109,6 +124,36 @@ class BodyComponents : public Components {
 
         /// Return the list of proxy-shapes of a body
         const List<Entity>& getProxyShapes(Entity bodyEntity) const;
+
+        /// Return true if the body is allowed to sleep
+        bool getIsAllowedToSleep(Entity bodyEntity) const;
+
+        /// Set the value to know if the body is allowed to sleep
+        void setIsAllowedToSleep(Entity bodyEntity, bool isAllowedToSleep) const;
+
+        /// Return true if the body is active
+        bool getIsActive(Entity bodyEntity) const;
+
+        /// Set the value to know if the body is active
+        void setIsActive(Entity bodyEntity, bool isActive) const;
+
+        /// Return true if the body is sleeping
+        bool getIsSleeping(Entity bodyEntity) const;
+
+        /// Set the value to know if the body is sleeping
+        void setIsSleeping(Entity bodyEntity, bool isSleeping) const;
+
+        /// Return the sleep time
+        decimal getSleepTime(Entity bodyEntity) const;
+
+        /// Set the sleep time
+        void setSleepTime(Entity bodyEntity, decimal sleepTime) const;
+
+        /// Return the user data associated with the body
+        void* getUserData(Entity bodyEntity) const;
+
+        /// Set the user data associated with the body
+        void setUserData(Entity bodyEntity, void* userData) const;
 };
 
 // Add a proxy-shape to a body component
@@ -143,6 +188,86 @@ inline const List<Entity>& BodyComponents::getProxyShapes(Entity bodyEntity) con
     return mProxyShapes[mMapEntityToComponentIndex[bodyEntity]];
 }
 
+// Return true if the body is allowed to sleep
+inline bool BodyComponents::getIsAllowedToSleep(Entity bodyEntity) const {
+
+    assert(mMapEntityToComponentIndex.containsKey(bodyEntity));
+
+    return mIsAllowedToSleep[mMapEntityToComponentIndex[bodyEntity]];
+}
+
+// Set the value to know if the body is allowed to sleep
+inline void BodyComponents::setIsAllowedToSleep(Entity bodyEntity, bool isAllowedToSleep) const {
+
+    assert(mMapEntityToComponentIndex.containsKey(bodyEntity));
+
+    mIsAllowedToSleep[mMapEntityToComponentIndex[bodyEntity]] = isAllowedToSleep;
+}
+
+// Return true if the body is active
+inline bool BodyComponents::getIsActive(Entity bodyEntity) const {
+
+    assert(mMapEntityToComponentIndex.containsKey(bodyEntity));
+
+    return mIsActive[mMapEntityToComponentIndex[bodyEntity]];
+}
+
+// Set the value to know if the body is active
+inline void BodyComponents::setIsActive(Entity bodyEntity, bool isActive) const {
+
+    assert(mMapEntityToComponentIndex.containsKey(bodyEntity));
+
+    mIsActive[mMapEntityToComponentIndex[bodyEntity]] = isActive;
+}
+
+// Return true if the body is sleeping
+inline bool BodyComponents::getIsSleeping(Entity bodyEntity) const {
+
+    assert(mMapEntityToComponentIndex.containsKey(bodyEntity));
+
+    return mIsSleeping[mMapEntityToComponentIndex[bodyEntity]];
+}
+
+// Set the value to know if the body is sleeping
+inline void BodyComponents::setIsSleeping(Entity bodyEntity, bool isSleeping) const {
+
+    assert(mMapEntityToComponentIndex.containsKey(bodyEntity));
+
+    mIsSleeping[mMapEntityToComponentIndex[bodyEntity]] = isSleeping;
+}
+
+// Return the sleep time
+inline decimal BodyComponents::getSleepTime(Entity bodyEntity) const {
+
+    assert(mMapEntityToComponentIndex.containsKey(bodyEntity));
+
+    return mSleepTimes[mMapEntityToComponentIndex[bodyEntity]];
+}
+
+// Set the sleep time
+inline void BodyComponents::setSleepTime(Entity bodyEntity, decimal sleepTime) const {
+
+    assert(mMapEntityToComponentIndex.containsKey(bodyEntity));
+
+    mSleepTimes[mMapEntityToComponentIndex[bodyEntity]] = sleepTime;
+}
+
+// Return the user data associated with the body
+inline void* BodyComponents::getUserData(Entity bodyEntity) const {
+
+    assert(mMapEntityToComponentIndex.containsKey(bodyEntity));
+
+    return mUserData[mMapEntityToComponentIndex[bodyEntity]];
+}
+
+// Set the user data associated with the body
+inline void BodyComponents::setUserData(Entity bodyEntity, void* userData) const {
+
+    assert(mMapEntityToComponentIndex.containsKey(bodyEntity));
+
+    mUserData[mMapEntityToComponentIndex[bodyEntity]] = userData;
+}
+
 }
 
 #endif
diff --git a/src/components/Components.cpp b/src/components/Components.cpp
index 87e06e80..ea3e3521 100644
--- a/src/components/Components.cpp
+++ b/src/components/Components.cpp
@@ -150,7 +150,7 @@ void Components::removeComponent(Entity entity) {
     assert(mNbComponents == static_cast<uint32>(mMapEntityToComponentIndex.size()));
 }
 
-// Notify if a given entity is disabled (sleeping or inactive) or not
+// Notify if a given entity is disabled (sleeping) or not
 void Components::setIsEntityDisabled(Entity entity, bool isDisabled) {
 
     const uint32 index = mMapEntityToComponentIndex[entity];
diff --git a/src/components/Components.h b/src/components/Components.h
index 320104a3..a7a04fb8 100644
--- a/src/components/Components.h
+++ b/src/components/Components.h
@@ -107,10 +107,10 @@ class Components {
         /// Remove a component
         void removeComponent(Entity entity);
 
-        /// Return true if an entity is sleeping
+        /// Return true if an entity is disabled
         bool getIsEntityDisabled(Entity entity) const;
 
-        /// Notify if a given entity is sleeping
+        /// Notify if a given entity is disabled
         void setIsEntityDisabled(Entity entity, bool isDisabled);
 
         /// Return true if there is a component for a given entity
diff --git a/src/engine/CollisionWorld.cpp b/src/engine/CollisionWorld.cpp
index 20c08fb8..4476dae5 100644
--- a/src/engine/CollisionWorld.cpp
+++ b/src/engine/CollisionWorld.cpp
@@ -206,7 +206,7 @@ void CollisionWorld::destroyCollisionBody(CollisionBody* collisionBody) {
     mMemoryManager.release(MemoryManager::AllocationType::Pool, collisionBody, sizeof(CollisionBody));
 }
 
-// Notify the world if a body is disabled (sleeping or inactive) or not
+// Notify the world if a body is disabled (sleeping) or not
 void CollisionWorld::notifyBodyDisabled(Entity bodyEntity, bool isDisabled) {
 
     if (isDisabled == mBodyComponents.getIsEntityDisabled(bodyEntity)) return;
diff --git a/src/engine/CollisionWorld.h b/src/engine/CollisionWorld.h
index aef8201d..6868d26e 100644
--- a/src/engine/CollisionWorld.h
+++ b/src/engine/CollisionWorld.h
@@ -196,6 +196,7 @@ class CollisionWorld {
         // -------------------- Friendship -------------------- //
 
         friend class CollisionDetection;
+        friend class Body;
         friend class CollisionBody;
         friend class RigidBody;
         friend class ProxyShape;
diff --git a/src/engine/DynamicsWorld.cpp b/src/engine/DynamicsWorld.cpp
index afa5fe3b..c27661bc 100644
--- a/src/engine/DynamicsWorld.cpp
+++ b/src/engine/DynamicsWorld.cpp
@@ -817,15 +817,17 @@ void DynamicsWorld::updateSleepingBodies() {
                 !body->isAllowedToSleep()) {
 
                 // Reset the sleep time of the body
-                body->mSleepTime = decimal(0.0);
+                mBodyComponents.setSleepTime(body->getEntity(), decimal(0.0));
                 minSleepTime = decimal(0.0);
             }
             else {  // If the body velocity is below the sleeping velocity threshold
 
                 // Increase the sleep time
-                body->mSleepTime += mTimeStep;
-                if (body->mSleepTime < minSleepTime) {
-                    minSleepTime = body->mSleepTime;
+                decimal sleepTime = mBodyComponents.getSleepTime(body->getEntity());
+                mBodyComponents.setSleepTime(body->getEntity(), sleepTime + mTimeStep);
+                sleepTime = mBodyComponents.getSleepTime(body->getEntity());
+                if (sleepTime < minSleepTime) {
+                    minSleepTime = sleepTime;
                 }
             }
         }