diff --git a/Assets/Scripts/Controls/Inputs/ComSystem/ComWrapper.cs b/Assets/Scripts/Controls/Inputs/ComSystem/ComWrapper.cs
index 7879c8b..0fea2c1 100644
--- a/Assets/Scripts/Controls/Inputs/ComSystem/ComWrapper.cs
+++ b/Assets/Scripts/Controls/Inputs/ComSystem/ComWrapper.cs
@@ -1,12 +1,10 @@
using System;
-using System.Collections;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using RR.Game2D.Core.Managers;
using UnityEngine;
using UnityEngine.Events;
-using Random = UnityEngine.Random;
namespace RR.Common.Controls
{
@@ -30,7 +28,6 @@ namespace RR.Common.Controls
#region Приватные поля
private const string REQUEST_INPUT = "91";
- private const string LIGHTSIGNAL_PREFIX = "80";
private static int h; // идентификатор хэндла
private static readonly object bufferLock = new object(); // Блокировка для синхронизации доступа к COM-порту
@@ -55,7 +52,11 @@ namespace RR.Common.Controls
// ВАЖНО: 0 = кнопка нажата, 1 = кнопка отпущена, поэтому по умолчанию все единицы
private static string lastInputBits = "11111111111111111111111111"; // 26 бит по умолчанию
- private Coroutine blinkingCoroutine;
+ // Контроллер подсветки (добавляется автоматически вместе с этим компонентом)
+ private LightController _light;
+
+ /// Доступ к контроллеру подсветки.
+ public LightController Light => _light;
#endregion
@@ -83,11 +84,14 @@ namespace RR.Common.Controls
if (!saveMoneyBetweenSessions) PlayerPrefs.SetInt("CoinsCount", 0);
CreditsCount = PlayerPrefs.GetInt("CoinsCount", 0);
+ // Получаем или создаём LightController
+ _light = GetComponent() ?? gameObject.AddComponent();
+
initPort();
// Отправляем сигнал запуска игры
Send("2171");
- Blink();
+ _light.Blink();
// Запускаем асинхронный опрос порта
pollCancellationTokenSource = new CancellationTokenSource();
@@ -146,47 +150,6 @@ namespace RR.Common.Controls
}
}
- ///
- /// Отправляет команду управления подсветкой на периферийную плату.
- ///
- /// Режим подсветки из перечисления LightMode
- ///
- /// Формирует команду вида "80XXX" где XXX - код режима подсветки.
- /// Для добавления новых режимов необходимо обновить вложенный метод getLightString + добавить режим в перечисление.
- ///
- public static void Send(LightMode lightMode)
- {
- try
- {
- string signal = LIGHTSIGNAL_PREFIX + getLightString(lightMode);
- Send(signal);
-
- //ВОТЭТОТ МЕТОД ПОД СВОИ ПОДСВЕТКИ НАДО ПОДГОНЯТЬ
- string getLightString(LightMode mode) =>
-
- mode switch
- {
- LightMode.Idle1 => "500",
- LightMode.Idle2 => "507",
- LightMode.Orange => "501",
- LightMode.Blue => "502",
- LightMode.Win => "503",
- LightMode.Lose => "504",
- LightMode.Prize => "505",
- LightMode.Tama => "513",
- LightMode.Dog => "514",
- LightMode.Sam => "515",
- LightMode.Mistress => "516",
-
- _ => "500"
- };
-
- }
- catch
- {
- // DebugWindow.Message("Ошибка отправки светового сигнала.");
- }
- }
///
/// Выполняет списание платы за запуск игры.
@@ -231,22 +194,16 @@ namespace RR.Common.Controls
return false;
}
- public void Blink()
- {
- StopBlink();
-
- blinkingCoroutine = StartCoroutine(BlinkingCoroutine());
-
-
- }
-
- public void StopBlink(bool enableHat = true)
- {
- if (blinkingCoroutine != null) StopCoroutine(blinkingCoroutine);
- blinkingCoroutine = null;
- Send(enableHat ? "2131" : "2130"); // включаем или выключаем шляпу
- }
-
+ ///
+ /// Запускает мигание подсветки. Делегируется в .
+ ///
+ public void Blink() => _light.Blink();
+
+ ///
+ /// Останавливает мигание подсветки. Делегируется в .
+ ///
+ public void StopBlink(bool enableHat = true) => _light.StopBlink(enableHat);
+
///
/// Получаем текущий баланс кредитов
///
@@ -651,34 +608,8 @@ namespace RR.Common.Controls
}
}
- private static IEnumerator BlinkingCoroutine()
- {
- while (true)
- {
- float randomFloat = Random.Range(0f, 1f);
-
- Send(randomFloat < 0.5f ? "2130" : "2131");
-
- yield return new WaitForSeconds(0.5f);
- }
- }
-
#endregion
}
- public enum LightMode
- {
- Idle1,
- Idle2,
- Orange,
- Blue,
- Win,
- Lose,
- Prize,
- Tama,
- Dog,
- Sam,
- Mistress
- }
}
diff --git a/Assets/Scripts/Controls/Inputs/ComSystem/LightController.cs b/Assets/Scripts/Controls/Inputs/ComSystem/LightController.cs
new file mode 100644
index 0000000..21b9607
--- /dev/null
+++ b/Assets/Scripts/Controls/Inputs/ComSystem/LightController.cs
@@ -0,0 +1,265 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using Random = UnityEngine.Random;
+
+namespace RR.Common.Controls
+{
+ ///
+ /// Управляет подсветкой периферийной платы по протоколу 85XXYY:
+ ///
+ /// - XX — код эффекта ()
+ /// - YY — время в секундах (00–99)
+ ///
+ /// Команда 85 (без параметров) отключает рендеринг и освобождает память.
+ /// Поддерживает цепочки эффектов через :
+ ///
+ /// SetLight(LightMode.VerticalWave, 3).Then(LightMode.DiagonalWave, 3).Loop();
+ ///
+ ///
+ public class LightController : MonoBehaviour
+ {
+ // ───────────────────────── Инспектор ─────────────────────────
+
+ [Header("Команды шляпы")]
+ [Tooltip("COM-команда для включения шляпы")]
+ [SerializeField] private string hatOnCommand = "2131";
+ [Tooltip("COM-команда для выключения шляпы")]
+ [SerializeField] private string hatOffCommand = "2130";
+
+ [Header("Мигание")]
+ [Tooltip("Интервал между переключениями при мигании (секунды)")]
+ [SerializeField] [Range(0.05f, 5f)] private float blinkInterval = 0.5f;
+ [Tooltip("Случайный разброс интервала (±секунды). 0 = строго равномерно")]
+ [SerializeField] [Range(0f, 2f)] private float blinkIntervalVariance;
+
+ [Header("Световые эффекты")]
+ [Tooltip("Эффект по умолчанию при вызове SetLight без аргументов")]
+ [SerializeField] private LightMode defaultLightMode = LightMode.Rainbow;
+ [Tooltip("Время эффекта по умолчанию (секунды, 0–99)")]
+ [SerializeField] [Range(0, 99)] private int defaultDuration = 3;
+
+ // ───────────────────────── Приватное состояние ─────────────────────────
+
+ private Coroutine _blinkingCoroutine;
+ private LightSequence _activeSequence;
+
+ private const string EffectPrefix = "85";
+
+ // ───────────────────────── Свойства ─────────────────────────
+
+ /// Время эффекта по умолчанию (используется в ).
+ public int DefaultDuration => defaultDuration;
+
+ // ===========================start: PUBLIC API===========================
+
+ ///
+ /// Включает эффект по умолчанию и возвращает для построения цепочки.
+ ///
+ public LightSequence SetLight() => SetLight(defaultLightMode, defaultDuration);
+
+ ///
+ /// Включает эффект на время по умолчанию и возвращает для построения цепочки.
+ ///
+ public LightSequence SetLight(LightMode mode) => SetLight(mode, defaultDuration);
+
+ ///
+ /// Включает световой эффект на указанное время и возвращает для построения цепочки.
+ /// Если вызвать без .Then() / .Loop() — эффект запустится немедленно как одиночный.
+ ///
+ /// Эффект подсветки
+ /// Время эффекта (0–99 секунд)
+ public LightSequence SetLight(LightMode mode, int durationSeconds)
+ {
+ StopSequence();
+ _activeSequence = new LightSequence(this, mode, durationSeconds);
+ _activeSequence.Play();
+ return _activeSequence;
+ }
+
+ ///
+ /// Останавливает текущую активную последовательность эффектов и отключает рендеринг.
+ ///
+ public void StopSequence()
+ {
+ _activeSequence?.Stop();
+ _activeSequence = null;
+ }
+
+ ///
+ /// Останавливает все эффекты и отключает рендеринг платы (85).
+ ///
+ public void StopAllEffects()
+ {
+ StopSequence();
+ ComWrapper.Send(EffectPrefix);
+ }
+
+ ///
+ /// Запускает мигание шляпы с настроенным интервалом.
+ ///
+ public void Blink() => Blink(blinkInterval);
+
+ ///
+ /// Запускает мигание шляпы с явно указанным интервалом.
+ ///
+ public void Blink(float interval)
+ {
+ StopBlink(enableHat: false);
+ _blinkingCoroutine = StartCoroutine(BlinkingCoroutine(interval));
+ }
+
+ ///
+ /// Меняет интервал мигания на лету; перезапускает мигание, если оно активно.
+ ///
+ public void SetBlinkInterval(float interval)
+ {
+ blinkInterval = Mathf.Max(0.05f, interval);
+ if (_blinkingCoroutine != null) Blink(blinkInterval);
+ }
+
+ ///
+ /// Останавливает мигание шляпы.
+ ///
+ /// Оставить шляпу включённой после остановки
+ public void StopBlink(bool enableHat = true)
+ {
+ if (_blinkingCoroutine != null)
+ {
+ StopCoroutine(_blinkingCoroutine);
+ _blinkingCoroutine = null;
+ }
+
+ ComWrapper.Send(enableHat ? hatOnCommand : hatOffCommand);
+ }
+
+ /// Возвращает true, если мигание шляпы сейчас активно.
+ public bool IsBlinking => _blinkingCoroutine != null;
+
+ /// Возвращает true, если последовательность эффектов сейчас активна.
+ public bool IsSequencePlaying => _activeSequence?.IsPlaying ?? false;
+
+ // ===========================end: PUBLIC API===========================
+
+ ///
+ /// Отправляет COM-команду для одного шага последовательности.
+ /// Используется из .
+ ///
+ public void SendCommand(LightMode mode, int durationSeconds)
+ {
+ ComWrapper.Send(BuildCommand(mode, durationSeconds));
+ }
+
+ // ReSharper disable once IteratorNeverReturns — корутина намеренно бесконечная
+ private IEnumerator BlinkingCoroutine(float interval)
+ {
+ while (true)
+ {
+ ComWrapper.Send(Random.Range(0f, 1f) < 0.5f ? hatOnCommand : hatOffCommand);
+
+ float wait = blinkIntervalVariance > 0f
+ ? Mathf.Max(0.05f, interval + Random.Range(-blinkIntervalVariance, blinkIntervalVariance))
+ : interval;
+
+ yield return new WaitForSeconds(wait);
+ }
+ }
+
+ private static string BuildCommand(LightMode mode, int durationSeconds)
+ {
+ if (mode == LightMode.Off)
+ return EffectPrefix;
+
+ int xx = (int)mode;
+ int yy = Mathf.Clamp(durationSeconds, 0, 99);
+ return $"{EffectPrefix}{xx:D2}{yy:D2}";
+ }
+
+ ///
+ /// Строитель последовательности световых эффектов.
+ /// Создаётся через .
+ ///
+ /// SetLight(LightMode.VerticalWave, 3).Then(LightMode.DiagonalWave, 3).Loop();
+ /// SetLight(LightMode.VerticalWave, 3).Then(LightMode.Off);
+ /// SetLight(LightMode.Rainbow, 5);
+ ///
+ ///
+ public class LightSequence
+ {
+ private readonly struct Step
+ {
+ public readonly LightMode Mode;
+ public readonly int DurationSeconds;
+ public Step(LightMode mode, int durationSeconds) { Mode = mode; DurationSeconds = durationSeconds; }
+ }
+
+ private readonly List _steps = new();
+ private readonly LightController _controller;
+ private bool _looping;
+ private Coroutine _coroutine;
+
+ internal LightSequence(LightController controller, LightMode firstMode, int firstDuration)
+ {
+ _controller = controller;
+ _steps.Add(new Step(firstMode, firstDuration));
+ }
+
+ /// Добавляет следующий эффект с временем по умолчанию.
+ public LightSequence Then(LightMode mode) => Then(mode, _controller.DefaultDuration);
+
+ /// Добавляет следующий эффект с указанным временем.
+ public LightSequence Then(LightMode mode, int durationSeconds)
+ {
+ _steps.Add(new Step(mode, durationSeconds));
+ return this;
+ }
+
+ ///
+ /// Зацикливает последовательность. Для остановки — .
+ ///
+ public LightSequence Loop()
+ {
+ _looping = true;
+ Play();
+ return this;
+ }
+
+ /// Запускает последовательность один раз.
+ public LightSequence Play()
+ {
+ Stop();
+ _coroutine = _controller.StartCoroutine(RunSequence());
+ return this;
+ }
+
+ /// Останавливает выполнение последовательности.
+ public void Stop()
+ {
+ if (_coroutine == null) return;
+ _controller.StopCoroutine(_coroutine);
+ _coroutine = null;
+ }
+
+ /// Возвращает true, если последовательность сейчас выполняется.
+ public bool IsPlaying => _coroutine != null;
+
+ // ReSharper disable once IteratorNeverReturns — цикл намеренно бесконечный при _looping=true
+ private IEnumerator RunSequence()
+ {
+ do
+ {
+ foreach (Step step in _steps)
+ {
+ _controller.SendCommand(step.Mode, step.DurationSeconds);
+
+ if (step.Mode != LightMode.Off && step.DurationSeconds > 0)
+ yield return new WaitForSeconds(step.DurationSeconds);
+ }
+ }
+ while (_looping);
+
+ _coroutine = null;
+ }
+ }
+ }
+}
diff --git a/Assets/Scripts/Controls/Inputs/ComSystem/LightController.cs.meta b/Assets/Scripts/Controls/Inputs/ComSystem/LightController.cs.meta
new file mode 100644
index 0000000..dcfe4a9
--- /dev/null
+++ b/Assets/Scripts/Controls/Inputs/ComSystem/LightController.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 9b5ae7d3aa86455381891033da97820b
+timeCreated: 1771504477
\ No newline at end of file
diff --git a/Assets/Scripts/Controls/Inputs/ComSystem/LightMode.cs b/Assets/Scripts/Controls/Inputs/ComSystem/LightMode.cs
new file mode 100644
index 0000000..6710e65
--- /dev/null
+++ b/Assets/Scripts/Controls/Inputs/ComSystem/LightMode.cs
@@ -0,0 +1,52 @@
+namespace RR.Common.Controls
+{
+ ///
+ /// Эффекты подсветки периферийной платы (протокол 85XXYY).
+ /// XX — код эффекта, YY — время в секундах.
+ /// Команда 85 (без параметров) отключает рендеринг эффектов и освобождает память.
+ ///
+ public enum LightMode
+ {
+ /// Отключить рендеринг эффектов (освобождает память). Команда: 85
+ Off = -1,
+
+ /// Горизонтальная волна. XX = 40
+ HorizontalWave = 40,
+
+ /// Вертикальная волна. XX = 41
+ VerticalWave = 41,
+
+ /// Диагональная волна. XX = 42
+ DiagonalWave = 42,
+
+ /// Радуга. XX = 43
+ Rainbow = 43,
+
+ /// Волна вверх. XX = 44
+ WaveUp = 44,
+
+ /// Вертикальная волна вверх. XX = 45
+ VerticalWaveUp = 45,
+
+ /// Конечная волна. XX = 46
+ FinalWave = 46,
+
+ /// Синяя волна. XX = 47
+ BlueWave = 47,
+
+ /// Диагональная волна 2. XX = 48
+ DiagonalWave2 = 48,
+
+ /// Падающие ряды. XX = 49
+ FallingRows = 49,
+
+ /// Оранжевая волна. XX = 50
+ OrangeWave = 50,
+
+ /// Морская волна. XX = 51
+ SeaWave = 51,
+
+ /// Диагональная волна 3. XX = 52
+ DiagonalWave3 = 52,
+ }
+}
diff --git a/Assets/Scripts/Controls/Inputs/ComSystem/LightMode.cs.meta b/Assets/Scripts/Controls/Inputs/ComSystem/LightMode.cs.meta
new file mode 100644
index 0000000..d87645b
--- /dev/null
+++ b/Assets/Scripts/Controls/Inputs/ComSystem/LightMode.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 2d1d29b94c0748148217efb46bcc2816
+timeCreated: 1771504563
\ No newline at end of file
diff --git a/Assets/Scripts/Editor/MouseWorldPositionOverlay.cs b/Assets/Scripts/Editor/MouseWorldPositionOverlay.cs
index ad95fe8..546180d 100644
--- a/Assets/Scripts/Editor/MouseWorldPositionOverlay.cs
+++ b/Assets/Scripts/Editor/MouseWorldPositionOverlay.cs
@@ -4,6 +4,9 @@ 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
@@ -132,4 +135,5 @@ public class MouseWorldPositionOverlay : Overlay
}
}
+} // namespace RR.Common.InspectorOverrides
#endif
diff --git a/Assets/Scripts/Managers/GameManager.cs b/Assets/Scripts/Managers/GameManager.cs
index 24823ff..993a907 100644
--- a/Assets/Scripts/Managers/GameManager.cs
+++ b/Assets/Scripts/Managers/GameManager.cs
@@ -33,6 +33,8 @@ namespace RR.Game2D.Core.Managers
// Plate control for game
public ComWrapper Plate { get; private set; }
+ // Light control for game
+ public LightController Light => Plate != null ? Plate.Light : null;
// Globals
[Header("Globals")]
@@ -330,6 +332,7 @@ public void TogglePause() => SetPause(!IsPaused);
Logger.Log(gameObject.name,$"Game start time = {_gameStartTime}");
if (Plate) Plate.StopBlink();
+ Light?.SetLight(LightMode.Rainbow, 99);
// Включаем отслеживание бездействия
if (Inactivity != null) Inactivity.EnableInactivityCheck();
@@ -369,23 +372,27 @@ public void TogglePause() => SetPause(!IsPaused);
/// Окончание игры.
/// Загружает сцену главного меню
///
- private void GameOver() // => LoadScene("MainMenu", false);
+ private void GameOver()
{
float totalTime = Time.unscaledTime - _gameStartTime;
// Отключаем отслеживание бездействия
if (Inactivity != null) Inactivity.DisableInactivityCheck();
+
+ Light?.SetLight(LightMode.BlueWave, 30);
GameOverEvent?.Invoke(totalTime);
}
// --
- private void GameWin() // => LoadScene("MainMenu", false);
+ private void GameWin()
{
float totalTime = Time.unscaledTime - _gameStartTime;
// Отключаем отслеживание бездействия
if (Inactivity != null) Inactivity.DisableInactivityCheck();
+
+ Light?.SetLight(LightMode.FinalWave, 30);
GameWonEvent?.Invoke(totalTime);
}
@@ -466,6 +473,7 @@ public void TogglePause() => SetPause(!IsPaused);
if (useUI) SceneManager.LoadScene("Level UI", LoadSceneMode.Additive);
else
{
+ Light?.SetLight(LightMode.Off);
Plate.Blink();
_shouldSpawnPlayer = false;
}
diff --git a/Assets/Scripts/UI/StatsWindowUIController.cs b/Assets/Scripts/UI/StatsWindowUIController.cs
index 4aeedcf..c9ab7c4 100644
--- a/Assets/Scripts/UI/StatsWindowUIController.cs
+++ b/Assets/Scripts/UI/StatsWindowUIController.cs
@@ -5,6 +5,9 @@ using TMPro;
using UnityEngine;
using UnityEngine.InputSystem;
+namespace RR.Common.UI
+{
+
public class StatsWindowUIController : MonoBehaviour
{
[Header("Управление")]
@@ -103,3 +106,4 @@ public class StatsWindowUIController : MonoBehaviour
onDone?.Invoke();
}
}
+} // namespace RR.Common.UI
diff --git a/Assets/Scripts/Utilities/AdvancedLogging_Test.cs b/Assets/Scripts/Utilities/AdvancedLogging_Test.cs
index a40b146..f7daaed 100644
--- a/Assets/Scripts/Utilities/AdvancedLogging_Test.cs
+++ b/Assets/Scripts/Utilities/AdvancedLogging_Test.cs
@@ -1,175 +1,176 @@
using UnityEngine;
using System;
-using RR.Common.Utility;
-///
-/// Продвинутый пример использования системы логирования.
-/// Демонстрирует различные сценарии использования FileLogger и CompositeLogger.
-///
-public class AdvancedLogging_Test : MonoBehaviour
+namespace RR.Common.Utility
{
- private CompositeLogger compositeLogger;
- private FileLogger mainFileLogger;
- private FileLogger errorFileLogger;
-
- void Start()
- {
- SetupAdvancedLogging();
- DemonstrateLogging();
- }
-
///
- /// Настройка продвинутой системы логирования с несколькими выходными файлами
+ /// Продвинутый пример использования системы логирования.
+ /// Демонстрирует различные сценарии использования FileLogger и CompositeLogger.
///
- private void SetupAdvancedLogging()
+ public class AdvancedLogging_Test : MonoBehaviour
{
- // Создаём композитный логгер
- compositeLogger = new CompositeLogger();
- compositeLogger.Initialize();
+ private CompositeLogger compositeLogger;
+ private FileLogger mainFileLogger;
+ private FileLogger errorFileLogger;
- // Главный файл - все логи
- mainFileLogger = new FileLogger(
- System.IO.Path.Combine(Application.persistentDataPath, "full_log.txt"),
- append: true
- );
- mainFileLogger.filterLogType = LogType.Log; // Все типы сообщений
-
- // Отдельный файл только для ошибок и исключений
- errorFileLogger = new FileLogger(
- System.IO.Path.Combine(Application.persistentDataPath, "errors_only.txt"),
- append: true
- );
- errorFileLogger.filterLogType = LogType.Warning; // Только Warning, Error, Exception
-
- // Добавляем оба логгера
- compositeLogger.AddLoggers(mainFileLogger, errorFileLogger);
-
- Debug.Log($"Логирование настроено. Файлы в: {Application.persistentDataPath}");
- }
-
- ///
- /// Демонстрация различных типов логирования
- ///
- private void DemonstrateLogging()
- {
- // Простые сообщения
- compositeLogger.Log("=== Демонстрация системы логирования ===");
-
- // Сообщения с тегами
- compositeLogger.Log("SYSTEM", "Игра инициализирована");
- compositeLogger.LogWarning("AUDIO", "Громкость музыки установлена в 0.5");
-
- // Форматированные сообщения
- string playerName = "Player1";
- int score = 1000;
- compositeLogger.LogFormat(LogType.Log, "Игрок {0} набрал {1} очков", playerName, score);
-
- // Логирование с контекстом
- compositeLogger.Log("Объект создан", this.gameObject);
-
- // Имитация ошибки
- compositeLogger.LogError("ERROR", "Это тестовая ошибка - будет в обоих файлах!");
-
- // Имитация исключения
- try
+ void Start()
{
- throw new InvalidOperationException("Тестовое исключение для демонстрации");
- }
- catch (Exception ex)
- {
- compositeLogger.LogException(ex, this.gameObject);
+ SetupAdvancedLogging();
+ DemonstrateLogging();
}
- // Информация о путях
- Debug.Log($"Полный лог: {Application.persistentDataPath}/full_log.txt");
- Debug.Log($"Только ошибки: {Application.persistentDataPath}/errors_only.txt");
- }
+ ///
+ /// Настройка продвинутой системы логирования с несколькими выходными файлами
+ ///
+ private void SetupAdvancedLogging()
+ {
+ // Создаём композитный логгер
+ compositeLogger = new CompositeLogger();
+ compositeLogger.Initialize();
- ///
- /// Пример метода для логирования игровых событий
- ///
- public void LogGameEvent(string eventName, params object[] parameters)
- {
- string paramStr = string.Join(", ", parameters);
- compositeLogger.Log("GAME_EVENT", $"{eventName}: {paramStr}");
- }
+ // Главный файл - все логи
+ mainFileLogger = new FileLogger(
+ System.IO.Path.Combine(Application.persistentDataPath, "full_log.txt"),
+ append: true
+ );
+ mainFileLogger.filterLogType = LogType.Log; // Все типы сообщений
- ///
- /// Пример метода для логирования производительности
- ///
- public void LogPerformance(string operation, float duration)
- {
- if (duration > 0.016f) // Больше 16мс (60 FPS)
- {
- compositeLogger.LogWarning("PERFORMANCE", $"{operation} занял {duration * 1000:F2}мс");
- }
- else
- {
- compositeLogger.Log("PERFORMANCE", $"{operation} выполнен за {duration * 1000:F2}мс");
- }
- }
+ // Отдельный файл только для ошибок и исключений
+ errorFileLogger = new FileLogger(
+ System.IO.Path.Combine(Application.persistentDataPath, "errors_only.txt"),
+ append: true
+ );
+ errorFileLogger.filterLogType = LogType.Warning; // Только Warning, Error, Exception
- ///
- /// Пример обёртки для измерения времени выполнения
- ///
- public void PerformOperationWithLogging(string operationName, Action operation)
- {
- float startTime = Time.realtimeSinceStartup;
-
- try
- {
- operation.Invoke();
- float duration = Time.realtimeSinceStartup - startTime;
- LogPerformance(operationName, duration);
- }
- catch (Exception ex)
- {
- compositeLogger.LogException(ex);
- compositeLogger.LogError("OPERATION", $"Операция '{operationName}' завершилась с ошибкой");
- }
- }
+ // Добавляем оба логгера
+ compositeLogger.AddLoggers(mainFileLogger, errorFileLogger);
- void Update()
- {
- // Пример: логируем нажатия клавиш
- if (Input.GetKeyDown(KeyCode.L))
- {
- LogGameEvent("KeyPress", "L", Time.time);
+ Debug.Log($"Логирование настроено. Файлы в: {Application.persistentDataPath}");
}
- if (Input.GetKeyDown(KeyCode.F))
+ ///
+ /// Демонстрация различных типов логирования
+ ///
+ private void DemonstrateLogging()
{
- // Принудительная запись на диск
- mainFileLogger.Flush();
- errorFileLogger.Flush();
- compositeLogger.Log("SYSTEM", "Логи принудительно сохранены на диск");
+ // Простые сообщения
+ compositeLogger.Log("=== Демонстрация системы логирования ===");
+
+ // Сообщения с тегами
+ compositeLogger.Log("SYSTEM", "Игра инициализирована");
+ compositeLogger.LogWarning("AUDIO", "Громкость музыки установлена в 0.5");
+
+ // Форматированные сообщения
+ string playerName = "Player1";
+ int score = 1000;
+ compositeLogger.LogFormat(LogType.Log, "Игрок {0} набрал {1} очков", playerName, score);
+
+ // Логирование с контекстом
+ compositeLogger.Log("Объект создан", this.gameObject);
+
+ // Имитация ошибки
+ compositeLogger.LogError("ERROR", "Это тестовая ошибка - будет в обоих файлах!");
+
+ // Имитация исключения
+ try
+ {
+ throw new InvalidOperationException("Тестовое исключение для демонстрации");
+ }
+ catch (Exception ex)
+ {
+ compositeLogger.LogException(ex, this.gameObject);
+ }
+
+ // Информация о путях
+ Debug.Log($"Полный лог: {Application.persistentDataPath}/full_log.txt");
+ Debug.Log($"Только ошибки: {Application.persistentDataPath}/errors_only.txt");
}
- if (Input.GetKeyDown(KeyCode.C))
+ ///
+ /// Пример метода для логирования игровых событий
+ ///
+ public void LogGameEvent(string eventName, params object[] parameters)
{
- // Очистка логов
- mainFileLogger.Clear();
- errorFileLogger.Clear();
- compositeLogger.Log("SYSTEM", "Файлы логов очищены");
+ string paramStr = string.Join(", ", parameters);
+ compositeLogger.Log("GAME_EVENT", $"{eventName}: {paramStr}");
}
- }
- void OnApplicationQuit()
- {
- compositeLogger.Log("SYSTEM", "Приложение завершается...");
-
- // Важно: освобождаем ресурсы
- mainFileLogger?.Dispose();
- errorFileLogger?.Dispose();
-
- Debug.Log("Файловые логгеры закрыты");
- }
+ ///
+ /// Пример метода для логирования производительности
+ ///
+ public void LogPerformance(string operation, float duration)
+ {
+ if (duration > 0.016f) // Больше 16мс (60 FPS)
+ {
+ compositeLogger.LogWarning("PERFORMANCE", $"{operation} занял {duration * 1000:F2}мс");
+ }
+ else
+ {
+ compositeLogger.Log("PERFORMANCE", $"{operation} выполнен за {duration * 1000:F2}мс");
+ }
+ }
- void OnDestroy()
- {
- // На всякий случай
- mainFileLogger?.Dispose();
- errorFileLogger?.Dispose();
+ ///
+ /// Пример обёртки для измерения времени выполнения
+ ///
+ public void PerformOperationWithLogging(string operationName, Action operation)
+ {
+ float startTime = Time.realtimeSinceStartup;
+
+ try
+ {
+ operation.Invoke();
+ float duration = Time.realtimeSinceStartup - startTime;
+ LogPerformance(operationName, duration);
+ }
+ catch (Exception ex)
+ {
+ compositeLogger.LogException(ex);
+ compositeLogger.LogError("OPERATION", $"Операция '{operationName}' завершилась с ошибкой");
+ }
+ }
+
+ void Update()
+ {
+ // Пример: логируем нажатия клавиш
+ if (Input.GetKeyDown(KeyCode.L))
+ {
+ LogGameEvent("KeyPress", "L", Time.time);
+ }
+
+ if (Input.GetKeyDown(KeyCode.F))
+ {
+ // Принудительная запись на диск
+ mainFileLogger.Flush();
+ errorFileLogger.Flush();
+ compositeLogger.Log("SYSTEM", "Логи принудительно сохранены на диск");
+ }
+
+ if (Input.GetKeyDown(KeyCode.C))
+ {
+ // Очистка логов
+ mainFileLogger.Clear();
+ errorFileLogger.Clear();
+ compositeLogger.Log("SYSTEM", "Файлы логов очищены");
+ }
+ }
+
+ void OnApplicationQuit()
+ {
+ compositeLogger.Log("SYSTEM", "Приложение завершается...");
+
+ // Важно: освобождаем ресурсы
+ mainFileLogger?.Dispose();
+ errorFileLogger?.Dispose();
+
+ Debug.Log("Файловые логгеры закрыты");
+ }
+
+ void OnDestroy()
+ {
+ // На всякий случай
+ mainFileLogger?.Dispose();
+ errorFileLogger?.Dispose();
+ }
}
}
-
diff --git a/Assets/Scripts/Utilities/DebugSettings.cs b/Assets/Scripts/Utilities/DebugSettings.cs
index 2852847..d88710d 100644
--- a/Assets/Scripts/Utilities/DebugSettings.cs
+++ b/Assets/Scripts/Utilities/DebugSettings.cs
@@ -1,14 +1,16 @@
using UnityEngine;
-
using RR.Game2D.Core.Managers;
-public class DebugSettings : MonoBehaviour
+namespace RR.Common.Utility
{
- [SerializeField] private int livesCount = 99;
- [SerializeField] private int coinsCount;
- // Start is called once before the first execution of Update after the MonoBehaviour is created
- void Start()
+ public class DebugSettings : MonoBehaviour
{
- GameManager.Instance.Lives = livesCount;
+ [SerializeField] private int livesCount = 99;
+ [SerializeField] private int coinsCount;
+
+ void Start()
+ {
+ GameManager.Instance.Lives = livesCount;
+ }
}
}
diff --git a/Packages/manifest.json b/Packages/manifest.json
index f47dbca..3efee6b 100644
--- a/Packages/manifest.json
+++ b/Packages/manifest.json
@@ -1,17 +1,17 @@
{
"dependencies": {
"com.github-glitchenzo.nugetforunity": "https://github.com/GlitchEnzo/NuGetForUnity.git?path=/src/NuGetForUnity",
- "com.unity.ai.inference": "2.4.1",
+ "com.unity.ai.inference": "2.5.0",
"com.unity.cinemachine": "3.1.5",
- "com.unity.collab-proxy": "2.10.2",
+ "com.unity.collab-proxy": "2.11.3",
"com.unity.feature.2d": "2.0.2",
"com.unity.ide.rider": "3.0.39",
- "com.unity.ide.visualstudio": "2.0.25",
- "com.unity.inputsystem": "1.17.0",
+ "com.unity.ide.visualstudio": "2.0.26",
+ "com.unity.inputsystem": "1.18.0",
"com.unity.multiplayer.center": "1.0.1",
"com.unity.render-pipelines.universal": "17.3.0",
"com.unity.test-framework": "1.6.0",
- "com.unity.timeline": "1.8.9",
+ "com.unity.timeline": "1.8.10",
"com.unity.ugui": "2.0.0",
"com.unity.visualeffectgraph": "17.3.0",
"com.unity.visualscripting": "1.9.9",
diff --git a/Packages/packages-lock.json b/Packages/packages-lock.json
index e271208..51ac49d 100644
--- a/Packages/packages-lock.json
+++ b/Packages/packages-lock.json
@@ -8,11 +8,11 @@
"hash": "34432703a177c97631a4eb1d908f086037c67969"
},
"com.unity.2d.animation": {
- "version": "13.0.2",
+ "version": "13.0.4",
"depth": 1,
"source": "registry",
"dependencies": {
- "com.unity.2d.common": "12.0.1",
+ "com.unity.2d.common": "12.0.2",
"com.unity.2d.sprite": "1.0.0",
"com.unity.collections": "2.4.3",
"com.unity.modules.animation": "1.0.0",
@@ -34,7 +34,7 @@
"url": "https://packages.unity.com"
},
"com.unity.2d.common": {
- "version": "12.0.1",
+ "version": "12.0.2",
"depth": 2,
"source": "registry",
"dependencies": {
@@ -106,22 +106,22 @@
"url": "https://packages.unity.com"
},
"com.unity.2d.tooling": {
- "version": "1.0.0",
+ "version": "1.0.2",
"depth": 1,
"source": "registry",
"dependencies": {
- "com.unity.2d.common": "12.0.1",
+ "com.unity.2d.common": "12.0.2",
"com.unity.modules.uielements": "1.0.0"
},
"url": "https://packages.unity.com"
},
"com.unity.ai.inference": {
- "version": "2.4.1",
+ "version": "2.5.0",
"depth": 0,
"source": "registry",
"dependencies": {
"com.unity.burst": "1.8.17",
- "com.unity.dt.app-ui": "1.3.1",
+ "com.unity.dt.app-ui": "1.3.3",
"com.unity.collections": "2.4.3",
"com.unity.nuget.newtonsoft-json": "3.2.1",
"com.unity.modules.imageconversion": "1.0.0"
@@ -129,7 +129,7 @@
"url": "https://packages.unity.com"
},
"com.unity.burst": {
- "version": "1.8.26",
+ "version": "1.8.27",
"depth": 1,
"source": "registry",
"dependencies": {
@@ -149,7 +149,7 @@
"url": "https://packages.unity.com"
},
"com.unity.collab-proxy": {
- "version": "2.10.2",
+ "version": "2.11.3",
"depth": 0,
"source": "registry",
"dependencies": {},
@@ -191,7 +191,7 @@
"depth": 0,
"source": "builtin",
"dependencies": {
- "com.unity.2d.animation": "13.0.2",
+ "com.unity.2d.animation": "13.0.4",
"com.unity.2d.pixel-perfect": "5.1.1",
"com.unity.2d.psdimporter": "12.0.1",
"com.unity.2d.sprite": "1.0.0",
@@ -199,7 +199,7 @@
"com.unity.2d.tilemap": "1.0.0",
"com.unity.2d.tilemap.extras": "6.0.1",
"com.unity.2d.aseprite": "3.0.1",
- "com.unity.2d.tooling": "1.0.0"
+ "com.unity.2d.tooling": "1.0.2"
}
},
"com.unity.ide.rider": {
@@ -212,16 +212,16 @@
"url": "https://packages.unity.com"
},
"com.unity.ide.visualstudio": {
- "version": "2.0.25",
+ "version": "2.0.26",
"depth": 0,
"source": "registry",
"dependencies": {
- "com.unity.test-framework": "1.1.31"
+ "com.unity.test-framework": "1.1.33"
},
"url": "https://packages.unity.com"
},
"com.unity.inputsystem": {
- "version": "1.17.0",
+ "version": "1.18.0",
"depth": 0,
"source": "registry",
"dependencies": {
@@ -345,7 +345,7 @@
"url": "https://packages.unity.com"
},
"com.unity.timeline": {
- "version": "1.8.9",
+ "version": "1.8.10",
"depth": 0,
"source": "registry",
"dependencies": {
diff --git a/ProjectSettings/ProjectVersion.txt b/ProjectSettings/ProjectVersion.txt
index 879b68f..aad22be 100644
--- a/ProjectSettings/ProjectVersion.txt
+++ b/ProjectSettings/ProjectVersion.txt
@@ -1,2 +1,2 @@
-m_EditorVersion: 6000.3.2f1
-m_EditorVersionWithRevision: 6000.3.2f1 (a9779f353c9b)
+m_EditorVersion: 6000.3.8f1
+m_EditorVersionWithRevision: 6000.3.8f1 (1c7db571dde0)