using System.Linq; using Godot; namespace KarrotStarterTemplate.Common.CameraController; [GlobalClass] public partial class CharacterCameraController : Node3D { [ExportCategory("Nodes")] [Export] public Node3D characterToFollow { get; set; } [ExportCategory("Properties")] [ExportGroup("Mouse input")] [Export] public bool enableInput = true; [Export] public float mouseSensitivity { get; set; } = .5f; [Export] public Vector2 cameraTiltLimit { get; set; } = new(-45f, 45f); [ExportGroup("Player")] [Export] public bool followPlayer = true; [Export(PropertyHint.Range, "0, 1")] public float followDelay { get; set; } = .5f; [Export] public bool rotatePlayer = true; [Export(PropertyHint.Range, "0, 1")] public float rotateDelay { get; set; } = .5f; private Camera3D _camera; // todo private SpringArm3D _springArm; private Vector2 _mouseInput = Vector2.Zero; public Camera3D camera => _camera; public SpringArm3D springArm => _springArm; // Called when the node enters the scene tree for the first time. public override void _Ready() { if (Engine.IsEditorHint()) { TopLevel = true; return; } characterToFollow ??= (CharacterBody3D)GetParent(); _springArm = GetChildren().OfType().First(); _camera = _springArm.GetChildren().OfType().First(); GlobalPosition = characterToFollow.GlobalPosition; // Input.SetMouseMode(Input.MouseModeEnum.Captured); } public override void _UnhandledInput(InputEvent @event) { if (Engine.IsEditorHint()) { return; } if (!enableInput) { return; } if (@event is InputEventMouseMotion mouseMotion) { _mouseInput = -mouseMotion.Relative * mouseSensitivity; } } public override void _PhysicsProcess(double delta) { if (Engine.IsEditorHint()) { return; } if (followPlayer) { float weight = Mathf.Clamp(20 * (1 - followDelay) * (float)delta, 0,1 ); GlobalPosition = followDelay > 0 ? GlobalPosition.Lerp(characterToFollow.GlobalPosition, weight) : characterToFollow.GlobalPosition; } if (rotatePlayer) { float weight = Mathf.Clamp(20 * (1 - rotateDelay) * (float)delta, 0,1 ); Vector3 v = characterToFollow.GlobalRotation; characterToFollow.GlobalRotation = new Vector3(v.X, Mathf.LerpAngle(v.Y, _springArm.GlobalRotation.Y, weight) , v.Z); } if (enableInput) { _springArm.Rotation += new Vector3(_mouseInput.Y * (float)delta, 0f, 0f); Rotation += new Vector3(0f, _mouseInput.X * (float)delta, characterToFollow.GlobalPosition.Y); var (x, y, z) = _springArm.RotationDegrees; _springArm.RotationDegrees = new Vector3(Mathf.Clamp(x, cameraTiltLimit.X, cameraTiltLimit.Y), y, z); _mouseInput = Vector2.Zero; } } // Called every frame. 'delta' is the elapsed time since the previous frame. public override void _Process(double delta) { if (Engine.IsEditorHint()) { return; } if (Input.IsActionJustPressed("click")) { var position2D = GetViewport().GetMousePosition(); var dropPlane = new Plane(new Vector3(0, 10f, 0), 0f); var position3D = dropPlane.IntersectsRay(camera.ProjectRayOrigin(position2D), camera.ProjectRayNormal(position2D)); if (position3D != null) { GD.Print(position3D); DebugDraw3D.DrawSphere(position3D ?? Vector3.Zero, .5f, Colors.Aqua, 2f); } } } } /* TODO: 1. Zrobić enuma z presetami if Input.is_action_pressed("click"): var position2D = get_viewport().get_mouse_position() var dropPlane = Plane(Vector3(0, 0, 10), z) var position3D = dropPlane.intersects_ray(camera.project_ray_origin(position2D),camera.project_ray_normal(position2D)) print(position3D) */