73 lines
1.8 KiB
GDScript
73 lines
1.8 KiB
GDScript
class_name Socket
|
|
extends Node3D
|
|
|
|
@export var snapPoint: Marker3D
|
|
@export var snapArea: Area3D
|
|
@export var snapDistance: float = 0.5
|
|
@export var lockOnSnap: bool = true
|
|
|
|
var candidate: Pickupable = null
|
|
var snappedObject: Pickupable = null
|
|
|
|
func _ready() -> void:
|
|
if snapArea:
|
|
snapArea.body_entered.connect(onBodyEntered)
|
|
snapArea.body_exited.connect(onBodyExited)
|
|
|
|
func isInRange(object: Pickupable) -> bool:
|
|
if object == null:
|
|
return false
|
|
|
|
if object.snapAnchor == null:
|
|
return false
|
|
|
|
var distance := object.snapAnchor.global_position.distance_to(
|
|
snapPoint.global_position
|
|
)
|
|
|
|
return distance <= snapDistance
|
|
|
|
func getSnapTransform(object: Pickupable) -> Transform3D:
|
|
var objectTransform := object.body.global_transform
|
|
var anchorTransform := object.snapAnchor.global_transform
|
|
|
|
# Where is the SnapAnchor relative to the Rigidbody?
|
|
var anchorOffset := objectTransform.affine_inverse() * anchorTransform
|
|
|
|
# We want the SnapAnchor to have exactly the same
|
|
# transform as the Socket's SnapPoint.
|
|
return snapPoint.global_transform * anchorOffset.affine_inverse()
|
|
|
|
func snapObject(object: Pickupable):
|
|
if not isInRange(object):
|
|
return
|
|
|
|
var targetTransform := getSnapTransform(object)
|
|
|
|
var body := object.body
|
|
|
|
body.linear_velocity = Vector3.ZERO
|
|
body.angular_velocity = Vector3.ZERO
|
|
|
|
body.global_transform = targetTransform
|
|
|
|
if lockOnSnap:
|
|
body.freeze = true
|
|
|
|
snappedObject = object
|
|
candidate = null
|
|
|
|
func onBodyEntered(body: Node3D):
|
|
if body is RigidBody3D and body.get_parent() is Pickupable:
|
|
var pickup = body.get_parent() as Pickupable
|
|
pickup.currentSocket = self
|
|
candidate = pickup
|
|
|
|
func onBodyExited(body: Node3D):
|
|
if body is RigidBody3D and body.get_parent() is Pickupable:
|
|
var pickup = body.get_parent() as Pickupable
|
|
if pickup.currentSocket == self:
|
|
pickup.currentSocket = null
|
|
if candidate == pickup:
|
|
candidate = null
|