From 0d9694736632bb3df1db3003ad932d28e12f7218 Mon Sep 17 00:00:00 2001 From: copygirl Date: Thu, 3 Oct 2024 22:36:43 +0200 Subject: [PATCH] Implement our own spring-arm-like functionality --- player/CameraController.cs | 50 +++++++++++++++++++++++++++++--------- player/character.tscn | 20 +++++---------- 2 files changed, 44 insertions(+), 26 deletions(-) diff --git a/player/CameraController.cs b/player/CameraController.cs index aca0b83..8991845 100644 --- a/player/CameraController.cs +++ b/player/CameraController.cs @@ -1,28 +1,29 @@ -public partial class CameraController : SpringArm3D +public partial class CameraController : Camera3D { - [Export] public float MovementSmoothing { get; set; } = 8.0f; + [ExportCategory("Follow")] + [Export] public float FollowDistance { get; set; } = 1.2f; + [Export] public float FollowYOffset { get; set; } = 1.0f; + [Export] public float FollowSmoothing { get; set; } = 12.0f; + [ExportCategory("Rotation")] [Export] public Vector2 MouseSensitivity { get; set; } = new(0.2f, 0.2f); // Degrees per pixel. - - [Export] public float PitchMinimum { get; set; } = 30; - [Export] public float PitchMaximum { get; set; } = 65; + [Export] public float PitchMinimum { get; set; } = 20; + [Export] public float PitchMaximum { get; set; } = 65; [Export] public float PitchSmoothing { get; set; } = 12.0f; - // FIXME: Fix the "snappyness" when moving slowly. - // FIXME: Fix spring arm clipping through terrain and similar. // TODO: Gradually return to maximum spring length. // TODO: Turn player transparent as the camera moves closer. public static bool IsMouseCaptured => Input.MouseMode == Input.MouseModeEnum.Captured; - Vector3 _offset; Node3D _player; + Vector3 _smoothPlayerPos; public override void _Ready() { - _offset = Position; _player = this.GetParentOrThrow(); - Transform = _player.GlobalTransform.Translated(_offset); + _smoothPlayerPos = _player.GlobalPosition; + Transform = _player.GlobalTransform.Translated(new(0.0f, FollowYOffset, 0.0f)); } public override void _Input(InputEvent ev) @@ -56,10 +57,35 @@ public partial class CameraController : SpringArm3D RotationDegrees = new(pitch, yaw, 0); } - public override void _Process(double delta) + public override void _PhysicsProcess(double delta) { - Position = Position.Damp(_offset + _player.GlobalPosition, MovementSmoothing, delta); + _smoothPlayerPos = _smoothPlayerPos.Damp(_player.GlobalPosition, FollowSmoothing, delta); + + var target = _smoothPlayerPos + + Basis.Z * FollowDistance + + Vector3.Up * FollowYOffset; + Position = OffsetRayIntersection(_smoothPlayerPos, target, 0.2f); + } + + Vector3 OffsetRayIntersection(Vector3 from, Vector3 to, float margin) + { + const PhysicsLayer CollisionMask = PhysicsLayer.Terrain + | PhysicsLayer.Objects; + var query = PhysicsRayQueryParameters3D.Create(from, to, (uint)CollisionMask); + var result = GetWorld3D().DirectSpaceState.IntersectRay(query); + if (result.Count > 0) { + var hit = (Vector3)result["position"]; + var safeDistance = Max(0, from.DistanceTo(hit) - margin); + return from + (to - from).Normalized() * safeDistance; + } else { + // No intersection occured, + return to; + } + } + + public override void _Process(double delta) + { var pitch = RotationDegrees.X; var (min, max) = (-PitchMaximum, -PitchMinimum); if (pitch < min) pitch = pitch.Damp(min, PitchSmoothing, delta); diff --git a/player/character.tscn b/player/character.tscn index 357099e..0264925 100644 --- a/player/character.tscn +++ b/player/character.tscn @@ -20,26 +20,18 @@ collision_mask = 3 floor_max_angle = 0.698132 [node name="MeshInstance3D" type="MeshInstance3D" parent="."] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.15, 0) mesh = SubResource("SphereMesh_7ljg8") [node name="CollisionShape3D" type="CollisionShape3D" parent="."] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.2, 0) +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.05, 0) shape = SubResource("SphereShape3D_6qbb2") -[node name="MovementController" type="Node" parent="."] -script = ExtResource("1_akh08") - -[node name="CameraArm" type="SpringArm3D" parent="."] -transform = Transform3D(1, 0, 0, 0, 0.766044, 0.642788, 0, -0.642788, 0.766044, 0, 0.1, 0) +[node name="Camera" type="Camera3D" parent="."] top_level = true -collision_mask = 3 -spring_length = 2.0 -margin = 0.05 -script = ExtResource("2_2din1") - -[node name="Camera" type="Camera3D" parent="CameraArm"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 2) current = true size = 4.5 far = 500.0 +script = ExtResource("2_2din1") + +[node name="MovementController" type="Node" parent="."] +script = ExtResource("1_akh08")