Weird error when reparenting, but only when player is looking in a certain direction?

Godot Version

4.2.1 (Also affects 4.3-dev2)

Question

Hello, I’m getting an error when reparenting non-child node A to child node B and back again. The really weird thing, though, is that it only happens if I’m looking in a certain direction (I think) the second time. I have absolutely no idea what the cause of this could be. The error in question:

  <C++ Source>   scene/main/node.cpp:120 @ _notification()
  <Stack Trace>  Player.gd:61 @ body_pickup()
                 Player.gd:52 @ _physics_process()

Relevant code (full version in project):


@onready var pickup_position = $Camera3D/Pickup

var ball: RigidBody3D
var cooldown = 1.0

26 func _physics_process(delta):
...
48    if Input.is_action_just_pressed("shoot"):
49        if ball:
50            ball.freeze = false
51            ball.apply_central_impulse(camera.global_transform.basis.z * -7)
52            ball.reparent(get_parent())
53            ball = null
54            cooldown = 0.5

58 func body_pickup(body):
59    if body is RigidBody3D:
60        if cooldown <= 0:
61            body.reparent(pickup_position)
62            body.global_position = pickup_position.global_position
63            body.freeze = true
64            ball = body

Example project that shows my problem. Is this a problem with my programming, or with the engine?
Thank you for your time :slight_smile:

extends CharacterBody3D


const SPEED = 5.0
const JUMP_VELOCITY = 4.5

@onready var camera = $Camera3D
const SENSITIVITY = 0.1

@onready var pickup_position = $Camera3D/Pickup
@onready var world=$".."

var ball: RigidBody3D
var cooldown = 1.0

# Get the gravity from the project settings to be synced with RigidBody nodes.
var gravity = ProjectSettings.get_setting("physics/3d/default_gravity")

func _ready():
	Input.mouse_mode = Input.MOUSE_MODE_CAPTURED

func _input(event):
	if event is InputEventMouseMotion:
		camera.rotation_degrees.x -= event.relative.y * SENSITIVITY
		rotation_degrees.y -= event.relative.x * SENSITIVITY

func _physics_process(delta):
	# Add the gravity.
	if not is_on_floor():
		velocity.y -= gravity * delta

	# Handle jump.
	if Input.is_action_just_pressed("ui_accept") and is_on_floor():
		velocity.y = JUMP_VELOCITY

	# Get the input direction and handle the movement/deceleration.
	# As good practice, you should replace UI actions with custom gameplay actions.
	var input_dir = Input.get_vector("move_left", "move_right", "move_up", "move_down")
	var direction = (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
	if direction:
		velocity.x = direction.x * SPEED
		velocity.z = direction.z * SPEED
	else:
		velocity.x = move_toward(velocity.x, 0, SPEED)
		velocity.z = move_toward(velocity.z, 0, SPEED)

	move_and_slide()
	
	if Input.is_action_just_pressed("shoot"):
		if ball:
			print("throw")
			ball.freeze = false
			ball.apply_central_impulse(camera.global_transform.basis.z * -7)
			ball.reparent(world)
			ball = null
			cooldown = 0.5
	
	cooldown -= delta

func body_pickup(body):
	if body is RigidBody3D:
		if cooldown <= 0:
			body.reparent(pickup_position)
			body.global_position = pickup_position.global_position
			body.freeze = true
			ball = body

copy and paste to all of Player.gd
it should be no error again

Unfortunately, this doesn’t seem to have changed anything. I’m still experiencing the same issue as before.

extends CharacterBody3D

var pickup=false

const SPEED = 5.0
const JUMP_VELOCITY = 4.5

@onready var camera = $Camera3D
const SENSITIVITY = 0.1

@onready var pickup_position = $Camera3D/Pickup
@onready var world=$".."

var ball: RigidBody3D
var cooldown = 1.0

# Get the gravity from the project settings to be synced with RigidBody nodes.
var gravity = ProjectSettings.get_setting("physics/3d/default_gravity")

func _ready():
	Input.mouse_mode = Input.MOUSE_MODE_CAPTURED

func _input(event):
	if event is InputEventMouseMotion:
		camera.rotation_degrees.x -= event.relative.y * SENSITIVITY
		rotation_degrees.y -= event.relative.x * SENSITIVITY

func _physics_process(delta):
	# Add the gravity.
	if not is_on_floor():
		velocity.y -= gravity * delta

	# Handle jump.
	if Input.is_action_just_pressed("ui_accept") and is_on_floor():
		velocity.y = JUMP_VELOCITY

	# Get the input direction and handle the movement/deceleration.
	# As good practice, you should replace UI actions with custom gameplay actions.
	var input_dir = Input.get_vector("move_left", "move_right", "move_up", "move_down")
	var direction = (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
	if direction:
		velocity.x = direction.x * SPEED
		velocity.z = direction.z * SPEED
	else:
		velocity.x = move_toward(velocity.x, 0, SPEED)
		velocity.z = move_toward(velocity.z, 0, SPEED)

	move_and_slide()
	
	if Input.is_action_just_pressed("shoot"):
		if ball:
			ball.freeze = false
			ball.reparent(world)
			ball.apply_central_impulse(camera.global_transform.basis.z * -7)
			ball = null
			cooldown = 0.5
	
	cooldown -= delta

func body_pickup(body):
	if body is RigidBody3D and not ball:
		if cooldown <= 0:
			if pickup:
				return
			pickup=true
			body.reparent(pickup_position)
			body.global_position = pickup_position.global_position
			body.freeze = true
			ball = body
			pickup=false

this should work now

the GIF:
ball

This has fixed it! So the problem was that the ball was leaving the player, then immediately being re-parented before the code had finished. Thank you @zdrmlpzdrmlp for your support :smiley:

1 Like

in my testing, the ball is pickup twice or more. so it gives that error. So, i added the boolean pickup and also not ball to make it really only picking up the ball once