![]() |
Attention | Topic was automatically imported from the old Question2Answer platform. |
![]() |
Asked By | CosmicKid |
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.
Current implementation
Ball.gd:
extends RigidBody2D
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
[...]
func _integrate_forces(state):
print("_integrate_forces(state)")
if should_reset_position:
state.transform.origin = pos_to_reset
should_reset_position = false
enable_contact_monitor = true
func _process(delta):
[...]
if reset_timer < TIME_TO_RESET:
reset_timer += delta
if reset_timer > TIME_TO_RESET:
_queue_ball_reset()
contact_monitor = enable_contact_monitor
func _queue_ball_reset():
set_mode(RigidBody2D.MODE_RIGID)
# Set sleeping to false so that _integrate_forces can be called again
sleeping = false
stop_playback = false
should_reset_position = true
func reset(pos_to_reset):
self.pos_to_reset = pos_to_reset
set_mode(RigidBody2D.MODE_STATIC)
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 _integrate_forces
. stop_playback
is for handling audio so it’s not important here.
Problem
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 _process
and _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.
Question
Is there any better way to implement this? Is RigidBody2D appropriate for that?