I got it working, using RigidBody3D’s linear_velocityvariable to move the object instead, along with a damping system to avoid overshooting, and like in the Novetus video, I added rotation and position support for dragging onto off-grid objects. This script has a few problems however, mainly being that it does not disable the collision on the RigidBody3D (as it would cause it to not collide with the dragged_to object, meaning the safe move behavior would be disabled), and this causes the player to be able to ride atop the RigidBody3D, and also causes the part to suffer friction on the ground, meaning it will be less precise. Most of these problems are solvable however, by reducing the friction, and setting the collision mask on the object whilst it is dragged. Here’s the full program:
extends RayCast3D
var text
var offset = Vector3(0, 0, 0)
var collider
var saved_part
var dragged_to_part
var can_grab = false
var drag_count = 0 # if print(get_collider()) zero, then change can_grab but like otherwise you are already grabbing a part
var rot_count_x = 0
var rot_count_y = 0
var rot_count_z = 0
var weld_count = 0
var part_rotation = Vector3(0, 0, 0)
var saved_part_name = ""
func _physics_process(delta):
#if button_toggle.button_toggle: # debug
var par = get_parent()
var play = par.get_parent()
collider = get_collider()
#print(saved_part)
if collider:
if not collider.name == "Floor": # exclude floor
saved_part_name = collider.name
#play.get_child(4).text = saved_part_name # debug
#print(get_collision_normal().inverse()) # debug
if drag_count == 0:
saved_part = collider
add_exception(collider)
can_grab = true
drag_count += 1
#if not collider or collider and collider.name == "Floor": # debug
#play.get_child(4).text = saved_part_name # debug
if can_grab and Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT):
weld_count = 0
#if button_toggle.button_toggle: # debug
var targ_pos = get_collision_point()
var norm = get_collision_normal()
var aabb = _calculate_spatial_bounds(saved_part, false)
var rounded_pos = snappedvec3(targ_pos, 0.25)
if can_grab:
force_raycast_update()
if get_collider():
dragged_to_part = get_collider()
#print("Ground: ", dragged_to_part) # debug
#print("dragged: ", saved_part)saved_part # debug
#saved_part.position = (rounded_pos - offset) + norm * (aabb.size / 2)
var pos_offset
if dragged_to_part:
pos_offset = dragged_to_part.position - Vector3(int(dragged_to_part.position.x), int(dragged_to_part.position.y), int(dragged_to_part.position.z)) # get decimal for position offset
var pos = ((rounded_pos - offset) + (norm * pos_offset) * (aabb.size / 2))
var dir
if saved_part is RigidBody3D:
dir = saved_part.global_position.direction_to(pos)
var dist = saved_part.position.distance_to(pos)
var highest_size = max(saved_part.scale.x, saved_part.scale.y, saved_part.scale.z) # avoid bugs with differently sized parts
if dist > (4 + highest_size): # allows moving parts into enclosed spaces easily, e.g a submarine or enclosed car, as otherwise it will just get stuck on the dragged_to part
saved_part.freeze = true
print(highest_size)
saved_part.position = pos
else:
saved_part.linear_velocity = dir * 60 * dist # 60 = drag speed
saved_part.lock_rotation = true
saved_part.freeze = false
if Input.is_key_pressed(KEY_R) and rot_count_x == 0:
part_rotation += Vector3(0, 90, 0)
rot_count_x += 1
if Input.is_key_pressed(KEY_T) and rot_count_z == 0:
part_rotation += Vector3(0, 0, 90)
rot_count_z += 1
if not Input.is_key_pressed(KEY_R):
rot_count_x = 0
if not Input.is_key_pressed(KEY_T):
rot_count_z = 0
if saved_part is RigidBody3D:
saved_part.set_rotation_degrees(part_rotation + dragged_to_part.rotation_degrees)
if can_grab and Input.is_action_just_pressed("click"):
var offset = get_collision_point() - saved_part.position
if not Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT):
if can_grab and saved_part and drag_count == 1:
if saved_part is RigidBody3D:
saved_part.lock_rotation = false
drag_count = 0
remove_exception(saved_part)
if can_grab:
can_grab = false
dragged_to_part = null
func _calculate_spatial_bounds(parent : Node3D, exclude_top_level_transform: bool) -> AABB: # taken from reddit
var bounds : AABB = AABB()
if parent is VisualInstance3D:
bounds = parent.get_aabb();
for i in range(parent.get_child_count()):
var child : Node3D = parent.get_child(i)
if child:
var child_bounds : AABB = _calculate_spatial_bounds(child, false)
if bounds.size == Vector3.ZERO && parent:
bounds = child_bounds
else:
bounds = bounds.merge(child_bounds)
if bounds.size == Vector3.ZERO && !parent:
bounds = AABB(Vector3(-0.2, -0.2, -0.2), Vector3(0.4, 0.4, 0.4))
if !exclude_top_level_transform:
bounds = parent.transform * bounds
return bounds
func snappedvec3(vec3: Vector3, snap_rate: float):
return Vector3(snapped(vec3.x, snap_rate), snapped(vec3.y, snap_rate), snapped(vec3.z, snap_rate))
I also added a check for if the RigidBody3D is stuck on something, e.g if you are trying to build a submarine, and need to put in an engine or some component, and the part gets stuck on the outside of the submarine, the part will be moved automatically once it gets past a certain distance threshold (in this case it is 4).
I also tried using CharacterBody3D’s move_and_slide() for this, but as I plan to have the objects be mostly physics based, it didn’t work out very well
Sorry for asking such a broad question, I’ll try to narrow it down more next time!