using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.InputSystem; public class ItemPipe : MonoBehaviour { [Header("Pipe")] [SerializeField] private Transform spawnPoint; [Header("Configuration")] [SerializeField] private ItemPipeConfig config; [Header("Temporary testing")] [SerializeField] private bool spawnOnE = true; private bool isSpawning; public float CooldownDuration => config != null ? config.SpawnCooldown : 0f; public float CooldownRemaining { get; private set; } public int CooldownSecondsRemaining => Mathf.CeilToInt(CooldownRemaining); public bool CanSpawnItems => config != null && !isSpawning && CooldownRemaining <= 0f; private void Update() { if (CooldownRemaining > 0f) CooldownRemaining = Mathf.Max(0f, CooldownRemaining - Time.deltaTime); if (!spawnOnE || Keyboard.current == null) return; if (Keyboard.current.eKey.wasPressedThisFrame) SpawnItems(); } public void SpawnItems() { if (!CanSpawnItems) return; StartCoroutine(SpawnSequence(config)); } private IEnumerator SpawnSequence(ItemPipeConfig activeConfig) { isSpawning = true; List spawnQueue = BuildSpawnQueue(activeConfig); for (int i = 0; i < spawnQueue.Count; i++) { Spawn(spawnQueue[i], activeConfig); if (i < spawnQueue.Count - 1) yield return new WaitForSeconds(activeConfig.SpawnInterval); } isSpawning = false; CooldownRemaining = activeConfig.SpawnCooldown; } private List BuildSpawnQueue(ItemPipeConfig activeConfig) { List queue = new(); // Добавляем предметы в точном количестве. foreach (ItemPipeConfig.GuaranteedItem item in activeConfig.GuaranteedItems) { if (item.prefab == null) continue; for (int i = 0; i < item.amount; i++) queue.Add(item.prefab); } // Выбираем указанное количество случайных предметов. for (int i = 0; i < activeConfig.RandomItemCount; i++) { GameObject selectedPrefab = ChooseWeightedRandom(activeConfig); if (selectedPrefab != null) queue.Add(selectedPrefab); } // Перемешиваем гарантированные и случайные предметы вместе. Shuffle(queue); return queue; } private GameObject ChooseWeightedRandom(ItemPipeConfig activeConfig) { float totalWeight = 0f; foreach (ItemPipeConfig.RandomItem item in activeConfig.RandomItems) { if (item.prefab != null && item.weight > 0f) totalWeight += item.weight; } if (totalWeight <= 0f) return null; float roll = Random.value * totalWeight; float currentWeight = 0f; foreach (ItemPipeConfig.RandomItem item in activeConfig.RandomItems) { if (item.prefab == null || item.weight <= 0f) continue; currentWeight += item.weight; if (roll < currentWeight) return item.prefab; } return null; } private void Shuffle(List queue) { for (int i = queue.Count - 1; i > 0; i--) { int randomIndex = Random.Range(0, i + 1); (queue[i], queue[randomIndex]) = (queue[randomIndex], queue[i]); } } private void Spawn(GameObject prefab, ItemPipeConfig activeConfig) { if (prefab == null || spawnPoint == null) return; float offsetX = RandomRange(-activeConfig.RandomSpawnX, activeConfig.RandomSpawnX); float offsetZ = RandomRange(-activeConfig.RandomSpawnZ, activeConfig.RandomSpawnZ); Vector3 spawnPosition = spawnPoint.position + spawnPoint.right * offsetX + spawnPoint.forward * offsetZ; GameObject item = Instantiate( prefab, spawnPosition, Random.rotationUniform ); if (item.TryGetComponent(out Rigidbody body)) { Vector3 worldVelocityChange = spawnPoint.TransformDirection(activeConfig.LocalVelocityChange); body.AddForce(worldVelocityChange, ForceMode.VelocityChange); } } private float RandomRange(float min, float max) { return Random.Range(min, max); } }