|
| 1 | +using OpenCvSharp; |
| 2 | +using EliteAI.Capture; |
| 3 | +using EliteAI.Input; |
| 4 | + |
| 5 | +namespace EliteAI; |
| 6 | + |
| 7 | +/// <summary> |
| 8 | +/// Autopilot program with navball/target detection and flight control |
| 9 | +/// </summary> |
| 10 | +public class AutopilotProgram |
| 11 | +{ |
| 12 | + public static void Run() |
| 13 | + { |
| 14 | + var regions = new ScreenRegions( |
| 15 | + EliteAI.Capture.ScreenCapture.ScreenWidth, |
| 16 | + EliteAI.Capture.ScreenCapture.ScreenHeight); |
| 17 | + |
| 18 | + // Only load templates for non-navball regions (navball uses circle detection) |
| 19 | + regions.LoadTemplates(); |
| 20 | + |
| 21 | + // Create target detector (handles both target marker and navball) |
| 22 | + var target = regions.CreateTarget(); |
| 23 | + |
| 24 | + // Create autopilot (0.05 = 5% deadzone) |
| 25 | + var autopilot = new SimpleAutopilot(deadzone: 0.05f); |
| 26 | + bool autopilotEnabled = false; |
| 27 | + |
| 28 | + // Create global hotkey for 'P' (VK_P = 0x50) |
| 29 | + var toggleHotkey = new GlobalHotkey(0x50); |
| 30 | + |
| 31 | + Console.WriteLine("Press 'P' to toggle autopilot (works from any window!), 'q' to quit"); |
| 32 | + |
| 33 | + while (true) |
| 34 | + { |
| 35 | + using var frame = EliteAI.Capture.ScreenCapture.GetFrame(); |
| 36 | + |
| 37 | + // Get the best available target (tries target marker first, falls back to navball) |
| 38 | + var aimResult = target.AimAtTarget(frame); |
| 39 | + |
| 40 | + // Visualization: Draw navball if detected |
| 41 | + var navballCircle = target.GetNavballCircle(frame); |
| 42 | + if (navballCircle != null) |
| 43 | + { |
| 44 | + // Draw the detected navball circle |
| 45 | + Cv2.Circle(frame, (Point)navballCircle.Center, (int)navballCircle.Radius, Scalar.LimeGreen, 2); |
| 46 | + Cv2.Circle(frame, (Point)navballCircle.Center, 2, Scalar.Red, 3); // Center point |
| 47 | + |
| 48 | + // If using navball for aiming, show the target dot |
| 49 | + if (aimResult.HasValue && aimResult.Value.source == "Navball") |
| 50 | + { |
| 51 | + var (x, y, _) = aimResult.Value; |
| 52 | + var targetScreenX = navballCircle.Center.X + (x * navballCircle.Radius); |
| 53 | + var targetScreenY = navballCircle.Center.Y + (y * navballCircle.Radius); |
| 54 | + |
| 55 | + Cv2.Circle(frame, new Point((int)targetScreenX, (int)targetScreenY), 5, Scalar.Cyan, -1); |
| 56 | + |
| 57 | + // Show blue filter debug window |
| 58 | + var center = navballCircle.Center; |
| 59 | + var radius = navballCircle.Radius; |
| 60 | + var regionSize = (int)(radius * 2.2); |
| 61 | + var regionLeft = (int)(center.X - regionSize / 2); |
| 62 | + var regionTop = (int)(center.Y - regionSize / 2); |
| 63 | + regionLeft = Math.Max(0, Math.Min(regionLeft, EliteAI.Capture.ScreenCapture.ScreenWidth - regionSize)); |
| 64 | + regionTop = Math.Max(0, Math.Min(regionTop, EliteAI.Capture.ScreenCapture.ScreenHeight - regionSize)); |
| 65 | + |
| 66 | + var debugRect = new Rect(regionLeft, regionTop, regionSize, regionSize); |
| 67 | + using var navballRegion = new Mat(frame, debugRect); |
| 68 | + using var blueFiltered = Filters.FilterByColor(navballRegion, Filters.BlueColorRange); |
| 69 | + Cv2.ImShow("Blue Filtered (Target Dot)", blueFiltered); |
| 70 | + } |
| 71 | + } |
| 72 | + |
| 73 | + // Visualization: Draw target marker if detected (regardless of being used) |
| 74 | + var targetMarkerPos = target.GetTargetMarker(frame); |
| 75 | + if (targetMarkerPos.HasValue) |
| 76 | + { |
| 77 | + var (x, y) = targetMarkerPos.Value; |
| 78 | + var screenCenterX = EliteAI.Capture.ScreenCapture.ScreenWidth / 2f; |
| 79 | + var screenCenterY = EliteAI.Capture.ScreenCapture.ScreenHeight / 2f; |
| 80 | + |
| 81 | + // Calculate target position from normalized coordinates |
| 82 | + var targetScreenX = screenCenterX + (x * screenCenterX * 0.5f); |
| 83 | + var targetScreenY = screenCenterY + (y * screenCenterY * 0.5f); |
| 84 | + |
| 85 | + // Draw the detected target marker (magenta circle) |
| 86 | + Cv2.Circle(frame, new Point((int)targetScreenX, (int)targetScreenY), 10, Scalar.Magenta, 3); |
| 87 | + |
| 88 | + // Draw crosshair at screen center |
| 89 | + Cv2.Line(frame, new Point((int)screenCenterX - 20, (int)screenCenterY), |
| 90 | + new Point((int)screenCenterX + 20, (int)screenCenterY), Scalar.Yellow, 2); |
| 91 | + Cv2.Line(frame, new Point((int)screenCenterX, (int)screenCenterY - 20), |
| 92 | + new Point((int)screenCenterX, (int)screenCenterY + 20), Scalar.Yellow, 2); |
| 93 | + } |
| 94 | + |
| 95 | + // Debug: Show Target search region and filtered view |
| 96 | + var targetRegion = regions.Regions[RegionName.Target]; |
| 97 | + var targetRect = targetRegion.GetRect(EliteAI.Capture.ScreenCapture.ScreenWidth, EliteAI.Capture.ScreenCapture.ScreenHeight); |
| 98 | + Cv2.Rectangle(frame, targetRect, Scalar.Orange, 1); |
| 99 | + |
| 100 | + // Show the orange-filtered region being used for detection |
| 101 | + using var targetSearchRegion = new Mat(frame, targetRect); |
| 102 | + using var orangeFiltered = Filters.FilterByColor(targetSearchRegion, Filters.Orange2ColorRange); |
| 103 | + Cv2.ImShow("Target Orange Filtered", orangeFiltered); |
| 104 | + |
| 105 | + // Update autopilot with the best available target |
| 106 | + if (aimResult.HasValue) |
| 107 | + { |
| 108 | + var (x, y, source) = aimResult.Value; |
| 109 | + |
| 110 | + if (autopilotEnabled) |
| 111 | + { |
| 112 | + autopilot.Update(x, y); |
| 113 | + Console.WriteLine($"{source}: Target=({x:F2}, {y:F2}) | AUTOPILOT ACTIVE"); |
| 114 | + } |
| 115 | + else |
| 116 | + { |
| 117 | + Console.WriteLine($"{source}: Target=({x:F2}, {y:F2})"); |
| 118 | + } |
| 119 | + } |
| 120 | + else |
| 121 | + { |
| 122 | + Console.WriteLine("No target detected"); |
| 123 | + if (autopilotEnabled) |
| 124 | + autopilot.Stop(); |
| 125 | + } |
| 126 | + |
| 127 | + // Draw region bounds |
| 128 | + var searchRect = target.SearchRegion; |
| 129 | + Cv2.Rectangle(frame, searchRect, new Scalar(0, 255, 255), 1); |
| 130 | + |
| 131 | + // Draw autopilot status |
| 132 | + var statusLabel = autopilotEnabled ? "AUTOPILOT: ON (P to disable)" : "AUTOPILOT: OFF (P to enable)"; |
| 133 | + Cv2.PutText(frame, statusLabel, new Point(10, 30), |
| 134 | + HersheyFonts.HersheySimplex, 0.7, autopilotEnabled ? Scalar.LimeGreen : Scalar.Red, 2); |
| 135 | + |
| 136 | + // Show full screen at 50% size |
| 137 | + using var resizedFrame = new Mat(); |
| 138 | + Cv2.Resize(frame, resizedFrame, new Size(), 0.5, 0.5); |
| 139 | + Cv2.ImShow("NavBall Target Detection", resizedFrame); |
| 140 | + |
| 141 | + // Check for global hotkey press |
| 142 | + if (toggleHotkey.WasPressed()) |
| 143 | + { |
| 144 | + autopilotEnabled = !autopilotEnabled; |
| 145 | + if (!autopilotEnabled) |
| 146 | + autopilot.Stop(); |
| 147 | + Console.WriteLine($"Autopilot {(autopilotEnabled ? "ENABLED" : "DISABLED")}"); |
| 148 | + } |
| 149 | + |
| 150 | + // Wait 1ms for key press (for 'q' to quit) |
| 151 | + var key = Cv2.WaitKey(1); |
| 152 | + |
| 153 | + // Break on 'q' or ESC |
| 154 | + if (key is 'q' or 27) break; |
| 155 | + } |
| 156 | + |
| 157 | + // Clean up |
| 158 | + autopilot.Stop(); |
| 159 | + regions.DisposeTemplates(); |
| 160 | + Cv2.DestroyAllWindows(); |
| 161 | + Console.WriteLine("Autopilot stopped."); |
| 162 | + } |
| 163 | +} |
0 commit comments