using System; using System.Collections.Generic; using Components.Tiles; using Core; using DG.Tweening; using Settings; using Sirenix.OdinInspector; using UnityEngine; using Application = Core.Application; namespace Systems { public class EnvironmentController : SystemBase, ITick { [Serializable] private class TileHolder { public event Action OnTransitionComplete; [SerializeField] private int tileCount; [SerializeField] private float tileLength; [SerializeField] private float loopOffset; [SerializeField] private Transform tileHolder; private float _movementSpeed; private List _tiles; private int _currentTile; private PoolSystem _pool; private ObjectList _currentType; private bool _inTransition; public void ClearReferences() { OnTransitionComplete = null; tileHolder = null; _tiles = null; } public void Initialize(ObjectList inTileType, PoolSystem inPool) { _pool = inPool; _currentType = inTileType; _tiles = new List(); for (var i = 0; i < tileCount; i++) { var position = Vector3.forward * i * tileLength; var tile = _pool.Spawn(_currentType, position, Quaternion.identity, tileHolder); tile.Initialize(); _tiles.Add(tile); } } public void MoveTiles(Vector3 inMovementAxis) { var count = _tiles.Count; var translation = inMovementAxis * (-_movementSpeed * Time.deltaTime); // var translation = Vector3.back * (_movementSpeed * Time.deltaTime); for (var i = 0; i < count; i++) _tiles[i].Transform.Translate(translation); var currentTile = _tiles[_currentTile].Transform; if (currentTile.position.z > -loopOffset) return; var lastTrack = (_currentTile - 1) < 0 ? count - 1 : _currentTile - 1; currentTile.localPosition = _tiles[lastTrack].Transform.localPosition + Vector3.forward * tileLength; _currentTile = ++_currentTile >= count ? 0 : _currentTile; if (!_inTransition || _currentTile != tileCount) return; for (var i = 0; i < tileCount; i++) { var tile = _tiles[i]; _pool.Despawn(tile.Transform, tile.ResetTile); } _tiles.RemoveRange(0, tileCount); _currentTile = 0; OnTransitionComplete?.Invoke(); OnTransitionComplete = null; _inTransition = false; } public void TransitionEnvironment(ObjectList inTileType) { // (issue reverted for now) // TODO: -+Refactors // TODO: if no background is present, pre-initialize with the next active background to avoid lag. if (_inTransition) { OnTransitionComplete = null; return; } if (_currentType == inTileType) { OnTransitionComplete?.Invoke(); OnTransitionComplete = null; return; } _currentType = inTileType; _inTransition = true; var lastTrack = (_currentTile - 1) < 0 ? _tiles.Count - 1 : _currentTile - 1; var lastPosition = _tiles[lastTrack].Transform.localPosition; for (var i = 0; i < tileCount; i++) { var position = lastPosition + Vector3.forward * ((i + 1) * tileLength); var tile = _pool.Spawn(_currentType, position, Quaternion.identity, tileHolder); tile.Initialize(); _tiles.Add(tile); } _currentTile = 0; } public void UpdateSpeed(float inSpeed) => _movementSpeed = inSpeed; public void SetVisibility(bool isVisible) => tileHolder.gameObject.SetActive(isVisible); } [BoxGroup("Tile Settings")] [SerializeField] private TileHolder groundTilesHolder; [BoxGroup("Tile Settings")] [SerializeField] private TileHolder backgroundTilesHolder; [BoxGroup("Color Settings")] [SerializeField] private float colorTransitionDuration = 1.6f; [BoxGroup("Color Settings")] [SerializeField] private Material emissionMaterial; [BoxGroup("Color Settings")] [SerializeField] private Material fogMaterial; [BoxGroup("Color Settings")] [SerializeField] private Material forceFieldMaterial; [BoxGroup("Transition Settings")] [SerializeField] private ParticleSystem transitionEffect; [BoxGroup("Transition Settings")] [SerializeField] private ParticleSystem fallingParticles; [BoxGroup("Transition Settings")] [SerializeField] private ParticleSystem.MinMaxCurve openCurve; [BoxGroup("Transition Settings")] [SerializeField] private ParticleSystem.MinMaxCurve closedCurve; private const string EmissionProperty = "_EmissionColor"; private const string FogProperty = "FogColor"; private const float SpeedFactor = 1.85f; private bool _flipCurve; private PoolSystem _pSystem; protected override void ReleaseReferences() { // TODO: Add clearance for holders. _pSystem = null; groundTilesHolder = null; backgroundTilesHolder = null; } public void InitializeEnvironment(DifficultyStage inConfig) { _pSystem = Application.GetSystem(); groundTilesHolder.Initialize(inConfig.groundTile, _pSystem); groundTilesHolder.UpdateSpeed(inConfig.environmentSpeed); backgroundTilesHolder.Initialize(inConfig.backgroundTile, _pSystem); backgroundTilesHolder.SetVisibility(inConfig.hasBackground); backgroundTilesHolder.UpdateSpeed(inConfig.environmentSpeed / SpeedFactor); var fallColor = fallingParticles.colorOverLifetime; fallColor.color = inConfig.transitionColor; emissionMaterial.DOColor(inConfig.emissionColor, EmissionProperty, 0f); fogMaterial.DOColor(inConfig.emissionColor, FogProperty, 0f); forceFieldMaterial.DOColor(inConfig.emissionColor, EmissionProperty, 0f); } public void TransitionEnvironment(DifficultyStage inConfig) { var size = transitionEffect.sizeOverLifetime; size.size = _flipCurve ? closedCurve : openCurve; _flipCurve = !_flipCurve; var colorLifeTime = transitionEffect.colorOverLifetime; colorLifeTime.color = inConfig.transitionColor; transitionEffect.Play(); if (inConfig.hasBackground) backgroundTilesHolder.SetVisibility(true); else groundTilesHolder.OnTransitionComplete += () => backgroundTilesHolder.SetVisibility(false); groundTilesHolder.TransitionEnvironment(inConfig.groundTile); groundTilesHolder.UpdateSpeed(inConfig.environmentSpeed); backgroundTilesHolder.TransitionEnvironment(inConfig.backgroundTile); backgroundTilesHolder.UpdateSpeed(inConfig.environmentSpeed / SpeedFactor); var fallColor = fallingParticles.colorOverLifetime; fallColor.color = inConfig.transitionColor; emissionMaterial.DOColor(inConfig.emissionColor, EmissionProperty, colorTransitionDuration); fogMaterial.DOColor(inConfig.emissionColor, FogProperty, colorTransitionDuration); forceFieldMaterial.DOColor(inConfig.emissionColor, EmissionProperty, colorTransitionDuration); } public void Tick() { if (!IsRun) return; var direction = transform.forward; groundTilesHolder.MoveTiles(direction); backgroundTilesHolder.MoveTiles(direction); } } }