![]() |
Attention | Topic was automatically imported from the old Question2Answer platform. |
![]() |
Asked By | LowFlyingBear |
Hello,
I am a total noob in Godot and I am working on a simple 2D game.
In this game I have a ball which is a RigidBody2D (with the mode set to RIGID) and a platform which is a StaticBody2D.
The ball is launched in the air and bounces from the platform.
I need to reset the ball to the initial position after 2 bounces.
I do this by setting the ball’s mode to STATIC and changing its position.
Then I need to relaunch the ball from the initial position.
This doesn’t work for some reason, when I switch the ball back to RIGID mode it starts from the last position where it was before I reset the position.
Could you please explain what I am doing wrong here?
The code:
extends Node2D
# The goal of this script is to:
# 1. Launch the ball after waiting for 5 seconds
# 2. Reset the ball's position to what it was in the beginning after 2 collisions with the platform
# 3. Go to 1
onready var ball_rigid_body_2d = $BallRigidBody2D
onready var ball_collision_shape = $BallRigidBody2D/CollisionShape2D
var initial_ball_position:Vector2 = Vector2.ZERO
var collision_count:int = 0
var reset:bool = false
func _ready():
initial_ball_position = ball_rigid_body_2d.position
create_timer()
func create_timer():
var timer = Timer.new()
timer.connect("timeout", self, "_on_timer_timeout")
add_child(timer)
timer.start(5)
# Should relaunch the ball every 5 seconds
func _on_timer_timeout():
ball_rigid_body_2d.mode = RigidBody2D.MODE_RIGID
ball_collision_shape.disabled = false
# Reset velocities
ball_rigid_body_2d.linear_velocity *= 0
ball_rigid_body_2d.angular_velocity *= 0
# Reset the collision counter
collision_count = 0
var impulse_vector = Vector2(1, -1)
ball_rigid_body_2d.apply_central_impulse(impulse_vector * 100)
func _physics_process(delta):
if reset:
reset = false
ball_rigid_body_2d.mode = RigidBody2D.MODE_STATIC
ball_rigid_body_2d.linear_velocity *= 0
ball_rigid_body_2d.angular_velocity *= 0
ball_rigid_body_2d.position = initial_ball_position
ball_collision_shape.disabled = true
func _on_BallBody_body_entered(body):
print("Collision!")
collision_count += 1
# Reset after 2 collisions
if collision_count > 1:
reset = true
Here is a short animation of the issue.
I created a super simple test project to demonstrate the problem
Thank you.
Here is the working solution (big thanks to zenbobilly) :
godot-launch-ball-test
I added the source code, in case the file is no longer available:
SceneRoot.gd
extends Node2D
# The goal of this script is to:
# 1. Launch the ball
# 2. Reset the ball's position after 2 collisions with the platform to what it was in the beginning
# 3. Go to 1
onready var ball_rigid_body_2d:Ball = $BallRigidBody2D
var ball_initial_position: = Vector2.ZERO
var collision_count: = 0
var timer_interval: = 7
func _ready():
ball_initial_position = ball_rigid_body_2d.position
ball_rigid_body_2d.connect("body_entered", self, "_on_BallRigidBody2D_body_entered")
launch_ball()
create_timer()
func launch_ball() -> void:
var strength: = 220
var impulse_vector = Vector2(1, -1)
ball_rigid_body_2d.make_rigid_and_apply_impulse(impulse_vector * strength)
func reset_ball() -> void:
ball_rigid_body_2d.make_static_and_set_position(ball_initial_position)
func create_timer():
var timer = Timer.new()
timer.connect("timeout", self, "_on_timer_timeout")
add_child(timer)
timer.start(timer_interval)
# Relaunch the ball on timer
func _on_timer_timeout():
collision_count = 0
launch_ball()
func _on_BallRigidBody2D_body_entered(body:Node):
print("Collision!")
collision_count += 1
# Reset after 2 collisions
if collision_count > 1:
reset_ball()
BallRigidBody2D.gd
extends RigidBody2D
class_name Ball
onready var ball_collision_shape = $CollisionShape2D
var _position: = Vector2.ZERO
var _reset_position: = false
var _impulse: = Vector2.ZERO
var _apply_impulse: = false
func make_ridid_deferred() -> void:
set_deferred("mode", RigidBody2D.MODE_RIGID)
ball_collision_shape.set_deferred("disabled", false)
func make_static_deferred() -> void:
set_deferred("mode", RigidBody2D.MODE_STATIC)
ball_collision_shape.set_deferred("disabled", true)
func make_static_and_set_position(position:Vector2):
_position = position
_reset_position = true
func make_rigid_and_apply_impulse(impulse:Vector2):
_impulse = impulse
_apply_impulse = true
# It is important to call the two metods below here, not in the _integrate_forces
make_ridid_deferred()
func _integrate_forces(state):
if _reset_position:
_reset_position = false
# Stop all movement
state.linear_velocity = Vector2.ZERO
state.angular_velocity = 0
state.transform.origin = _position
# Make the ball static and disable collision after the current frame's physics step
make_static_deferred()
elif _apply_impulse:
_apply_impulse = false
apply_central_impulse(_impulse)
Project tree:
- SceneRoot
- BallRigidBody2D
- BallSprite
- CollisionShape2D
- PlatformStaticBody2D
- CollisionShape2D
- ColorRect
- BallRigidBody2D
LowFlyingBear | 2022-08-23 08:14