Area3d.position = Vector3d(x,y,z) appears to not work as it should...

Godot Version

4.4

Question

I am trying to orphan (disconnect from parent) and reparent an Area3D in my game. When I do this the Area3D (and all child geometry moves quite some distance from where it was originally placed).

Oddly if I use a tween like this it works (moves the Area3D back to where it was originally):

var position_tween = create_tween()
position_tween.tween_property(this_module, "position", Vector3(this_module.position.x,this_module.position.y,0.0) , 0.1)

But if I do this it doesn’t:

this_module.position = Vector3(this_module.position.x,this_module.position.y,0.0)

Nothing I’ve tried seems to move the Area3D back to where it was before being orphaned.

I would much prefer to just move the object (using position or similar) instead of hacking it with a tween.

Could anyone please help with working out what’s going on here?

-------------- UPDATE --------------

Now that i’ve added additional objects to it, the tween isn’t even working!

I guess my question is “If I reparent an object how can I get it to STAY PUT? and not move to what seems to be some random location in the world?”

-------------- UPDATE 2 --------------

 this_module.reparent(new_parent, true) 

and

this_module.reparent(new_parent, false)

Do reparent correctly, however the objects still move far away, and I cannot seem to move them back

You found the proper solution already:

this_module.reparent(new_parent, true)

How is this not working for you? Can you show your scene tree and ideally a short video showcasing the issue?

I’ve decided to change tack on this and instead am going to rotate the objects around “the hard way”. I’ve made this work this afternoon - however I need some help with animating the rotation - this is a space station rotating section (to create gravity) and whilst i can arbitrarily rotate the whole rotatable sections now - I am unsure how to make it animated

func rotate_around_point(point: Vector3, axis: Vector3, angle: float):
	var this_module = self
	
	var transform = this_module.global_transform
	var basis = this_module.transform.basis
	var position = this_module.transform.origin

	# Translate to origin
	var translated_transform = Transform3D(basis, position - point)

	# Rotate around the origin
	var rotated_transform = translated_transform.rotated(axis, angle)

	# Translate back
	var final_transform = Transform3D(rotated_transform.basis, rotated_transform.origin + point)
	this_module.global_transform = final_transform
	

func rotate_around_rotator_ring (rotation_amount_in_degrees: float) -> void:
	var this_module = self
	#check if it is a rotator ring
	if !object_is_component_type(this_module, ComponentType.ROTATOR_RING):
                # iterate through all connected rotator rings for this module
		for crr in this_module.connected_rotator_rings:
			var rotation_axis = crr.get_rotation_axis()
			this_module.rotate_around_point(crr.global_transform.origin, rotation_axis, deg_to_rad(rotation_amount_in_degrees))
	else: # it's a rotator ring so just rotate it around itself
		var rotation_axis = Vector3(0.0,0.0,-1.0) # this is a rotation relative to itself so we can just use a default z axis for rotation
		this_module.rotate(rotation_axis, deg_to_rad(rotation_amount_in_degrees))
		
# this is to be called on rotator ring objects ONLY
func get_rotation_axis() -> Vector3:
	var axis_of_rotation = Vector3.ZERO
	if component_type == ComponentType.ROTATOR_RING:
		# get the 2 normal anchors
		var normal_anchor_1 = null
		var normal_anchor_2 = null
		for child in get_all_children(self):
			if "NormalAnchor1" in child.name:
				normal_anchor_1 = child
			elif "NormalAnchor2" in child.name:
				normal_anchor_2 = child
		
		# work out the axis of rotation
		if normal_anchor_1 and normal_anchor_2:
			axis_of_rotation = normal_anchor_1.global_transform.origin - normal_anchor_2.global_transform.origin # anti clockwise
			axis_of_rotation = axis_of_rotation.normalized()
	
	return axis_of_rotation

The following is how I am interacting with it currently

