Godot Version
4.2.2
Question
I have a script to “hold” Rigdbodies, these rigdbodies are saved on _read() as a packed scene and spawned when the player triggers a area2d.
The objects spawned from the scenes packed at runtime have random forces applied to them when holded.
Here is a example project: project on drive
here is the code for the level loader:
extends Area2D
@export var level: Node2D
var packed_level: PackedScene = null
var loaded = false
var instantiated_level: Node2D
var lvl_global_position: Vector2
func set_owner_recursive(node, owner):
node.owner = owner
for child in node.get_children():
set_owner_recursive(child, owner)
func _ready():
if level == null:
print("No level to load")
queue_free()
return
set_owner_recursive(level, level)
lvl_global_position = level.global_position
var packed_scene = PackedScene.new()
var result = packed_scene.pack(level)
if result == OK:
packed_level = packed_scene
print("Scene packed successfully: %s" % level.name)
else:
print("Failed to pack the scene.")
queue_free()
level.queue_free()
func _process(delta):
if packed_level == null:
return
var player_found = false
var overlapping_bodies = get_overlapping_bodies()
for body in overlapping_bodies:
if body.is_in_group("player"):
player_found = true
if not loaded:
instantiate_level()
break
if instantiated_level != null and not player_found:
if not instantiated_level.is_queued_for_deletion():
instantiated_level.queue_free()
instantiated_level = null
loaded = false
func instantiate_level():
instantiated_level = packed_level.instantiate()
get_parent().add_child(instantiated_level)
instantiated_level.global_position = lvl_global_position
set_owner_recursive(instantiated_level, get_tree().root)
loaded = true
reset_physics(instantiated_level)
print("Level instantiated")
func reset_physics(node):
for body in node.get_children():
if body is RigidBody2D:
body.linear_velocity = Vector2.ZERO
body.angular_velocity = 0.0
for child in body.get_children():
reset_physics(child)
and here the code for handle objects:
extends AnimatedSprite2D
var holded: RigidBody2D = null
var ray_result = null
var holding_timer = 0.0
var holding_just_pressed = false
var collision_shapes = []
var animated_sprites = []
var ray
func _ready():
ray = get_child(0) as ShapeCast2D
func interact_process(creature: Creature):
update_ray_position(creature)
if creature.hold_input:
holding_just_pressed = holding_timer == 0.0
holding_timer = creature.d
else:
holding_timer = 0.0
if holded:
handle_holding(creature)
else:
find_and_hold_target(creature)
update_animation(creature)
func update_ray_position(creature: Creature):
if creature.dir_input != Vector2.ZERO:
ray.target_position = creature.dir_input * 8
ray.position = Vector2.ZERO
func handle_holding(creature: Creature):
play("holding")
holded.global_position = global_position
if holding_just_pressed:
throw_object(creature)
func throw_object(creature: Creature):
print("Throwing object")
holded.get_parent().remove_child(holded)
creature.get_parent().add_child(holded)
holded.global_position = creature.global_position
holded.owner = get_parent()
for shape in collision_shapes:
shape.set_deferred("disabled", false)
for sprite in animated_sprites:
sprite.play("idle")
reset_physics_state(holded)
holded.apply_central_impulse(creature.dir_input.normalized() * 1000 / (holded.mass + 1))
holded = null
collision_shapes.clear()
animated_sprites.clear()
func find_and_hold_target(creature: Creature):
ray.force_shapecast_update()
for i in range(ray.get_collision_count()):
var potential_holded = ray.get_collider(i) as RigidBody2D
if potential_holded and potential_holded.mass < 20.0:
if holding_just_pressed:
hold_object(potential_holded)
break
func hold_object(potential_holded: RigidBody2D):
print("Holding object")
potential_holded.get_parent().remove_child(potential_holded)
add_child(potential_holded)
get_all_colliders(potential_holded)
holded = potential_holded
holded.owner = get_tree().root
set_owner_recursive(holded, get_tree().root)
reset_physics_state(holded)
for shape in collision_shapes:
shape.set_deferred("disabled", true)
print("Collider %s disabled" % shape.name)
for sprite in animated_sprites:
sprite.play("holded")
func update_animation(creature: Creature):
if abs(creature.dir_input.x) < 0.4:
play("idle", 1)
else:
play("walk")
func get_all_colliders(node):
if node.is_class("CollisionShape2D"):
collision_shapes.append(node)
elif node.is_class("AnimatedSprite2D"):
animated_sprites.append(node)
for child in node.get_children():
get_all_colliders(child)
func set_owner_recursive(node, owner):
node.owner = owner
for child in node.get_children():
set_owner_recursive(child, owner)
func reset_physics_state(body: RigidBody2D):
body.linear_velocity = Vector2.ZERO
body.angular_velocity = 0.0
print("Physics reset for RigidBody2D: %s" % body.name)