using System; using System.Collections.Generic; using System.Linq; using Cysharp.Threading.Tasks; using Unity.Mathematics; using UnityEngine; using Object = UnityEngine.Object; namespace DanieleMarotta.RiversongCodeShowcase { public class RoadVisualizationManager : GameSystem, IInitializable, IDisposable { [InjectService] private GameConfig _config; [InjectService] private IScene _scene; [InjectService] private ISignalBus _signalBus; [InjectService] private ITileSpace _tileSpace; [InjectService] private World _world; private readonly List _prefabs = new(); private readonly Dictionary _visualizations = new(); private GameObject _placementVfxPrefab; public RoadVisualizationManager(IServiceLocator serviceLocator) : base(serviceLocator) { } public async UniTask InitializeAsync() { var tilePrefabTasks = _config.Roads.Tiles.Select(tilePrefabRef => tilePrefabRef.LoadAssetAsync().ToUniTask()).ToArray(); var placementVfxTask = _config.Roads.PlacementVfxPrefab.LoadAssetAsync().ToUniTask(); var tilePrefabs = await UniTask.WhenAll(tilePrefabTasks); _prefabs.AddRange(tilePrefabs); _placementVfxPrefab = await placementVfxTask; _signalBus.Subscribe(OnRoadTileChanged); } public void Dispose() { foreach (var tilePrefabRef in _config.Roads.Tiles) tilePrefabRef.ReleaseAsset(); _config.Roads.PlacementVfxPrefab.ReleaseAsset(); _signalBus.Unsubscribe(OnRoadTileChanged); } private void OnRoadTileChanged(RoadTileUpdatedSignal signal) { var tile = signal.Tile; UpdateTile(tile); if (tile.x > 0) UpdateTile(tile + new int2(-1, 0)); if (tile.x < _world.Size.x - 1) UpdateTile(tile + new int2(1, 0)); if (tile.y > 0) UpdateTile(tile + new int2(0, -1)); if (tile.y < _world.Size.y - 1) UpdateTile(tile + new int2(0, 1)); if (signal.RoadTileAdded) SpawnPlacementVfx(tile); } private void UpdateTile(int2 tile) { if (_visualizations.TryGetValue(tile, out var visualization)) { Object.Destroy(visualization); _visualizations.Remove(tile); } if (!_world.RoadNetwork.IsRoadTile(tile)) return; visualization = Object.Instantiate(GetRoadTilePrefab(tile), _scene.SceneFolders.RoadTiles); visualization.transform.position = _tileSpace.TileToWorld(tile) + new Vector3(0, 0.001f, 0); _visualizations.Add(tile, visualization); } private GameObject GetRoadTilePrefab(int2 tile) { var connectivity = _world.RoadNetwork.GetConnectivity(tile); return _prefabs[(int)connectivity]; } private void SpawnPlacementVfx(int2 tile) { var position = _tileSpace.TileToWorld(tile); Object.Instantiate(_placementVfxPrefab, position, Quaternion.identity); } } }