I’m making a little clone of Portal for fun, and right now I’m working on the boxes.
I have a RigidBody3D that gets picked up and the tutorial I watched used Input.is_action_pressed(“interact”)
which is fine, but I want it to toggle between being held and not being held.
I tried getting this by putting this process into the code for my player:
func _process(delta):
var holding= false
var object = interactioncast.get_collider()
if interactioncast.is_colliding():
if object.is_in_group("pickup"):
if Input.is_action_just_pressed("interact"):
if not holding:
holding= true
while holding:
object.global_position= Socket.global_position
object.global_rotation= Socket.global_rotation
object.linear_velocity= Vector3(0.1, 0.5, 0.1)
if holding:
holding= false
the issue is that the “while” condition completely freezes my game and only lets the while loop compute. I can’t think of any other way to get it to work because is_action_just_pressed only picks up the object for a small amount of time.
I also need to figure out how to stop the box from clipping through walls but that’s another issue entirely.
Your while should be part of a process or physics_process, but RigidBodies don’t like having their position updated directly, you will have to freeze the object or apply forces to move the RigidBody towards your target position. You will need to keep track of the object with a member variable, not local to _process
var holding_object: RigidBody = null
func _unhandled_input(event: InputEvent) -> void:
if event.is_action_pressed("interact"):
if holding_object: # drop object
holding_object = null
else:
var object = interactioncast.get_collider()
if interactioncast.is_colliding():
if object.is_in_group("pickup"):
holding_object = object
func _physics_process(delta: float) -> void:
if holding_object:
holding_object.apply_central_force(<a variable that points towards your target direction>)
A script must run from bottom to top (with the exception of awaits) to start the next frame, your while loop traps the game’s process forever.
You don’t need a while loop. Your _process() is already a loop, so take advantage of that.
Also, I would put the event handling in the _unhandled_input() callback instead and handle only necessary logic in the _physics_process().
Something like that should work:
var held_object: Node
func _unhandled_input(event: InputEvent) -> void:
if event.is_action_pressed("interact"):
if held_object:
held_object = null
elif interactioncast.is_colliding():
var interacted_object: Node = interactioncast.get_collider()
if interacted_object.is_in_group("pickup"):
held_object = interacted_object
func _physics_process(_delta: float) -> void:
if held_object:
held_object.global_position= Socket.global_position
held_object.global_rotation= Socket.global_rotation
held_object.linear_velocity= Vector3(0.1, 0.5, 0.1)
And I see @gertkeno already mentioned about directly adjusting RigidBodies - you should avoid that if possible.