if object_is_attachment_type(currently_selected_object, AttachmentType.PROPULSION):
			# we have a propulsion unit selected - turn it on
			currently_selected_object.thrusters_ignited = !currently_selected_object.thrusters_ignited
			
			if currently_selected_object.thrusters_ignited:
				# use the propulsion unit's connected rotator ring(s) to get things moving
				for crr in currently_selected_object.connected_rotator_rings:
					# get all the objects that are also connected to this rotator ring
					var rotating_modules = get_all_modules_connected_to_rotator_ring(crr)
					var increments = 360 / rotator_rotation_increment
					for n in range(increments):
						for rm in rotating_modules:
							rm.rotate_around_rotator_ring(rotator_rotation_increment)
						crr.rotate_around_rotator_ring(rotator_rotation_increm

How would I go about tweening or lerping this?

You should be able to tween it with tween_method() at the end of your code snippet instead of using the for loop. Try it out and let me know if you get stuck with something.

I am struggling to work this out wchc - the place I am calling this from has no knowledge of the current nor future destination of the object (which i believe tween_method requires) - would you be able to provide a code snippet i could use?

After looking deeper into your code I decided to go with the tween_property methods inside your rotate methods. Here are the snippets, but I have no way of testing this code without access to the rest of your codebase, so I can only hope it works for you. If not, try to debug it and let me know if you get stuck somewhere and if that even remotely does what you need.

func rotate_around_point(point: Vector3, axis: Vector3, angle: float):
	var this_module = self
	
	var transform = this_module.global_transform
	var basis = this_module.transform.basis
	var position = this_module.transform.origin
	
	# Translate to origin
	var translated_transform = Transform3D(basis, position - point)
	
	# Rotate around the origin
	var rotated_transform = translated_transform.rotated(axis, angle)
	
	# Translate back
	var final_transform = Transform3D(rotated_transform.basis, rotated_transform.origin + point)
	#this_module.global_transform = final_transform
	
	# Tween the transform instead and await for it to finish
	var tween_duration: float = 1.0
	var tween: Tween = create_tween()
	tween.tween_property(this_module, "global_transform", final_transform, tween_duration)
	await tween.finished


func rotate_around_rotator_ring (rotation_amount_in_degrees: float) -> void:
	var this_module = self
	#check if it is a rotator ring
	if !object_is_component_type(this_module, ComponentType.ROTATOR_RING):
		# iterate through all connected rotator rings for this module
		for crr in this_module.connected_rotator_rings:
			var rotation_axis = crr.get_rotation_axis()
			
			# Await the coroutine
			await this_module.rotate_around_point(crr.global_transform.origin, rotation_axis, deg_to_rad(rotation_amount_in_degrees))
	else: # it's a rotator ring so just rotate it around itself
		var rotation_axis = Vector3(0.0,0.0,-1.0) # this is a rotation relative to itself so we can just use a default z axis for rotation
		#this_module.rotate(rotation_axis, deg_to_rad(rotation_amount_in_degrees))
		
		# Tween the rotation instead and await for it to finish
		var tween_duration: float = 1.0
		var tween: Tween = create_tween()
		tween.tween_property(this_module, "rotation", this_module.basis.rotated(rotation_axis, deg_to_rad(rotation_amount_in_degrees)), tween_duration)
		await tween.finished
if object_is_attachment_type(currently_selected_object, AttachmentType.PROPULSION):
			# we have a propulsion unit selected - turn it on
			currently_selected_object.thrusters_ignited = !currently_selected_object.thrusters_ignited
			
			if currently_selected_object.thrusters_ignited:
				# use the propulsion unit's connected rotator ring(s) to get things moving
				for crr in currently_selected_object.connected_rotator_rings:
					# get all the objects that are also connected to this rotator ring
					var rotating_modules = get_all_modules_connected_to_rotator_ring(crr)
					var increments = 360 / rotator_rotation_increment
					for n in range(increments):
						for rm in rotating_modules:

							# Await the coroutines before trying to rotate the next part
							await rm.rotate_around_rotator_ring(rotator_rotation_increment)
						await crr.rotate_around_rotator_ring(rotator_rotation_increm

Thanks for this, it KINDA works, the issue though is this is moving A LOT of objects around a central fulcrum and with the above method it moves them out of sync. I will try to see if I can make it bring them into sync. Thanks for all the help so far!

1 Like