using System.Collections; using UnityEngine; using Boxes; public class VanController : MonoBehaviour { [Header("Движение")] public float forwardSpeed = 5.0f; public float moveSpeed = 10.0f; [Header("Спавн коробок")] public BoxData[] availableBoxes; public float spawnInterval = 0.5f; public float boxEjectionForce = 2f; public float boxTorqueForce = 5f; [Header("AI Уклонения")] public float detectionDistance = 40f; public LayerMask trafficLayer; private int _currentLaneIndex = 3; private float _targetX; private bool _isChangingLane; private float _totalSpawnWeight; private bool _isAlive = true; private int[] _safeLanesBuffer; private void OnEnable() { GameEvents.OnPlayerDied += StopActivities; } private void OnDisable() { GameEvents.OnPlayerDied -= StopActivities; } void Start() { _targetX = transform.position.x; _totalSpawnWeight = 0; foreach (var box in availableBoxes) { _totalSpawnWeight += box.spawnWeight; } _safeLanesBuffer = new int[RoadManager.Instance.GetLanesCount()]; StartCoroutine(SpawnBoxesInfinitely()); StartCoroutine(AvoidanceRoutine()); } void Update() { if (!_isAlive) return; transform.Translate(Vector3.forward * forwardSpeed * Time.deltaTime); Vector3 newPos = transform.position; newPos.x = Mathf.Lerp(newPos.x, _targetX, Time.deltaTime * moveSpeed); transform.position = newPos; } private void StopActivities() => _isAlive = false; IEnumerator SpawnBoxesInfinitely() { while (_isAlive) { yield return new WaitForSeconds(spawnInterval); SpawnPhysicalBox(); } } void SpawnPhysicalBox() { BoxData boxToSpawn = GetRandomBoxType(); if (boxToSpawn == null || boxToSpawn.boxPrefab == null) return; GameObject box = SimpleObjectPool.Instance.Get(boxToSpawn.boxPrefab, transform.position, Random.rotation); Box boxComponent = box.GetComponent(); if (boxComponent != null) boxComponent.Init(boxToSpawn); Rigidbody rb = box.GetComponent(); if (rb != null) { rb.linearVelocity = Vector3.zero; rb.angularVelocity = Vector3.zero; rb.AddForce(Vector3.back * boxEjectionForce, ForceMode.Impulse); rb.AddTorque(Random.insideUnitSphere * boxTorqueForce, ForceMode.Impulse); } } BoxData GetRandomBoxType() { if (availableBoxes.Length == 0) return null; float randomValue = Random.Range(0, _totalSpawnWeight); float currentWeight = 0; foreach (var boxData in availableBoxes) { currentWeight += boxData.spawnWeight; if (randomValue <= currentWeight) return boxData; } return null; } IEnumerator AvoidanceRoutine() { while (_isAlive) { yield return new WaitForSeconds(0.2f); if (_isChangingLane) continue; if (IsObstacleAhead()) TryToEvade(); } } bool IsObstacleAhead() => Physics.Raycast(transform.position, Vector3.forward, detectionDistance, trafficLayer); void TryToEvade() { int safeLanesCount = 0; int totalLanes = RoadManager.Instance.GetLanesCount(); for (int i = 0; i < totalLanes; i++) { if (i == _currentLaneIndex) continue; float laneX = RoadManager.Instance.GetLaneX(i); Vector3 checkPosition = new Vector3(laneX, transform.position.y, transform.position.z); if (!Physics.Raycast(checkPosition, Vector3.forward, detectionDistance, trafficLayer)) { _safeLanesBuffer[safeLanesCount] = i; safeLanesCount++; } } if (safeLanesCount > 0) { int chosenLane = _safeLanesBuffer[Random.Range(0, safeLanesCount)]; StartCoroutine(ChangeLane(chosenLane)); } } IEnumerator ChangeLane(int newLaneIndex) { _isChangingLane = true; _currentLaneIndex = newLaneIndex; _targetX = RoadManager.Instance.GetLaneX(newLaneIndex); yield return new WaitForSeconds(0.6f); _isChangingLane = false; } }