Fixed doors by unlocking angular axis (x and z), renamed Door.gd to HingeInteractable.gd
This commit is contained in:
+1
-3
@@ -1,6 +1,6 @@
|
|||||||
[gd_scene format=3 uid="uid://hmpweoahtner"]
|
[gd_scene format=3 uid="uid://hmpweoahtner"]
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://cyw8ng7alo12e" path="res://Scripts/Door.gd" id="1_1vvux"]
|
[ext_resource type="Script" uid="uid://cyw8ng7alo12e" path="res://Scripts/HingeInteractable.gd" id="1_1vvux"]
|
||||||
|
|
||||||
[sub_resource type="BoxMesh" id="BoxMesh_va8t4"]
|
[sub_resource type="BoxMesh" id="BoxMesh_va8t4"]
|
||||||
size = Vector3(0.2, 3, 0.2)
|
size = Vector3(0.2, 3, 0.2)
|
||||||
@@ -57,8 +57,6 @@ transform = Transform3D(-4.371139e-08, -0.635, 0, 1, -2.7756732e-08, 0, 0, 0, 1,
|
|||||||
shape = SubResource("BoxShape3D_476pq")
|
shape = SubResource("BoxShape3D_476pq")
|
||||||
|
|
||||||
[node name="DoorBody" type="RigidBody3D" parent="." unique_id=1982348670]
|
[node name="DoorBody" type="RigidBody3D" parent="." unique_id=1982348670]
|
||||||
axis_lock_angular_x = true
|
|
||||||
axis_lock_angular_z = true
|
|
||||||
mass = 10.0
|
mass = 10.0
|
||||||
angular_damp = 5.0
|
angular_damp = 5.0
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -47,7 +47,7 @@ snapAngleThreshold = 0.5
|
|||||||
snapVelocityThreshold = 5.0
|
snapVelocityThreshold = 5.0
|
||||||
|
|
||||||
[node name="MedievalDoor" parent="." unique_id=1143822269 instance=ExtResource("3_jw32o")]
|
[node name="MedievalDoor" parent="." unique_id=1143822269 instance=ExtResource("3_jw32o")]
|
||||||
transform = Transform3D(1.5, 0, 0, 0, 1.5, 0, 0, 0, 1.5, 7.1977696, -0.02157104, -1.6521502)
|
transform = Transform3D(0.9396926, 0, 0.34202012, 0, 1, 0, -0.34202012, 0, 0.9396926, 7.1977696, -0.02157104, -1.6521502)
|
||||||
|
|
||||||
[node name="Block" type="Node3D" parent="." unique_id=1216126902]
|
[node name="Block" type="Node3D" parent="." unique_id=1216126902]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -8.362265, 2.041253, 0)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -8.362265, 2.041253, 0)
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
[ext_resource type="Texture2D" uid="uid://dulhjsunch31g" path="res://Textures/Door/Wood.jpg" id="1_fgasx"]
|
[ext_resource type="Texture2D" uid="uid://dulhjsunch31g" path="res://Textures/Door/Wood.jpg" id="1_fgasx"]
|
||||||
[ext_resource type="Texture2D" uid="uid://dp4cgjr828p7j" path="res://Textures/Door/Stone.jpg" id="2_fpqxj"]
|
[ext_resource type="Texture2D" uid="uid://dp4cgjr828p7j" path="res://Textures/Door/Stone.jpg" id="2_fpqxj"]
|
||||||
[ext_resource type="Texture2D" uid="uid://jydmkkryke23" path="res://Textures/Door/Door.jpg" id="4_8du8j"]
|
[ext_resource type="Texture2D" uid="uid://jydmkkryke23" path="res://Textures/Door/Door.jpg" id="4_8du8j"]
|
||||||
[ext_resource type="Script" uid="uid://cyw8ng7alo12e" path="res://Scripts/Door.gd" id="5_3u0t0"]
|
[ext_resource type="Script" uid="uid://cyw8ng7alo12e" path="res://Scripts/HingeInteractable.gd" id="5_3u0t0"]
|
||||||
[ext_resource type="Texture2D" uid="uid://cq1svjaaumlba" path="res://Textures/Door/RustedMetal.jpg" id="5_pao41"]
|
[ext_resource type="Texture2D" uid="uid://cq1svjaaumlba" path="res://Textures/Door/RustedMetal.jpg" id="5_pao41"]
|
||||||
|
|
||||||
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_5ubf6"]
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_5ubf6"]
|
||||||
@@ -273,8 +273,6 @@ metadata/_custom_type_script = "uid://cyw8ng7alo12e"
|
|||||||
[node name="DoorBody" type="RigidBody3D" parent="DoorLeft" unique_id=1047666100]
|
[node name="DoorBody" type="RigidBody3D" parent="DoorLeft" unique_id=1047666100]
|
||||||
collision_layer = 4
|
collision_layer = 4
|
||||||
collision_mask = 9
|
collision_mask = 9
|
||||||
axis_lock_angular_x = true
|
|
||||||
axis_lock_angular_z = true
|
|
||||||
mass = 10.0
|
mass = 10.0
|
||||||
angular_damp = 5.0
|
angular_damp = 5.0
|
||||||
|
|
||||||
@@ -303,8 +301,6 @@ metadata/_custom_type_script = "uid://cyw8ng7alo12e"
|
|||||||
[node name="DoorBody" type="RigidBody3D" parent="DoorRight" unique_id=1795020957]
|
[node name="DoorBody" type="RigidBody3D" parent="DoorRight" unique_id=1795020957]
|
||||||
collision_layer = 4
|
collision_layer = 4
|
||||||
collision_mask = 9
|
collision_mask = 9
|
||||||
axis_lock_angular_x = true
|
|
||||||
axis_lock_angular_z = true
|
|
||||||
mass = 10.0
|
mass = 10.0
|
||||||
angular_damp = 5.0
|
angular_damp = 5.0
|
||||||
|
|
||||||
|
|||||||
-135
@@ -1,135 +0,0 @@
|
|||||||
extends Interactable
|
|
||||||
class_name Door
|
|
||||||
|
|
||||||
@export var body: RigidBody3D
|
|
||||||
@export var springStrength: float = 200.0
|
|
||||||
@export var springDamping: float= 50.0
|
|
||||||
@export var maxGrabDistance: float = 6.0
|
|
||||||
@export var mouseForce: float = 0.02
|
|
||||||
|
|
||||||
@export var hinge: HingeJoint3D
|
|
||||||
@export var hingeAngularUpperLimit: float = 120
|
|
||||||
@export var hingeAngularLowerLimit: float = -120
|
|
||||||
|
|
||||||
@export var snapAngleThreshold: float = 1
|
|
||||||
@export var snapVelocityThreshold: float = 5.0
|
|
||||||
|
|
||||||
@export var mouseHorizontalFactor: float = 1.0
|
|
||||||
@export var mouseVerticalFactor: float = 1.0
|
|
||||||
|
|
||||||
var dragging: bool = false
|
|
||||||
var grabLocal: Vector3 = Vector3.ZERO
|
|
||||||
var handOffset: Vector3 = Vector3.ZERO
|
|
||||||
|
|
||||||
func _ready() -> void:
|
|
||||||
hinge.set_param(HingeJoint3D.PARAM_LIMIT_LOWER, deg_to_rad(hingeAngularLowerLimit))
|
|
||||||
hinge.set_param(HingeJoint3D.PARAM_LIMIT_UPPER, deg_to_rad(hingeAngularUpperLimit))
|
|
||||||
|
|
||||||
func _physics_process(_delta):
|
|
||||||
if dragging:
|
|
||||||
return
|
|
||||||
|
|
||||||
var angle = get_hinge_angle()
|
|
||||||
var ang_vel = get_hinge_ang_vel()
|
|
||||||
|
|
||||||
if abs(rad_to_deg(angle)) > snapAngleThreshold:
|
|
||||||
return
|
|
||||||
|
|
||||||
if abs(ang_vel) > snapVelocityThreshold:
|
|
||||||
return
|
|
||||||
|
|
||||||
# Strong damping near closed position
|
|
||||||
var damping = springDamping * 4.0
|
|
||||||
|
|
||||||
# PD controller torque toward angle 0
|
|
||||||
var torque = -angle * springStrength - ang_vel * damping
|
|
||||||
|
|
||||||
var axis = hinge.global_transform.basis.y
|
|
||||||
body.apply_torque(axis * torque)
|
|
||||||
|
|
||||||
func beginInteract(player, hitPosition: Vector3):
|
|
||||||
dragging = true
|
|
||||||
handOffset = Vector3.ZERO
|
|
||||||
grabLocal = body.to_local(hitPosition)
|
|
||||||
player.setMouseFactors(mouseHorizontalFactor, mouseVerticalFactor)
|
|
||||||
|
|
||||||
func updateInteract(player):
|
|
||||||
if !dragging:
|
|
||||||
return
|
|
||||||
|
|
||||||
var worldGrab = body.to_global(grabLocal)
|
|
||||||
|
|
||||||
handOffset += player.camera.global_basis.x * player.interactionMouseDelta.x * mouseForce
|
|
||||||
handOffset += -player.camera.global_basis.y * player.interactionMouseDelta.y * mouseForce
|
|
||||||
handOffset = handOffset.limit_length(0.3)
|
|
||||||
|
|
||||||
var targetHand = player.hand.global_position + handOffset
|
|
||||||
|
|
||||||
var error = targetHand - worldGrab
|
|
||||||
|
|
||||||
var handDistance = player.hand.global_position.distance_to(worldGrab)
|
|
||||||
if handDistance > maxGrabDistance:
|
|
||||||
player.stopInteraction()
|
|
||||||
return
|
|
||||||
|
|
||||||
var offset = worldGrab - body.global_position
|
|
||||||
|
|
||||||
var pointVelocity = body.linear_velocity + body.angular_velocity.cross(offset)
|
|
||||||
|
|
||||||
var hingeAxis = body.global_basis.y
|
|
||||||
|
|
||||||
var tangent = hingeAxis.cross(offset)
|
|
||||||
if tangent.length_squared() < 0.0001:
|
|
||||||
return
|
|
||||||
tangent = tangent.normalized()
|
|
||||||
|
|
||||||
var tangentError = tangent * error.dot(tangent)
|
|
||||||
var tangentVelocity = tangent * pointVelocity.dot(tangent)
|
|
||||||
|
|
||||||
var force = tangentError * springStrength - tangentVelocity * springDamping
|
|
||||||
|
|
||||||
body.apply_force(force, offset)
|
|
||||||
|
|
||||||
func endInteract(player):
|
|
||||||
dragging = false
|
|
||||||
handOffset = Vector3.ZERO
|
|
||||||
player.setMouseFactors(1.0, 1.0)
|
|
||||||
|
|
||||||
#func get_hinge_angle() -> float:
|
|
||||||
#var body_basis = body.global_transform.basis
|
|
||||||
#var hinge_basis = hinge.global_transform.basis
|
|
||||||
#
|
|
||||||
## Body forward vector in world space
|
|
||||||
#var forward = body_basis.z
|
|
||||||
#
|
|
||||||
## Convert forward vector into hinge local space
|
|
||||||
#var local_forward = hinge_basis.inverse() * forward
|
|
||||||
#
|
|
||||||
## Angle around hinge axis (Y)
|
|
||||||
#return atan2(local_forward.x, local_forward.z)
|
|
||||||
|
|
||||||
func get_hinge_angle() -> float:
|
|
||||||
var hinge_axis = hinge.global_transform.basis.y.normalized()
|
|
||||||
|
|
||||||
# Door forward direction
|
|
||||||
var fwd = body.global_transform.basis.z.normalized()
|
|
||||||
|
|
||||||
# Reference forward direction (door closed direction)
|
|
||||||
var ref = hinge.global_transform.basis.z.normalized()
|
|
||||||
|
|
||||||
# Remove hinge axis component (project onto hinge plane)
|
|
||||||
var fwd_proj = (fwd - hinge_axis * fwd.dot(hinge_axis)).normalized()
|
|
||||||
var ref_proj = (ref - hinge_axis * ref.dot(hinge_axis)).normalized()
|
|
||||||
|
|
||||||
# Signed angle
|
|
||||||
var angle = atan2(
|
|
||||||
hinge_axis.dot(ref_proj.cross(fwd_proj)),
|
|
||||||
ref_proj.dot(fwd_proj)
|
|
||||||
)
|
|
||||||
|
|
||||||
return angle
|
|
||||||
|
|
||||||
|
|
||||||
func get_hinge_ang_vel() -> float:
|
|
||||||
var axis = hinge.global_transform.basis.y.normalized()
|
|
||||||
return body.angular_velocity.dot(axis)
|
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
extends Interactable
|
||||||
|
class_name HingeInteractable
|
||||||
|
|
||||||
|
@export var body: RigidBody3D
|
||||||
|
@export var springStrength: float = 100.0
|
||||||
|
@export var springDamping: float = 50.0
|
||||||
|
@export var maxGrabDistance: float = 6.0
|
||||||
|
@export var mouseForce: float = 0.02
|
||||||
|
|
||||||
|
@export var hinge: HingeJoint3D
|
||||||
|
@export var hingeAngularUpperLimit: float = 120.0
|
||||||
|
@export var hingeAngularLowerLimit: float = -120.0
|
||||||
|
|
||||||
|
@export var snapAngleThreshold: float = 1.0
|
||||||
|
@export var snapVelocityThreshold: float = 5.0
|
||||||
|
|
||||||
|
@export var mouseHorizontalFactor: float = 1.0
|
||||||
|
@export var mouseVerticalFactor: float = 1.0
|
||||||
|
|
||||||
|
var dragging: bool = false
|
||||||
|
var grabLocal: Vector3 = Vector3.ZERO
|
||||||
|
var handOffsetLocal: Vector3 = Vector3.ZERO
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
hinge.set_param(HingeJoint3D.PARAM_LIMIT_LOWER, deg_to_rad(hingeAngularLowerLimit))
|
||||||
|
hinge.set_param(HingeJoint3D.PARAM_LIMIT_UPPER, deg_to_rad(hingeAngularUpperLimit))
|
||||||
|
|
||||||
|
func beginInteract(player, hitPosition: Vector3):
|
||||||
|
dragging = true
|
||||||
|
handOffsetLocal = Vector3.ZERO
|
||||||
|
grabLocal = body.to_local(hitPosition)
|
||||||
|
player.setMouseFactors(mouseHorizontalFactor, mouseVerticalFactor)
|
||||||
|
|
||||||
|
func updateInteract(player):
|
||||||
|
if !dragging:
|
||||||
|
return
|
||||||
|
body.sleeping = false
|
||||||
|
|
||||||
|
var camLocalX = body.global_basis.inverse() * player.camera.global_basis.x
|
||||||
|
var camLocalY = body.global_basis.inverse() * player.camera.global_basis.y
|
||||||
|
|
||||||
|
handOffsetLocal += camLocalX * player.interactionMouseDelta.x * mouseForce
|
||||||
|
handOffsetLocal += -camLocalY * player.interactionMouseDelta.y * mouseForce
|
||||||
|
handOffsetLocal = handOffsetLocal.limit_length(0.3)
|
||||||
|
|
||||||
|
var worldGrab = body.to_global(grabLocal)
|
||||||
|
var handDistance = player.hand.global_position.distance_to(worldGrab)
|
||||||
|
if handDistance > maxGrabDistance:
|
||||||
|
player.stopInteraction()
|
||||||
|
return
|
||||||
|
|
||||||
|
var targetHandLocal = body.to_local(player.hand.global_position) + handOffsetLocal
|
||||||
|
var errorLocal = targetHandLocal - grabLocal
|
||||||
|
|
||||||
|
var bodyAngularVelocityLocal = body.global_basis.inverse() * body.angular_velocity
|
||||||
|
var bodyLinearVelocityLocal = body.global_basis.inverse() * body.linear_velocity
|
||||||
|
var pointVelocityLocal = bodyLinearVelocityLocal + bodyAngularVelocityLocal.cross(grabLocal)
|
||||||
|
|
||||||
|
var hingeAxisGlobal = hinge.global_basis.z
|
||||||
|
var hingeAxisLocal = (body.global_basis.inverse() * hingeAxisGlobal).normalized()
|
||||||
|
|
||||||
|
var hingePositionLocal = body.to_local(hinge.global_position)
|
||||||
|
var leverArm = grabLocal - hingePositionLocal
|
||||||
|
var tangentLocal = hingeAxisLocal.cross(leverArm)
|
||||||
|
if tangentLocal.length_squared() < 0.0001:
|
||||||
|
return
|
||||||
|
|
||||||
|
tangentLocal = tangentLocal.normalized()
|
||||||
|
var tangentError = tangentLocal * errorLocal.dot(tangentLocal)
|
||||||
|
var tangentVelocity = tangentLocal * pointVelocityLocal.dot(tangentLocal)
|
||||||
|
|
||||||
|
var forceLocal = tangentError * springStrength - tangentVelocity * springDamping
|
||||||
|
var forceGlobal = body.global_basis * forceLocal
|
||||||
|
var offsetGlobal = body.global_basis * grabLocal
|
||||||
|
body.apply_force(forceGlobal, offsetGlobal)
|
||||||
|
|
||||||
|
func endInteract(player):
|
||||||
|
dragging = false
|
||||||
|
handOffsetLocal = Vector3.ZERO
|
||||||
|
player.setMouseFactors(1.0, 1.0)
|
||||||
@@ -128,5 +128,3 @@ func _physics_process(delta: float) -> void:
|
|||||||
lastUpdateTime = 0.0
|
lastUpdateTime = 0.0
|
||||||
|
|
||||||
lerpParameters(delta)
|
lerpParameters(delta)
|
||||||
print("Audio:", global_position)
|
|
||||||
print("Camera:", get_viewport().get_camera_3d().global_position)
|
|
||||||
|
|||||||
Reference in New Issue
Block a user