Physics2DServer created rigidbody2d not collision with StaticBody2D

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By myhalibobo

this my code , it can Can simulate physical fall , but not collison with StaticBody2D

extends Node2D

var vs = VisualServer
var ps = Physics2DServer
func _ready():
    create_virus()

func create_virus():
    #创建body
    var body = ps.body_create()

    #设置模式
    ps.body_set_mode(body, ps.BODY_MODE_RIGID)
    ps.body_set_collision_layer(body,1)
    ps.body_set_collision_mask(body,1)
    #添加形状
    var shape = RectangleShape2D.new()
    shape.extents = Vector2(100, 100)
    ps.body_add_shape(body, shape)
    #设置body到当前空间
    ps.body_set_space(body, get_world_2d().space)
    #初始化位置
    var xform = Transform2D().translated(Vector2(1080/2, 1920/2))
    ps.body_set_state(body, ps.BODY_STATE_TRANSFORM, xform)
    #canvasItem
    var sprite = create_item("res://icon.png")
    ps.body_set_force_integration_callback(body, self, "_body_moved", sprite)

 func create_item(path):
    var ci_rid = VisualServer.canvas_item_create()
    VisualServer.canvas_item_set_parent(ci_rid, get_canvas_item())
    var sprite = load(path)
    VisualServer.canvas_item_add_texture_rect(ci_rid, Rect2(sprite.get_size() / 2, sprite.get_size()), sprite)
    return ci_rid

func _body_moved(state, index):
    VisualServer.canvas_item_set_transform(index, state.transform)

I’m in the same situation.

Did you find the cause of the problem?

nthrack | 2020-01-27 09:08

:bust_in_silhouette: Reply From: hearto

Hello,
If somebody is looking for an answer for this problem years later. I was having the same issue and tracked the solution.
The main problem is the collision between Area2d, Body2D generated Physics2DServer and StaticBody2D Bodies. For this to work the StaticBody2D only reacts to entities with the monitorable flag enabled, here are the steps:

  1. Set the collision masks and layers to make the collision happen in the same way as the godot collision nodes require.

  2. Optional: add a body enter callback, this will be triggered when the area enters the static body. Physics2DServer::get_singleton()->area_set_monitor_callback(area_rid, area_rid, “callback_method_name”); The method callback signature is: void _on_body_monitor(int p_status, const RID& p_collider, int p_instance, int p_shape, int p_self_shape);

  3. And the actual solution of the problem for Godot 3.x: Physics2DServer::get_singleton()->area_set_monitorable(area_rid, true);

Now this solution is slow, still better than vanilla nodes. In comparison this had 6x better performance and without the monitorable flag enabled is 40x better performance.
For the same reason the user from this post followed another approach instead of the Physics2DServer using Physics2DShapeQueryParameters inside the process.
This is a good solution if you have a project already done, but if you can change all the static bodies to areas for example, the performance will be leagues better.
In our case I fixed it using a hybrid approach. I do area and body collisions using Physics2DServer with monitorable off and I created an additional configurable collision layer for static body manual collisions as in our case all of them are in the same layers. Then in physics process query for all static bodies using query server using the same collision data. The advantage of this option is that you have more control about when the static body query is done and you can do this action each 5 frames for example instead of every physics frame. This approach has disadvantages too, scales very badly with persistent separated objects. It’s very good for short lived objects in the same screen, for example hundreds of bullets in the same screen where the monitorable scales very badly.

As note samdze bullet hell native plugin has monitorable off by default if somebody is interested in a ready available implementation.