diff options
Diffstat (limited to 'modules/bullet/area_bullet.cpp')
-rw-r--r-- | modules/bullet/area_bullet.cpp | 180 |
1 files changed, 108 insertions, 72 deletions
diff --git a/modules/bullet/area_bullet.cpp b/modules/bullet/area_bullet.cpp index c3bd84c329..10a71d65df 100644 --- a/modules/bullet/area_bullet.cpp +++ b/modules/bullet/area_bullet.cpp @@ -59,8 +59,8 @@ AreaBullet::AreaBullet() : AreaBullet::~AreaBullet() { // signal are handled by godot, so just clear without notify - for (int i = overlappingObjects.size() - 1; 0 <= i; --i) { - overlappingObjects[i].object->on_exit_area(this); + for (int i = 0; i < overlapping_shapes.size(); i++) { + overlapping_shapes[i].other_object->on_exit_area(this); } } @@ -70,89 +70,140 @@ void AreaBullet::dispatch_callbacks() { } isScratched = false; - // Reverse order because I've to remove EXIT objects - for (int i = overlappingObjects.size() - 1; 0 <= i; --i) { - OverlappingObjectData &otherObj = overlappingObjects.write[i]; + // Reverse order so items can be removed. + for (int i = overlapping_shapes.size() - 1; i >= 0; i--) { + OverlappingShapeData &overlapping_shape = overlapping_shapes.write[i]; - switch (otherObj.state) { + switch (overlapping_shape.state) { case OVERLAP_STATE_ENTER: - otherObj.state = OVERLAP_STATE_INSIDE; - call_event(otherObj.object, PhysicsServer3D::AREA_BODY_ADDED); - otherObj.object->on_enter_area(this); + overlapping_shape.state = OVERLAP_STATE_INSIDE; + call_event(overlapping_shape, PhysicsServer3D::AREA_BODY_ADDED); + if (_overlapping_shape_count(overlapping_shape.other_object) == 1) { + // This object's first shape being added. + overlapping_shape.other_object->on_enter_area(this); + } break; case OVERLAP_STATE_EXIT: - call_event(otherObj.object, PhysicsServer3D::AREA_BODY_REMOVED); - otherObj.object->on_exit_area(this); - overlappingObjects.remove(i); // Remove after callback + call_event(overlapping_shape, PhysicsServer3D::AREA_BODY_REMOVED); + if (_overlapping_shape_count(overlapping_shape.other_object) == 1) { + // This object's last shape being removed. + overlapping_shape.other_object->on_exit_area(this); + } + overlapping_shapes.remove_at(i); // Remove after callback break; + case OVERLAP_STATE_INSIDE: { + if (overlapping_shape.other_object->getType() == TYPE_RIGID_BODY) { + RigidBodyBullet *body = static_cast<RigidBodyBullet *>(overlapping_shape.other_object); + body->scratch_space_override_modificator(); + } + break; + } case OVERLAP_STATE_DIRTY: - case OVERLAP_STATE_INSIDE: break; } } } -void AreaBullet::call_event(CollisionObjectBullet *p_otherObject, PhysicsServer3D::AreaBodyStatus p_status) { - InOutEventCallback &event = eventsCallbacks[static_cast<int>(p_otherObject->getType())]; - Object *areaGodoObject = ObjectDB::get_instance(event.event_callback_id); +void AreaBullet::call_event(const OverlappingShapeData &p_overlapping_shape, PhysicsServer3D::AreaBodyStatus p_status) { + InOutEventCallback &event = eventsCallbacks[static_cast<int>(p_overlapping_shape.other_object->getType())]; - if (!areaGodoObject) { - event.event_callback_id = ObjectID(); + if (!event.event_callback.is_valid()) { + event.event_callback = Callable(); return; } call_event_res[0] = p_status; - call_event_res[1] = p_otherObject->get_self(); // Other body - call_event_res[2] = p_otherObject->get_instance_id(); // instance ID - call_event_res[3] = 0; // other_body_shape ID - call_event_res[4] = 0; // self_shape ID + call_event_res[1] = p_overlapping_shape.other_object->get_self(); // RID + call_event_res[2] = p_overlapping_shape.other_object->get_instance_id(); // Object ID + call_event_res[3] = p_overlapping_shape.other_shape_id; // Other object's shape ID + call_event_res[4] = p_overlapping_shape.our_shape_id; // This area's shape ID Callable::CallError outResp; - areaGodoObject->call(event.event_callback_method, (const Variant **)call_event_res_ptr, 5, outResp); + Variant ret; + event.event_callback.call((const Variant **)call_event_res, 5, ret, outResp); } -void AreaBullet::scratch() { - if (isScratched) { - return; +int AreaBullet::_overlapping_shape_count(CollisionObjectBullet *p_other_object) { + int count = 0; + for (int i = 0; i < overlapping_shapes.size(); i++) { + if (overlapping_shapes[i].other_object == p_other_object) { + count++; + } } - isScratched = true; + return count; } -void AreaBullet::clear_overlaps(bool p_notify) { - for (int i = overlappingObjects.size() - 1; 0 <= i; --i) { - if (p_notify) { - call_event(overlappingObjects[i].object, PhysicsServer3D::AREA_BODY_REMOVED); +int AreaBullet::_find_overlapping_shape(CollisionObjectBullet *p_other_object, uint32_t p_other_shape_id, uint32_t p_our_shape_id) { + for (int i = 0; i < overlapping_shapes.size(); i++) { + const OverlappingShapeData &overlapping_shape = overlapping_shapes[i]; + if (overlapping_shape.other_object == p_other_object && overlapping_shape.other_shape_id == p_other_shape_id && overlapping_shape.our_shape_id == p_our_shape_id) { + return i; } - overlappingObjects[i].object->on_exit_area(this); } - overlappingObjects.clear(); + return -1; } -void AreaBullet::remove_overlap(CollisionObjectBullet *p_object, bool p_notify) { - for (int i = overlappingObjects.size() - 1; 0 <= i; --i) { - if (overlappingObjects[i].object == p_object) { - if (p_notify) { - call_event(overlappingObjects[i].object, PhysicsServer3D::AREA_BODY_REMOVED); - } - overlappingObjects[i].object->on_exit_area(this); - overlappingObjects.remove(i); - break; +void AreaBullet::mark_all_overlaps_dirty() { + OverlappingShapeData *overlapping_shapes_w = overlapping_shapes.ptrw(); + for (int i = 0; i < overlapping_shapes.size(); i++) { + // Don't overwrite OVERLAP_STATE_ENTER state. + if (overlapping_shapes_w[i].state != OVERLAP_STATE_ENTER) { + overlapping_shapes_w[i].state = OVERLAP_STATE_DIRTY; } } } -int AreaBullet::find_overlapping_object(CollisionObjectBullet *p_colObj) { - const int size = overlappingObjects.size(); - for (int i = 0; i < size; ++i) { - if (overlappingObjects[i].object == p_colObj) { - return i; +void AreaBullet::mark_object_overlaps_inside(CollisionObjectBullet *p_other_object) { + OverlappingShapeData *overlapping_shapes_w = overlapping_shapes.ptrw(); + for (int i = 0; i < overlapping_shapes.size(); i++) { + if (overlapping_shapes_w[i].other_object == p_other_object && overlapping_shapes_w[i].state == OVERLAP_STATE_DIRTY) { + overlapping_shapes_w[i].state = OVERLAP_STATE_INSIDE; } } - return -1; +} + +void AreaBullet::set_overlap(CollisionObjectBullet *p_other_object, uint32_t p_other_shape_id, uint32_t p_our_shape_id) { + int i = _find_overlapping_shape(p_other_object, p_other_shape_id, p_our_shape_id); + if (i == -1) { // Not found, create new one. + OverlappingShapeData overlapping_shape(p_other_object, OVERLAP_STATE_ENTER, p_other_shape_id, p_our_shape_id); + overlapping_shapes.push_back(overlapping_shape); + p_other_object->notify_new_overlap(this); + isScratched = true; + } else { + overlapping_shapes.ptrw()[i].state = OVERLAP_STATE_INSIDE; + } +} + +void AreaBullet::mark_all_dirty_overlaps_as_exit() { + OverlappingShapeData *overlapping_shapes_w = overlapping_shapes.ptrw(); + for (int i = 0; i < overlapping_shapes.size(); i++) { + if (overlapping_shapes[i].state == OVERLAP_STATE_DIRTY) { + overlapping_shapes_w[i].state = OVERLAP_STATE_EXIT; + isScratched = true; + } + } +} + +void AreaBullet::remove_object_overlaps(CollisionObjectBullet *p_object) { + // Reverse order so items can be removed. + for (int i = overlapping_shapes.size() - 1; i >= 0; i--) { + if (overlapping_shapes[i].other_object == p_object) { + overlapping_shapes.remove_at(i); + } + } +} + +void AreaBullet::clear_overlaps() { + for (int i = 0; i < overlapping_shapes.size(); i++) { + call_event(overlapping_shapes[i], PhysicsServer3D::AREA_BODY_REMOVED); + overlapping_shapes[i].other_object->on_exit_area(this); + } + overlapping_shapes.clear(); } void AreaBullet::set_monitorable(bool p_monitorable) { monitorable = p_monitorable; + updated = true; } bool AreaBullet::is_monitoring() const { @@ -162,6 +213,7 @@ bool AreaBullet::is_monitoring() const { void AreaBullet::main_shape_changed() { CRASH_COND(!get_main_shape()); btGhost->setCollisionShape(get_main_shape()); + updated = true; } void AreaBullet::reload_body() { @@ -174,7 +226,7 @@ void AreaBullet::reload_body() { void AreaBullet::set_space(SpaceBullet *p_space) { // Clear the old space if there is one if (space) { - clear_overlaps(false); + clear_overlaps(); isScratched = false; // Remove this object form the physics world @@ -192,24 +244,7 @@ void AreaBullet::on_collision_filters_change() { if (space) { space->reload_collision_filters(this); } -} - -void AreaBullet::add_overlap(CollisionObjectBullet *p_otherObject) { - scratch(); - overlappingObjects.push_back(OverlappingObjectData(p_otherObject, OVERLAP_STATE_ENTER)); - p_otherObject->notify_new_overlap(this); -} - -void AreaBullet::put_overlap_as_exit(int p_index) { - scratch(); - overlappingObjects.write[p_index].state = OVERLAP_STATE_EXIT; -} - -void AreaBullet::put_overlap_as_inside(int p_index) { - // This check is required to be sure this body was inside - if (OVERLAP_STATE_DIRTY == overlappingObjects[p_index].state) { - overlappingObjects.write[p_index].state = OVERLAP_STATE_INSIDE; - } + updated = true; } void AreaBullet::set_param(PhysicsServer3D::AreaParameter p_param, const Variant &p_value) { @@ -241,6 +276,7 @@ void AreaBullet::set_param(PhysicsServer3D::AreaParameter p_param, const Variant default: WARN_PRINT("Area doesn't support this parameter in the Bullet backend: " + itos(p_param)); } + isScratched = true; } Variant AreaBullet::get_param(PhysicsServer3D::AreaParameter p_param) const { @@ -267,21 +303,21 @@ Variant AreaBullet::get_param(PhysicsServer3D::AreaParameter p_param) const { } } -void AreaBullet::set_event_callback(Type p_callbackObjectType, ObjectID p_id, const StringName &p_method) { +void AreaBullet::set_event_callback(Type p_callbackObjectType, const Callable &p_callback) { InOutEventCallback &ev = eventsCallbacks[static_cast<int>(p_callbackObjectType)]; - ev.event_callback_id = p_id; - ev.event_callback_method = p_method; + ev.event_callback = p_callback; /// Set if monitoring - if (eventsCallbacks[0].event_callback_id.is_valid() || eventsCallbacks[1].event_callback_id.is_valid()) { + if (!eventsCallbacks[0].event_callback.is_null() || !eventsCallbacks[1].event_callback.is_null()) { set_godot_object_flags(get_godot_object_flags() | GOF_IS_MONITORING_AREA); } else { set_godot_object_flags(get_godot_object_flags() & (~GOF_IS_MONITORING_AREA)); + clear_overlaps(); } } bool AreaBullet::has_event_callback(Type p_callbackObjectType) { - return eventsCallbacks[static_cast<int>(p_callbackObjectType)].event_callback_id.is_valid(); + return !eventsCallbacks[static_cast<int>(p_callbackObjectType)].event_callback.is_null(); } void AreaBullet::on_enter_area(AreaBullet *p_area) { |