From 343e927db9b2fde246a14a3d680d500b7aefa191 Mon Sep 17 00:00:00 2001 From: miikapalosaari Date: Sat, 26 Sep 2026 09:48:59 +0300 Subject: [PATCH] Fixed doors by unlocking angular axis (x and z), renamed Door.gd to HingeInteractable.gd --- Scenes/Door.tscn | 4 +- Scenes/Main.tscn | 2 +- Scenes/MedievalDoor.tscn | 6 +- Scripts/Door.gd | 135 ------------------ Scripts/HingeInteractable.gd | 80 +++++++++++ .../{Door.gd.uid => HingeInteractable.gd.uid} | 0 Scripts/SpatialAudioPlayer.gd | 2 - 7 files changed, 83 insertions(+), 146 deletions(-) delete mode 100644 Scripts/Door.gd create mode 100644 Scripts/HingeInteractable.gd rename Scripts/{Door.gd.uid => HingeInteractable.gd.uid} (100%) diff --git a/Scenes/Door.tscn b/Scenes/Door.tscn index f2c82aa..37526d8 100644 --- a/Scenes/Door.tscn +++ b/Scenes/Door.tscn @@ -1,6 +1,6 @@ [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"] 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") [node name="DoorBody" type="RigidBody3D" parent="." unique_id=1982348670] -axis_lock_angular_x = true -axis_lock_angular_z = true mass = 10.0 angular_damp = 5.0 diff --git a/Scenes/Main.tscn b/Scenes/Main.tscn index 76b329c..ba77925 100644 --- a/Scenes/Main.tscn +++ b/Scenes/Main.tscn @@ -47,7 +47,7 @@ snapAngleThreshold = 0.5 snapVelocityThreshold = 5.0 [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] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -8.362265, 2.041253, 0) diff --git a/Scenes/MedievalDoor.tscn b/Scenes/MedievalDoor.tscn index 07f963b..cd2fa84 100644 --- a/Scenes/MedievalDoor.tscn +++ b/Scenes/MedievalDoor.tscn @@ -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://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="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"] [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] collision_layer = 4 collision_mask = 9 -axis_lock_angular_x = true -axis_lock_angular_z = true mass = 10.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] collision_layer = 4 collision_mask = 9 -axis_lock_angular_x = true -axis_lock_angular_z = true mass = 10.0 angular_damp = 5.0 diff --git a/Scripts/Door.gd b/Scripts/Door.gd deleted file mode 100644 index c031a3e..0000000 --- a/Scripts/Door.gd +++ /dev/null @@ -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) diff --git a/Scripts/HingeInteractable.gd b/Scripts/HingeInteractable.gd new file mode 100644 index 0000000..90103d0 --- /dev/null +++ b/Scripts/HingeInteractable.gd @@ -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) diff --git a/Scripts/Door.gd.uid b/Scripts/HingeInteractable.gd.uid similarity index 100% rename from Scripts/Door.gd.uid rename to Scripts/HingeInteractable.gd.uid diff --git a/Scripts/SpatialAudioPlayer.gd b/Scripts/SpatialAudioPlayer.gd index cfadb73..95cf77e 100644 --- a/Scripts/SpatialAudioPlayer.gd +++ b/Scripts/SpatialAudioPlayer.gd @@ -128,5 +128,3 @@ func _physics_process(delta: float) -> void: lastUpdateTime = 0.0 lerpParameters(delta) - print("Audio:", global_position) - print("Camera:", get_viewport().get_camera_3d().global_position)