0

I have a problem with the engine Godot, with the errors "body set shape disabled" and "body set shape as one-way collision".

In my project I have built four scenes:

  • The platform scene formed by (StaticBody2D which has as child objects(CollisionShape2D, Sprite, Position2D, Area2D which in turn has a child object(Collisionshape2D))

  • The missile scene formed by (RigidBody2D which has as child objects(CollisionShape2D and Sprite));

  • The spaceship scene formed by (Kinematicbody2D which has as child objects(Sprite and CollisionShape2D));

  • The main scene which has as root node Node and as child objects: (platform and spaceship).

Moreover I have two scripts: one in the spaceship scene, on the Kinematicbody2D node; and then in the platform scene on the StaticBody2D node.

Basically when I start the game there is the platform at the top center and then there is the Area2D (with the CollisionShape2D to detect when a body enters the area and then there is also the Position2D that I set for a position where it should instantiate the missile at runtime).

When a body enters the Area2D the platform should instantiate a missile (which does nothing for the moment).

The problem arises when I direct the spaceship in the Area2D and the platform instantiates many times (more than 200-300 times per second) the missile and this is the moment when the game crashes. I get the errors that I wrote above and then I have to close it.

Spaceship Code:

extends KinematicBody2D

var target
var click
var dir
var collision
var speed = 200

func _input(event):
    if event is InputEventMouseButton:
        target = get_global_mouse_position()
        click = true

func _physics_process(delta):
    if click:
        dir = position.direction_to(target)
        collision = move_and_collide(dir * speed * delta)
        if collision:
            pass

Platform Code:

extends StaticBody2D

var trigger
var missileScene = preload("res://scenes/Missile.tscn")
var missile

func _on_DangerArea_body_entered(body):
    if body is KinematicBody2D:
        trigger = true
    while(trigger):
        missile = missileScene.instance()
        $SpawnPosition.add_child(missile)
        yield(get_tree().create_timer(3),"timeout")

func _on_DangerArea_body_exited(body):
    if body is KinematicBody2D:
        trigger = false
halfer
  • 19,824
  • 17
  • 99
  • 186
Peppe32
  • 23
  • 3
  • 1
    Please read [Under what circumstances may I add “urgent” or other similar phrases to my question, in order to obtain faster answers?](//meta.stackoverflow.com/q/326569) - the summary is that this is not an ideal way to address volunteers, and is probably counterproductive to obtaining answers. Please refrain from adding this to your questions. – halfer Aug 27 '21 at 22:08
  • Does this answer your question? [Godot 3.2.1. Can't change this state while flushing queries. Use call\_deferred() or set\_deferred() to change monitoring state instead](https://stackoverflow.com/questions/63206231/godot-3-2-1-cant-change-this-state-while-flushing-queries-use-call-deferred) – WebF0x Aug 14 '22 at 21:57

2 Answers2

1

I ran into same error today , this is my guess.

You can't directly add a rigid body (my case) while on a physics frame (like on area enter).

The add_child process may trigger some engine code stuff and they're not allowed to process on the physics frame.

So ,the workaround is: just try replace $SpawnPosition.add_child(missile) with $SpawnPosition.call_defered("add_child",missile) and it'll work.

Enigmaxp
  • 36
  • 3
0

The signal body_entered will happen for each PhysicsBody2D (KinematicBody2D, RigidBody2D, StaticBody2D) that enters the Area2D. And that includes the missiles.

Yes, you are checking if the body is a KinematicBody2D. But when a KinematicBody2D enters, it sets trigger to true, allowing all bodies to enter the loop.

First of all, I suggest to reject bodies by returning:

func _on_DangerArea_body_entered(body):
    if not body is KinematicBody2D:
        return

    # ...

And second, you can use a regular timer to spawn missiles (and that way, you also know that there is at most one timer running):

extends StaticBody2D

var timer:Timer
var missileScene:PackedScene = preload("res://scenes/Missile.tscn")

func _ready():
    timer = Timer.new()
    add_child(timer)
    timer.set_wait_time(3)
    timer.connect("timeout", self, "instance_missile")

func _on_DangerArea_body_entered(body):
    if not body is KinematicBody2D:
        return

    timer.start()

func _on_DangerArea_body_exited(body):
    if not body is KinematicBody2D:
        return

    timer.stop()

func instance_missile():
    var missile := missileScene.instance()
    $SpawnPosition.add_child(missile)

The following might or might not be useful in your game: You can use node groups, or register classes so you can be more specific than is KinematicBody2D. Another thing you can do is add the bodies you care about to an Array when they enter, and remove them when they exit, so you know when they all exited.


By the way, the first thing I noticed while transcribing the code: You never set click to false (or something other than true).

It appears you want to handle click for one physics frame. For that you don't need _input. Use Input.is_action_just_pressed in _physics_process instead. In fact, I would encourage to begin that way, and only move to _input if you need to. And a lot of times you don't.

Theraot
  • 31,890
  • 5
  • 57
  • 86
  • Thank you but I would like to ask you exactly where did I go wrong? – Peppe32 Aug 25 '21 at 18:57
  • @Gius My understanding of what happens is the following: The `KinematicBody2D` enters the `Area2D`, then the code sets `trigger` to true, spawns a missile, and yields on a timer. Now the recently spawned missile entered the `Area2D`, `trigger` is already true, so it spawns a missile, and yields on a timer. Now the recently spawned missile entered the `Area2D`, `trigger` is already true, so it spawns a missile, and yields on a timer. Now the recently spawned missile entered the `Area2D`, `trigger` is already true, so it spawns a missile, and so on. *I hope that makes sense.* – Theraot Aug 25 '21 at 19:00
  • No I mean what I did wrong in the code, that is, what mistake I made in the code I wrote at the beginning. More precisely, I mean the mistake I made that caused me to generate the two errors in the question I asked.. – Peppe32 Aug 25 '21 at 21:18
  • @Gius The errors, for what I understand the errors are from the functions [`body_set_shape_disabled`](https://docs.godotengine.org/en/stable/classes/class_physics2dserver.html#class-physics2dserver-method-body-set-shape-disabled) and [`body_set_shape_as_one_way_collision`](https://docs.godotengine.org/en/stable/classes/class_physics2dserver.html#class-physics2dserver-method-body-set-shape-as-one-way-collision). I don't know what exactly the errors were. – Theraot Aug 25 '21 at 21:56