I'm trying to make a system so my character can pick up items. specifically items that are in the "canGrab" group. For this, I created an Empty Node in my character where a Raycast and a Marker3D are located. In this empty node I added the following script
extends Node3D
@export var raycast: RayCast3D
@export var grabPos: Node3D
var picked = null
func _physics_process(delta: float) -> void:
if Input.is_action_just_pressed("Interact"):
can_grab()
if Input.is_action_just_pressed("DropObj"):
if picked:
release_object()
if picked:
picked.global_transform.origin = grabPos.global_transform.origin
picked.global_transform.basis = grabPos.global_transform.basis
func can_grab() -> void:
if raycast.is_colliding():
var collider = raycast.get_collider()
if collider.is_in_group("canGrab"):
if picked:
release_object()
picked = collider
func release_object() -> void:
if picked:
picked = null
When I first tried it I thought it was working fine, but it wasn’t. When I grab the object, it can get stuck in other objects in the environment. And when I drop it, it sometimes gets thrown out.
In release_object(), you could explicitly set the position of the object so it doesn’t fly off.
Alternatively, maybe you could disable the CollisionShape of the object while it’s picked up so it no longer interacts with other objects. Then re-enable it inside release_object()
Thanks for answering.
I tried what you told me about specifying the position before dropping the object, but it worked the same (I probably didn’t know how to implement it, I’m still a bit new to this).
Instead, I made the object be in “sleeping” mode while I pick it up, so it doesn’t fly away when I drop it.
As for the collisions you told me, what I wanted was that when picking up the object, it could collide with the environment, something it didn’t do, or not correctly.
So I came up with the idea of ​​implementing a CollisionShape3D inside the player that is invisible and disabled. But when picking up an object it takes the shape of the object.
With this it works much better, although it still has its errors. I don’t know how functional or adequate this is, but it’s already progress.
Now this is my script
extends Node3D
@export var raycast: RayCast3D
@export var grabPos: Marker3D
var picked : RigidBody3D = null
@export var altCollision: CollisionShape3D
func _ready() -> void:
altCollision.visible = false
altCollision.disabled = true
func _physics_process(delta: float) -> void:
if Input.is_action_just_pressed("Interact"):
can_grab()
if Input.is_action_just_pressed("DropObj"):
if picked:
release_object()
if picked:
picked.global_transform.origin = grabPos.global_transform.origin
picked.global_transform.basis = grabPos.global_transform.basis
picked.sleeping = true
altCollision.visible = true
altCollision.disabled = false
altCollision.global_transform.origin = picked.global_transform.origin
altCollision.global_transform.basis = picked.global_transform.basis
func can_grab() -> void:
if raycast.is_colliding():
var collider = raycast.get_collider()
if collider.is_in_group("canGrab"):
if picked:
release_object()
picked = collider
picked.sleeping = false
for child in picked.get_children():
if child is CollisionShape3D:
altCollision.shape = child.shape
print(altCollision.shape)
break
picked.set_collision_layer_value(2, false)
picked.set_collision_layer_value(5, true)
func release_object() -> void:
if picked:
picked.sleeping = false
altCollision.visible = false
altCollision.disabled = true
picked.set_collision_layer_value(2, true)
picked.set_collision_layer_value(5, false)
picked = null