Danro/Assets/Scripts/Editor/MouseWorldPositionOverlay.cs
Danil Iarosh 6b02c76ef3
Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Has been cancelled
refactor: LightController + LightSequence, протокол 85XXYY, namespace
LightController / LightMode:
- Новый LightMode.cs: enum эффектов под протокол 85XXYY (13 эффектов + Off)
  значения enum = коды команд XX, Off=-1 генерирует просто '85'
- Новый LightController.cs: управление подсветкой платы
  * SetLight(mode, duration) → строит команду 85XXYY, возвращает LightSequence
  * Blink() / StopBlink() / SetBlinkInterval() — мигание шляпы
  * StopSequence() / StopAllEffects() — остановка эффектов
  * Все параметры (hatOn/hatOff, blinkInterval, defaultMode/Duration) в инспекторе
- Вложенный класс LightSequence — builder цепочек эффектов:
  SetLight(A,3).Then(B,3).Then(C,3).Loop()
  SetLight(A,3).Then(LightMode.Off)
  SetLight(A,5) — одиночный эффект
GameManager:
- Добавлено свойство Light (→ Plate.Light)
- GameWin   → SetLight(FinalWave, 30)
- GameOver  → SetLight(BlueWave, 30)
- NewGame   → SetLight(Rainbow, 99)
- LoadScene MainMenu → SetLight(Off) + Blink()
namespace (добавлены в файлы без namespace):
- Editor/MouseWorldPositionOverlay.cs  → RR.Common.InspectorOverrides
- UI/StatsWindowUIController.cs        → RR.Common.UI
- Utilities/AdvancedLogging_Test.cs    → RR.Common.Utility
- Utilities/DebugSettings.cs           → RR.Common.Utility
2026-02-19 16:52:59 +03:00

140 lines
4.4 KiB
C#

#if UNITY_EDITOR && UNITY_2021_2_OR_NEWER
using UnityEditor;
using UnityEditor.Overlays;
using UnityEngine;
using UnityEngine.UIElements;
namespace RR.Common.InspectorOverrides
{
[Overlay(typeof(SceneView), id: "mouse-world-position", displayName: "Mouse World Position")]
[Icon("d_Grid.BoxTool")]
public class MouseWorldPositionOverlay : Overlay
{
private enum PlaneMode { XY, XZ, YZ, CameraFacing }
private static readonly float[] Multipliers = { 1f, 10f, 100f, 1000f, 10000f, 100000f, 1000000f };
private PlaneMode planeMode = PlaneMode.XY;
private float planeOffset;
private int decimals = 2;
private Vector3 displayWorld;
private bool hasPoint;
private Label positionLabel;
public override void OnCreated()
{
SceneView.duringSceneGui += OnSceneGUI;
}
public override void OnWillBeDestroyed()
{
SceneView.duringSceneGui -= OnSceneGUI;
}
public override VisualElement CreatePanelContent()
{
VisualElement root = new() { style = { minWidth = 220 } };
// Плоскость
EnumField planeModeField = new("Плоскость", planeMode);
planeModeField.RegisterValueChangedCallback(evt => planeMode = (PlaneMode)evt.newValue);
root.Add(planeModeField);
// Смещение
FloatField offsetField = new("Смещение") { value = planeOffset };
offsetField.RegisterValueChangedCallback(evt => planeOffset = evt.newValue);
root.Add(offsetField);
// Знаки после запятой
SliderInt decimalsSlider = new("Знаки", 0, 6) { value = decimals, showInputField = true };
decimalsSlider.RegisterValueChangedCallback(evt => decimals = evt.newValue);
root.Add(decimalsSlider);
// Позиция (только для чтения)
positionLabel = new Label("—") { style = { marginTop = 8, unityFontStyleAndWeight = FontStyle.Bold } };
root.Add(positionLabel);
// Кнопка копирования
Button copyButton = new(() =>
{
if (!hasPoint) return;
string f = "F" + decimals;
EditorGUIUtility.systemCopyBuffer = $"{displayWorld.x.ToString(f)}, {displayWorld.y.ToString(f)}, {displayWorld.z.ToString(f)}";
}) { text = "Копировать (x,y,z)" };
root.Add(copyButton);
return root;
}
private void OnSceneGUI(SceneView sv)
{
if (containerWindow != sv) return;
Event e = Event.current;
if (e == null) return;
if (e.type != EventType.MouseMove && e.type != EventType.MouseDrag && e.type != EventType.Repaint)
return;
Ray ray = HandleUtility.GUIPointToWorldRay(e.mousePosition);
hasPoint = TryGetPoint(ray, sv.camera, out Vector3 world);
if (hasPoint)
{
float mult = Multipliers[decimals];
displayWorld = new Vector3(
Mathf.Ceil(world.x * mult) / mult,
Mathf.Ceil(world.y * mult) / mult,
Mathf.Ceil(world.z * mult) / mult
);
string f = "F" + decimals;
positionLabel?.schedule.Execute(() =>
positionLabel.text = $"X:{displayWorld.x.ToString(f)} Y:{displayWorld.y.ToString(f)} Z:{displayWorld.z.ToString(f)}"
);
}
else
{
positionLabel?.schedule.Execute(() => positionLabel.text = "—");
}
}
private bool TryGetPoint(Ray ray, Camera cam, out Vector3 world)
{
Plane plane;
switch (planeMode)
{
case PlaneMode.XY:
plane = new Plane(Vector3.forward, new Vector3(0f, 0f, planeOffset));
break;
case PlaneMode.XZ:
plane = new Plane(Vector3.up, new Vector3(0f, planeOffset, 0f));
break;
case PlaneMode.YZ:
plane = new Plane(Vector3.right, new Vector3(planeOffset, 0f, 0f));
break;
case PlaneMode.CameraFacing:
default:
plane = new Plane(cam.transform.forward, cam.transform.position);
break;
}
if (plane.Raycast(ray, out float enter))
{
world = ray.GetPoint(enter);
return true;
}
world = default;
return false;
}
}
} // namespace RR.Common.InspectorOverrides
#endif