From e12ca0bb669febe45030e2e1e555409409731afd Mon Sep 17 00:00:00 2001 From: rowan Date: Sat, 21 Jun 2025 23:48:43 -0400 Subject: [PATCH] improved aiming accuracy --- godot/project.godot | 5 +++ godot/scenes/level.tscn | 2 ++ godot/scenes/player.tscn | 7 +++-- godot/src/player.gd | 65 ++++++++++++++++++++++----------------- godot/src/player_input.gd | 43 +++++++++++++++++--------- 5 files changed, 78 insertions(+), 44 deletions(-) diff --git a/godot/project.godot b/godot/project.godot index befdda0..7d34827 100644 --- a/godot/project.godot +++ b/godot/project.godot @@ -19,6 +19,10 @@ config/icon="res://icon.svg" PhantomCameraManager="*res://addons/phantom_camera/scripts/managers/phantom_camera_manager.gd" +[debug_draw_3d] + +settings/addon_root_folder="res://addons/debug_draw_3d/addons/debug_draw_3d" + [editor_plugins] enabled=PackedStringArray("res://addons/FreeControl/plugin.cfg", "res://addons/godot_object_serializer/plugin.cfg", "res://addons/phantom_camera/plugin.cfg") @@ -123,6 +127,7 @@ ui_close_inventory={ [layer_names] 3d_physics/layer_2="interaction" +3d_physics/layer_3="ground" [physics] diff --git a/godot/scenes/level.tscn b/godot/scenes/level.tscn index 29e96fc..ed2e8e8 100644 --- a/godot/scenes/level.tscn +++ b/godot/scenes/level.tscn @@ -33,11 +33,13 @@ transform = Transform3D(50, 0, 0, 0, 50, 0, 0, 0, 50, 0, 0, 0) mesh = SubResource("PlaneMesh_rd3vj") [node name="StaticBody3D" type="StaticBody3D" parent="MeshInstance3D"] +collision_layer = 5 [node name="CollisionShape3D" type="CollisionShape3D" parent="MeshInstance3D/StaticBody3D"] shape = SubResource("WorldBoundaryShape3D_w7c3h") [node name="Player" parent="." instance=ExtResource("1_2q6dc")] +aim_offset = Vector3(0, 1.5, 1.25) [node name="PhantomCamera3D" type="Node3D" parent="." node_paths=PackedStringArray("follow_target")] transform = Transform3D(1, 0, 0, 0, 0.707106, 0.707106, 0, -0.707106, 0.707106, 0, 10, 10) diff --git a/godot/scenes/player.tscn b/godot/scenes/player.tscn index a1d08f0..2e094ed 100644 --- a/godot/scenes/player.tscn +++ b/godot/scenes/player.tscn @@ -2,7 +2,7 @@ [ext_resource type="PackedScene" uid="uid://dpmbimh6m4ari" path="res://scenes/player_mesh.tscn" id="1_3vyb7"] [ext_resource type="Script" uid="uid://50vv0ta67tgl" path="res://src/player.gd" id="1_qhqgy"] -[ext_resource type="Script" uid="uid://877g2wvcupw6" path="res://src/player_input.gd" id="3_dqkch"] +[ext_resource type="Script" uid="uid://cngjp2wws4ld2" path="res://src/player_input.gd" id="3_dqkch"] [ext_resource type="Script" uid="uid://c3wlcxy4vnm2i" path="res://src/interactor.gd" id="4_dqkch"] [ext_resource type="Script" uid="uid://csjl56hf0fnoy" path="res://src/item_container.gd" id="5_qlg0r"] [ext_resource type="Script" uid="uid://k1ihjmhj7ix" path="res://src/equipment_handler.gd" id="5_smehm"] @@ -195,19 +195,21 @@ transitions = ["Start", "Unarmed", SubResource("AnimationNodeStateMachineTransit [node name="Player" type="CharacterBody3D" node_paths=PackedStringArray("input", "interactor", "equipment") groups=["persist"]] script = ExtResource("1_qhqgy") +aim_offset = Vector3(0, 6, 0) input = NodePath("Input") interactor = NodePath("Interactor") equipment = NodePath("Weapon") [node name="Input" type="Node" parent="."] script = ExtResource("3_dqkch") +ground_collision_mask = 4 [node name="Inventory" type="Node" parent="."] script = ExtResource("5_qlg0r") inventory = ExtResource("6_tuyoq") [node name="Weapon" type="BoneAttachment3D" parent="."] -transform = Transform3D(0.00876506, 0.0120414, 0.00178277, 0.00882159, -0.00779736, 0.00929411, 0.00838767, -0.00438243, -0.0116379, -0.128585, 1.36723, 0.500051) +transform = Transform3D(0.00788866, 0.0124171, 0.00292984, 0.00882159, -0.00779736, 0.00929411, 0.00921674, -0.00316481, -0.0114033, -0.177614, 1.36723, 0.484807) bone_name = "mixamorigRightHandMiddle1" bone_idx = 24 use_external_skeleton = true @@ -232,6 +234,7 @@ transform = Transform3D(1.2, 0, 0, 0, 1.2, 0, 0, 0, 1.2, 0, 1, 0) shape = SubResource("CapsuleShape3D_g2els") [node name="Mesh" parent="." instance=ExtResource("1_3vyb7")] +transform = Transform3D(0.995056, 0, -0.0993198, 0, 1, 0, 0.0993198, 0, 0.995056, 0, 0, 0) [node name="AnimationTree" type="AnimationTree" parent="."] root_node = NodePath("../Mesh") diff --git a/godot/src/player.gd b/godot/src/player.gd index 29dbd6f..5707eaf 100644 --- a/godot/src/player.gd +++ b/godot/src/player.gd @@ -2,59 +2,68 @@ class_name Player extends CharacterBody3D @export var walk_speed: float = 4.0 @export var run_speed: float = 6.0 +@export var aim_offset: Vector3 = Vector3(0, 1.3, 0) @export var input: PlayerInput @export var interactor: Interactor @export var equipment: EquipmentHandler var is_running: bool: - get: return velocity and input.is_running + get: return velocity and input.is_running var is_carrying_item: bool: - get: return equipment.has_equipped_item + get: return equipment.has_equipped_item var is_weapon_ready: bool: - get: return is_carrying_item and input.is_weapon_ready + get: return is_carrying_item and input.is_weapon_ready func _ready() -> void: - input.connect('interact', _on_interact) - input.connect('fire', _on_fire) + input.connect('interact', _on_interact) + input.connect('fire', _on_fire) func _physics_process(delta: float) -> void: - if is_weapon_ready: - rotate_toward_look(delta) - else: - move_and_rotate(delta) + if is_weapon_ready: + rotate_toward_look(delta) + else: + move_and_rotate(delta) func move_and_rotate(_delta: float): - var speed = run_speed if input.is_running else walk_speed - velocity = input.next_velocity(speed) - if !velocity.is_zero_approx(): - look_at(global_position + velocity, Vector3.UP, true) - move_and_slide() + var speed = run_speed if input.is_running else walk_speed + velocity = input.next_velocity(speed) + if !velocity.is_zero_approx(): + look_at(global_position + velocity, Vector3.UP, true) + move_and_slide() func rotate_toward_look(_delta: float): - velocity = Vector3.ZERO - var target = input.get_look_target(global_position) - if target.is_some(): - look_at(target.unwrap(), Vector3.UP, true) + velocity = Vector3.ZERO + var target = input.get_look_target(global_position) + if target.is_some(): + var target_point = target.unwrap() + var mouse_dir = (target_point - global_position) + if mouse_dir.length_squared() > 0.0001: + var desired_basis = Basis.looking_at(mouse_dir.normalized(), Vector3.UP) + var yaw = desired_basis.get_euler().y + rotation.y = fmod(yaw + PI, TAU) + + rotation.x = 0.0 + rotation.z = 0.0 func _on_interact(): - interactor.interact_nearest() + interactor.interact_nearest() func _on_fire(): - if is_weapon_ready: - equipment.use() + if is_weapon_ready: + equipment.use() func on_save(): - return { - position = position, - rotation = rotation - } + return { + position = position, + rotation = rotation + } func on_before_load(): - pass + pass func on_load(data: Dictionary): - position = data.position - rotation = data.rotation + position = data.position + rotation = data.rotation diff --git a/godot/src/player_input.gd b/godot/src/player_input.gd index a6171e6..4147e91 100644 --- a/godot/src/player_input.gd +++ b/godot/src/player_input.gd @@ -34,6 +34,8 @@ signal ready_weapon signal unready_weapon signal fire +@export_flags_3d_physics var ground_collision_mask: int = 0 + var last_known_device: Device = Device.Unknown var _is_running: bool = false @@ -76,19 +78,11 @@ var movement_dir: Vector2: 'move_up', 'move_down' ).normalized() -var _mouse_position: Vector2: - get: - var viewport = get_viewport() - var mouse_pos = viewport.get_mouse_position() - var cam = viewport.get_camera_3d() - var space_state = cam.get_world_3d().direct_space_state - var origin = cam.project_ray_origin(mouse_pos) - var end = origin + (cam.project_ray_normal(mouse_pos) * cam.far) - var query = PhysicsRayQueryParameters3D.create(origin, end) +var _active_camera: Camera3D: + get: return get_viewport().get_camera_3d() - var result = space_state.intersect_ray(query) - var position = result.get('position') as Vector3 - return Vector2(position.x, position.z) +var _mouse_position: Vector2: + get: return get_viewport().get_mouse_position() var _analog_dir: Vector2: get: return Input.get_vector( @@ -131,11 +125,32 @@ func _unhandled_input(event: InputEvent) -> void: func next_velocity(speed: float, dir: Vector2 = movement_dir) -> Vector3: return Vector3(dir.x, 0, dir.y) * speed +func get_mouse_look() -> Vector3: + var cam: Camera3D = _active_camera # Use your convenient getter + + if not cam: + return Vector3.ZERO # Should not happen, but good for safety + + var mouse_pos = _mouse_position # Your 2D mouse position getter + + var ray_origin = cam.project_ray_origin(mouse_pos) + var ray_direction = cam.project_ray_normal(mouse_pos) + + var plane_normal = Vector3.UP # Normal vector of a horizontal plane + var plane_d = 1.5 # The 'D' in the plane equation Ax+By+Cz=D + var denominator = plane_normal.dot(ray_direction) + if abs(denominator) < 0.0001: + return Vector3(ray_origin.x, 1.5, ray_origin.z) + + var t = (plane_d - plane_normal.dot(ray_origin)) / denominator + var intersection_point = ray_origin + ray_direction * t + + return intersection_point + func get_look_target(position: Vector3) -> Option: match last_known_device: Device.KeyboardMouse: - var pos = _mouse_position - return Option.some(Vector3(pos.x, position.y, pos.y)) + return Option.some(get_mouse_look()) Device.Gamepad: var pos = _analog_dir if pos.is_zero_approx():