From 5dd8dcac4052a0cae2bb8edfeeedede33f455ffa Mon Sep 17 00:00:00 2001 From: Jonathan McCaffrey Date: Sun, 27 Sep 2026 15:08:55 +0000 Subject: [PATCH] AI: Add .NET MAUI star map position editor --- .../ZeroSpace.MapEditor/Views/MapDrawable.cs | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 ZeroSpace/ZeroSpace.MapEditor/Views/MapDrawable.cs diff --git a/ZeroSpace/ZeroSpace.MapEditor/Views/MapDrawable.cs b/ZeroSpace/ZeroSpace.MapEditor/Views/MapDrawable.cs new file mode 100644 index 0000000..e4223e9 --- /dev/null +++ b/ZeroSpace/ZeroSpace.MapEditor/Views/MapDrawable.cs @@ -0,0 +1,77 @@ +using Microsoft.Maui.Graphics; +using ZeroSpace.MapEditor.Models; + +namespace ZeroSpace.MapEditor.Views; + +/// +/// Draws the star map: connection lines between connected systems and +/// one circle per system. Names are intentionally not drawn on the +/// canvas; details live in the inspector. +/// +public sealed class MapDrawable : IDrawable +{ + public const double NodeRadius = 14; + + public IList Nodes { get; set; } = Array.Empty(); + + public Func FindNode { get; set; } = _ => null; + + /// Screen pixels per world unit. + public double Scale { get; set; } = 1; + + public double OffsetX { get; set; } + + public double OffsetY { get; set; } + + public void Draw(ICanvas canvas, RectF dirtyRect) + { + canvas.FillColor = Color.FromArgb("#1e2430"); + canvas.FillRectangle(dirtyRect); + + PointF ToScreen(double worldX, double worldY) => + new((float)(worldX * Scale + OffsetX), (float)(worldY * Scale + OffsetY)); + + // Connections first, so nodes draw on top of the lines. + canvas.StrokeColor = Color.FromArgb("#5b6b82"); + canvas.StrokeSize = Math.Max(1, (float)(1.5 * Scale)); + foreach (var node in Nodes) + { + var from = ToScreen(node.X, node.Y); + foreach (var name in node.Doc.ConnectedSystems) + { + var target = FindNode(name); + if (target is null || ReferenceEquals(target, node)) + { + continue; + } + + var to = ToScreen(target.X, target.Y); + canvas.DrawLine(from, to); + } + } + + foreach (var node in Nodes) + { + var center = ToScreen(node.X, node.Y); + var radius = (float)(NodeRadius * Scale); + + canvas.FillColor = ColorForKind(node.Doc.Kind); + canvas.FillCircle(center, radius); + + if (node.IsSelected) + { + canvas.StrokeColor = Colors.White; + canvas.StrokeSize = 3; + canvas.DrawCircle(center, radius + 6); + } + } + } + + public static Color ColorForKind(string kind) => kind switch + { + "Homeworld" => Color.FromArgb("#43a047"), + "Core" => Color.FromArgb("#fb8c00"), + "Side" => Color.FromArgb("#4a90d9"), + _ => Color.FromArgb("#9aa5b1"), + }; +}