using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.InputSystem; public class ItemPipe : MonoBehaviour { [Serializable] private class GuaranteedItem { public GameObject prefab; [Min(1)] public int amount = 1; } [Serializable] private class RandomItem { public GameObject prefab; [Min(0)] public float weight = 1f; } [Header("Pipe")] [SerializeField] private Transform spawnPoint; [SerializeField, Min(0.05f)] private float spawnInterval = 0.5f; [Header("Instant velocity change")] [SerializeField] private Vector3 localVelocityChange = Vector3.forward * 4.5f; [Header("Guaranteed items")] [SerializeField] private List guaranteedItems = new(); [Header("Random items")] [SerializeField, Min(0)] private int randomItemCount = 5; [SerializeField] private List randomItems = new(); [Header("Spawn position randomization")] [SerializeField, Min(0f)] private float randomSpawnX = 0.2f; [SerializeField, Min(0f)] private float randomSpawnZ = 0.2f; [Header("Temporary testing")] [SerializeField] private bool spawnOnE = true; private bool isSpawning; private void Update() { if (!spawnOnE || isSpawning || Keyboard.current == null) return; if (Keyboard.current.eKey.wasPressedThisFrame) StartCoroutine(SpawnSequence()); } private IEnumerator SpawnSequence() { isSpawning = true; List spawnQueue = BuildSpawnQueue(); foreach (GameObject prefab in spawnQueue) { Spawn(prefab); yield return new WaitForSeconds(spawnInterval); } isSpawning = false; } private List BuildSpawnQueue() { List queue = new(); // Добавляем предметы в точном количестве. foreach (GuaranteedItem item in guaranteedItems) { if (item.prefab == null) continue; for (int i = 0; i < item.amount; i++) queue.Add(item.prefab); } // Выбираем указанное количество случайных предметов. for (int i = 0; i < randomItemCount; i++) { GameObject selectedPrefab = ChooseWeightedRandom(); if (selectedPrefab != null) queue.Add(selectedPrefab); } // Перемешиваем гарантированные и случайные предметы вместе. Shuffle(queue); return queue; } private GameObject ChooseWeightedRandom() { float totalWeight = 0f; foreach (RandomItem item in randomItems) { if (item.prefab != null && item.weight > 0f) totalWeight += item.weight; } if (totalWeight <= 0f) return null; float roll = UnityEngine.Random.value * totalWeight; float currentWeight = 0f; foreach (RandomItem item in 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 = UnityEngine.Random.Range(0, i + 1); (queue[i], queue[randomIndex]) = (queue[randomIndex], queue[i]); } } private void Spawn(GameObject prefab) { if (prefab == null || spawnPoint == null) return; float offsetX = RandomRange(-randomSpawnX, randomSpawnX); float offsetZ = RandomRange(-randomSpawnZ, randomSpawnZ); Vector3 spawnPosition = spawnPoint.position + spawnPoint.right * offsetX + spawnPoint.forward * offsetZ; GameObject item = Instantiate( prefab, spawnPosition, UnityEngine.Random.rotationUniform ); if (item.TryGetComponent(out Rigidbody body)) { Vector3 worldVelocityChange = spawnPoint.TransformDirection(localVelocityChange); body.AddForce(worldVelocityChange, ForceMode.VelocityChange); } } private float RandomRange(float min, float max) { return UnityEngine.Random.Range(min, max); } }