Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Has been cancelled
- Добавлен `ScoreSystem` — singleton-компонент, отслеживающий монеты, убитых врагов и экологические очки; финальный счёт вычисляется по формуле `Score = E × (P + 45C + 90K + 10K²) − 0.5T` с раздельными множителями для победы и проигрыша. - Добавлен `EnvironmentalCollectibleBase` — абстрактный базовый класс для подбираемых экологических объектов: срабатывает по триггеру, поддерживает пулинг, при подборе регистрирует очки в `ScoreSystem`. - Добавлен `LeafCollectible` — листик с синусоидальным горизонтальным дрейфом, вращением и детекцией земли. - Добавлен `BatCollectible` — летучая мышь с синусоидальным вертикальным движением, ограниченным горизонтальным блужданием и случайными сменами направления; переворачивает спрайт по X при смене направления. - Добавлен `EnvironmentalPool` — простой объектный пул по prefab-ключу с прогревом (`Warmup`) и возвратом объектов. - Добавлен `EnvironmentalCollectibleSpawner` — взвешенный случайный спаунер, поддерживающий фиксированное количество активных объектов; поддерживает лимиты по типу, принудительный выбор одного prefab и область спауна через `BoxCollider2D` или ручной `Bounds`. - В `CoinCollectible.TryPickup` добавлен вызов `ScoreSystem.Instance?.RegisterCoinCollected()`. - В `EnemyController.Die` добавлен guard через флаг `_isDead` для предотвращения повторного срабатывания; добавлен вызов `ScoreSystem.Instance?.RegisterEnemyKilled()`. - В `GameManager` добавлен вызов `ScoreSystem.Instance?.ResetStats()` при старте новой игры и при потере жизни.
78 lines
2.9 KiB
C#
78 lines
2.9 KiB
C#
using UnityEngine;
|
|
|
|
namespace RR.Common.Entities.Props
|
|
{
|
|
public sealed class BatCollectible : EnvironmentalCollectibleBase
|
|
{
|
|
[SerializeField] private float moveSpeed = 1.75f;
|
|
[SerializeField] private float verticalAmplitude = 0.35f;
|
|
[SerializeField] private float verticalFrequency = 2.4f;
|
|
[SerializeField] private float horizontalWaveAmplitude = 0.2f;
|
|
[SerializeField] private float horizontalWaveFrequency = 1.35f;
|
|
[SerializeField] private float maxRange = 3.5f;
|
|
[SerializeField] private float directionChangeIntervalMin = 1.5f;
|
|
[SerializeField] private float directionChangeIntervalMax = 3.5f;
|
|
|
|
private Vector3 _anchorPosition;
|
|
private Vector3 _currentPosition;
|
|
private float _time;
|
|
private float _directionTimer;
|
|
private float _nextDirectionChangeTime;
|
|
private int _moveDirection;
|
|
|
|
protected override void OnSpawned()
|
|
{
|
|
_anchorPosition = SpawnPosition;
|
|
_currentPosition = transform.position;
|
|
_time = 0f;
|
|
_directionTimer = 0f;
|
|
_moveDirection = 1;
|
|
_nextDirectionChangeTime = Random.Range(directionChangeIntervalMin, directionChangeIntervalMax);
|
|
}
|
|
|
|
protected override void TickBehaviour(float dt)
|
|
{
|
|
_time += dt;
|
|
_directionTimer += dt;
|
|
|
|
if (_directionTimer >= _nextDirectionChangeTime)
|
|
{
|
|
FlipDirection();
|
|
_directionTimer = 0f;
|
|
_nextDirectionChangeTime = Random.Range(directionChangeIntervalMin, directionChangeIntervalMax);
|
|
}
|
|
|
|
Vector3 position = _currentPosition;
|
|
position.x += _moveDirection * moveSpeed * dt;
|
|
|
|
float xOffsetFromAnchor = position.x - _anchorPosition.x;
|
|
if (Mathf.Abs(xOffsetFromAnchor) > maxRange)
|
|
{
|
|
position.x = _anchorPosition.x + Mathf.Sign(xOffsetFromAnchor) * maxRange;
|
|
FlipDirection();
|
|
_directionTimer = 0f;
|
|
_nextDirectionChangeTime = Random.Range(directionChangeIntervalMin, directionChangeIntervalMax);
|
|
}
|
|
|
|
float verticalOffset = Mathf.Sin(_time * verticalFrequency) * verticalAmplitude;
|
|
float horizontalOffset = Mathf.Sin(_time * horizontalWaveFrequency) * horizontalWaveAmplitude;
|
|
|
|
position.y = _anchorPosition.y + verticalOffset;
|
|
position.x += horizontalOffset * dt;
|
|
|
|
_currentPosition = position;
|
|
transform.position = position;
|
|
}
|
|
|
|
private void FlipDirection()
|
|
{
|
|
_moveDirection = -_moveDirection;
|
|
|
|
Vector3 scale = transform.localScale;
|
|
float xScale = Mathf.Abs(scale.x);
|
|
scale.x = _moveDirection > 0 ? xScale : -xScale;
|
|
transform.localScale = scale;
|
|
}
|
|
}
|
|
}
|