using Godot; using System; using SJK.Math; public partial class RTSCamera : Node3D { [Export] public Camera3D camera; Vector3 positionStartPos; Vector3 positionOffsetPos; Vector3 lastTransalation; Vector3 cameraTargetOffset; Action Update_CurrentFunc; //Generic bookkeeping variables; Vector2 LastMousePostition; //Camera Dragging Bookkeeping variables Vector3 LastMouseGroundPlanePositon; //Camera Rotating Bookkeeping variables float CameraRotateSpeed = .5f; bool isDraging; public override void _Ready() { Update_CurrentFunc = Update_DetectModeStart; } void Update_DetectModeStart() { if (Input.IsActionJustPressed("move_mouse")) { //Mouse Left went Down //Does nothing basicly } else if (Input.IsActionPressed("move_mouse") && GetViewport().GetMousePosition() != LastMousePostition) { LastMouseGroundPlanePositon = camera.MouseToGroundPlane() ?? Vector3.Zero; Update_CurrentFunc = Update_CameraDrag; Update_CurrentFunc(); // GD.Print("1"); } else if (Input.IsActionPressed("camera_rotate") && GetViewport().GetMousePosition() != LastMousePostition) { LastMouseGroundPlanePositon = camera.MouseToGroundPlane() ?? Vector3.Zero; Update_CurrentFunc = Update_RotateCamera; Update_CurrentFunc(); // GD.Print("2"); } } public override void _Process(double delta) { if (Input.IsActionJustPressed("ui_cancel")) { CancelUpdateFunc(); } GD.PrintS(positionStartPos,positionOffsetPos,lastTransalation,LastMouseGroundPlanePositon,LastMousePostition,cameraTargetOffset,scrollAmount); Update_CurrentFunc(); Update_CameraScroll((float)delta); LastMousePostition = GetViewport().GetMousePosition(); camera.Fov = Mathf.Lerp(camera.Fov, Mathf.Lerp(90, 50, (camera.Position.Y - 5) / (80 - 5)), (float)delta * 10); } void CancelUpdateFunc() { Update_CurrentFunc = Update_DetectModeStart; } void Update_CameraDrag() { if (Input.IsActionJustReleased("move_mouse")) { CancelUpdateFunc(); } var hitpos = camera.MouseToGroundPlane() ?? Vector3.Zero; var diff = LastMouseGroundPlanePositon - hitpos; GlobalTranslate(diff); LastMouseGroundPlanePositon = hitpos = camera.MouseToGroundPlane() ?? Vector3.Zero; } float scrollAmount; public override void _UnhandledInput(InputEvent @event) { scrollAmount += Input.IsActionJustReleased("mouse_scroll_up") ? 1 : 0; scrollAmount += Input.IsActionJustReleased("mouse_scroll_down") ? -1 : 0; if (@event is InputEventKey eventKey && eventKey.Keycode == Key.F) { GlobalPosition = Vector3.Zero; camera.Position = Vector3.Zero; CancelUpdateFunc(); } } void Update_CameraScroll(float delta) { // Zoom to scrollwheel // float scrollAmount = Input.IsActionJustReleased("mouse_scroll_up")?1:0; // scrollAmount += Input.IsActionJustReleased( "mouse_scroll_down")?-1:0; // GD.Print(scrollAmount); float minHeight = 2; float maxHeight = 30; // Move camera towards hitPos // var hitPos = camera.MouseToGroundPlane(); // Vector3 dir = hitPos - camera.Translation; var dir = -camera.GlobalTransform.Basis.Z * .5f; var p = camera.Position; // Stop zooming out at a certain distance. // TODO: Maybe you should still slide around at 20 zoom? if (scrollAmount > 0 || p.Y < (maxHeight - 0.1f)) { cameraTargetOffset += dir * scrollAmount; } DebugDraw3D.DrawArrow(Vector3.Zero,cameraTargetOffset); Vector3 lastCameraPosition = camera.Position; camera.Position = camera.Position.Lerp(camera.Position + cameraTargetOffset, delta); cameraTargetOffset -= camera.Position - lastCameraPosition; p = camera.Position; if (p.Y < minHeight) { p.Y = minHeight; } if (p.Y > maxHeight) { p.Y = maxHeight; } camera.Position = p; // Change camera angle camera.RotationDegrees = new Vector3( Mathf.Lerp(-50, -75, camera.Position.Y / maxHeight), camera.RotationDegrees.Y, camera.RotationDegrees.Z ); scrollAmount = 0; } void Update_RotateCamera() { if (!Input.IsActionPressed("move_mouse")) { CancelUpdateFunc(); } Vector2 hitpos = GetViewport().GetMousePosition(); Vector2 diff = LastMousePostition - hitpos; camera.RotationDegrees = new Vector3( camera.RotationDegrees.X, camera.RotationDegrees.Y + (diff.X * CameraRotateSpeed), camera.RotationDegrees.Z ); LastMousePostition = hitpos = GetViewport().GetMousePosition(); } } public static partial class SJKMath { public static Vector3? MouseToPlane(this Plane plane, Camera3D viewCamera, Vector2? mousePos = null) { var from = viewCamera.ProjectRayOrigin( mousePos ?? viewCamera.GetViewport().GetMousePosition()); var normal = viewCamera.ProjectRayNormal(mousePos ?? viewCamera.GetViewport().GetMousePosition()); return plane.IntersectsRay(from, normal); } public static Vector3? MouseToGroundPlane(this Camera3D viewCamera, Vector2? mousePos = null, float offset = 0) => (Plane.PlaneXZ with { D = offset }).MouseToPlane(viewCamera, mousePos); }