Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Has been cancelled
- доработан flow призовой витрины и связанного UI: добавлены `PrizeStandButtonView` и `RulesPrizeListPage`, обновлены `PrizeStandController`, `PrizeStandPrize`, `PrizeStandModal`, `PrizeStandSettingsModal`, `LevelPrizeSettingsModal`, `QRCodeSettingsModal`, `BalanceDisplay`, `ButtonTextFocusColor` и связанные prefab'ы, чтобы улучшить настройку, навигацию, отображение кнопок и prize flow - расширена система настроек и сохранения значений: `OptionPicker` получил отдельный формат `ValueSelector`, обновлены `SettingsDatabase`, `SettingEntryDrawer`, `SettingUIItem`, `SettingsUIGenerator`, `ValueSelectorRow` и `MainSettingsDatabase.asset`, а сохранение option picker-значений, включая `gameplay.gameDifficulty`, исправлено и синхронизировано с остальными настройками - добавлены универсальные спавнеры сущностей: реализованы `EntitySpawner` и `EntitySpawnerManager` с поддержкой весов префабов, точек спавна, заполнения по проценту, ограничений на количество и автоспавна при инициализации - доработана логика игрового спавна и сложности: процент инициализационного спавна может зависеть от настройки `gameplay.gameDifficulty` с градациями 25/50/75/100, в одном цикле массового спавна повторно не используется та же точка, а gizmo спавнера теперь показывает только сами точки без линий - упрощена работа в редакторе Unity и добавлены editor-инструменты: в `GameManager` лицензия пропускается при запуске в `UNITY_EDITOR`, а `HierarchySelectionCounter`, `HierarchySelectionCountOverlay` и `HierarchyBulkRenamerWindow` добавляют подсчет выделения, realtime overlay в `SceneView` и массовое переименование объектов по правилам нумерации из Unity Project Settings - синхронизированы сцены, ресурсы и UI-ассеты под новый flow: обновлены `MainMenu`, `Level UI`, уровни `1-1` и `1-2`, строки настроек, кнопки, TMP/font assets, изображения UI, `prizes.json` и recovery-данные после правок интерфейса и логики - очищены и переразложены часть внешних и служебных ресурсов: удалён пакет `Lava_Flowing_Shader`, переименованы/заменены отдельные UI-prefab'ы и добавлены сопутствующие проектные артефакты, которые сейчас используются обновлённой конфигурацией проекта
157 lines
4.5 KiB
C#
157 lines
4.5 KiB
C#
using System;
|
|
using RR.Game2D.Behaviour;
|
|
using UnityEngine;
|
|
|
|
namespace RR.Common.Entities.Props
|
|
{
|
|
[RequireComponent(typeof(Collider2D))]
|
|
public abstract class EnvironmentalCollectibleBase : MonoBehaviour
|
|
{
|
|
[SerializeField] private int points = 1;
|
|
[SerializeField] private string playerTag = "Player";
|
|
[Tooltip("Время жизни в секундах. 0 или меньше — бесконечно.")]
|
|
[SerializeField] private float defaultLifetime;
|
|
|
|
private bool _collected;
|
|
private int _defaultPoints;
|
|
private float _defaultLifetimeBackup;
|
|
private float _lifetime;
|
|
private float _age;
|
|
private Collider2D _trigger;
|
|
private Vector3 _spawnPosition;
|
|
|
|
public event Action<EnvironmentalCollectibleBase> Collected;
|
|
|
|
public int Points => points;
|
|
public Vector3 SpawnPosition => _spawnPosition;
|
|
public virtual bool CountsTowardsSharedCollectionLimit => false;
|
|
|
|
protected virtual void Awake()
|
|
{
|
|
_defaultPoints = Mathf.Max(0, points);
|
|
_defaultLifetimeBackup = defaultLifetime;
|
|
_trigger = GetComponent<Collider2D>();
|
|
ValidateTrigger();
|
|
}
|
|
|
|
protected virtual void Update()
|
|
{
|
|
float dt = Time.deltaTime;
|
|
|
|
if (_lifetime > 0f && !_collected)
|
|
{
|
|
_age += dt;
|
|
if (_age >= _lifetime)
|
|
{
|
|
Despawn();
|
|
return;
|
|
}
|
|
}
|
|
|
|
TickBehaviour(dt);
|
|
}
|
|
|
|
protected virtual void OnValidate()
|
|
{
|
|
if (points < 0) points = 0;
|
|
_defaultPoints = points;
|
|
_defaultLifetimeBackup = defaultLifetime;
|
|
ValidateTrigger();
|
|
}
|
|
|
|
private void OnTriggerEnter2D(Collider2D other)
|
|
{
|
|
// Unity 2D trigger callbacks usually require at least one of the colliding objects to have a Rigidbody2D.
|
|
if (_collected || other == null) return;
|
|
if (!other.CompareTag(playerTag)) return;
|
|
|
|
Collect(other.transform);
|
|
}
|
|
|
|
public void InitializeForSpawn(
|
|
Vector3 spawnPosition,
|
|
int? pointsOverride,
|
|
float? lifetimeOverride = null)
|
|
{
|
|
_spawnPosition = spawnPosition;
|
|
points = pointsOverride.HasValue ? Mathf.Max(0, pointsOverride.Value) : _defaultPoints;
|
|
_lifetime = lifetimeOverride.HasValue ? lifetimeOverride.Value : _defaultLifetimeBackup;
|
|
_age = 0f;
|
|
|
|
ResetStateForReuse();
|
|
}
|
|
|
|
public void ResetStateForReuse()
|
|
{
|
|
_collected = false;
|
|
_age = 0f;
|
|
_spawnPosition = transform.position;
|
|
OnSpawned();
|
|
}
|
|
|
|
protected void Collect(Transform collector)
|
|
{
|
|
if (_collected) return;
|
|
|
|
_collected = true;
|
|
OnCollected();
|
|
|
|
if (CountsTowardsSharedCollectionLimit)
|
|
{
|
|
ScoreSystem.Instance?.RegisterSharedEnvironmentalCollectibleCollected(points);
|
|
}
|
|
else if (points > 0)
|
|
{
|
|
ScoreSystem.Instance?.RegisterEnvironmentalPoints(points);
|
|
}
|
|
|
|
Collected?.Invoke(this);
|
|
Destroy(gameObject);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Деспаун по истечении времени жизни — без начисления очков.
|
|
/// </summary>
|
|
private void Despawn()
|
|
{
|
|
if (_collected) return;
|
|
_collected = true;
|
|
|
|
OnDespawned();
|
|
|
|
|
|
Collected?.Invoke(this);
|
|
Destroy(gameObject);
|
|
}
|
|
|
|
protected virtual void OnSpawned()
|
|
{
|
|
}
|
|
|
|
protected virtual void OnCollected()
|
|
{
|
|
}
|
|
|
|
protected virtual void OnDespawned()
|
|
{
|
|
}
|
|
|
|
protected abstract void TickBehaviour(float dt);
|
|
|
|
private void ValidateTrigger()
|
|
{
|
|
if (_trigger == null)
|
|
_trigger = GetComponent<Collider2D>();
|
|
|
|
if (_trigger == null)
|
|
{
|
|
Debug.LogError($"[{nameof(EnvironmentalCollectibleBase)}] Missing Collider2D on {name}.", this);
|
|
return;
|
|
}
|
|
|
|
if (!_trigger.isTrigger)
|
|
Debug.LogError($"[{nameof(EnvironmentalCollectibleBase)}] Collider2D on {name} must have isTrigger enabled.", this);
|
|
}
|
|
}
|
|
}
|