using System; using Unity.Collections; using UnityEngine; using UnityEngine.UIElements; namespace CrosshairComponents { public class ThreeArmCrosshair : VisualElement { // Need this uxml traits and factory for it to show up in editor public new class UxmlTraits : VisualElement.UxmlTraits { public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc) { base.Init(ve, bag, cc); } } public new class UxmlFactory : UxmlFactory { } static CustomStyleProperty s_TrackColor = new CustomStyleProperty("--track-color"); static CustomStyleProperty s_ProgressColor = new CustomStyleProperty("--progress-color"); Color m_TrackColor = Color.white; Color m_SpeedColor = Color.white; // This is the label that displays the percentage. Label m_Label; // This is the number that the Label displays as a percentage. float m_Speed; public float speed { get => m_Speed; set { // Whenever the progress property changes, MarkDirtyRepaint() is named. This causes a call to the // generateVisualContents callback. m_Speed = value; m_Label.text = Mathf.Clamp(Mathf.Round(value), 0, 100) + "%"; MarkDirtyRepaint(); } } public ThreeArmCrosshair() { // Create a Label, add a USS class name, and add it to this visual tree. m_Label = new Label(); Add(m_Label); // Register a callback after custom style resolution. RegisterCallback(evt => CustomStylesResolved(evt)); // Register a callback to generate the visual content of the control. generateVisualContent += GenerateVisualContent; } static void CustomStylesResolved(CustomStyleResolvedEvent evt) { ThreeArmCrosshair element = (ThreeArmCrosshair)evt.currentTarget; element.UpdateCustomStyles(); } // After the custom colors are resolved, this method uses them to color the meshes and (if necessary) repaint // the control. void UpdateCustomStyles() { bool repaint = false; if (customStyle.TryGetValue(s_ProgressColor, out m_SpeedColor)) repaint = true; if (customStyle.TryGetValue(s_TrackColor, out m_TrackColor)) repaint = true; if (repaint) MarkDirtyRepaint(); } void GenerateVisualContent(MeshGenerationContext context) { float width = contentRect.width; float height = contentRect.height; float length = height / 100; Vector2 centre = new Vector2(width / 2, height / 2); Vector2 centreArm = new Vector2(centre.x, centre.y - length); float angle = (float)(Math.PI / 3); float angleSin = (float)Math.Sin(angle); Vector2 rightArm = new Vector2(centre.x + angleSin * length, centre.y + angleSin * length); Vector2 leftArm = new Vector2(centre.x - angleSin * length, centre.y + angleSin * length); var painter = context.painter2D; painter.lineWidth = 1.0f; painter.lineCap = LineCap.Butt; painter.strokeColor = m_TrackColor; painter.BeginPath(); painter.MoveTo(centre); painter.LineTo(centreArm); painter.Stroke(); painter.BeginPath(); painter.MoveTo(centre); painter.LineTo(rightArm); painter.Stroke(); painter.BeginPath(); painter.MoveTo(centre); painter.LineTo(leftArm); painter.Stroke(); } } public class FourArmCrosshair : VisualElement { // Need this uxml traits and factory for it to show up in editor public new class UxmlTraits : VisualElement.UxmlTraits { public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc) { base.Init(ve, bag, cc); } } public new class UxmlFactory : UxmlFactory { } // These are USS class names for the control overall and the label. public static readonly string ussClassName = "crosshair"; public static readonly string ussLabelClassName = "crosshair__label"; static CustomStyleProperty s_TrackColor = new CustomStyleProperty("--track-color"); static CustomStyleProperty s_ProgressColor = new CustomStyleProperty("--progress-color"); Color m_TrackColor = Color.white; Color m_SpeedColor = Color.white; // This is the label that displays the percentage. Label m_Label; // This is the number that the Label displays as a percentage. float m_Speed; public float speed { get => m_Speed; set { // Whenever the progress property changes, MarkDirtyRepaint() is named. This causes a call to the // generateVisualContents callback. m_Speed = value; m_Label.text = Mathf.Clamp(Mathf.Round(value), 0, 100) + "%"; MarkDirtyRepaint(); } } public FourArmCrosshair() { // Create a Label, add a USS class name, and add it to this visual tree. m_Label = new Label(); Add(m_Label); // Register a callback after custom style resolution. RegisterCallback(evt => CustomStylesResolved(evt)); // Register a callback to generate the visual content of the control. generateVisualContent += GenerateVisualContent; } static void CustomStylesResolved(CustomStyleResolvedEvent evt) { FourArmCrosshair element = (FourArmCrosshair)evt.currentTarget; element.UpdateCustomStyles(); } // After the custom colors are resolved, this method uses them to color the meshes and (if necessary) repaint // the control. void UpdateCustomStyles() { bool repaint = false; if (customStyle.TryGetValue(s_ProgressColor, out m_SpeedColor)) repaint = true; if (customStyle.TryGetValue(s_TrackColor, out m_TrackColor)) repaint = true; if (repaint) MarkDirtyRepaint(); } void GenerateVisualContent(MeshGenerationContext context) { float width = contentRect.width; float height = contentRect.height; float length = height / 100; Vector2 centre = new Vector2(width / 2, height / 2); Vector2 topArm = new Vector2(centre.x, centre.y - length); Vector2 rightArm = new Vector2(centre.x + length, centre.y); Vector2 leftArm = new Vector2(centre.x - length, centre.y); Vector2 bottomArm = new Vector2(centre.x, centre.y + length); var painter = context.painter2D; painter.lineWidth = 1.0f; painter.lineCap = LineCap.Butt; painter.strokeColor = m_TrackColor; painter.BeginPath(); painter.MoveTo(centre); painter.LineTo(topArm); painter.Stroke(); painter.BeginPath(); painter.MoveTo(centre); painter.LineTo(bottomArm); painter.Stroke(); painter.BeginPath(); painter.MoveTo(centre); painter.LineTo(rightArm); painter.Stroke(); painter.BeginPath(); painter.MoveTo(centre); painter.LineTo(leftArm); painter.Stroke(); } } }