How to implement dragging of an object by a character in 3D?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Ilja Vost

Hello everyone, good time of the day!

I’m trying to implement object drag system in my experimental 3D game.

For example, how it works in “Untitled goose game” and what I want to achieve:

I tried next:

  1. I tried to connect my object (RigidBody3D) with node inside BoneAttachment3D by PinJoint3d(or HingJoint3d). But it’s not working as expected.
  2. I tried to move my object (Rigidbody3d) by linear_velocity to my node inside BoneAttachment3D. But it’s not working as expected, too.

Is it possible somehow connect object to character bone? Or maybe you have another idea?

:bust_in_silhouette: Reply From: ibrahim.semab

One approach you can take is to use a KinematicBody3D for the object that the player can drag, and then use the move_and_slide() function to move it around. Here’s an example of how you can achieve this:

Attach a KinematicBody3D node as a child of your draggable object node.
Set the mass of the KinematicBody3D to 0.
Set the collision shape of the KinematicBody3D to match the shape of your draggable object.
Add a script to the KinematicBody3D node and implement the input handling code to move the node when dragged.
Here’s an example implementation of the drag code in the KinematicBody3D script:

extends KinematicBody3D

var is_dragging = false

func _physics_process(delta):
    if is_dragging:
        var input_vec = Input.get_action_strength("ui_mouse") * Vector2(1, -1)
        var mouse_ray = get_viewport().get_camera().project_ray_origin(get_local_mouse_position())
        var new_pos = mouse_ray.get_origin() + mouse_ray.get_direction() * 2
        var new_transform = Transform(Basis(), new_pos)
        set_transform(new_transform)
        move_and_slide(Vector3(), Vector3.UP)
        
func _input(event):
    if event is InputEventMouseButton:
        if event.is_pressed() and event.button_index == BUTTON_LEFT:
            is_dragging = true
        else:
            is_dragging = false

In this code, we use Input.get_action_strength(“ui_mouse”) to get the amount of input from the mouse. We then use get_viewport().get_camera().project_ray_origin(get_local_mouse_position()) to get a ray from the camera to the current mouse position in world space. We use this ray to calculate the new position of the KinematicBody3D node, and then set its transform to this new position.

Finally, we call move_and_slide() to update the KinematicBody3D’s position, and pass in a zero velocity vector and the UP vector as arguments to ensure that it slides along the ground.