I've been trying to create a small volleyball android game. What I want to do is stop the ball when it hits the ground and let players move through it (no collision detection at this point). After three seconds, I want to respawn the ball and let it collide with players again.
export var sounds = 
const TIME_TO_RESET = 3.0
var reset_timer = TIME_TO_RESET
var pos_to_reset = null
# Queue ball respawn in _process function - any change to ball's position
# needs to be done in _integrate_forces (beacuse it's RigidBody2D)
var should_reset_position = false
# Used to disable contact_monitor when ball needs to be respawned
# and enable it again after _integrate_forces is called - this way
# ball is not affected by any collisions before respawned
var enable_contact_monitor = true
state.transform.origin = pos_to_reset
should_reset_position = false
enable_contact_monitor = true
if reset_timer < TIME_TO_RESET:
reset_timer += delta
if reset_timer > TIME_TO_RESET:
contact_monitor = enable_contact_monitor
# Set sleeping to false so that _integrate_forces can be called again
sleeping = false
stop_playback = false
should_reset_position = true
self.pos_to_reset = pos_to_reset
reset_timer = 0.0
stop_playback = true
enable_contact_monitor = false
Ball is a RigidBody2D. When it hits ground, its
reset method is called. Its movement is stopped (
set_mode(RigidBody2D.MODE_STATIC)) as well as collision detection (
enable_contact_monitor = false). After three seconds, I switch it back to RigidBody2D and reset its position in
stop_playback is for handling audio so it's not important here.
After many tries, it works almost perfectly except one thing. Generally, queuing the change of
contact_monitor to true in
_integrate_forces ensures that when I switch the ball back to
RigidBody2D it's not affected by any force that could be applied during that switch. Namely, if a player stands near the disabled ball this collision may still be detected and it'll change ball's velocity - instead of falling down after the respawn the ball will fly in some direction.
I managed to eliminate this problem except there are some random moments when this happens again. I'm not sure how Godot handles
_integrate_forces but it feels to me like these run on separate threads and it could be that
contact_monitor is set to true before
_integrate_forces is done affecting ball's initial velocity after respawn.
I tried to add another if statement to
_integrate_forces which sets ball's velocity to zero vector in the next run of this method. It solves the problem completely but the ball still moves slightly when it respawns which looks like a tiny visual glitch. Also, it makes the code look dirtier.
Is there any better way to implement this? Is RigidBody2D appropriate for that?