void RigidBodyBullet::reload_space_override_modificator() { // Make sure that kinematic bodies have their total gravity calculated if (!is_active() && PhysicsServer::BODY_MODE_KINEMATIC != mode) return; Vector3 newGravity(space->get_gravity_direction() * space->get_gravity_magnitude()); real_t newLinearDamp(linearDamp); real_t newAngularDamp(angularDamp); AreaBullet *currentArea; // Variable used to calculate new gravity for gravity point areas, it is pointed by currentGravity pointer Vector3 support_gravity(0, 0, 0); int countCombined(0); for (int i = areaWhereIamCount - 1; 0 <= i; --i) { currentArea = areasWhereIam[i]; if (PhysicsServer::AREA_SPACE_OVERRIDE_DISABLED == currentArea->get_spOv_mode()) { continue; } /// Here is calculated the gravity if (currentArea->is_spOv_gravityPoint()) { /// It calculates the direction of new gravity support_gravity = currentArea->get_transform().xform(currentArea->get_spOv_gravityVec()) - get_transform().get_origin(); real_t distanceMag = support_gravity.length(); // Normalized in this way to avoid the double call of function "length()" if (distanceMag == 0) { support_gravity.x = 0; support_gravity.y = 0; support_gravity.z = 0; } else { support_gravity.x /= distanceMag; support_gravity.y /= distanceMag; support_gravity.z /= distanceMag; } /// Here is calculated the final gravity if (currentArea->get_spOv_gravityPointDistanceScale() > 0) { // Scaled gravity by distance support_gravity *= currentArea->get_spOv_gravityMag() / Math::pow(distanceMag * currentArea->get_spOv_gravityPointDistanceScale() + 1, 2); } else { // Unscaled gravity support_gravity *= currentArea->get_spOv_gravityMag(); } } else { support_gravity = currentArea->get_spOv_gravityVec() * currentArea->get_spOv_gravityMag(); } switch (currentArea->get_spOv_mode()) { ///case PhysicsServer::AREA_SPACE_OVERRIDE_DISABLED: /// This area does not affect gravity/damp. These are generally areas /// that exist only to detect collisions, and objects entering or exiting them. /// break; case PhysicsServer::AREA_SPACE_OVERRIDE_COMBINE: /// This area adds its gravity/damp values to whatever has been /// calculated so far. This way, many overlapping areas can combine /// their physics to make interesting newGravity += support_gravity; newLinearDamp += currentArea->get_spOv_linearDamp(); newAngularDamp += currentArea->get_spOv_angularDamp(); ++countCombined; break; case PhysicsServer::AREA_SPACE_OVERRIDE_COMBINE_REPLACE: /// This area adds its gravity/damp values to whatever has been calculated /// so far. Then stops taking into account the rest of the areas, even the /// default one. newGravity += support_gravity; newLinearDamp += currentArea->get_spOv_linearDamp(); newAngularDamp += currentArea->get_spOv_angularDamp(); ++countCombined; goto endAreasCycle; case PhysicsServer::AREA_SPACE_OVERRIDE_REPLACE: /// This area replaces any gravity/damp, even the default one, and /// stops taking into account the rest of the areas. newGravity = support_gravity; newLinearDamp = currentArea->get_spOv_linearDamp(); newAngularDamp = currentArea->get_spOv_angularDamp(); countCombined = 1; goto endAreasCycle; case PhysicsServer::AREA_SPACE_OVERRIDE_REPLACE_COMBINE: /// This area replaces any gravity/damp calculated so far, but keeps /// calculating the rest of the areas, down to the default one. newGravity = support_gravity; newLinearDamp = currentArea->get_spOv_linearDamp(); newAngularDamp = currentArea->get_spOv_angularDamp(); countCombined = 1; break; } } endAreasCycle: if (1 < countCombined) { newGravity /= countCombined; newLinearDamp /= countCombined; newAngularDamp /= countCombined; } btVector3 newBtGravity; G_TO_B(newGravity * gravity_scale, newBtGravity); btBody->setGravity(newBtGravity); btBody->setDamping(newLinearDamp, newAngularDamp); }
PhysicsServer::AreaSpaceOverrideMode BulletPhysicsServer::area_get_space_override_mode(RID p_area) const { AreaBullet *area = area_owner.get(p_area); ERR_FAIL_COND_V(!area, PhysicsServer::AREA_SPACE_OVERRIDE_DISABLED); return area->get_spOv_mode(); }