using System.Collections.Generic; using UnityEngine; namespace Code.Gameplay.Level { public class LevelBuilder : MonoBehaviour { [Header("Tile Settings")] [SerializeField] private GameObject[] tilePrefabs; [SerializeField] private float tileLength = 6f; [SerializeField] private int numberOfTiles = 20; [SerializeField] private Transform playerTransform; [Header("Environment Settings")] [SerializeField] private GameObject[] treePrefabs; [SerializeField] private float sideOffset = 10f; [SerializeField] private float treeRandomSpread = 2f; [Header("Obstacles Settings")] [SerializeField] private GameObject[] lowObstacles; [SerializeField] private GameObject[] highObstacles; [SerializeField] private GameObject[] movingLowObstacles; [SerializeField] private GameObject[] movingHighObstacles; [Range(0, 100)] [SerializeField] private int obstacleChance = 40; [SerializeField] private float laneDistance = 5f; private readonly List _activeTiles = new(); private readonly List _activeEnvironment = new(); private float _spawnZ; private void Start() { for (var i = 0; i < numberOfTiles; i++) { SpawnTile(i < 10 ? 0 : Random.Range(0, tilePrefabs.Length), i >= 10); } } private void Update() { if (playerTransform.position.z - 35 > _spawnZ - numberOfTiles * tileLength) { SpawnTile(Random.Range(0, tilePrefabs.Length), true); DeleteTile(); } } private void SpawnTile(int tileIndex, bool spawnItems) { var tile = Instantiate(tilePrefabs[tileIndex], transform.forward * _spawnZ, transform.rotation); _activeTiles.Add(tile); SpawnEnvironment(_spawnZ); if (spawnItems) { SpawnObstacle(_spawnZ); } _spawnZ += tileLength; } private void SpawnObstacle(float zPos) { if (Random.Range(0, 100) > obstacleChance) return; var lane = Random.Range(-1, 2); var spawnPos = new Vector3(lane * laneDistance, 0, zPos); var type = Random.Range(0, 4); var prefab = type switch { 0 => GetRandom(lowObstacles), 1 => GetRandom(highObstacles), 2 => GetRandom(movingLowObstacles), 3 => GetRandom(movingHighObstacles), _ => null }; if (prefab) { var obs = Instantiate(prefab, spawnPos, Quaternion.Euler(0, 180, 0)); obs.transform.SetParent(_activeTiles[^1].transform); } } private GameObject GetRandom(GameObject[] array) { return array.Length > 0 ? array[Random.Range(0, array.Length)] : null; } private void SpawnEnvironment(float zPos) { var envContainer = new GameObject("EnvGroup_" + zPos); envContainer.transform.SetParent(transform); CreateTree(-sideOffset, zPos, envContainer.transform); CreateTree(sideOffset, zPos, envContainer.transform); _activeEnvironment.Add(envContainer); } private void CreateTree(float xOffset, float zPos, Transform parent) { if (treePrefabs.Length == 0) return; var spawnPos = new Vector3(xOffset + Random.Range(-treeRandomSpread, treeRandomSpread), 0, zPos + Random.Range(-treeRandomSpread, treeRandomSpread)); var tree = Instantiate(treePrefabs[Random.Range(0, treePrefabs.Length)], spawnPos, Quaternion.Euler(0, Random.Range(0, 360), 0)); tree.transform.SetParent(parent); } private void DeleteTile() { Destroy(_activeTiles[0]); _activeTiles.RemoveAt(0); Destroy(_activeEnvironment[0]); _activeEnvironment.RemoveAt(0); } } }